diff --git a/.gitignore b/.gitignore
index 7165536..0d12ff1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,5 @@ migrate_working_dir/
.packages
build/
credentials.json
+.flutter-plugins
+.flutter-plugins-dependencies
\ No newline at end of file
diff --git a/README.md b/README.md
index aadf226..45369f1 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,37 @@
# Flutter Credit/Debit Card Form
-### Preview
+## Features
+
+- [x] Scan card with camera
+- [x] Set value programmatically
+- [x] Create a custom theme
+- [x] Listen for input value changes
+- [x] Show card type icon
+
+## Preview
-### Usage
+## Usage
```dart
+import 'package:credit_card_form/credit_card_form.dart';
+
+...
+
+CardDataInputController controller = CardDataInputController();
+
CreditCardForm(
theme: CreditCardLightTheme(),
- onChanged: (CreditCardResult result) {
- print(result.cardNumber);
- print(result.cardHolderName);
- print(result.expirationMonth);
- print(result.expirationYear);
- print(result.cardType);
- print(result.cvc);
+ controller: controller,
+ onChanged: (CardData data) {
+ print(data.cardNumber);
+ print(data.cardHolderName);
+ print(data.expiredDate);
+ print(data.expiredMonth);
+ print(data.expiredYear);
+ print(data.cardType);
+ print(data.cvc);
},
),
```
@@ -23,7 +39,7 @@ CreditCardForm(
| Param | Description |
| -------------------- | ------------------------------------------------------------ |
| `theme` | card theme `CreditCardLightTheme()` or `CreditCardDarkTheme` |
-| `onChanged` required | listen for input values changed |
+| `onChanged`(required)| listen for input values changed |
| `cardNumberLabel` | label for card number input |
| `cardHolderLabel` | label for card holder name input |
| `hideCardHolder` | default (false) |
@@ -33,28 +49,26 @@ CreditCardForm(
| `cvcLength` | length for security code. default (4) |
| `cvcIcon` | Icon widget for security code. |
| `fontSize` | font size for all inputs and labels. default (16) |
-| `controller` | `CreditCardController()` to set initial value to inputs |
-
-### Set Credit Card Value Initially
+| `controller` | `CardDataInputController()` |
+| `enableScanner` | default (false), If set to true, please ensure you have granted camera permission in android and ios|
+| `scannerIcon` | Icon widget for scanner button. |
-```dart
-CreditCardController controller = CreditCardController();
+Note: For more information about enabling scanner, please refer to the [Card Scanner Package](https://pub.dev/packages/card_scanner)
-CreditCardForm(
- controller: controller,
- onChanged: (CreditCardResult result) {
- },
-),
+## Set Credit Card Value Programmatically
-controller.setValue(CreditCardValue(
- cardNumber: '4242 4242 4242 4242',
- cardHolderName: 'John Wick',
- expiryDate: '08/25',
-));
+```dart
+CardDataInputController controller = CardDataInputController();
+controller.value = CardData(
+ cardNumber: '4242424242424242',
+ cardHolderName: 'Zin Kyaw Kyaw',
+ expiredDate: '11/23',
+ cvc: '123',
+);
```
-### How to create custom theme
+## How to create custom theme
```dart
class CustomCardTheme implements CreditCardTheme {
@@ -70,10 +84,11 @@ class CustomCardTheme implements CreditCardTheme {
CreditCardForm(
theme: CustomCardTheme(),
- onChanged: (CreditCardResult result) {
+ onChanged: (CardData data) {
},
),
```
-### Development
+## Development
+
Want to contribute? Great! Fork the repo and create PR to us.
diff --git a/images/scanner.png b/images/scanner.png
new file mode 100644
index 0000000..e499cab
Binary files /dev/null and b/images/scanner.png differ
diff --git a/images/unionpay.png b/images/unionpay.png
new file mode 100644
index 0000000..966a498
Binary files /dev/null and b/images/unionpay.png differ
diff --git a/lib/card_types.dart b/lib/card_types.dart
new file mode 100644
index 0000000..3c87bd8
--- /dev/null
+++ b/lib/card_types.dart
@@ -0,0 +1,15 @@
+part of credit_card_form;
+
+enum CardType {
+ master,
+ visa,
+ verve,
+ discover,
+ americanExpress,
+ dinersClub,
+ jcb,
+ others,
+ unionPay,
+ mir,
+ invalid
+}
diff --git a/lib/component.dart b/lib/component.dart
deleted file mode 100644
index 4ce9eb2..0000000
--- a/lib/component.dart
+++ /dev/null
@@ -1,240 +0,0 @@
-part of credit_card_form;
-
-class CreditCardForm extends StatefulWidget {
- final String? cardNumberLabel;
- final String? cardHolderLabel;
- final bool? hideCardHolder;
- final String? expiredDateLabel;
- final String? cvcLabel;
- final Widget? cvcIcon;
- final int? cardNumberLength;
- final int? cvcLength;
- final double fontSize;
- final CreditCardTheme? theme;
- final Function(CreditCardResult) onChanged;
- final CreditCardController? controller;
- const CreditCardForm({
- super.key,
- this.theme,
- required this.onChanged,
- this.cardNumberLabel,
- this.cardHolderLabel,
- this.hideCardHolder = false,
- this.expiredDateLabel,
- this.cvcLabel,
- this.cvcIcon,
- this.cardNumberLength = 16,
- this.cvcLength = 4,
- this.fontSize = 16,
- this.controller,
- });
-
- @override
- State createState() => _CreditCardFormState();
-}
-
-class _CreditCardFormState extends State {
- Map params = {
- "card": '',
- "expired_date": '',
- "card_holder_name": '',
- "cvc": '',
- };
-
- Map cardImg = {
- "img": 'credit_card.png',
- "width": 30.0,
- };
-
- Map controllers = {
- "card": TextEditingController(),
- "expired_date": TextEditingController(),
- "card_holder_name": TextEditingController(),
- "cvc": TextEditingController(),
- };
-
- String error = '';
-
- CardType? cardType;
-
- @override
- void dispose() {
- controllers.forEach((key, value) => value.dispose());
- super.dispose();
- }
-
- @override
- void initState() {
- handleController();
- super.initState();
- }
-
- @override
- Widget build(BuildContext context) {
- CreditCardTheme theme = widget.theme ?? CreditCardLightTheme();
- return Container(
- decoration: BoxDecoration(
- color: theme.backgroundColor,
- border: Border.all(color: theme.borderColor, width: 1),
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(10),
- topRight: Radius.circular(10),
- bottomLeft: Radius.circular(10),
- bottomRight: Radius.circular(10),
- ),
- ),
- child: Column(
- children: [
- TextInputWidget(
- theme: theme,
- fontSize: widget.fontSize,
- controller: controllers['card'],
- label: widget.cardNumberLabel ?? 'Card number',
- bottom: 1,
- formatters: [
- FilteringTextInputFormatter.digitsOnly,
- LengthLimitingTextInputFormatter(widget.cardNumberLength),
- CardNumberInputFormatter(),
- ],
- onChanged: (val) {
- Map img = CardUtils.getCardIcon(val);
- CardType type =
- CardUtils.getCardTypeFrmNumber(val.replaceAll(' ', ''));
- setState(() {
- cardImg = img;
- cardType = type;
- params['card'] = val;
- });
- emitResult();
- },
- suffixIcon: Padding(
- padding: const EdgeInsets.all(8),
- child: Image.asset(
- 'images/${cardImg['img']}',
- package: 'credit_card_form',
- width: cardImg['width'] as double?,
- ),
- ),
- ),
- if (widget.hideCardHolder == false)
- TextInputWidget(
- theme: theme,
- fontSize: widget.fontSize,
- label: widget.cardHolderLabel ?? 'Card holder name',
- controller: controllers['card_holder_name'],
- bottom: 1,
- onChanged: (val) {
- setState(() {
- params['card_holder_name'] = val;
- });
- emitResult();
- },
- keyboardType: TextInputType.name,
- ),
- Row(
- children: [
- Expanded(
- child: TextInputWidget(
- theme: theme,
- fontSize: widget.fontSize,
- label: widget.expiredDateLabel ?? 'MM/YY',
- right: 1,
- onChanged: (val) {
- setState(() {
- params['expired_date'] = val;
- });
- emitResult();
- },
- controller: controllers['expired_date'],
- formatters: [
- CardExpirationFormatter(),
- LengthLimitingTextInputFormatter(5)
- ],
- ),
- ),
- Expanded(
- child: TextInputWidget(
- theme: theme,
- fontSize: widget.fontSize,
- label: widget.cvcLabel ?? 'CVC',
- controller: controllers['cvc'],
- password: true,
- onChanged: (val) {
- setState(() {
- params['cvc'] = val;
- });
- emitResult();
- },
- formatters: [
- FilteringTextInputFormatter.digitsOnly,
- LengthLimitingTextInputFormatter(widget.cvcLength)
- ],
- suffixIcon: Padding(
- padding: const EdgeInsets.all(8),
- child: widget.cvcIcon ??
- Image.asset(
- 'images/cvc.png',
- package: 'credit_card_form',
- height: 25,
- ),
- ),
- ),
- )
- ],
- )
- ],
- ),
- );
- }
-
- emitResult() {
- List res = params['expired_date'].split('/');
- CreditCardResult result = CreditCardResult(
- cardNumber: params['card'].replaceAll(' ', ''),
- cvc: params['cvc'],
- cardHolderName: params['card_holder_name'],
- expirationMonth: res[0] ?? '',
- expirationYear: res.asMap().containsKey(1) ? res[1] : '',
- cardType: cardType,
- );
- widget.onChanged(result);
- }
-
- handleController() {
- if (widget.controller != null) {
- widget.controller?.addListener(() {
- CreditCardValue? initialValue = widget.controller?.value;
- if (initialValue?.cardNumber != null) {
- TextEditingValue cardNumber =
- FilteringTextInputFormatter.digitsOnly.formatEditUpdate(
- const TextEditingValue(text: ''),
- TextEditingValue(text: initialValue!.cardNumber.toString()),
- );
-
- cardNumber = LengthLimitingTextInputFormatter(19).formatEditUpdate(
- const TextEditingValue(text: ''),
- TextEditingValue(text: cardNumber.text),
- );
-
- cardNumber = CardNumberInputFormatter().formatEditUpdate(
- const TextEditingValue(text: ''),
- TextEditingValue(text: cardNumber.text),
- );
-
- controllers['card']?.value = cardNumber;
- }
- if (initialValue?.cardHolderName != null) {
- controllers['card_holder_name']?.text =
- initialValue!.cardHolderName.toString();
- }
- if (initialValue?.expiryDate != null) {
- controllers['expired_date']?.value =
- CardExpirationFormatter().formatEditUpdate(
- const TextEditingValue(text: ''),
- TextEditingValue(text: initialValue!.expiryDate.toString()),
- );
- }
- });
- }
- }
-}
diff --git a/lib/credit_card_form.dart b/lib/credit_card_form.dart
index c050779..a27acd0 100644
--- a/lib/credit_card_form.dart
+++ b/lib/credit_card_form.dart
@@ -1,59 +1,13 @@
library credit_card_form;
+import 'package:card_scanner/card_scanner.dart';
import 'package:credit_card_form/text_input_widget.dart';
import 'package:credit_card_form/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-part 'component.dart';
+part 'card_types.dart';
+part 'credit_card_form_widget.dart';
+part 'scanner_button.dart';
part 'theme.dart';
-
-enum CardType {
- master,
- visa,
- verve,
- discover,
- americanExpress,
- dinersClub,
- jcb,
- others,
- mir,
- invalid
-}
-
-class CreditCardController extends ChangeNotifier {
- CreditCardValue value = CreditCardValue();
-
- void setValue(CreditCardValue initialValue) {
- value = initialValue;
- notifyListeners();
- }
-}
-
-class CreditCardResult {
- final String cardNumber;
- final String cvc;
- final String cardHolderName;
- final String expirationMonth;
- final String expirationYear;
- final CardType? cardType;
- const CreditCardResult({
- required this.cardNumber,
- required this.cvc,
- required this.cardHolderName,
- required this.expirationMonth,
- required this.expirationYear,
- this.cardType,
- });
-}
-
-class CreditCardValue {
- String? cardNumber;
- String? cardHolderName;
- String? expiryDate;
- CreditCardValue({
- this.cardNumber,
- this.cardHolderName,
- this.expiryDate,
- });
-}
+part 'types.dart';
diff --git a/lib/credit_card_form_widget.dart b/lib/credit_card_form_widget.dart
new file mode 100644
index 0000000..3706049
--- /dev/null
+++ b/lib/credit_card_form_widget.dart
@@ -0,0 +1,177 @@
+part of credit_card_form;
+
+class CreditCardForm extends StatefulWidget {
+ final String? cardNumberLabel;
+ final String? cardHolderLabel;
+ final bool? hideCardHolder;
+ final bool? enableScanner;
+ final Widget? scannerIcon;
+ final CardScanOptions? scanOptions;
+ final String? expiredDateLabel;
+ final String? cvcLabel;
+ final Widget? cvcIcon;
+ final int? cardNumberLength;
+ final int? cvcLength;
+ final double fontSize;
+ final CreditCardTheme? theme;
+ final Function(CardData) onChanged;
+ final CardDataInputController controller;
+ const CreditCardForm({
+ super.key,
+ this.theme,
+ required this.onChanged,
+ this.cardNumberLabel,
+ this.cardHolderLabel,
+ this.hideCardHolder = false,
+ this.enableScanner = false,
+ this.scannerIcon,
+ this.scanOptions,
+ this.expiredDateLabel,
+ this.cvcLabel,
+ this.cvcIcon,
+ this.cardNumberLength = 16,
+ this.cvcLength = 4,
+ this.fontSize = 16,
+ required this.controller,
+ });
+
+ @override
+ State createState() => _CreditCardFormState();
+}
+
+class _CreditCardFormState extends State {
+ // card image
+ CardImage cardImage = const CardImage();
+
+ // card type
+ CardType? cardType;
+
+ @override
+ void dispose() {
+ widget.controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ widget.controller.cardNumber.addListener(() {
+ setState(() {
+ cardImage = CardUtils.getCardIcon(widget.controller.cardNumber.text);
+ cardType = widget.controller.value.cardType;
+ emitResult();
+ });
+ });
+ widget.controller.cardHolderName.addListener(() {
+ emitResult();
+ });
+ widget.controller.expiredDate.addListener(() {
+ emitResult();
+ });
+ widget.controller.cvc.addListener(() {
+ emitResult();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ CreditCardTheme theme = widget.theme ?? CreditCardLightTheme();
+ return Container(
+ decoration: BoxDecoration(
+ color: theme.backgroundColor,
+ border: Border.all(color: theme.borderColor, width: 1),
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(10),
+ topRight: Radius.circular(10),
+ bottomLeft: Radius.circular(10),
+ bottomRight: Radius.circular(10),
+ ),
+ ),
+ child: Column(children: [
+ // [card number]
+ TextInputWidget(
+ theme: theme,
+ fontSize: widget.fontSize,
+ controller: widget.controller.cardNumber,
+ label: widget.cardNumberLabel ?? 'Card number',
+ bottom: 1,
+ formatters: [
+ FilteringTextInputFormatter.digitsOnly,
+ LengthLimitingTextInputFormatter(widget.cardNumberLength),
+ CardNumberInputFormatter(),
+ ],
+ onChanged: noop,
+ suffixIcon: Padding(
+ padding: const EdgeInsets.all(8),
+ child: widget.enableScanner == true && cardType == null
+ ? ScannerButton(
+ controller: widget.controller,
+ onChanged: widget.onChanged,
+ scannerIcon: widget.scannerIcon,
+ scanOptions: widget.scanOptions,
+ )
+ : cardImage.render(),
+ ),
+ ),
+ // [card holder name]
+ if (widget.hideCardHolder == false)
+ TextInputWidget(
+ theme: theme,
+ fontSize: widget.fontSize,
+ label: widget.cardHolderLabel ?? 'Card holder name',
+ controller: widget.controller.cardHolderName,
+ bottom: 1,
+ onChanged: noop,
+ keyboardType: TextInputType.name,
+ ),
+ // [expired date]
+ Row(
+ children: [
+ Expanded(
+ child: TextInputWidget(
+ theme: theme,
+ fontSize: widget.fontSize,
+ label: widget.expiredDateLabel ?? 'MM/YY',
+ right: 1,
+ onChanged: noop,
+ controller: widget.controller.expiredDate,
+ formatters: [
+ CardExpirationFormatter(),
+ LengthLimitingTextInputFormatter(5)
+ ],
+ ),
+ ),
+ // [cvc]
+ Expanded(
+ child: TextInputWidget(
+ theme: theme,
+ fontSize: widget.fontSize,
+ label: widget.cvcLabel ?? 'CVC',
+ controller: widget.controller.cvc,
+ password: true,
+ onChanged: noop,
+ formatters: [
+ FilteringTextInputFormatter.digitsOnly,
+ LengthLimitingTextInputFormatter(widget.cvcLength)
+ ],
+ suffixIcon: Padding(
+ padding: const EdgeInsets.all(8),
+ child: widget.cvcIcon ??
+ Image.asset(
+ 'images/cvc.png',
+ package: 'credit_card_form',
+ height: 25,
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ ]),
+ );
+ }
+
+ emitResult() {
+ widget.onChanged(widget.controller.value);
+ }
+}
diff --git a/lib/scanner_button.dart b/lib/scanner_button.dart
new file mode 100644
index 0000000..bf9175e
--- /dev/null
+++ b/lib/scanner_button.dart
@@ -0,0 +1,52 @@
+part of credit_card_form;
+
+class ScannerButton extends StatelessWidget {
+ final CardDataInputController controller;
+
+ final CardScanOptions? scanOptions;
+
+ final Widget? scannerIcon;
+
+ final Function(CardData) onChanged;
+
+ const ScannerButton({
+ super.key,
+ required this.controller,
+ required this.onChanged,
+ this.scanOptions,
+ this.scannerIcon,
+ });
+
+ void onTap() async {
+ CardDetails? cardDetails = await CardScanner.scanCard(
+ scanOptions: scanOptions ??
+ const CardScanOptions(
+ scanExpiryDate: true,
+ cardScannerTimeOut: 3000,
+ enableLuhnCheck: false,
+ considerPastDatesInExpiryDateScan: true,
+ ),
+ );
+ if (cardDetails != null) {
+ controller.value = CardData(
+ cardNumber: cardDetails.cardNumber,
+ cardHolderName: cardDetails.cardHolderName,
+ expiredDate: cardDetails.expiryDate,
+ );
+ onChanged(controller.value);
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: onTap,
+ child: scannerIcon ??
+ Image.asset(
+ 'images/scanner.png',
+ package: 'credit_card_form',
+ width: 30.0,
+ ),
+ );
+ }
+}
diff --git a/lib/types.dart b/lib/types.dart
new file mode 100644
index 0000000..4ae5c90
--- /dev/null
+++ b/lib/types.dart
@@ -0,0 +1,134 @@
+part of credit_card_form;
+
+class CreditCardController extends ChangeNotifier {
+ CardData value = CardData();
+
+ void setValue(CardData initialValue) {
+ value = initialValue;
+ notifyListeners();
+ }
+}
+
+class CardData {
+ String cardNumber;
+ String expiredDate;
+ String cardHolderName;
+ String cvc;
+ CardType? cardType;
+
+ CardData({
+ this.cardNumber = '',
+ this.expiredDate = '',
+ this.cardHolderName = '',
+ this.cvc = '',
+ this.cardType,
+ }) {
+ // remove all spaces
+ cardNumber = cardNumber.replaceAll(' ', '');
+ }
+
+ // get expired month
+ String get expiredMonth {
+ if (expiredDate.isEmpty) return '';
+ List year = expiredDate.split('/');
+ if (year.isNotEmpty) return year[0];
+ return '';
+ }
+
+ // get expired year
+ String get expiredYear {
+ if (expiredDate.isEmpty) return '';
+ List year = expiredDate.split('/');
+ if (year.length > 1) return year[1];
+ return '';
+ }
+}
+
+class CardDataInputController extends ChangeNotifier {
+ TextEditingController cardNumber;
+ TextEditingController expiredDate;
+ TextEditingController cardHolderName;
+ TextEditingController cvc;
+
+ CardDataInputController({
+ TextEditingController? cardNumber,
+ TextEditingController? expiredDate,
+ TextEditingController? cardHolderName,
+ TextEditingController? cvc,
+ }) : cardNumber = cardNumber ?? TextEditingController(),
+ expiredDate = expiredDate ?? TextEditingController(),
+ cardHolderName = cardHolderName ?? TextEditingController(),
+ cvc = cvc ?? TextEditingController();
+
+ @override
+ void dispose() {
+ super.dispose();
+ cardNumber.dispose();
+ expiredDate.dispose();
+ cardHolderName.dispose();
+ cvc.dispose();
+ }
+
+ set value(CardData data) {
+ // format to text only
+ TextEditingValue formattedCardNumber =
+ FilteringTextInputFormatter.digitsOnly.formatEditUpdate(
+ const TextEditingValue(text: ''),
+ TextEditingValue(text: data.cardNumber.toString()),
+ );
+
+ // limit to 19 digits
+ formattedCardNumber = LengthLimitingTextInputFormatter(19).formatEditUpdate(
+ const TextEditingValue(text: ''),
+ TextEditingValue(text: formattedCardNumber.text),
+ );
+
+ // format to card number
+ formattedCardNumber = CardNumberInputFormatter().formatEditUpdate(
+ const TextEditingValue(text: ''),
+ TextEditingValue(text: formattedCardNumber.text),
+ );
+
+ cardNumber.text = formattedCardNumber.text;
+
+ // expired date
+ expiredDate.value = CardExpirationFormatter().formatEditUpdate(
+ const TextEditingValue(text: ''),
+ TextEditingValue(text: data.expiredDate.toString()),
+ );
+
+ // card holder name
+ cardHolderName.text = data.cardHolderName;
+
+ // cvc
+ cvc.text = data.cvc;
+ }
+
+ CardData get value {
+ return CardData(
+ cardNumber: cardNumber.text,
+ expiredDate: expiredDate.text,
+ cardHolderName: cardHolderName.text,
+ cvc: cvc.text,
+ cardType: CardUtils.getCardTypeFrmNumber(cardNumber.text),
+ );
+ }
+}
+
+class CardImage {
+ final String img;
+ final double width;
+
+ const CardImage({
+ this.img = 'credit_card.png',
+ this.width = 30.0,
+ });
+
+ Widget render() {
+ return Image.asset(
+ 'images/$img',
+ package: 'credit_card_form',
+ width: width,
+ );
+ }
+}
diff --git a/lib/utils.dart b/lib/utils.dart
index a6b4731..c4e3212 100644
--- a/lib/utils.dart
+++ b/lib/utils.dart
@@ -51,8 +51,8 @@ class CardNumberInputFormatter extends TextInputFormatter {
}
class CardUtils {
- static Map getCardIcon(input) {
- CardType cardType =
+ static CardImage getCardIcon(String input) {
+ CardType? cardType =
CardUtils.getCardTypeFrmNumber(input.replaceAll(' ', ''));
String img = "";
double imgWidth = 30.0;
@@ -85,6 +85,10 @@ class CardUtils {
img = 'brand_mir.png';
imgWidth = 50.0;
break;
+ case CardType.unionPay:
+ img = 'unionpay.png';
+ imgWidth = 50.0;
+ break;
case CardType.others:
img = 'credit_card.png';
break;
@@ -92,11 +96,14 @@ class CardUtils {
img = 'credit_card.png';
break;
}
- return {"img": img, "width": imgWidth};
+ return CardImage(img: img, width: imgWidth);
}
- static CardType getCardTypeFrmNumber(String input) {
- CardType cardType;
+ static CardType? getCardTypeFrmNumber(String input) {
+ if (input.isEmpty) {
+ return null;
+ }
+ CardType? cardType;
if (input.startsWith(RegExp(
r'((5[1-5])|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720))'))) {
cardType = CardType.master;
@@ -112,6 +119,8 @@ class CardUtils {
cardType = CardType.jcb;
} else if (input.startsWith(RegExp(r'(220[0-4])'))) {
cardType = CardType.mir;
+ } else if (input.startsWith(RegExp(r'(62|81)'))) {
+ cardType = CardType.unionPay;
} else if (input.length <= 8) {
cardType = CardType.others;
} else {
@@ -132,3 +141,5 @@ class HexColor extends Color {
return int.parse(hexColor, radix: 16);
}
}
+
+void noop(_) => {};
diff --git a/pubspec.yaml b/pubspec.yaml
index 371d725..2d4e685 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,15 +1,16 @@
name: credit_card_form
description: Flutter Credit/Debit Card Form.
-version: 0.0.7
+version: 1.0.0
homepage: https://github.com/necessarylion/flutter-credit-card-form
environment:
- sdk: '>=2.18.2 <3.0.0'
+ sdk: '>=2.18.2 <4.0.0'
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
+ card_scanner:
dev_dependencies:
flutter_test: