├── Example ├── Screens │ └── dark1.gif ├── Demo1-not library │ ├── CreditCardForm │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── Amex.imageset │ │ │ │ ├── amex.png │ │ │ │ └── Contents.json │ │ │ ├── Visa.imageset │ │ │ │ ├── visa (1).png │ │ │ │ └── Contents.json │ │ │ ├── chip.imageset │ │ │ │ ├── CC_chip.png │ │ │ │ └── Contents.json │ │ │ ├── Discover.imageset │ │ │ │ ├── discover.png │ │ │ │ └── Contents.json │ │ │ ├── MasterCard.imageset │ │ │ │ ├── mastercard.png │ │ │ │ └── Contents.json │ │ │ ├── JCB.imageset │ │ │ │ ├── 1478638835_jcb_card_payment.png │ │ │ │ └── Contents.json │ │ │ ├── Diners Club.imageset │ │ │ │ ├── 1478638761_dinner_club.png │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── AppDelegate.swift │ │ └── ViewController.swift │ ├── CreditCardForm.xcworkspace │ │ ├── xcuserdata │ │ │ └── atakishiyev.xcuserdatad │ │ │ │ ├── xcdebugger │ │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── contents.xcworkspacedata │ ├── Podfile │ └── Podfile.lock └── Demo2-CreditCardFormLibarary │ ├── Demo │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── JCB.imageset │ │ │ ├── JCB.png │ │ │ └── Contents.json │ │ ├── Amex.imageset │ │ │ ├── Amex.png │ │ │ └── Contents.json │ │ ├── Visa.imageset │ │ │ ├── Visa.png │ │ │ └── Contents.json │ │ ├── chip.imageset │ │ │ ├── chip.png │ │ │ └── Contents.json │ │ ├── Discover.imageset │ │ │ ├── Discover.png │ │ │ └── Contents.json │ │ ├── Diners Club.imageset │ │ │ ├── Diners Club.png │ │ │ └── Contents.json │ │ ├── Mastercard.imageset │ │ │ ├── Mastercard.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── CreditCardForm.xcworkspace │ │ ├── xcuserdata │ │ │ └── atakishiyev.xcuserdatad │ │ │ │ ├── xcdebugger │ │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── contents.xcworkspacedata │ ├── TextField.swift │ ├── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── AppDelegate.swift │ └── ViewController.swift │ ├── Demo.xcworkspace │ ├── xcuserdata │ │ └── atakishiyev.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── xcschemes │ │ └── Demo.xcscheme │ ├── Demo.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── atakishiyev.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcuserdata │ │ └── atakishiyev.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── project.pbxproj │ ├── Podfile │ └── Podfile.lock ├── CreditCardForm ├── Images.xcassets │ ├── Contents.json │ ├── JCB.imageset │ │ ├── JCB.png │ │ └── Contents.json │ ├── Amex.imageset │ │ ├── Amex.png │ │ └── Contents.json │ ├── Visa.imageset │ │ ├── Visa.png │ │ └── Contents.json │ ├── chip.imageset │ │ ├── chip.png │ │ └── Contents.json │ ├── amexCvc.imageset │ │ ├── Group-1.png │ │ ├── Group.png │ │ └── Contents.json │ ├── Discover.imageset │ │ ├── Discover.png │ │ └── Contents.json │ ├── UnionPay.imageset │ │ ├── UnionPay.png │ │ └── Contents.json │ ├── MasterCard.imageset │ │ ├── Mastercard.png │ │ └── Contents.json │ └── Diners Club.imageset │ │ ├── Diners Club.png │ │ └── Contents.json ├── Classes │ ├── AKMaskFieldEvent.swift │ ├── AKMaskFieldStatus.swift │ ├── CreditCardValidationType.swift │ ├── AKMaskFieldPatternCharacter.swift │ ├── AKMaskFieldBlockCharacter.swift │ ├── Utilities.swift │ ├── AKMaskFieldBlock.swift │ ├── AKMaskFieldUtility.swift │ ├── CreditCardValidator.swift │ ├── AKMaskField.swift │ └── CreditCardFormView.swift └── CreditCardForm.h ├── CreditCardForm.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── atakishiyev.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── atakishiyev.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── CreditCardForm.xcscheme └── project.pbxproj ├── .gitignore ├── .travis.yml ├── CreditCardFormTests ├── Info.plist └── CreditCardFormTests.swift ├── Info.plist ├── CreditCardForm.podspec ├── LICENSE └── README.md /Example/Screens/dark1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Screens/dark1.gif -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/JCB.imageset/JCB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/JCB.imageset/JCB.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Amex.imageset/Amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/Amex.imageset/Amex.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Visa.imageset/Visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/Visa.imageset/Visa.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/chip.imageset/chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/chip.imageset/chip.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/amexCvc.imageset/Group-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/amexCvc.imageset/Group-1.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/amexCvc.imageset/Group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/amexCvc.imageset/Group.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Discover.imageset/Discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/Discover.imageset/Discover.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/UnionPay.imageset/UnionPay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/UnionPay.imageset/UnionPay.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/MasterCard.imageset/Mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/MasterCard.imageset/Mastercard.png -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Diners Club.imageset/Diners Club.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm/Images.xcassets/Diners Club.imageset/Diners Club.png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Amex.imageset/amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/Amex.imageset/amex.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/JCB.imageset/JCB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/JCB.imageset/JCB.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Amex.imageset/Amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Amex.imageset/Amex.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Visa.imageset/Visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Visa.imageset/Visa.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/chip.imageset/chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/chip.imageset/chip.png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Visa.imageset/visa (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/Visa.imageset/visa (1).png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/chip.imageset/CC_chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/chip.imageset/CC_chip.png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Discover.imageset/discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/Discover.imageset/discover.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Discover.imageset/Discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Discover.imageset/Discover.png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/MasterCard.imageset/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/MasterCard.imageset/mastercard.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Diners Club.imageset/Diners Club.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Diners Club.imageset/Diners Club.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Mastercard.imageset/Mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Mastercard.imageset/Mastercard.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/JCB.imageset/1478638835_jcb_card_payment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/JCB.imageset/1478638835_jcb_card_payment.png -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Diners Club.imageset/1478638761_dinner_club.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm/Assets.xcassets/Diners Club.imageset/1478638761_dinner_club.png -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/project.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/CreditCardForm.xcodeproj/project.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo1-not library/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | ## Build generated 4 | build/ 5 | DerivedData/ 6 | 7 | Example/Demo1-not library/Pods/ 8 | Example/Demo2-CreditCardFormLibarary/Pods/ 9 | 10 | CreditCardFormTests/ 11 | CreditCardForm.xcodeproj/project.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate 12 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo/CreditCardForm.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcodeproj/project.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orazz/CreditCardForm-iOS/HEAD/Example/Demo2-CreditCardFormLibarary/Demo.xcodeproj/project.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode11 2 | language: objective-c 3 | podfile: Example/Demo2-CreditCardFormLibarary/Podfile 4 | before_install: 5 | - gem install cocoapods 6 | - pod repo update 7 | - pod install --project-directory=Example/Demo2-CreditCardFormLibarary/ 8 | script: xcodebuild -workspace Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace -scheme Demo -sdk iphonesimulator 9 | -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/JCB.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "JCB.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Amex.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Amex.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Visa.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Visa.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/chip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "chip.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Discover.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Discover.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/UnionPay.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "UnionPay.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/MasterCard.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Mastercard.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/CreditCardForm.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/Diners Club.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Diners Club.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Amex.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "amex.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Amex.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Amex.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/JCB.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "JCB.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Visa.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Visa.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/chip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "chip.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | target 'Demo' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for Demo 9 | pod "Stripe" 10 | pod 'CreditCardForm', :git => 'https://github.com/orazz/CreditCardForm-iOS', branch: 'master' 11 | # pod 'CreditCardForm' 12 | end 13 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Visa.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "visa (1).png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/chip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "CC_chip.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Discover.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "discover.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/MasterCard.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mastercard.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Discover.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Discover.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldEvent.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | /// Event constant value received after manipulations with the Mask Field. 12 | enum AKMaskFieldEvent { 13 | case error, insert, delete ,replace 14 | } 15 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldStatus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldStatus.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | /// The Mask Field, Block and Block Character status property constant. 12 | enum AKMaskFieldStatus { 13 | case clear, incomplete, complete 14 | } 15 | -------------------------------------------------------------------------------- /Example/Demo1-not library/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'CreditCardForm' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for CreditCardForm 9 | pod "Stripe" 10 | pod 'AKMaskField', :git => 'https://github.com/artemkrachulov/AKMaskField.git', :tag => 'v2.0.1' 11 | pod "CreditCardValidator" 12 | end 13 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Diners Club.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Diners Club.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/Mastercard.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Mastercard.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/JCB.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1478638835_jcb_card_payment.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CreditCardForm/Images.xcassets/amexCvc.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "Group.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "Group-1.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/Diners Club.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1478638761_dinner_club.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcuserdata/atakishiyev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Demo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcodeproj/xcuserdata/atakishiyev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SuppressBuildableAutocreation 8 | 9 | 8EC8C45A1DED83D10044FB44 10 | 11 | primary 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /CreditCardForm/CreditCardForm.h: -------------------------------------------------------------------------------- 1 | // 2 | // CreditCardForm.h 3 | // CreditCardForm 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/28/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CreditCardForm. 12 | FOUNDATION_EXPORT double CreditCardFormVersionNumber; 13 | 14 | //! Project version string for CreditCardForm. 15 | FOUNDATION_EXPORT const unsigned char CreditCardFormVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/TextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextField.swift 3 | // Demo 4 | // 5 | // Created by Oraz Atakishiyev on 5/30/20. 6 | // Copyright © 2020 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TextField: UITextField { 12 | 13 | let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) 14 | 15 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 16 | return bounds.inset(by: padding) 17 | } 18 | 19 | override open func placeholderRect(forBounds bounds: CGRect) -> CGRect { 20 | return bounds.inset(by: padding) 21 | } 22 | 23 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 24 | return bounds.inset(by: padding) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/xcuserdata/atakishiyev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CreditCardForm.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 8EC8C3C81DEC8C3E0044FB44 16 | 17 | primary 18 | 19 | 20 | 8EC8C3D11DEC8C3E0044FB44 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CreditCardFormTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CreditCardForm (0.2.0) 3 | - Stripe (17.0.3) 4 | 5 | DEPENDENCIES: 6 | - CreditCardForm (from `https://github.com/orazz/CreditCardForm-iOS`, branch `master`) 7 | - Stripe 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Stripe 12 | 13 | EXTERNAL SOURCES: 14 | CreditCardForm: 15 | :branch: master 16 | :git: https://github.com/orazz/CreditCardForm-iOS 17 | 18 | CHECKOUT OPTIONS: 19 | CreditCardForm: 20 | :commit: dbafedcf6ecebb7d6c6b75d1f3bc8787a95e5b10 21 | :git: https://github.com/orazz/CreditCardForm-iOS 22 | 23 | SPEC CHECKSUMS: 24 | CreditCardForm: bba4aad545236f97f2dc45ea3bed0cb57d5e0e99 25 | Stripe: 30ba9a2ac7297e93de561fed695222ef980ee521 26 | 27 | PODFILE CHECKSUM: b70fd5f5c314cafe698f9253d5a630d5a098ec25 28 | 29 | COCOAPODS: 1.8.4 30 | -------------------------------------------------------------------------------- /Example/Demo1-not library/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AKMaskField (2.0.1) 3 | - CreditCardValidator (0.3.2) 4 | - Stripe (8.0.7) 5 | 6 | DEPENDENCIES: 7 | - AKMaskField (from `https://github.com/artemkrachulov/AKMaskField.git`, tag `v2.0.1`) 8 | - CreditCardValidator 9 | - Stripe 10 | 11 | EXTERNAL SOURCES: 12 | AKMaskField: 13 | :git: https://github.com/artemkrachulov/AKMaskField.git 14 | :tag: v2.0.1 15 | 16 | CHECKOUT OPTIONS: 17 | AKMaskField: 18 | :git: https://github.com/artemkrachulov/AKMaskField.git 19 | :tag: v2.0.1 20 | 21 | SPEC CHECKSUMS: 22 | AKMaskField: cf9e98c5ebd459998f5db1bdc6e810479a865063 23 | CreditCardValidator: f2e0fc0f273e3f303513d35745df23d336eb1d67 24 | Stripe: 2bb9646115745d0ee8c7799e6872c57ba5dc6cc5 25 | 26 | PODFILE CHECKSUM: 52647c88b71ca77c6f2e3325345490e01c88351e 27 | 28 | COCOAPODS: 1.1.0.rc.2 29 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/CreditCardValidationType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreditCardValidationType.swift 3 | // 4 | // Created by Vitaliy Kuzmenko on 02/06/15. 5 | // Copyright (c) 2015. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | public func ==(lhs: CreditCardValidationType, rhs: CreditCardValidationType) -> Bool { 11 | return lhs.name == rhs.name 12 | } 13 | 14 | public struct CreditCardValidationType: Equatable { 15 | 16 | public var name: String 17 | 18 | public var regex: String 19 | 20 | public init(dict: [String: Any]) { 21 | if let name = dict["name"] as? String { 22 | self.name = name 23 | } else { 24 | self.name = "" 25 | } 26 | 27 | if let regex = dict["regex"] as? String { 28 | self.regex = regex 29 | } else { 30 | self.regex = "" 31 | } 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldPatternCharacter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldPatternCharacter.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | /// Single block character pattern constant. 12 | enum AKMaskFieldPatternCharacter: String { 13 | 14 | // MARK: - Constants 15 | 16 | case NumberDecimal = "d" 17 | case NonDecimal = "D" 18 | case NonWord = "W" 19 | case Alphabet = "a" 20 | case AnyChar = "." 21 | 22 | /// Returns regular expression pattern. 23 | func pattern() -> String { 24 | switch self { 25 | case .NumberDecimal : return "\\d" 26 | case .NonDecimal : return "\\D" 27 | case .NonWord : return "\\W" 28 | case .Alphabet : return "[a-zA-Z]" 29 | default : return "." 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CreditCardForm.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "CreditCardForm" 4 | s.version = "0.2.0" 5 | s.summary = "CreditCardForm is iOS framework" 6 | 7 | s.description = "CreditCardForm is iOS framework that allows developers to create the UI which replicates an actual Credit Card" 8 | s.homepage = "https://github.com/CreditCardForm" 9 | s.screenshots = 'https://camo.githubusercontent.com/e30bcc0537ff4aa4adae4f39ad664aeb2fd7db76/68747470733a2f2f646f746a70672e636f2f3862752e706e67' 10 | s.license = { :type => "MIT" } 11 | s.author = { "orazz" => "orazz.tm@gmail.com" } 12 | s.platform = :ios, "8.0" 13 | s.source = { :git => "https://github.com/orazz/CreditCardForm-iOS.git", :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = '8.0' 16 | 17 | s.source_files = "CreditCardForm/Classes/*.swift", "CreditCardForm/*.{h,m}" 18 | s.resource_bundles = { 19 | 'CreditCardForm' => ['CreditCardForm/Images.xcassets'] 20 | } 21 | s.frameworks = 'UIKit' 22 | s.swift_versions = "4.2" 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 - 2017 Orazz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CreditCardFormTests/CreditCardFormTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreditCardFormTests.swift 3 | // CreditCardFormTests 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/28/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import CreditCardForm 11 | 12 | class CreditCardFormTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldBlockCharacter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldBlockCharacter.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | import Foundation 12 | 13 | /// A structure that contains the block character main properties. 14 | public struct AKMaskFieldBlockCharacter { 15 | 16 | // MARK: - General 17 | 18 | /// Character index in the block. 19 | var index: Int 20 | 21 | /// The block index in the mask. 22 | var blockIndex: Int 23 | 24 | /// Current character status. 25 | var status: AKMaskFieldStatus 26 | 27 | // MARK: - Pattern 28 | 29 | /// The mask pattern character. 30 | var pattern: AKMaskFieldPatternCharacter! 31 | 32 | /// Location of the pattern character in the mask. 33 | var patternRange: NSRange 34 | 35 | // MARK: - Mask template 36 | 37 | /// The mask template character. 38 | var template: Character! 39 | 40 | /// Location of the mask template character in the mask template. 41 | var templateRange: NSRange 42 | } -------------------------------------------------------------------------------- /CreditCardForm/Classes/Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.swift 3 | // CreditCardForm 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/29/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | class func hexStr ( hexStr : NSString, alpha : CGFloat) -> UIColor { 13 | let hexStr = hexStr.replacingOccurrences(of: "#", with: "") 14 | let scanner = Scanner(string: hexStr as String) 15 | var color: UInt32 = 0 16 | if scanner.scanHexInt32(&color) { 17 | let r = CGFloat((color & 0xFF0000) >> 16) / 255.0 18 | let g = CGFloat((color & 0x00FF00) >> 8) / 255.0 19 | let b = CGFloat(color & 0x0000FF) / 255.0 20 | return UIColor(red:r,green:g,blue:b,alpha:alpha) 21 | } else { 22 | print("invalid hex string", terminator: "") 23 | return UIColor.white; 24 | } 25 | } 26 | } 27 | 28 | extension Bundle { 29 | /// Create a new Bundle instance for 'Image.xcassets'. 30 | /// 31 | /// - Returns: a new bundle which contains 'Image.xcassets'. 32 | static func currentBundle() -> Bundle { 33 | let bundle = Bundle(for: CreditCardFormView.self) 34 | if let path = bundle.path(forResource: "CreditCardForm", ofType: "bundle") { 35 | return Bundle(path: path)! 36 | } else { 37 | return bundle 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldBlock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldBlock.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | import Foundation 12 | 13 | /// A structure that contains the mask block main properties. 14 | public struct AKMaskFieldBlock { 15 | 16 | // MARK: - General 17 | 18 | /// Block index in the mask 19 | var index: Int 20 | 21 | /// Returns the current block status. 22 | var status: AKMaskFieldStatus { 23 | 24 | let completedChars: [AKMaskFieldBlockCharacter] = chars.filter { return $0.status != .clear } 25 | 26 | switch completedChars.count { 27 | case 0 : return .clear 28 | case chars.count : return .complete 29 | default : return .incomplete 30 | } 31 | } 32 | 33 | /// An array containing all characters inside block. 34 | var chars: [AKMaskFieldBlockCharacter] 35 | 36 | // MARK: - Pattern 37 | 38 | /// The mask pattern that represent current block. 39 | var pattern: String { 40 | 41 | var pattern: String = "" 42 | for char in chars { 43 | pattern += char.pattern.rawValue 44 | } 45 | return pattern 46 | } 47 | 48 | /// Location of the mask pattern in the mask. 49 | var patternRange: NSRange { 50 | return NSMakeRange(chars.first!.patternRange.location, chars.count) 51 | } 52 | 53 | // MARK: - Mask template 54 | 55 | /// The mask template string that represent current block. 56 | var template: String { 57 | var template: String = "" 58 | for char in chars { 59 | template.append(char.template) 60 | } 61 | return template 62 | } 63 | 64 | /// Location of the mask template string in the mask template. 65 | var templateRange: NSRange { 66 | return NSMakeRange(chars.first!.templateRange.location, chars.count) 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CreditCardForum 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/5/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Demo 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/29/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcworkspace/xcshareddata/xcschemes/Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskFieldUtility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskFieldUtility.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | 11 | import UIKit 12 | 13 | class AKMaskFieldUtility { 14 | 15 | /// [Source](http://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index) 16 | class func rangeFromString(_ string: String, nsRange: NSRange) -> Range! { 17 | 18 | 19 | guard 20 | let from16 = string.utf16.index(string.utf16.startIndex, offsetBy: nsRange.location, limitedBy: string.utf16.endIndex), 21 | let to16 = string.utf16.index(from16, offsetBy: nsRange.length, limitedBy: string.utf16.endIndex), 22 | let from = String.Index(from16, within: string), 23 | let to = String.Index(to16, within: string) 24 | else { return nil } 25 | return from ..< to 26 | /* 27 | 28 | let from16 = string.utf16.startIndex.advancedBy(nsRange.location, limit: string.utf16.endIndex) 29 | let to16 = from16.advancedBy(nsRange.length, limit: string.utf16.endIndex) 30 | 31 | if let from = String.Index(from16, within: string), 32 | let to = String.Index(to16, within: string) { 33 | return from ..< to 34 | } 35 | return nil*/ 36 | } 37 | 38 | class func substring(_ sourceString: String?, withNSRange range: NSRange) -> String { 39 | guard let sourceString = sourceString else { 40 | return "" 41 | } 42 | #if swift(>=4) 43 | return String(sourceString[rangeFromString(sourceString, nsRange: range)]) 44 | #else 45 | return sourceString.substring(with: rangeFromString(sourceString, nsRange: range)) 46 | #endif 47 | } 48 | 49 | class func replace(_ sourceString: inout String!, withString string: String, inRange range: NSRange) { 50 | sourceString = sourceString.replacingCharacters(in: rangeFromString(sourceString, nsRange: range), with: string) 51 | } 52 | 53 | class func replacingOccurrencesOfString(_ string: inout String!, target: String, withString replacement: String) { 54 | string = string.replacingOccurrences(of: target, with: replacement, options: .regularExpression, range: nil) 55 | } 56 | 57 | class func maskField(_ maskField: UITextField, moveCaretToPosition position: Int) { 58 | guard let caretPosition = maskField.position(from: maskField.beginningOfDocument, offset: position) else { 59 | return 60 | } 61 | 62 | maskField.selectedTextRange = maskField.textRange(from: caretPosition, to: caretPosition) 63 | } 64 | 65 | class func matchesInString(_ string: String, pattern: String) -> [NSTextCheckingResult] { 66 | return try! 67 | NSRegularExpression(pattern: pattern, options: .caseInsensitive) 68 | .matches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, string.count)) 69 | } 70 | 71 | class func findIntersection(_ ranges: [NSRange], withRange range: NSRange) -> [NSRange?] { 72 | 73 | var intersectRanges = [NSRange?]() 74 | 75 | for r in ranges { 76 | 77 | var intersectRange: NSRange! 78 | 79 | let delta = r.location - range.location 80 | var location, length, tail: Int 81 | 82 | if delta <= 0 { 83 | location = range.location 84 | length = range.length 85 | tail = r.length - abs(delta) 86 | } else { 87 | location = r.location 88 | length = r.length 89 | tail = range.length - abs(delta) 90 | } 91 | 92 | if tail > 0 && length > 0 { 93 | intersectRange = NSMakeRange(location, min(tail, length)) 94 | } 95 | 96 | intersectRanges.append(intersectRange) 97 | } 98 | return intersectRanges 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/xcshareddata/xcschemes/CreditCardForm.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/CreditCardValidator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreditCardValidator.swift 3 | // 4 | // Created by Vitaliy Kuzmenko on 02/06/15. 5 | // Copyright (c) 2015. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | public class CreditCardValidator { 11 | 12 | public lazy var types: [CreditCardValidationType] = { 13 | var types = [CreditCardValidationType]() 14 | for object in CreditCardValidator.types { 15 | types.append(CreditCardValidationType(dict: object)) 16 | } 17 | return types 18 | }() 19 | 20 | public init() { } 21 | 22 | /** 23 | Get card type from string 24 | 25 | - parameter string: card number string 26 | 27 | - returns: CreditCardValidationType structure 28 | */ 29 | public func type(from string: String) -> CreditCardValidationType? { 30 | for type in types { 31 | let predicate = NSPredicate(format: "SELF MATCHES %@", type.regex) 32 | let numbersString = self.onlyNumbers(string: string) 33 | if predicate.evaluate(with: numbersString) { 34 | return type 35 | } 36 | } 37 | return nil 38 | } 39 | 40 | /** 41 | Validate card number 42 | 43 | - parameter string: card number string 44 | 45 | - returns: true or false 46 | */ 47 | public func validate(string: String) -> Bool { 48 | let numbers = self.onlyNumbers(string: string) 49 | if numbers.count < 9 { 50 | return false 51 | } 52 | 53 | var reversedString = "" 54 | let range: Range = numbers.startIndex.. () in 57 | reversedString += substring! 58 | } 59 | 60 | var oddSum = 0, evenSum = 0 61 | let reversedArray = reversedString 62 | 63 | for (i, s) in reversedArray.enumerated() { 64 | 65 | let digit = Int(String(s))! 66 | 67 | if i % 2 == 0 { 68 | evenSum += digit 69 | } else { 70 | oddSum += digit / 5 + (2 * digit) % 10 71 | } 72 | } 73 | return (oddSum + evenSum) % 10 == 0 74 | } 75 | 76 | /** 77 | Validate card number string for type 78 | 79 | - parameter string: card number string 80 | - parameter type: CreditCardValidationType structure 81 | 82 | - returns: true or false 83 | */ 84 | public func validate(string: String, forType type: CreditCardValidationType) -> Bool { 85 | return self.type(from: string) == type 86 | } 87 | 88 | public func onlyNumbers(string: String) -> String { 89 | let set = CharacterSet.decimalDigits.inverted 90 | let numbers = string.components(separatedBy: set) 91 | return numbers.joined(separator: "") 92 | } 93 | 94 | // MARK: - Loading data 95 | 96 | private static let types = [ 97 | [ 98 | "name": "Amex", 99 | "regex": "^3[47][0-9]{5,}$" 100 | ], [ 101 | "name": "Visa", 102 | "regex": "^4[0-9]{6,}$" 103 | ], [ 104 | "name": "MasterCard", 105 | "regex": "^5[1-5][0-9]{5,}$" 106 | ], [ 107 | "name": "Maestro", 108 | "regex": "^(?:5[0678]\\d\\d|6304|6390|67\\d\\d)\\d{8,15}$" 109 | ], [ 110 | "name": "Diners Club", 111 | "regex": "^3(?:0[0-5]|[68][0-9])[0-9]{4,}$" 112 | ], [ 113 | "name": "JCB", 114 | "regex": "^(?:2131|1800|35[0-9]{3})[0-9]{3,}$" 115 | ], [ 116 | "name": "Discover", 117 | "regex": "^6(?:011|5[0-9]{2})[0-9]{3,}$" 118 | ], [ 119 | "name": "UnionPay", 120 | "regex": "^62[0-5]\\d{13,16}$" 121 | ] 122 | ] 123 | 124 | } 125 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Demo 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/29/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Stripe 11 | import CreditCardForm 12 | 13 | class ViewController: UIViewController, STPPaymentCardTextFieldDelegate { 14 | 15 | @IBOutlet weak var creditCardView: CreditCardFormView! 16 | let paymentTextField = STPPaymentCardTextField() 17 | private var cardHolderNameTextField: TextField! 18 | private var cardParams: STPPaymentMethodCardParams! 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | creditCardView.cardHolderString = "Oraz Atakishiyev" 23 | creditCardView.cardGradientColors[Brands.Amex.rawValue] = [UIColor.red, UIColor.black] 24 | creditCardView.cardNumberFont = UIFont(name: "HelveticaNeue", size: 20)! 25 | creditCardView.cardPlaceholdersFont = UIFont(name: "HelveticaNeue", size: 10)! 26 | creditCardView.cardTextFont = UIFont(name: "HelveticaNeue", size: 12)! 27 | 28 | paymentTextField.postalCodeEntryEnabled = false 29 | 30 | createTextField() 31 | 32 | cardParams = STPPaymentMethodCardParams() 33 | cardParams.number = "375987654321111" 34 | cardParams.expMonth = 03 35 | cardParams.expYear = 23 36 | cardParams.cvc = "7997" 37 | self.paymentTextField.cardParams = cardParams 38 | } 39 | 40 | override func viewDidAppear(_ animated: Bool) { 41 | super.viewDidAppear(animated) 42 | 43 | // load saved card params 44 | creditCardView.paymentCardTextFieldDidChange(cardNumber: cardParams.number, expirationYear: cardParams!.expYear as? UInt, expirationMonth: cardParams!.expMonth as? UInt, cvc: cardParams.cvc) 45 | } 46 | 47 | func createTextField() { 48 | cardHolderNameTextField = TextField(frame: CGRect(x: 15, y: 199, width: self.view.frame.size.width - 30, height: 44)) 49 | cardHolderNameTextField.placeholder = "CARD HOLDER" 50 | cardHolderNameTextField.delegate = self 51 | cardHolderNameTextField.translatesAutoresizingMaskIntoConstraints = false 52 | cardHolderNameTextField.setBottomBorder() 53 | cardHolderNameTextField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged) 54 | view.addSubview(cardHolderNameTextField) 55 | 56 | paymentTextField.frame = CGRect(x: 15, y: 199, width: self.view.frame.size.width - 30, height: 44) 57 | paymentTextField.delegate = self 58 | paymentTextField.translatesAutoresizingMaskIntoConstraints = false 59 | paymentTextField.borderWidth = 0 60 | 61 | let border = CALayer() 62 | let width = CGFloat(1.0) 63 | border.borderColor = UIColor.darkGray.cgColor 64 | border.frame = CGRect(x: 0, y: paymentTextField.frame.size.height - width, width: paymentTextField.frame.size.width, height: paymentTextField.frame.size.height) 65 | border.borderWidth = width 66 | paymentTextField.layer.addSublayer(border) 67 | paymentTextField.layer.masksToBounds = true 68 | 69 | view.addSubview(paymentTextField) 70 | 71 | NSLayoutConstraint.activate([ 72 | cardHolderNameTextField.topAnchor.constraint(equalTo: creditCardView.bottomAnchor, constant: 20), 73 | cardHolderNameTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor), 74 | cardHolderNameTextField.widthAnchor.constraint(equalToConstant: self.view.frame.size.width-25), 75 | cardHolderNameTextField.heightAnchor.constraint(equalToConstant: 44) 76 | ]) 77 | 78 | NSLayoutConstraint.activate([ 79 | paymentTextField.topAnchor.constraint(equalTo: cardHolderNameTextField.bottomAnchor, constant: 20), 80 | paymentTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor), 81 | paymentTextField.widthAnchor.constraint(equalToConstant: self.view.frame.size.width-20), 82 | paymentTextField.heightAnchor.constraint(equalToConstant: 44) 83 | ]) 84 | } 85 | 86 | func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) { 87 | creditCardView.paymentCardTextFieldDidChange(cardNumber: textField.cardNumber, expirationYear: textField.expirationYear, expirationMonth: textField.expirationMonth, cvc: textField.cvc) 88 | } 89 | 90 | func paymentCardTextFieldDidEndEditingExpiration(_ textField: STPPaymentCardTextField) { 91 | creditCardView.paymentCardTextFieldDidEndEditingExpiration(expirationYear: textField.expirationYear) 92 | } 93 | 94 | func paymentCardTextFieldDidBeginEditingCVC(_ textField: STPPaymentCardTextField) { 95 | creditCardView.paymentCardTextFieldDidBeginEditingCVC() 96 | } 97 | 98 | func paymentCardTextFieldDidEndEditingCVC(_ textField: STPPaymentCardTextField) { 99 | creditCardView.paymentCardTextFieldDidEndEditingCVC() 100 | } 101 | } 102 | 103 | extension ViewController: UITextFieldDelegate { 104 | @objc func textFieldDidChange(_ textField: UITextField) { 105 | creditCardView.cardHolderString = textField.text! 106 | } 107 | 108 | func textFieldShouldReturn(_ textField: UITextField) -> Bool { 109 | if textField == cardHolderNameTextField { 110 | textField.resignFirstResponder() 111 | paymentTextField.becomeFirstResponder() 112 | } else if textField == paymentTextField { 113 | textField.resignFirstResponder() 114 | } 115 | return true 116 | } 117 | } 118 | 119 | extension UITextField { 120 | 121 | func setBottomBorder() { 122 | self.borderStyle = UITextField.BorderStyle.none 123 | let border = CALayer() 124 | let width = CGFloat(1.0) 125 | border.borderColor = UIColor.darkGray.cgColor 126 | border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height) 127 | border.borderWidth = width 128 | self.layer.addSublayer(border) 129 | self.layer.masksToBounds = true 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CreditCardForm 2 | 3 | [![CI Status](https://travis-ci.org/orazz/CreditCardForm-iOS.svg?branch=master)](https://travis-ci.org/orazz/CreditCardForm-iOS) 4 | CocoaPods compatible 6 | [![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | Swift 4.2 compatible 8 | Platform iOS 9 | License: MIT 10 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSV5DLQRJ5AH2&lc=US&item_name=Oraz%20Atakishiyev&item_number=PageMenu¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) 11 | 12 | CreditCardForm is iOS framework that allows developers to create the UI which replicates an actual Credit Card. 13 | 14 | Fixed typo use CreditCardForm instead ~~CreditCardForum~~ 15 | 16 | ### Screenshots 17 | 18 | 19 | ## Example 20 | 21 | To run the example project, clone the repo, and run `pod install` from the Demo-\* directory first. 22 | 23 | ## Supported Cards 24 | 25 | - [x] MasterCard 26 | - [x] Visa 27 | - [x] JCB 28 | - [x] Diners 29 | - [x] Discover 30 | - [x] Amex 31 | - [x] UnionPay 32 | 33 | ## Requirements 34 | 35 | * Xcode 8 36 | * iOS 8.1+ 37 | 38 | ## Installation 39 | 40 | #### Using [CocoaPods](http://cocoapods.org) 41 | 42 | CreditCardForm is available through CocoaPods. To install it, simply add the following line to your `Podfile`: 43 | 44 | ```ruby 45 | pod "CreditCardForm" 46 | ``` 47 | 48 | #### Using [Carthage](https://github.com/Carthage/Carthage) 49 | 50 | CreditCardForm is available through Carthage. To install it, simply add the following line to your `Cartfile`: 51 | 52 | ```ruby 53 | github "orazz/CreditCardForm-iOS" 54 | ``` 55 | 56 | #### Manually 57 | 58 | If you prefer not to use either of the aforementioned dependency managers, you can integrate CreditCardForm into your project manually. 59 | 60 | 1. Download and drop ```CreditCardForm``` in your project. 61 | 2. Done! 62 | 63 | ## Usage example 64 | 65 | First step: this framework integrated with Stripe, you must install [Stripe](https://stripe.com/docs/mobile/ios) 66 | 67 | #### Storyboard 68 | Create a view set a class CreditCardFormView (preferred frame size: 300x200).
69 | Following this you will have to go through a few simple steps outlined below in order to get everything up and running. 70 | ``` swift 71 | import Stripe 72 | import CreditCardForm 73 | ``` 74 | #### Swift 75 | ``` swift 76 | @IBOutlet weak var creditCardForm: CreditCardFormView! 77 | 78 | // Stripe textField 79 | let paymentTextField = STPPaymentCardTextField() 80 | ``` 81 | 82 | #### Add the following code in the viewDidLoad function in your view controller 83 | 84 | ```swift 85 | // Set up stripe textfield 86 | paymentTextField.frame = CGRect(x: 15, y: 199, width: self.view.frame.size.width - 30, height: 44) 87 | paymentTextField.translatesAutoresizingMaskIntoConstraints = false 88 | paymentTextField.borderWidth = 0 89 | 90 | let border = CALayer() 91 | let width = CGFloat(1.0) 92 | border.borderColor = UIColor.darkGray.cgColor 93 | border.frame = CGRect(x: 0, y: paymentTextField.frame.size.height - width, width: paymentTextField.frame.size.width, height: paymentTextField.frame.size.height) 94 | border.borderWidth = width 95 | paymentTextField.layer.addSublayer(border) 96 | paymentTextField.layer.masksToBounds = true 97 | 98 | view.addSubview(paymentTextField) 99 | 100 | NSLayoutConstraint.activate([ 101 | paymentTextField.topAnchor.constraint(equalTo: creditCardForm.bottomAnchor, constant: 20), 102 | paymentTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor), 103 | paymentTextField.widthAnchor.constraint(equalToConstant: self.view.frame.size.width-20), 104 | paymentTextField.heightAnchor.constraint(equalToConstant: 44) 105 | ]) 106 | ``` 107 | 108 | #### Delegate Methods 109 | 110 | In order to use the delegate methods first set the delegate of Stripe to the parent view controller when setting it up 111 | 112 | ``` swift 113 | paymentTextField.delegate = self 114 | ``` 115 | 116 | After that you will be able to set up the following delegate methods inside of your parent view controller 117 | 118 | ``` swift 119 | func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) { 120 | creditCardForm.paymentCardTextFieldDidChange(cardNumber: textField.cardNumber, expirationYear: textField.expirationYear, expirationMonth: textField.expirationMonth, cvc: textField.cvc) 121 | } 122 | 123 | func paymentCardTextFieldDidEndEditingExpiration(_ textField: STPPaymentCardTextField) { 124 | creditCardForm.paymentCardTextFieldDidEndEditingExpiration(expirationYear: textField.expirationYear) 125 | } 126 | 127 | func paymentCardTextFieldDidBeginEditingCVC(_ textField: STPPaymentCardTextField) { 128 | creditCardForm.paymentCardTextFieldDidBeginEditingCVC() 129 | } 130 | 131 | func paymentCardTextFieldDidEndEditingCVC(_ textField: STPPaymentCardTextField) { 132 | creditCardForm.paymentCardTextFieldDidEndEditingCVC() 133 | } 134 | ``` 135 | 136 | **You should now be ready to use CreditCardForm!!** 137 | 138 | ## Customization 139 | 140 | **1) Colors** 141 | ``` swift 142 | creditCardForm.backgroundColor (UIColor) 143 | creditCardForm.cardHolderExpireDateColor (UIColor) 144 | creditCardForm.cardHolderExpireDateTextColor (UIColor) 145 | creditCardForm.backLineColor (UIColor) 146 | 147 | // Brands Color brand name, front color, back color 148 | [String: [UIColor]] 149 | 150 | creditCardForm.cardGradientColors[Brands.Visa.rawValue] = [UIColor.blue, UIColor.red] 151 | 152 | // Set font 153 | creditCardForm.cardNumberFont = UIFont(name: "FontName", size: 20)! 154 | creditCardForm.cardPlaceholdersFont = UIFont(name: "FontName", size: 10)! 155 | creditCardForm.cardTextFont = UIFont(name: "FontName", size: 12)! 156 | ``` 157 | **2) Images** 158 | ``` swift 159 | creditCardForm.chipImage (UIImage) 160 | ``` 161 | **3) Placeholders** 162 | ``` swift 163 | creditCardForm.cardHolderString (String) 164 | creditCardForm.expireDatePlaceholderText (String) 165 | ``` 166 | **Card number: [Configuring the Mask Field](https://github.com/artemkrachulov/AKMaskField#configuring-the-mask-field)** 167 | ``` swift 168 | creditCardForm.cardNumberMaskExpression (String) 169 | creditCardForm.cardNumberMaskTemplate (String) 170 | 171 | creditCardForm.cardNumberFontSize (CGFloat) 172 | ``` 173 | ## Contribute 174 | 175 | We would love for you to contribute to **CreditCardForm**, check the ``LICENSE`` file for more info. 176 | 177 | ## Meta 178 | 179 | [Oraz Atakishiyev](https://github.com/orazz), [orazz.com](https://orazz.com) 180 | 181 | #### 3rd party libraries 182 | 183 | [CreditCardValidator](https://github.com/vitkuzmenko/CreditCardValidator)
184 | [AKMaskField](https://github.com/artemkrachulov/AKMaskField) 185 | 186 | ## License 187 | 188 | CreditCardForm is available under the MIT license. See the LICENSE file for more info. 189 | -------------------------------------------------------------------------------- /Example/Demo2-CreditCardFormLibarary/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8EA30DCE2482BE3900B53105 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA30DCD2482BE3900B53105 /* TextField.swift */; }; 11 | 8EC8C45F1DED83D10044FB44 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C45E1DED83D10044FB44 /* AppDelegate.swift */; }; 12 | 8EC8C4611DED83D10044FB44 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4601DED83D10044FB44 /* ViewController.swift */; }; 13 | 8EC8C4641DED83D10044FB44 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8EC8C4621DED83D10044FB44 /* Main.storyboard */; }; 14 | 8EC8C4661DED83D10044FB44 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8EC8C4651DED83D10044FB44 /* Assets.xcassets */; }; 15 | 8EC8C4691DED83D10044FB44 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8EC8C4671DED83D10044FB44 /* LaunchScreen.storyboard */; }; 16 | D7EC8EC8DADC52E74838081D /* Pods_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AD1CB681857222D8D4AF1BC /* Pods_Demo.framework */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 8EC8C4D91DED92620044FB44 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1BA2AAEE0DEE33072083F3FD /* Pods-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"; sourceTree = ""; }; 34 | 3AD1CB681857222D8D4AF1BC /* Pods_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 8EA30DCD2482BE3900B53105 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; 36 | 8EC8C45B1DED83D10044FB44 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 8EC8C45E1DED83D10044FB44 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 38 | 8EC8C4601DED83D10044FB44 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 39 | 8EC8C4631DED83D10044FB44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 40 | 8EC8C4651DED83D10044FB44 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 41 | 8EC8C4681DED83D10044FB44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 42 | 8EC8C46A1DED83D10044FB44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | CBFCE409C80D5996E69369E9 /* Pods-Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig"; sourceTree = ""; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | 8EC8C4581DED83D10044FB44 /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | D7EC8EC8DADC52E74838081D /* Pods_Demo.framework in Frameworks */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 8EC8C4521DED83D10044FB44 = { 59 | isa = PBXGroup; 60 | children = ( 61 | 8EC8C45D1DED83D10044FB44 /* Demo */, 62 | 8EC8C45C1DED83D10044FB44 /* Products */, 63 | CDAF11DB2D7B559BEABEB94A /* Pods */, 64 | AC1394A317E29C6ADDFCE125 /* Frameworks */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | 8EC8C45C1DED83D10044FB44 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 8EC8C45B1DED83D10044FB44 /* Demo.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | 8EC8C45D1DED83D10044FB44 /* Demo */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 8EC8C45E1DED83D10044FB44 /* AppDelegate.swift */, 80 | 8EC8C4601DED83D10044FB44 /* ViewController.swift */, 81 | 8EC8C4621DED83D10044FB44 /* Main.storyboard */, 82 | 8EC8C4651DED83D10044FB44 /* Assets.xcassets */, 83 | 8EC8C4671DED83D10044FB44 /* LaunchScreen.storyboard */, 84 | 8EC8C46A1DED83D10044FB44 /* Info.plist */, 85 | 8EA30DCD2482BE3900B53105 /* TextField.swift */, 86 | ); 87 | path = Demo; 88 | sourceTree = ""; 89 | }; 90 | AC1394A317E29C6ADDFCE125 /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 3AD1CB681857222D8D4AF1BC /* Pods_Demo.framework */, 94 | ); 95 | name = Frameworks; 96 | sourceTree = ""; 97 | }; 98 | CDAF11DB2D7B559BEABEB94A /* Pods */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 1BA2AAEE0DEE33072083F3FD /* Pods-Demo.debug.xcconfig */, 102 | CBFCE409C80D5996E69369E9 /* Pods-Demo.release.xcconfig */, 103 | ); 104 | name = Pods; 105 | sourceTree = ""; 106 | }; 107 | /* End PBXGroup section */ 108 | 109 | /* Begin PBXNativeTarget section */ 110 | 8EC8C45A1DED83D10044FB44 /* Demo */ = { 111 | isa = PBXNativeTarget; 112 | buildConfigurationList = 8EC8C46D1DED83D10044FB44 /* Build configuration list for PBXNativeTarget "Demo" */; 113 | buildPhases = ( 114 | 7D3C87E15FC61D189894AE69 /* [CP] Check Pods Manifest.lock */, 115 | 8EC8C4571DED83D10044FB44 /* Sources */, 116 | 8EC8C4581DED83D10044FB44 /* Frameworks */, 117 | 8EC8C4591DED83D10044FB44 /* Resources */, 118 | 7D953CEABE5FF802CACA32E6 /* [CP] Embed Pods Frameworks */, 119 | 8EC8C4D91DED92620044FB44 /* Embed Frameworks */, 120 | ); 121 | buildRules = ( 122 | ); 123 | dependencies = ( 124 | ); 125 | name = Demo; 126 | productName = Demo; 127 | productReference = 8EC8C45B1DED83D10044FB44 /* Demo.app */; 128 | productType = "com.apple.product-type.application"; 129 | }; 130 | /* End PBXNativeTarget section */ 131 | 132 | /* Begin PBXProject section */ 133 | 8EC8C4531DED83D10044FB44 /* Project object */ = { 134 | isa = PBXProject; 135 | attributes = { 136 | LastSwiftUpdateCheck = 0820; 137 | LastUpgradeCheck = 1000; 138 | ORGANIZATIONNAME = Veriloft; 139 | TargetAttributes = { 140 | 8EC8C45A1DED83D10044FB44 = { 141 | CreatedOnToolsVersion = 8.2; 142 | DevelopmentTeam = 683U48NZTT; 143 | LastSwiftMigration = 0910; 144 | ProvisioningStyle = Automatic; 145 | }; 146 | }; 147 | }; 148 | buildConfigurationList = 8EC8C4561DED83D10044FB44 /* Build configuration list for PBXProject "Demo" */; 149 | compatibilityVersion = "Xcode 3.2"; 150 | developmentRegion = English; 151 | hasScannedForEncodings = 0; 152 | knownRegions = ( 153 | English, 154 | en, 155 | Base, 156 | ); 157 | mainGroup = 8EC8C4521DED83D10044FB44; 158 | productRefGroup = 8EC8C45C1DED83D10044FB44 /* Products */; 159 | projectDirPath = ""; 160 | projectRoot = ""; 161 | targets = ( 162 | 8EC8C45A1DED83D10044FB44 /* Demo */, 163 | ); 164 | }; 165 | /* End PBXProject section */ 166 | 167 | /* Begin PBXResourcesBuildPhase section */ 168 | 8EC8C4591DED83D10044FB44 /* Resources */ = { 169 | isa = PBXResourcesBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | 8EC8C4691DED83D10044FB44 /* LaunchScreen.storyboard in Resources */, 173 | 8EC8C4661DED83D10044FB44 /* Assets.xcassets in Resources */, 174 | 8EC8C4641DED83D10044FB44 /* Main.storyboard in Resources */, 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | /* End PBXResourcesBuildPhase section */ 179 | 180 | /* Begin PBXShellScriptBuildPhase section */ 181 | 7D3C87E15FC61D189894AE69 /* [CP] Check Pods Manifest.lock */ = { 182 | isa = PBXShellScriptBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | ); 186 | inputPaths = ( 187 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 188 | "${PODS_ROOT}/Manifest.lock", 189 | ); 190 | name = "[CP] Check Pods Manifest.lock"; 191 | outputPaths = ( 192 | "$(DERIVED_FILE_DIR)/Pods-Demo-checkManifestLockResult.txt", 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | shellPath = /bin/sh; 196 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 197 | showEnvVarsInLog = 0; 198 | }; 199 | 7D953CEABE5FF802CACA32E6 /* [CP] Embed Pods Frameworks */ = { 200 | isa = PBXShellScriptBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | inputPaths = ( 205 | "${PODS_ROOT}/Target Support Files/Pods-Demo/Pods-Demo-frameworks.sh", 206 | "${BUILT_PRODUCTS_DIR}/CreditCardForm/CreditCardForm.framework", 207 | "${BUILT_PRODUCTS_DIR}/Stripe/Stripe.framework", 208 | ); 209 | name = "[CP] Embed Pods Frameworks"; 210 | outputPaths = ( 211 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CreditCardForm.framework", 212 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.framework", 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | shellPath = /bin/sh; 216 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Demo/Pods-Demo-frameworks.sh\"\n"; 217 | showEnvVarsInLog = 0; 218 | }; 219 | /* End PBXShellScriptBuildPhase section */ 220 | 221 | /* Begin PBXSourcesBuildPhase section */ 222 | 8EC8C4571DED83D10044FB44 /* Sources */ = { 223 | isa = PBXSourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | 8EA30DCE2482BE3900B53105 /* TextField.swift in Sources */, 227 | 8EC8C4611DED83D10044FB44 /* ViewController.swift in Sources */, 228 | 8EC8C45F1DED83D10044FB44 /* AppDelegate.swift in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin PBXVariantGroup section */ 235 | 8EC8C4621DED83D10044FB44 /* Main.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | 8EC8C4631DED83D10044FB44 /* Base */, 239 | ); 240 | name = Main.storyboard; 241 | sourceTree = ""; 242 | }; 243 | 8EC8C4671DED83D10044FB44 /* LaunchScreen.storyboard */ = { 244 | isa = PBXVariantGroup; 245 | children = ( 246 | 8EC8C4681DED83D10044FB44 /* Base */, 247 | ); 248 | name = LaunchScreen.storyboard; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXVariantGroup section */ 252 | 253 | /* Begin XCBuildConfiguration section */ 254 | 8EC8C46B1DED83D10044FB44 /* Debug */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 264 | CLANG_WARN_BOOL_CONVERSION = YES; 265 | CLANG_WARN_COMMA = YES; 266 | CLANG_WARN_CONSTANT_CONVERSION = YES; 267 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 268 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 269 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 270 | CLANG_WARN_EMPTY_BODY = YES; 271 | CLANG_WARN_ENUM_CONVERSION = YES; 272 | CLANG_WARN_INFINITE_RECURSION = YES; 273 | CLANG_WARN_INT_CONVERSION = YES; 274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 279 | CLANG_WARN_STRICT_PROTOTYPES = YES; 280 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | DEBUG_INFORMATION_FORMAT = dwarf; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | ENABLE_TESTABILITY = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_DYNAMIC_NO_PIC = NO; 290 | GCC_NO_COMMON_BLOCKS = YES; 291 | GCC_OPTIMIZATION_LEVEL = 0; 292 | GCC_PREPROCESSOR_DEFINITIONS = ( 293 | "DEBUG=1", 294 | "$(inherited)", 295 | ); 296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 298 | GCC_WARN_UNDECLARED_SELECTOR = YES; 299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 300 | GCC_WARN_UNUSED_FUNCTION = YES; 301 | GCC_WARN_UNUSED_VARIABLE = YES; 302 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 303 | MTL_ENABLE_DEBUG_INFO = YES; 304 | ONLY_ACTIVE_ARCH = YES; 305 | SDKROOT = iphoneos; 306 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 307 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 308 | TARGETED_DEVICE_FAMILY = "1,2"; 309 | }; 310 | name = Debug; 311 | }; 312 | 8EC8C46C1DED83D10044FB44 /* Release */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_ANALYZER_NONNULL = YES; 317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 318 | CLANG_CXX_LIBRARY = "libc++"; 319 | CLANG_ENABLE_MODULES = YES; 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 322 | CLANG_WARN_BOOL_CONVERSION = YES; 323 | CLANG_WARN_COMMA = YES; 324 | CLANG_WARN_CONSTANT_CONVERSION = YES; 325 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 327 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 328 | CLANG_WARN_EMPTY_BODY = YES; 329 | CLANG_WARN_ENUM_CONVERSION = YES; 330 | CLANG_WARN_INFINITE_RECURSION = YES; 331 | CLANG_WARN_INT_CONVERSION = YES; 332 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 333 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 334 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 335 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 337 | CLANG_WARN_STRICT_PROTOTYPES = YES; 338 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 344 | ENABLE_NS_ASSERTIONS = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 355 | MTL_ENABLE_DEBUG_INFO = NO; 356 | SDKROOT = iphoneos; 357 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 358 | TARGETED_DEVICE_FAMILY = "1,2"; 359 | VALIDATE_PRODUCT = YES; 360 | }; 361 | name = Release; 362 | }; 363 | 8EC8C46E1DED83D10044FB44 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | baseConfigurationReference = 1BA2AAEE0DEE33072083F3FD /* Pods-Demo.debug.xcconfig */; 366 | buildSettings = { 367 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 368 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 369 | DEVELOPMENT_TEAM = 683U48NZTT; 370 | INFOPLIST_FILE = Demo/Info.plist; 371 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 372 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.Demo; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 375 | SWIFT_VERSION = 4.2; 376 | }; 377 | name = Debug; 378 | }; 379 | 8EC8C46F1DED83D10044FB44 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | baseConfigurationReference = CBFCE409C80D5996E69369E9 /* Pods-Demo.release.xcconfig */; 382 | buildSettings = { 383 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 384 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 385 | DEVELOPMENT_TEAM = 683U48NZTT; 386 | INFOPLIST_FILE = Demo/Info.plist; 387 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 388 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.Demo; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 391 | SWIFT_VERSION = 4.2; 392 | }; 393 | name = Release; 394 | }; 395 | /* End XCBuildConfiguration section */ 396 | 397 | /* Begin XCConfigurationList section */ 398 | 8EC8C4561DED83D10044FB44 /* Build configuration list for PBXProject "Demo" */ = { 399 | isa = XCConfigurationList; 400 | buildConfigurations = ( 401 | 8EC8C46B1DED83D10044FB44 /* Debug */, 402 | 8EC8C46C1DED83D10044FB44 /* Release */, 403 | ); 404 | defaultConfigurationIsVisible = 0; 405 | defaultConfigurationName = Release; 406 | }; 407 | 8EC8C46D1DED83D10044FB44 /* Build configuration list for PBXNativeTarget "Demo" */ = { 408 | isa = XCConfigurationList; 409 | buildConfigurations = ( 410 | 8EC8C46E1DED83D10044FB44 /* Debug */, 411 | 8EC8C46F1DED83D10044FB44 /* Release */, 412 | ); 413 | defaultConfigurationIsVisible = 0; 414 | defaultConfigurationName = Release; 415 | }; 416 | /* End XCConfigurationList section */ 417 | }; 418 | rootObject = 8EC8C4531DED83D10044FB44 /* Project object */; 419 | } 420 | -------------------------------------------------------------------------------- /Example/Demo1-not library/CreditCardForm/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // CreditCardForum 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/5/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Stripe 11 | import AKMaskField 12 | import CreditCardValidator 13 | 14 | public enum Brands : String { 15 | case NONE, Visa, MasterCard, Amex, JCB, DEFAULT, Discover 16 | } 17 | 18 | class ViewController: UIViewController, STPPaymentCardTextFieldDelegate { 19 | 20 | let paymentTextField = STPPaymentCardTextField() 21 | var cardView: UIView! 22 | var backImage: UIImageView! 23 | var imageView: UIImageView! 24 | 25 | var cardNumber:AKMaskField! 26 | var cardHolder:UILabel! 27 | var fullname:UILabel! 28 | var expireDate: AKMaskField! 29 | var expireDateText: UILabel! 30 | var backView: UIView! 31 | var frontView: UIView! 32 | var backLine: UIView! 33 | var cvc: AKMaskField! 34 | var chipImg: UIImageView! 35 | 36 | var showingBack = false 37 | var gradientLayer: CAGradientLayer! 38 | 39 | var colors = [String : [UIColor]]() 40 | 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | 44 | colors[Brands.NONE.rawValue] = [UIColor.hexStr(hexStr: "#363434", alpha: 1), UIColor.hexStr(hexStr: "#363434", alpha: 1)] 45 | colors[Brands.Visa.rawValue] = [UIColor.hexStr(hexStr: "#5D8BF2", alpha: 1), UIColor.hexStr(hexStr: "#3545AE", alpha: 1)] 46 | colors[Brands.MasterCard.rawValue] = [UIColor.hexStr(hexStr: "#ED495A", alpha: 1), UIColor.hexStr(hexStr: "#8B1A2B", alpha: 1)] 47 | colors[Brands.Amex.rawValue] = [UIColor.hexStr(hexStr: "#005B9D", alpha: 1), UIColor.hexStr(hexStr: "#132972", alpha: 1)] 48 | colors[Brands.JCB.rawValue] = [UIColor.hexStr(hexStr: "#265797", alpha: 1), UIColor.hexStr(hexStr: "#3d6eaa", alpha: 1)] 49 | colors["Diners Club"] = [UIColor.hexStr(hexStr: "#5b99d8", alpha: 1), UIColor.hexStr(hexStr: "#4186CD", alpha: 1)] 50 | colors[Brands.Discover.rawValue] = [UIColor.hexStr(hexStr: "#e8a258", alpha: 1), UIColor.hexStr(hexStr: "#D97B16", alpha: 1)] 51 | colors[Brands.DEFAULT.rawValue] = [UIColor.hexStr(hexStr: "#5D8BF2", alpha: 1), UIColor.hexStr(hexStr: "#3545AE", alpha: 1)] 52 | 53 | createCard() 54 | 55 | paymentTextField.frame = CGRect(x: 15, y: 199, width: self.view.frame.size.width - 30, height: 44) 56 | paymentTextField.delegate = self 57 | paymentTextField.translatesAutoresizingMaskIntoConstraints = false 58 | paymentTextField.borderWidth = 0 59 | 60 | let border = CALayer() 61 | let width = CGFloat(1.0) 62 | border.borderColor = UIColor.darkGray.cgColor 63 | border.frame = CGRect(x: 0, y: paymentTextField.frame.size.height - width, width: paymentTextField.frame.size.width, height: paymentTextField.frame.size.height) 64 | border.borderWidth = width 65 | paymentTextField.layer.addSublayer(border) 66 | paymentTextField.layer.masksToBounds = true 67 | 68 | view.addSubview(paymentTextField) 69 | 70 | let top = paymentTextField.topAnchor.constraint(equalTo: cardView.bottomAnchor, constant: 20) 71 | let horizontalConstraint = paymentTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor) 72 | let widthConstraint = paymentTextField.widthAnchor.constraint(equalToConstant: self.view.frame.size.width-20) 73 | let heightConstraint = paymentTextField.heightAnchor.constraint(equalToConstant: 44) 74 | 75 | NSLayoutConstraint.activate([top, widthConstraint, heightConstraint, horizontalConstraint]) 76 | } 77 | 78 | func setGradientBackground(v: UIView, top: CGColor, bottom: CGColor) { 79 | let colorTop = top 80 | let colorBottom = bottom 81 | 82 | gradientLayer = CAGradientLayer() 83 | gradientLayer.colors = [ colorTop, colorBottom] 84 | gradientLayer.locations = [ 0.0, 1.0] 85 | gradientLayer.frame = v.bounds 86 | backView.backgroundColor = UIColor.hexStr(hexStr: "#363434", alpha: 1) 87 | v.layer.addSublayer(gradientLayer) 88 | } 89 | 90 | func createCard() { 91 | let frame = self.view.frame 92 | cardView = UIView(frame: CGRect(x: (frame.size.width - 300)/2, y: 64, width: 300, height: 200)) 93 | cardView.translatesAutoresizingMaskIntoConstraints = false 94 | cardView.layer.cornerRadius = 6 95 | cardView.backgroundColor = .red 96 | 97 | backView = UIView(frame: CGRect(x: (frame.size.width - 300)/2, y: 64, width: 300, height: 200)) 98 | backView.translatesAutoresizingMaskIntoConstraints = false 99 | backView.layer.cornerRadius = 6 100 | backView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY) 101 | backView.autoresizingMask = [UIViewAutoresizing.flexibleLeftMargin, UIViewAutoresizing.flexibleRightMargin, UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleBottomMargin] 102 | 103 | frontView = UIView(frame: CGRect(x: (frame.size.width - 300)/2, y: 64, width: 300, height: 200)) 104 | frontView.translatesAutoresizingMaskIntoConstraints = false 105 | frontView.layer.cornerRadius = 6 106 | frontView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY) 107 | frontView.autoresizingMask = [UIViewAutoresizing.flexibleLeftMargin, UIViewAutoresizing.flexibleRightMargin, UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleBottomMargin] 108 | 109 | backImage = UIImageView(frame: CGRect.zero) 110 | backImage.translatesAutoresizingMaskIntoConstraints = false 111 | backImage.image = UIImage(named: "back.jpg") 112 | backImage.contentMode = UIViewContentMode.scaleAspectFill 113 | 114 | //Card brand image 115 | imageView = UIImageView(frame: CGRect.zero) 116 | imageView.translatesAutoresizingMaskIntoConstraints = false 117 | imageView.contentMode = UIViewContentMode.scaleAspectFit 118 | 119 | //Credit card number 120 | cardNumber = AKMaskField() 121 | cardNumber.translatesAutoresizingMaskIntoConstraints = false 122 | cardNumber.maskExpression = "{....} {....} {....} {....}" 123 | //cardNumber.text = "XXXXXXXXXXXXXXXX" 124 | cardNumber.textColor = .white 125 | cardNumber.isUserInteractionEnabled = false 126 | cardNumber.textAlignment = NSTextAlignment.center 127 | cardNumber.font = UIFont(name: "Helvetica Neue", size: 20) 128 | 129 | //Card holder uilabel 130 | cardHolder = UILabel(frame: CGRect.zero) 131 | cardHolder.translatesAutoresizingMaskIntoConstraints = false 132 | cardHolder.font = UIFont(name: "Helvetica Neue", size: 10) 133 | cardHolder.text = "CARD HOLDER" 134 | cardHolder.textColor = UIColor.hexStr(hexStr: "#bdc3c7", alpha: 1) 135 | 136 | //Name 137 | fullname = UILabel(frame: CGRect.zero) 138 | fullname.translatesAutoresizingMaskIntoConstraints = false 139 | fullname.font = UIFont(name: "Helvetica Neue", size: 12) 140 | fullname.text = "Atakishi Oraz" 141 | fullname.textColor = .white 142 | 143 | //Expire Date 144 | expireDate = AKMaskField() 145 | expireDate.translatesAutoresizingMaskIntoConstraints = false 146 | expireDate.font = UIFont(name: "Helvetica Neue", size: 12) 147 | expireDate.maskExpression = "{..}/{..}" 148 | expireDate.text = paymentTextField.expirationPlaceholder 149 | expireDate.textColor = .white 150 | 151 | //Expire Date Text 152 | expireDateText = UILabel(frame: CGRect.zero) 153 | expireDateText.translatesAutoresizingMaskIntoConstraints = false 154 | expireDateText.font = UIFont(name: "Helvetica Neue", size: 10) 155 | expireDateText.text = "EXPIRY" 156 | expireDateText.textColor = UIColor.hexStr(hexStr: "#bdc3c7", alpha: 1) 157 | 158 | //BackLine 159 | backLine = UIView(frame: CGRect.zero) 160 | backLine.translatesAutoresizingMaskIntoConstraints = false 161 | backLine.backgroundColor = .black 162 | 163 | //CVC textfield 164 | cvc = AKMaskField() 165 | cvc.translatesAutoresizingMaskIntoConstraints = false 166 | cvc.maskExpression = "..." 167 | cvc.text = paymentTextField.cvc 168 | cvc.backgroundColor = .white 169 | cvc.textAlignment = NSTextAlignment.center 170 | cvc.isUserInteractionEnabled = false 171 | 172 | //Chip image 173 | chipImg = UIImageView(frame: CGRect.zero) 174 | chipImg.image = UIImage(named: "chip") 175 | chipImg.translatesAutoresizingMaskIntoConstraints = false 176 | chipImg.alpha = 0.5 177 | 178 | frontView.isHidden = false 179 | backView.isHidden = true 180 | 181 | cardView.clipsToBounds = true 182 | //frontView.addSubview(backImage) 183 | cardView.addSubview(frontView) 184 | 185 | setGradientBackground(v: frontView, top: UIColor.hexStr(hexStr: "#363434", alpha: 1).cgColor, bottom: UIColor.hexStr(hexStr: "#363434", alpha: 1).cgColor) 186 | 187 | frontView.addSubview(imageView) 188 | frontView.addSubview(cardHolder) 189 | frontView.addSubview(fullname) 190 | frontView.addSubview(cardNumber) 191 | frontView.addSubview(expireDate) 192 | frontView.addSubview(expireDateText) 193 | frontView.addSubview(chipImg) 194 | 195 | backView.addSubview(backLine) 196 | backView.addSubview(cvc) 197 | cardView.addSubview(backView) 198 | view.addSubview(cardView) 199 | 200 | //CardView 201 | let top = cardView.topAnchor.constraint(equalTo: view.topAnchor, constant: 64) 202 | let horizontalConstraint = cardView.centerXAnchor.constraint(equalTo: view.centerXAnchor) 203 | let widthConstraint = cardView.widthAnchor.constraint(equalToConstant: 300) 204 | let heightConstraint = cardView.heightAnchor.constraint(equalToConstant: 170) 205 | NSLayoutConstraint.activate([top, widthConstraint, heightConstraint, horizontalConstraint]) 206 | 207 | //Back View 208 | let frontViewtop = frontView.topAnchor.constraint(equalTo: view.topAnchor, constant: 64) 209 | let frontViewhorizontalConstraint = frontView.centerXAnchor.constraint(equalTo: view.centerXAnchor) 210 | let frontViewwidthConstraint = frontView.widthAnchor.constraint(equalToConstant: 300) 211 | let frontViewheightConstraint = frontView.heightAnchor.constraint(equalToConstant: 170) 212 | NSLayoutConstraint.activate([frontViewtop, frontViewhorizontalConstraint, frontViewwidthConstraint, frontViewheightConstraint]) 213 | 214 | //Back View 215 | let cardBacktop = backView.topAnchor.constraint(equalTo: view.topAnchor, constant: 64) 216 | let cardBackhorizontalConstraint = backView.centerXAnchor.constraint(equalTo: view.centerXAnchor) 217 | let cardBackwidthConstraint = backView.widthAnchor.constraint(equalToConstant: 300) 218 | let cardBackheightConstraint = backView.heightAnchor.constraint(equalToConstant: 170) 219 | NSLayoutConstraint.activate([cardBacktop, cardBackhorizontalConstraint, cardBackwidthConstraint, cardBackheightConstraint]) 220 | 221 | // //Background imageview 222 | // let backImgTop = backImage.topAnchor.constraint(equalTo: cardView.topAnchor) 223 | // let leadingCont = backImage.leadingAnchor.constraint(equalTo: cardView.leadingAnchor) 224 | // let trailingCont = backImage.trailingAnchor.constraint(equalTo: cardView.trailingAnchor) 225 | // let bottomCont = backImage.bottomAnchor.constraint(equalTo: cardView.bottomAnchor) 226 | // NSLayoutConstraint.activate([backImgTop, leadingCont, trailingCont, bottomCont]) 227 | 228 | //Card brand imageview 229 | let top1 = imageView.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 10) 230 | let trailing = imageView.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -10) 231 | let widthConstraint1 = imageView.widthAnchor.constraint(equalToConstant: 60) 232 | let heightConstraint1 = imageView.heightAnchor.constraint(equalToConstant: 40) 233 | NSLayoutConstraint.activate([top1, trailing, widthConstraint1, heightConstraint1]) 234 | 235 | //Card number 236 | let horizontalConstraintcardNumber = cardNumber.centerXAnchor.constraint(equalTo: cardView.centerXAnchor) 237 | let verticalConstraintcardNumber = cardNumber.centerYAnchor.constraint(equalTo: cardView.centerYAnchor) 238 | let widthConstraintcardNumber = cardNumber.widthAnchor.constraint(equalToConstant: 200) 239 | let heightConstraintcardNumber = cardNumber.heightAnchor.constraint(equalToConstant: 30) 240 | NSLayoutConstraint.activate([widthConstraintcardNumber, verticalConstraintcardNumber, heightConstraintcardNumber, horizontalConstraintcardNumber]) 241 | 242 | //Name 243 | let fullnameBottom = fullname.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -20) 244 | let fullnameleadingCont = fullname.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 15) 245 | NSLayoutConstraint.activate([fullnameBottom, fullnameleadingCont]) 246 | 247 | //Card Holder 248 | let cardHolderTop = cardHolder.bottomAnchor.constraint(equalTo: fullname.topAnchor, constant: -3) 249 | let cardHolderleadingCont = cardHolder.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 15) 250 | NSLayoutConstraint.activate([cardHolderTop, cardHolderleadingCont]) 251 | 252 | //Expire Date 253 | let expireDateBottom = expireDate.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -20) 254 | let expireDateleadingCont = expireDate.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -55) 255 | NSLayoutConstraint.activate([expireDateBottom, expireDateleadingCont]) 256 | 257 | //Expire Date Text 258 | let expireDateTextBottom = expireDateText.bottomAnchor.constraint(equalTo: expireDate.topAnchor, constant: -3) 259 | let expireDateTextLeadingCont = expireDateText.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -58) 260 | NSLayoutConstraint.activate([expireDateTextBottom, expireDateTextLeadingCont]) 261 | 262 | let chipImgtop = chipImg.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 15) 263 | let chipImgtrailing = chipImg.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 15) 264 | let chipImgwidthConstraint = chipImg.widthAnchor.constraint(equalToConstant: 45) 265 | let chipImgheightConstraint = chipImg.heightAnchor.constraint(equalToConstant: 30) 266 | NSLayoutConstraint.activate([chipImgtop, chipImgtrailing, chipImgwidthConstraint, chipImgheightConstraint]) 267 | 268 | //Back Line 269 | let backLinetop = backLine.topAnchor.constraint(equalTo: backView.topAnchor, constant: 20) 270 | let backLinehorizontalConstraint = backLine.centerXAnchor.constraint(equalTo: backView.centerXAnchor) 271 | let backLinewidthConstraint = backLine.widthAnchor.constraint(equalToConstant: 300) 272 | let backLineheightConstraint = backLine.heightAnchor.constraint(equalToConstant: 50) 273 | NSLayoutConstraint.activate([backLinetop, backLinehorizontalConstraint, backLinewidthConstraint, backLineheightConstraint]) 274 | 275 | //cvc 276 | let cvcTop = cvc.topAnchor.constraint(equalTo: backLine.bottomAnchor, constant: 10) 277 | let cvcwidthConstraint = cvc.widthAnchor.constraint(equalToConstant: 50) 278 | let cvcheightConstraint = cvc.heightAnchor.constraint(equalToConstant: 25) 279 | let trailingCVC = cvc.trailingAnchor.constraint(equalTo: backView.trailingAnchor, constant: -10) 280 | NSLayoutConstraint.activate([cvcTop, cvcwidthConstraint, cvcheightConstraint, trailingCVC]) 281 | } 282 | 283 | func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) { 284 | self.cardNumber.text = textField.cardNumber 285 | 286 | self.expireDate.text = NSString(format: "%02ld", textField.expirationMonth) as String + "/" + (NSString(format: "%02ld", textField.expirationYear) as String) 287 | 288 | if textField.expirationMonth == 0 { 289 | expireDate.text = "MM/YY" 290 | } 291 | let v = CreditCardValidator() 292 | self.cvc.text = textField.cvc 293 | 294 | if (textField.cardNumber?.characters.count)! >= 7 || (textField.cardNumber?.characters.count)! < 4 { 295 | 296 | guard let type = v.type(from: "\(textField.cardNumber!)") else { 297 | self.imageView.image = nil 298 | if let name = colors["NONE"] { 299 | setType(colors: [name[0].cgColor, name[1].cgColor], alpha: 0.5, back: name[0]) 300 | } 301 | return 302 | } 303 | 304 | // Visa, Mastercard, Amex etc. 305 | if let name = colors[type.name] { 306 | self.imageView.image = UIImage(named: type.name) 307 | setType(colors: [name[0].cgColor, name[1].cgColor], alpha: 1, back: name[0]) 308 | }else{ 309 | setType(colors: [self.colors["DEFAULT"]![0].cgColor, self.colors["DEFAULT"]![0].cgColor], alpha: 1, back: self.colors["DEFAULT"]![0]) 310 | } 311 | } 312 | } 313 | 314 | func setType(colors: [CGColor], alpha: CGFloat, back: UIColor) { 315 | UIView.animate(withDuration: 2, animations: { () -> Void in 316 | self.gradientLayer.colors = colors 317 | }) 318 | self.backView.backgroundColor = back 319 | self.chipImg.alpha = alpha 320 | } 321 | 322 | func paymentCardTextFieldDidEndEditingExpiration(_ textField: STPPaymentCardTextField) { 323 | 324 | if "\(textField.expirationYear)".characters.count <= 1 { 325 | expireDate.text = "MM/YY" 326 | } 327 | } 328 | 329 | func paymentCardTextFieldDidBeginEditingExpiration(_ textField: STPPaymentCardTextField) { 330 | 331 | } 332 | 333 | func paymentCardTextFieldDidBeginEditingCVC(_ textField: STPPaymentCardTextField) { 334 | if !showingBack { 335 | flip() 336 | showingBack = true 337 | } 338 | } 339 | 340 | func paymentCardTextFieldDidEndEditingCVC(_ textField: STPPaymentCardTextField) { 341 | if showingBack { 342 | flip() 343 | showingBack = false 344 | } 345 | } 346 | 347 | func flip() { 348 | var showingSide = frontView 349 | var hiddenSide = backView 350 | if showingBack { 351 | (showingSide, hiddenSide) = (backView, frontView) 352 | } 353 | 354 | UIView.transition(from:showingSide!, 355 | to: hiddenSide!, 356 | duration: 0.7, 357 | options: [UIViewAnimationOptions.transitionFlipFromRight, UIViewAnimationOptions.showHideTransitionViews], 358 | completion: nil) 359 | 360 | } 361 | 362 | } 363 | 364 | extension UIColor { 365 | class func hexStr ( hexStr : NSString, alpha : CGFloat) -> UIColor { 366 | let hexStr = hexStr.replacingOccurrences(of: "#", with: "") 367 | let scanner = Scanner(string: hexStr as String) 368 | var color: UInt32 = 0 369 | if scanner.scanHexInt32(&color) { 370 | let r = CGFloat((color & 0xFF0000) >> 16) / 255.0 371 | let g = CGFloat((color & 0x00FF00) >> 8) / 255.0 372 | let b = CGFloat(color & 0x0000FF) / 255.0 373 | return UIColor(red:r,green:g,blue:b,alpha:alpha) 374 | } else { 375 | print("invalid hex string", terminator: "") 376 | return UIColor.white; 377 | } 378 | } 379 | } 380 | 381 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/AKMaskField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AKMaskField.swift 3 | // AKMaskField 4 | // GitHub: https://github.com/artemkrachulov/AKMaskField 5 | // 6 | // Created by Artem Krachulov 7 | // Copyright (c) 2016 Artem Krachulov. All rights reserved. 8 | // Website: http://www.artemkrachulov.com/ 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 11 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 12 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 13 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in all copies or 17 | // substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 20 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 21 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 22 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | // v. 1.0 27 | // 28 | 29 | import UIKit 30 | 31 | /// AKMaskField is UITextField subclass which allows enter data in the fixed quantity 32 | /// and in the certain format (credit cards, telephone numbers, dates, etc.). 33 | /// You only need setup mask and mask template visible for the user. 34 | /// 35 | /// Example of usage (programmatically): 36 | /// 37 | /// ``` 38 | /// var field = AKMaskField() 39 | /// field.setMask("{dddd}-{DDDD}-{WaWa}-{aaaa}", withMaskTemplate: "ABCD-EFGH-IJKL-MNOP") 40 | /// ``` 41 | /// 42 | /// For more information click here [GitHub](https://github.com/artemkrachulov/AKMaskField) 43 | open class AKMaskField: UITextField { 44 | 45 | // MARK: - Configuring the Mask Field 46 | 47 | /// The string value that has blocks with pattern symbols that determine the certain format of input data. Wrap each mask block with proper bracket character. 48 | /// 49 | /// The predetermined formats (Mask symbol : Input format): 50 | /// 51 | /// - `d` : Number, decimal number from 0 to 9 52 | /// - `D` : Any symbol, except decimal number 53 | /// - `W` : Not an alphabetic symbol 54 | /// - `a` : Alphabetic symbol, a-Z 55 | /// - `.` : Corresponds to any symbol (default) 56 | /// 57 | /// Default value of this property is `nil`. 58 | @IBInspectable final public var maskExpression: String? { 59 | didSet { 60 | 61 | // - - - - - - - - - - - - 62 | // CHECKS 63 | // - - - - - - - - - - - - 64 | 65 | if guardMask { return } 66 | 67 | let brackets = AKMaskFieldUtility 68 | .matchesInString(maskExpression!, 69 | pattern: "(?<=\\\(maskBlockBrackets.left)).*?(?=\\\(maskBlockBrackets.right))") 70 | 71 | if brackets.isEmpty { return } 72 | 73 | // - - - - - - - - - - - - 74 | // SETUP 75 | // - - - - - - - - - - - - 76 | 77 | delegate = self 78 | 79 | maskTemplateText = maskExpression 80 | 81 | // - - - - - - - - - - - - 82 | // MASK OBJECT 83 | // - - - - - - - - - - - - 84 | 85 | maskBlocks = [AKMaskFieldBlock]() 86 | 87 | for (i, bracket) in brackets.enumerated() { 88 | 89 | // - - - - - - - - - - - - - - - - 90 | // Characters 91 | 92 | var characters = [AKMaskFieldBlockCharacter]() 93 | 94 | for y in 0.. (char: AKMaskFieldBlockCharacter, outsideBlock: Bool) { 282 | 283 | var nextBlockIndex: Int! 284 | 285 | var lowerBound = 0 286 | var upperBound = chars.count 287 | 288 | while lowerBound < upperBound { 289 | 290 | let midIndex = lowerBound + (upperBound - lowerBound) / 2 291 | let charLocation = chars[midIndex].templateRange.location 292 | 293 | if charLocation == location { 294 | return (chars[midIndex], false) 295 | } else if charLocation < location { 296 | lowerBound = midIndex + 1 297 | } else { 298 | upperBound = midIndex 299 | nextBlockIndex = midIndex 300 | } 301 | } 302 | 303 | return (chars[nextBlockIndex], true) 304 | } 305 | 306 | /// Check if current character match with pattern 307 | fileprivate func matchTextCharacter(_ textCharacter: Character, withMaskCharacter maskCharacter: AKMaskFieldBlockCharacter) -> Bool { 308 | return !AKMaskFieldUtility 309 | .matchesInString(String(textCharacter), 310 | pattern: maskCharacter.pattern.pattern()).isEmpty 311 | } 312 | 313 | fileprivate func updateMaskTemplateText() { 314 | AKMaskFieldUtility 315 | .replacingOccurrencesOfString(&maskTemplateText, 316 | target : "[\(maskBlockBrackets.left)\(maskBlockBrackets.right)]", 317 | withString : "") 318 | 319 | maskText = maskTemplateText 320 | 321 | refreshMask() 322 | } 323 | 324 | fileprivate func updateMaskTemplateTextFromBlock(_ index: Int) { 325 | 326 | AKMaskFieldUtility 327 | .replace(&maskTemplateText, 328 | withString : maskBlocks[index].template, 329 | inRange : maskBlocks[index].patternRange) 330 | } 331 | 332 | fileprivate struct AKMaskFieldProcessedBlock { 333 | var range : NSRange? 334 | var string : String = "" 335 | } 336 | 337 | fileprivate func moveCarret() { 338 | var position: Int 339 | 340 | switch maskStatus { 341 | case .clear : position = maskBlocks.first!.templateRange.location 342 | case .incomplete : position = maskBlocks.flatMap { $0.chars.filter { $0.status == .clear } }.first!.templateRange.location 343 | case .complete : position = Range(maskBlocks.last!.templateRange)!.upperBound 344 | } 345 | 346 | AKMaskFieldUtility.maskField(self, moveCaretToPosition: position) 347 | } 348 | } 349 | // MARK: - UITextFieldDelegate 350 | 351 | extension AKMaskField: UITextFieldDelegate { 352 | 353 | public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { 354 | return maskDelegate?.maskFieldShouldBeginEditing(self) ?? true 355 | } 356 | 357 | public func textFieldDidBeginEditing(_ textField: UITextField) { 358 | 359 | maskDelegate?.maskFieldDidBeginEditing(self) 360 | 361 | if guardMask { return } 362 | 363 | moveCarret() 364 | } 365 | 366 | public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { 367 | return maskDelegate?.maskFieldShouldEndEditing(self) ?? true 368 | } 369 | 370 | public func textFieldDidEndEditing(_ textField: UITextField) { 371 | maskDelegate?.maskFieldDidEndEditing(self) 372 | } 373 | 374 | public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 375 | 376 | // CHECKS 377 | 378 | if guardMask { return false } 379 | 380 | let maskBlocksChars = maskBlocks.flatMap { $0.chars } 381 | 382 | // EVENTS 383 | 384 | var event: AKMaskFieldEvent! 385 | 386 | var completed: Int = 0 387 | var cleared: Int = 0 388 | 389 | // PREPARE BLOCKS FOR USER PROCESSING 390 | 391 | var processedBlocks = [AKMaskFieldProcessedBlock]() 392 | 393 | // - - - - - - - - - - - - 394 | // STEP 1 395 | // Selected range 396 | 397 | // Find blocks with text which must be reset 398 | 399 | // a) Prepare an array with interserted ranges 400 | 401 | let intersertRanges = AKMaskFieldUtility 402 | .findIntersection(maskBlocks.map { return $0.templateRange }, withRange: range) 403 | 404 | // b) Create an array with interserted blocks 405 | 406 | for (i, intersertRange) in intersertRanges.enumerated() { 407 | 408 | var processedBlock = AKMaskFieldProcessedBlock() 409 | processedBlock.range = intersertRange 410 | 411 | if let intersertRange = intersertRange { 412 | processedBlock.range?.location = abs(maskBlocks[i].templateRange.location - intersertRange.location) 413 | } 414 | processedBlocks.append(processedBlock) 415 | } 416 | 417 | // - - - - - - - - - - - - 418 | // STEP 2 419 | // Replacement string 420 | 421 | var location = range.location 422 | var savedLocation = range.location 423 | 424 | for replacementCharacter in string { 425 | if location == maskText?.count { break } 426 | 427 | // Find next character 428 | // If character outside the block, jump to first character of the next block 429 | let nextCharacter = getNetCharacter(maskBlocksChars, fromLocation: location) 430 | 431 | var findMatches: Bool = false 432 | 433 | if nextCharacter.outsideBlock { 434 | 435 | // Check if replacement character match to mask template character in same location 436 | 437 | if replacementCharacter != Character(AKMaskFieldUtility.substring(maskTemplateText, withNSRange: NSMakeRange(location, 1))) && 438 | replacementCharacter != " " { 439 | 440 | savedLocation = location 441 | findMatches = true 442 | } 443 | } else { 444 | findMatches = true 445 | } 446 | 447 | if findMatches { 448 | if matchTextCharacter(replacementCharacter, withMaskCharacter: nextCharacter.char) { 449 | 450 | location = nextCharacter.char.templateRange.location 451 | let blockIndex = nextCharacter.char.blockIndex 452 | 453 | processedBlocks[blockIndex].string.append(replacementCharacter) 454 | 455 | if processedBlocks[blockIndex].range == nil { 456 | processedBlocks[blockIndex].range = NSMakeRange(nextCharacter.char.index, 0) 457 | } 458 | } else { 459 | 460 | location = savedLocation 461 | 462 | event = .error 463 | break 464 | } 465 | } 466 | 467 | location += 1 468 | } 469 | 470 | // USER PROCESSING 471 | 472 | for (i, processedBlock) in processedBlocks.enumerated() { 473 | if var _range = processedBlock.range { 474 | 475 | // Prepare data 476 | 477 | var _string = processedBlock.string 478 | 479 | // Grab all changed data 480 | let shouldChangeBlock = maskDelegate? 481 | .maskField(self, 482 | shouldChangeBlock : maskBlocks[i], 483 | inRange : &_range, 484 | replacementString : &_string) 485 | ?? true 486 | 487 | if shouldChangeBlock { 488 | 489 | // REVALIDATE 490 | 491 | // - - - - - - - - - - - - 492 | // Selected range 493 | 494 | if processedBlock.range!.location != _range.location || 495 | processedBlock.range!.length != _range.length { 496 | 497 | if let validatedRange = AKMaskFieldUtility 498 | .findIntersection([maskBlocks[i].templateRange], withRange: _range).first! as NSRange? { 499 | 500 | _range = validatedRange 501 | } 502 | } 503 | 504 | // - - - - - - - - - - - - 505 | // Replacement string 506 | 507 | if processedBlock.string != _string { 508 | 509 | var validatedString = "" 510 | 511 | // Start carret position 512 | var _location = _range.location 513 | 514 | for replacementCharacter in _string { 515 | if _location > maskBlocks[i].templateRange.length { break } 516 | 517 | if matchTextCharacter(replacementCharacter, withMaskCharacter: maskBlocks[i].chars[_location]) { 518 | validatedString.append(replacementCharacter) 519 | } else { 520 | event = .error 521 | break 522 | } 523 | _location += 1 524 | } 525 | 526 | _string = validatedString 527 | } 528 | 529 | // UPDATE MASK TEXT 530 | 531 | // - - - - - - - - - - - - 532 | // Replacement string 533 | 534 | if !_string.isEmpty { 535 | 536 | var maskTextRange = NSMakeRange(_range.location, _string.count) 537 | 538 | // Object 539 | 540 | for index in [Int](maskTextRange.location.. 0 { 571 | 572 | var maskTextRange = _range 573 | 574 | // Object 575 | 576 | for index in [Int](_range.location..<_range.location+_range.length) { 577 | maskBlocks[i].chars[index].status = .clear 578 | cleared += 1 579 | } 580 | 581 | // Mask text 582 | 583 | maskTextRange.location += maskBlocks[i].templateRange.location 584 | 585 | let cuttedTempalte = AKMaskFieldUtility 586 | .substring(maskTemplateText, withNSRange: maskTextRange) 587 | 588 | AKMaskFieldUtility 589 | .replace(&maskText, 590 | withString : cuttedTempalte, 591 | inRange : maskTextRange) 592 | 593 | } 594 | } 595 | } 596 | } 597 | 598 | // - - - - - - - - - - - - 599 | // DISPLAYED TEXT 600 | // - - - - - - - - - - - - 601 | 602 | refreshMask() 603 | 604 | AKMaskFieldUtility.maskField(self, moveCaretToPosition: location) 605 | 606 | // - - - - - - - - - - - - 607 | // EVENT 608 | // - - - - - - - - - - - - 609 | 610 | if completed != 0 { 611 | event = cleared == 0 ? .insert : .replace 612 | } else { 613 | if cleared != 0 { 614 | event = .delete 615 | } 616 | } 617 | 618 | if let event = event { 619 | maskDelegate?.maskField(self, didChangedWithEvent: event) 620 | } 621 | 622 | return false 623 | } 624 | 625 | public func textFieldShouldClear(_ textField: UITextField) -> Bool { 626 | text = nil 627 | 628 | return false 629 | } 630 | 631 | public func textFieldShouldReturn(_ textField: UITextField) -> Bool { 632 | return maskDelegate?.maskFieldShouldReturn(self) ?? true 633 | } 634 | 635 | fileprivate func debugmaskBlocks() { 636 | for block in maskBlocks { 637 | print("BLOCK :") 638 | print("index : \(block.index)") 639 | print("status : \(block.status)") 640 | print("pattern : \(block.pattern)") 641 | print("patternRange : \(block.patternRange)") 642 | print("template : \(block.template)") 643 | print("templateRange : \(block.templateRange)") 644 | print("CHARS :") 645 | for char in block.chars { 646 | print(" index : \(char.index)") 647 | print(" blockIndex : \(char.blockIndex)") 648 | print(" status : \(char.status)") 649 | print(" pattern : \(String(describing: char.pattern))") 650 | print(" patternRange : \(char.patternRange)") 651 | print(" template : \(String(describing: char.template))") 652 | print(" templateRange : \(char.templateRange)") 653 | } 654 | print("") 655 | } 656 | } 657 | } 658 | 659 | // MARK: - AKMaskFieldDelegate 660 | 661 | protocol AKMaskFieldDelegate: class { 662 | 663 | /// Asks the delegate if editing should begin in the specified mask field. 664 | /// 665 | /// - parameter maskField : The mask field in which editing is about to begin. 666 | func maskFieldShouldBeginEditing(_ maskField: AKMaskField) -> Bool 667 | 668 | /// Asks the delegate if editing should begin in the specified mask field. 669 | /// 670 | /// - parameter maskField : The mask field in which editing is about to begin. 671 | func maskFieldDidBeginEditing(_ maskField: AKMaskField) 672 | 673 | /// Asks the delegate if editing should stop in the specified mask field. 674 | /// 675 | /// - parameter maskField : The mask field in which editing is about to end. 676 | func maskFieldShouldEndEditing(_ maskField: AKMaskField) -> Bool 677 | 678 | /// Tells the delegate that editing stopped for the specified mask field. 679 | /// 680 | /// - parameter maskField : The mask field for which editing ended. 681 | func maskFieldDidEndEditing(_ maskField: AKMaskField) 682 | 683 | /// Tells the delegate that specified mask field change text with event. 684 | /// 685 | /// - parameter maskField : The mask field for which event changed. 686 | /// - parameter event : Event constant value received after manipulations. 687 | func maskField(_ maskField: AKMaskField, didChangedWithEvent event: AKMaskFieldEvent) 688 | 689 | /// Asks the delegate if the specified mask block should be changed. 690 | /// 691 | /// - parameter maskField : The mask field containing the text. 692 | /// - parameter block : Target block 693 | /// - parameter range : The range of characters to be replaced (inout parameter). 694 | /// - parameter string : The replacement string for the specified range (inout parameter). 695 | func maskField(_ maskField: AKMaskField, shouldChangeBlock block: AKMaskFieldBlock, inRange range: inout NSRange, replacementString string: inout String) -> Bool 696 | 697 | /// Asks the delegate if the mask field should process the pressing of the return button. 698 | /// 699 | /// - parameter maskField : The mask field whose return button was pressed. 700 | func maskFieldShouldReturn(_ maskField: AKMaskField) -> Bool 701 | } 702 | 703 | extension AKMaskFieldDelegate { 704 | func maskFieldShouldBeginEditing(_ maskField: AKMaskField) -> Bool { 705 | return true 706 | } 707 | func maskFieldDidBeginEditing(_ maskField: AKMaskField) {} 708 | func maskFieldShouldEndEditing(_ maskField: AKMaskField) -> Bool { 709 | return true 710 | } 711 | func maskFieldDidEndEditing(_ maskField: AKMaskField) {} 712 | func maskField(_ maskField: AKMaskField, didChangedWithEvent event: AKMaskFieldEvent) {} 713 | func maskField(_ maskField: AKMaskField, shouldChangeBlock block: AKMaskFieldBlock, inRange range: inout NSRange, replacementString string: inout String) -> Bool { 714 | return true 715 | } 716 | func maskFieldShouldReturn(_ maskField: AKMaskField) -> Bool { 717 | return true 718 | } 719 | } 720 | -------------------------------------------------------------------------------- /CreditCardForm.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5639844A00E3E6E670C48111 /* Pods_CreditCardFormTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B58AD822FD99C8D36962BC8 /* Pods_CreditCardFormTests.framework */; }; 11 | 8E1A520B1E7BF24500F02033 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 8E1A520A1E7BF24500F02033 /* LICENSE */; }; 12 | 8E68F4E01E98C9690086D6F3 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 8EC8C50B1DEDC0420044FB44 /* README.md */; }; 13 | 8EB6C7961DF93FD300225444 /* CreditCardForm.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 8EB6C7951DF93FD300225444 /* CreditCardForm.podspec */; }; 14 | 8EC8C3D31DEC8C3E0044FB44 /* CreditCardForm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EC8C3C91DEC8C3E0044FB44 /* CreditCardForm.framework */; }; 15 | 8EC8C3D81DEC8C3E0044FB44 /* CreditCardFormTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C3D71DEC8C3E0044FB44 /* CreditCardFormTests.swift */; }; 16 | 8EC8C4F81DEDA1340044FB44 /* AKMaskField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4ED1DEDA1340044FB44 /* AKMaskField.swift */; }; 17 | 8EC8C4F91DEDA1340044FB44 /* AKMaskFieldBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4EE1DEDA1340044FB44 /* AKMaskFieldBlock.swift */; }; 18 | 8EC8C4FA1DEDA1340044FB44 /* AKMaskFieldBlockCharacter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4EF1DEDA1340044FB44 /* AKMaskFieldBlockCharacter.swift */; }; 19 | 8EC8C4FB1DEDA1340044FB44 /* AKMaskFieldEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F01DEDA1340044FB44 /* AKMaskFieldEvent.swift */; }; 20 | 8EC8C4FC1DEDA1340044FB44 /* AKMaskFieldPatternCharacter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F11DEDA1340044FB44 /* AKMaskFieldPatternCharacter.swift */; }; 21 | 8EC8C4FD1DEDA1340044FB44 /* AKMaskFieldStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F21DEDA1340044FB44 /* AKMaskFieldStatus.swift */; }; 22 | 8EC8C4FE1DEDA1340044FB44 /* AKMaskFieldUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F31DEDA1340044FB44 /* AKMaskFieldUtility.swift */; }; 23 | 8EC8C4FF1DEDA1340044FB44 /* CreditCardFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F41DEDA1340044FB44 /* CreditCardFormView.swift */; }; 24 | 8EC8C5001DEDA1340044FB44 /* CreditCardValidationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F51DEDA1340044FB44 /* CreditCardValidationType.swift */; }; 25 | 8EC8C5011DEDA1340044FB44 /* CreditCardValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F61DEDA1340044FB44 /* CreditCardValidator.swift */; }; 26 | 8EC8C5021DEDA1340044FB44 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC8C4F71DEDA1340044FB44 /* Utilities.swift */; }; 27 | 8EC8C50A1DEDB5EA0044FB44 /* CreditCardForm.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC8C5091DEDB5EA0044FB44 /* CreditCardForm.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | 8EFED2811E2796A6002BE8D5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8EFED2801E2796A6002BE8D5 /* Images.xcassets */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 8EC8C3D41DEC8C3E0044FB44 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 8EC8C3C01DEC8C3E0044FB44 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 8EC8C3C81DEC8C3E0044FB44; 37 | remoteInfo = CreditCardForm; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 5B58AD822FD99C8D36962BC8 /* Pods_CreditCardFormTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CreditCardFormTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 8E1A520A1E7BF24500F02033 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; }; 44 | 8EB6C7951DF93FD300225444 /* CreditCardForm.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CreditCardForm.podspec; sourceTree = SOURCE_ROOT; }; 45 | 8EC8C3C91DEC8C3E0044FB44 /* CreditCardForm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CreditCardForm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 8EC8C3CD1DEC8C3E0044FB44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Info.plist; sourceTree = ""; }; 47 | 8EC8C3D21DEC8C3E0044FB44 /* CreditCardFormTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CreditCardFormTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 8EC8C3D71DEC8C3E0044FB44 /* CreditCardFormTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCardFormTests.swift; sourceTree = ""; }; 49 | 8EC8C3D91DEC8C3E0044FB44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 8EC8C4ED1DEDA1340044FB44 /* AKMaskField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskField.swift; path = Classes/AKMaskField.swift; sourceTree = ""; }; 51 | 8EC8C4EE1DEDA1340044FB44 /* AKMaskFieldBlock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldBlock.swift; path = Classes/AKMaskFieldBlock.swift; sourceTree = ""; }; 52 | 8EC8C4EF1DEDA1340044FB44 /* AKMaskFieldBlockCharacter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldBlockCharacter.swift; path = Classes/AKMaskFieldBlockCharacter.swift; sourceTree = ""; }; 53 | 8EC8C4F01DEDA1340044FB44 /* AKMaskFieldEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldEvent.swift; path = Classes/AKMaskFieldEvent.swift; sourceTree = ""; }; 54 | 8EC8C4F11DEDA1340044FB44 /* AKMaskFieldPatternCharacter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldPatternCharacter.swift; path = Classes/AKMaskFieldPatternCharacter.swift; sourceTree = ""; }; 55 | 8EC8C4F21DEDA1340044FB44 /* AKMaskFieldStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldStatus.swift; path = Classes/AKMaskFieldStatus.swift; sourceTree = ""; }; 56 | 8EC8C4F31DEDA1340044FB44 /* AKMaskFieldUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AKMaskFieldUtility.swift; path = Classes/AKMaskFieldUtility.swift; sourceTree = ""; }; 57 | 8EC8C4F41DEDA1340044FB44 /* CreditCardFormView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CreditCardFormView.swift; path = Classes/CreditCardFormView.swift; sourceTree = ""; }; 58 | 8EC8C4F51DEDA1340044FB44 /* CreditCardValidationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CreditCardValidationType.swift; path = Classes/CreditCardValidationType.swift; sourceTree = ""; }; 59 | 8EC8C4F61DEDA1340044FB44 /* CreditCardValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CreditCardValidator.swift; path = Classes/CreditCardValidator.swift; sourceTree = ""; }; 60 | 8EC8C4F71DEDA1340044FB44 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utilities.swift; path = Classes/Utilities.swift; sourceTree = ""; }; 61 | 8EC8C5091DEDB5EA0044FB44 /* CreditCardForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CreditCardForm.h; sourceTree = ""; }; 62 | 8EC8C50B1DEDC0420044FB44 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 63 | 8EFED2801E2796A6002BE8D5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 64 | ADEDAE40183C8D1AA2D6877F /* Pods_CreditCardForm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CreditCardForm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | 8EC8C3C51DEC8C3E0044FB44 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | 8EC8C3CF1DEC8C3E0044FB44 /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 8EC8C3D31DEC8C3E0044FB44 /* CreditCardForm.framework in Frameworks */, 80 | 5639844A00E3E6E670C48111 /* Pods_CreditCardFormTests.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 0C6147D0872EBEC9D5306BAC /* Pods */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | ); 91 | name = Pods; 92 | sourceTree = ""; 93 | }; 94 | 8EC8C3BF1DEC8C3E0044FB44 = { 95 | isa = PBXGroup; 96 | children = ( 97 | 8EC8C3CB1DEC8C3E0044FB44 /* CreditCardForm */, 98 | 8EC8C3D61DEC8C3E0044FB44 /* CreditCardFormTests */, 99 | 8EC8C3CA1DEC8C3E0044FB44 /* Products */, 100 | 0C6147D0872EBEC9D5306BAC /* Pods */, 101 | 8F926695DA4627EF2E17D452 /* Frameworks */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | 8EC8C3CA1DEC8C3E0044FB44 /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 8EC8C3C91DEC8C3E0044FB44 /* CreditCardForm.framework */, 109 | 8EC8C3D21DEC8C3E0044FB44 /* CreditCardFormTests.xctest */, 110 | ); 111 | name = Products; 112 | sourceTree = ""; 113 | }; 114 | 8EC8C3CB1DEC8C3E0044FB44 /* CreditCardForm */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 8EC8C3CD1DEC8C3E0044FB44 /* Info.plist */, 118 | 8EC8C5091DEDB5EA0044FB44 /* CreditCardForm.h */, 119 | 8EC8C4ED1DEDA1340044FB44 /* AKMaskField.swift */, 120 | 8EC8C4EE1DEDA1340044FB44 /* AKMaskFieldBlock.swift */, 121 | 8EC8C4EF1DEDA1340044FB44 /* AKMaskFieldBlockCharacter.swift */, 122 | 8EC8C4F01DEDA1340044FB44 /* AKMaskFieldEvent.swift */, 123 | 8EC8C4F11DEDA1340044FB44 /* AKMaskFieldPatternCharacter.swift */, 124 | 8EC8C4F21DEDA1340044FB44 /* AKMaskFieldStatus.swift */, 125 | 8EC8C4F31DEDA1340044FB44 /* AKMaskFieldUtility.swift */, 126 | 8EC8C4F41DEDA1340044FB44 /* CreditCardFormView.swift */, 127 | 8EC8C4F51DEDA1340044FB44 /* CreditCardValidationType.swift */, 128 | 8EC8C4F61DEDA1340044FB44 /* CreditCardValidator.swift */, 129 | 8EC8C4F71DEDA1340044FB44 /* Utilities.swift */, 130 | 8EFED2801E2796A6002BE8D5 /* Images.xcassets */, 131 | 8E1A520A1E7BF24500F02033 /* LICENSE */, 132 | 8EC8C50B1DEDC0420044FB44 /* README.md */, 133 | 8EB6C7951DF93FD300225444 /* CreditCardForm.podspec */, 134 | ); 135 | path = CreditCardForm; 136 | sourceTree = ""; 137 | }; 138 | 8EC8C3D61DEC8C3E0044FB44 /* CreditCardFormTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 8EC8C3D71DEC8C3E0044FB44 /* CreditCardFormTests.swift */, 142 | 8EC8C3D91DEC8C3E0044FB44 /* Info.plist */, 143 | ); 144 | path = CreditCardFormTests; 145 | sourceTree = ""; 146 | }; 147 | 8F926695DA4627EF2E17D452 /* Frameworks */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | ADEDAE40183C8D1AA2D6877F /* Pods_CreditCardForm.framework */, 151 | 5B58AD822FD99C8D36962BC8 /* Pods_CreditCardFormTests.framework */, 152 | ); 153 | name = Frameworks; 154 | sourceTree = ""; 155 | }; 156 | /* End PBXGroup section */ 157 | 158 | /* Begin PBXHeadersBuildPhase section */ 159 | 8EC8C3C61DEC8C3E0044FB44 /* Headers */ = { 160 | isa = PBXHeadersBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 8EC8C50A1DEDB5EA0044FB44 /* CreditCardForm.h in Headers */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXHeadersBuildPhase section */ 168 | 169 | /* Begin PBXNativeTarget section */ 170 | 8EC8C3C81DEC8C3E0044FB44 /* CreditCardForm */ = { 171 | isa = PBXNativeTarget; 172 | buildConfigurationList = 8EC8C3DD1DEC8C3E0044FB44 /* Build configuration list for PBXNativeTarget "CreditCardForm" */; 173 | buildPhases = ( 174 | 8EC8C3C41DEC8C3E0044FB44 /* Sources */, 175 | 8EC8C3C51DEC8C3E0044FB44 /* Frameworks */, 176 | 8EC8C3C61DEC8C3E0044FB44 /* Headers */, 177 | 8EC8C3C71DEC8C3E0044FB44 /* Resources */, 178 | ); 179 | buildRules = ( 180 | ); 181 | dependencies = ( 182 | ); 183 | name = CreditCardForm; 184 | productName = CreditCardForm; 185 | productReference = 8EC8C3C91DEC8C3E0044FB44 /* CreditCardForm.framework */; 186 | productType = "com.apple.product-type.framework"; 187 | }; 188 | 8EC8C3D11DEC8C3E0044FB44 /* CreditCardFormTests */ = { 189 | isa = PBXNativeTarget; 190 | buildConfigurationList = 8EC8C3E01DEC8C3E0044FB44 /* Build configuration list for PBXNativeTarget "CreditCardFormTests" */; 191 | buildPhases = ( 192 | 45DD3926D0EAE4A137E80F4C /* [CP] Check Pods Manifest.lock */, 193 | 8EC8C3CE1DEC8C3E0044FB44 /* Sources */, 194 | 8EC8C3CF1DEC8C3E0044FB44 /* Frameworks */, 195 | 8EC8C3D01DEC8C3E0044FB44 /* Resources */, 196 | 26EB313D2B550B79F7269AFA /* [CP] Embed Pods Frameworks */, 197 | F758523A7CC3E083F529AB08 /* [CP] Copy Pods Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | 8EC8C3D51DEC8C3E0044FB44 /* PBXTargetDependency */, 203 | ); 204 | name = CreditCardFormTests; 205 | productName = CreditCardFormTests; 206 | productReference = 8EC8C3D21DEC8C3E0044FB44 /* CreditCardFormTests.xctest */; 207 | productType = "com.apple.product-type.bundle.unit-test"; 208 | }; 209 | /* End PBXNativeTarget section */ 210 | 211 | /* Begin PBXProject section */ 212 | 8EC8C3C01DEC8C3E0044FB44 /* Project object */ = { 213 | isa = PBXProject; 214 | attributes = { 215 | LastSwiftUpdateCheck = 0820; 216 | LastUpgradeCheck = 1130; 217 | ORGANIZATIONNAME = Veriloft; 218 | TargetAttributes = { 219 | 8EC8C3C81DEC8C3E0044FB44 = { 220 | CreatedOnToolsVersion = 8.2; 221 | DevelopmentTeam = PRXV6FLQY4; 222 | LastSwiftMigration = 0820; 223 | ProvisioningStyle = Automatic; 224 | }; 225 | 8EC8C3D11DEC8C3E0044FB44 = { 226 | CreatedOnToolsVersion = 8.2; 227 | DevelopmentTeam = 683U48NZTT; 228 | ProvisioningStyle = Automatic; 229 | }; 230 | }; 231 | }; 232 | buildConfigurationList = 8EC8C3C31DEC8C3E0044FB44 /* Build configuration list for PBXProject "CreditCardForm" */; 233 | compatibilityVersion = "Xcode 3.2"; 234 | developmentRegion = en; 235 | hasScannedForEncodings = 0; 236 | knownRegions = ( 237 | en, 238 | Base, 239 | ); 240 | mainGroup = 8EC8C3BF1DEC8C3E0044FB44; 241 | productRefGroup = 8EC8C3CA1DEC8C3E0044FB44 /* Products */; 242 | projectDirPath = ""; 243 | projectRoot = ""; 244 | targets = ( 245 | 8EC8C3C81DEC8C3E0044FB44 /* CreditCardForm */, 246 | 8EC8C3D11DEC8C3E0044FB44 /* CreditCardFormTests */, 247 | ); 248 | }; 249 | /* End PBXProject section */ 250 | 251 | /* Begin PBXResourcesBuildPhase section */ 252 | 8EC8C3C71DEC8C3E0044FB44 /* Resources */ = { 253 | isa = PBXResourcesBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | 8E68F4E01E98C9690086D6F3 /* README.md in Resources */, 257 | 8E1A520B1E7BF24500F02033 /* LICENSE in Resources */, 258 | 8EFED2811E2796A6002BE8D5 /* Images.xcassets in Resources */, 259 | 8EB6C7961DF93FD300225444 /* CreditCardForm.podspec in Resources */, 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | 8EC8C3D01DEC8C3E0044FB44 /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXResourcesBuildPhase section */ 271 | 272 | /* Begin PBXShellScriptBuildPhase section */ 273 | 26EB313D2B550B79F7269AFA /* [CP] Embed Pods Frameworks */ = { 274 | isa = PBXShellScriptBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | inputPaths = ( 279 | ); 280 | name = "[CP] Embed Pods Frameworks"; 281 | outputPaths = ( 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | shellPath = /bin/sh; 285 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CreditCardFormTests/Pods-CreditCardFormTests-frameworks.sh\"\n"; 286 | showEnvVarsInLog = 0; 287 | }; 288 | 45DD3926D0EAE4A137E80F4C /* [CP] Check Pods Manifest.lock */ = { 289 | isa = PBXShellScriptBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | ); 293 | inputPaths = ( 294 | ); 295 | name = "[CP] Check Pods Manifest.lock"; 296 | outputPaths = ( 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | shellPath = /bin/sh; 300 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 301 | showEnvVarsInLog = 0; 302 | }; 303 | F758523A7CC3E083F529AB08 /* [CP] Copy Pods Resources */ = { 304 | isa = PBXShellScriptBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | ); 308 | inputPaths = ( 309 | ); 310 | name = "[CP] Copy Pods Resources"; 311 | outputPaths = ( 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | shellPath = /bin/sh; 315 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CreditCardFormTests/Pods-CreditCardFormTests-resources.sh\"\n"; 316 | showEnvVarsInLog = 0; 317 | }; 318 | /* End PBXShellScriptBuildPhase section */ 319 | 320 | /* Begin PBXSourcesBuildPhase section */ 321 | 8EC8C3C41DEC8C3E0044FB44 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 8EC8C5001DEDA1340044FB44 /* CreditCardValidationType.swift in Sources */, 326 | 8EC8C4F91DEDA1340044FB44 /* AKMaskFieldBlock.swift in Sources */, 327 | 8EC8C5021DEDA1340044FB44 /* Utilities.swift in Sources */, 328 | 8EC8C4F81DEDA1340044FB44 /* AKMaskField.swift in Sources */, 329 | 8EC8C5011DEDA1340044FB44 /* CreditCardValidator.swift in Sources */, 330 | 8EC8C4FA1DEDA1340044FB44 /* AKMaskFieldBlockCharacter.swift in Sources */, 331 | 8EC8C4FE1DEDA1340044FB44 /* AKMaskFieldUtility.swift in Sources */, 332 | 8EC8C4FC1DEDA1340044FB44 /* AKMaskFieldPatternCharacter.swift in Sources */, 333 | 8EC8C4FF1DEDA1340044FB44 /* CreditCardFormView.swift in Sources */, 334 | 8EC8C4FD1DEDA1340044FB44 /* AKMaskFieldStatus.swift in Sources */, 335 | 8EC8C4FB1DEDA1340044FB44 /* AKMaskFieldEvent.swift in Sources */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | 8EC8C3CE1DEC8C3E0044FB44 /* Sources */ = { 340 | isa = PBXSourcesBuildPhase; 341 | buildActionMask = 2147483647; 342 | files = ( 343 | 8EC8C3D81DEC8C3E0044FB44 /* CreditCardFormTests.swift in Sources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXSourcesBuildPhase section */ 348 | 349 | /* Begin PBXTargetDependency section */ 350 | 8EC8C3D51DEC8C3E0044FB44 /* PBXTargetDependency */ = { 351 | isa = PBXTargetDependency; 352 | target = 8EC8C3C81DEC8C3E0044FB44 /* CreditCardForm */; 353 | targetProxy = 8EC8C3D41DEC8C3E0044FB44 /* PBXContainerItemProxy */; 354 | }; 355 | /* End PBXTargetDependency section */ 356 | 357 | /* Begin XCBuildConfiguration section */ 358 | 8EC8C3DB1DEC8C3E0044FB44 /* Debug */ = { 359 | isa = XCBuildConfiguration; 360 | buildSettings = { 361 | ALWAYS_SEARCH_USER_PATHS = NO; 362 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 363 | CLANG_ANALYZER_NONNULL = YES; 364 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 365 | CLANG_CXX_LIBRARY = "libc++"; 366 | CLANG_ENABLE_MODULES = YES; 367 | CLANG_ENABLE_OBJC_ARC = YES; 368 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 369 | CLANG_WARN_BOOL_CONVERSION = YES; 370 | CLANG_WARN_COMMA = YES; 371 | CLANG_WARN_CONSTANT_CONVERSION = YES; 372 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INFINITE_RECURSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 380 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 381 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 384 | CLANG_WARN_STRICT_PROTOTYPES = YES; 385 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 386 | CLANG_WARN_UNREACHABLE_CODE = YES; 387 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 388 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 389 | COPY_PHASE_STRIP = NO; 390 | CURRENT_PROJECT_VERSION = 1; 391 | DEBUG_INFORMATION_FORMAT = dwarf; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | ENABLE_TESTABILITY = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu99; 395 | GCC_DYNAMIC_NO_PIC = NO; 396 | GCC_NO_COMMON_BLOCKS = YES; 397 | GCC_OPTIMIZATION_LEVEL = 0; 398 | GCC_PREPROCESSOR_DEFINITIONS = ( 399 | "DEBUG=1", 400 | "$(inherited)", 401 | ); 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 409 | MTL_ENABLE_DEBUG_INFO = YES; 410 | ONLY_ACTIVE_ARCH = YES; 411 | SDKROOT = iphoneos; 412 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 413 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 414 | SWIFT_VERSION = 4.2; 415 | TARGETED_DEVICE_FAMILY = "1,2"; 416 | VERSIONING_SYSTEM = "apple-generic"; 417 | VERSION_INFO_PREFIX = ""; 418 | }; 419 | name = Debug; 420 | }; 421 | 8EC8C3DC1DEC8C3E0044FB44 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 426 | CLANG_ANALYZER_NONNULL = YES; 427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 428 | CLANG_CXX_LIBRARY = "libc++"; 429 | CLANG_ENABLE_MODULES = YES; 430 | CLANG_ENABLE_OBJC_ARC = YES; 431 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 432 | CLANG_WARN_BOOL_CONVERSION = YES; 433 | CLANG_WARN_COMMA = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 443 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 444 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 446 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 447 | CLANG_WARN_STRICT_PROTOTYPES = YES; 448 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 449 | CLANG_WARN_UNREACHABLE_CODE = YES; 450 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 451 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 452 | COPY_PHASE_STRIP = NO; 453 | CURRENT_PROJECT_VERSION = 1; 454 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 455 | ENABLE_NS_ASSERTIONS = NO; 456 | ENABLE_STRICT_OBJC_MSGSEND = YES; 457 | GCC_C_LANGUAGE_STANDARD = gnu99; 458 | GCC_NO_COMMON_BLOCKS = YES; 459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 461 | GCC_WARN_UNDECLARED_SELECTOR = YES; 462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 463 | GCC_WARN_UNUSED_FUNCTION = YES; 464 | GCC_WARN_UNUSED_VARIABLE = YES; 465 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 466 | MTL_ENABLE_DEBUG_INFO = NO; 467 | SDKROOT = iphoneos; 468 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 469 | SWIFT_VERSION = 4.2; 470 | TARGETED_DEVICE_FAMILY = "1,2"; 471 | VALIDATE_PRODUCT = YES; 472 | VERSIONING_SYSTEM = "apple-generic"; 473 | VERSION_INFO_PREFIX = ""; 474 | }; 475 | name = Release; 476 | }; 477 | 8EC8C3DE1DEC8C3E0044FB44 /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 481 | CLANG_ENABLE_MODULES = YES; 482 | CODE_SIGN_IDENTITY = "Apple Development"; 483 | DEFINES_MODULE = YES; 484 | DEVELOPMENT_TEAM = PRXV6FLQY4; 485 | DYLIB_COMPATIBILITY_VERSION = 1; 486 | DYLIB_CURRENT_VERSION = 1; 487 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 488 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 489 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 490 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 491 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 492 | MARKETING_VERSION = 0.0.8; 493 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.CreditCardForm; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | SKIP_INSTALL = YES; 496 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 497 | SWIFT_VERSION = 5.0; 498 | }; 499 | name = Debug; 500 | }; 501 | 8EC8C3DF1DEC8C3E0044FB44 /* Release */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 505 | CLANG_ENABLE_MODULES = YES; 506 | CODE_SIGN_IDENTITY = "Apple Development"; 507 | DEFINES_MODULE = YES; 508 | DEVELOPMENT_TEAM = PRXV6FLQY4; 509 | DYLIB_COMPATIBILITY_VERSION = 1; 510 | DYLIB_CURRENT_VERSION = 1; 511 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 512 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 513 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 514 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 516 | MARKETING_VERSION = 0.0.8; 517 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.CreditCardForm; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | SKIP_INSTALL = YES; 520 | SWIFT_VERSION = 5.0; 521 | }; 522 | name = Release; 523 | }; 524 | 8EC8C3E11DEC8C3E0044FB44 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 528 | DEVELOPMENT_TEAM = 683U48NZTT; 529 | INFOPLIST_FILE = CreditCardFormTests/Info.plist; 530 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 531 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.CreditCardFormTests; 532 | PRODUCT_NAME = "$(TARGET_NAME)"; 533 | SWIFT_VERSION = 5.0; 534 | }; 535 | name = Debug; 536 | }; 537 | 8EC8C3E21DEC8C3E0044FB44 /* Release */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 541 | DEVELOPMENT_TEAM = 683U48NZTT; 542 | INFOPLIST_FILE = CreditCardFormTests/Info.plist; 543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 544 | PRODUCT_BUNDLE_IDENTIFIER = com.orazz.CreditCardFormTests; 545 | PRODUCT_NAME = "$(TARGET_NAME)"; 546 | SWIFT_VERSION = 5.0; 547 | }; 548 | name = Release; 549 | }; 550 | /* End XCBuildConfiguration section */ 551 | 552 | /* Begin XCConfigurationList section */ 553 | 8EC8C3C31DEC8C3E0044FB44 /* Build configuration list for PBXProject "CreditCardForm" */ = { 554 | isa = XCConfigurationList; 555 | buildConfigurations = ( 556 | 8EC8C3DB1DEC8C3E0044FB44 /* Debug */, 557 | 8EC8C3DC1DEC8C3E0044FB44 /* Release */, 558 | ); 559 | defaultConfigurationIsVisible = 0; 560 | defaultConfigurationName = Release; 561 | }; 562 | 8EC8C3DD1DEC8C3E0044FB44 /* Build configuration list for PBXNativeTarget "CreditCardForm" */ = { 563 | isa = XCConfigurationList; 564 | buildConfigurations = ( 565 | 8EC8C3DE1DEC8C3E0044FB44 /* Debug */, 566 | 8EC8C3DF1DEC8C3E0044FB44 /* Release */, 567 | ); 568 | defaultConfigurationIsVisible = 0; 569 | defaultConfigurationName = Release; 570 | }; 571 | 8EC8C3E01DEC8C3E0044FB44 /* Build configuration list for PBXNativeTarget "CreditCardFormTests" */ = { 572 | isa = XCConfigurationList; 573 | buildConfigurations = ( 574 | 8EC8C3E11DEC8C3E0044FB44 /* Debug */, 575 | 8EC8C3E21DEC8C3E0044FB44 /* Release */, 576 | ); 577 | defaultConfigurationIsVisible = 0; 578 | defaultConfigurationName = Release; 579 | }; 580 | /* End XCConfigurationList section */ 581 | }; 582 | rootObject = 8EC8C3C01DEC8C3E0044FB44 /* Project object */; 583 | } 584 | -------------------------------------------------------------------------------- /CreditCardForm/Classes/CreditCardFormView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreditCardForumView.swift 3 | // CreditCardForm 4 | // 5 | // Created by Atakishiyev Orazdurdy on 11/28/16. 6 | // Copyright © 2016 Veriloft. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum Brands : String { 12 | case NONE, Visa, UnionPay, MasterCard, Amex, JCB, DEFAULT, Discover 13 | } 14 | 15 | @IBDesignable 16 | public class CreditCardFormView : UIView { 17 | 18 | fileprivate var cardView: UIView = UIView(frame: .zero) 19 | fileprivate var backView: UIView = UIView(frame: .zero) 20 | fileprivate var frontView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 200)) 21 | fileprivate var gradientLayer = CAGradientLayer() 22 | fileprivate var showingBack:Bool = false 23 | 24 | fileprivate var backImage: UIImageView = UIImageView(frame: .zero) 25 | fileprivate var brandImageView = UIImageView(frame: .zero) 26 | fileprivate var cardNumber:AKMaskField = AKMaskField(frame: .zero) 27 | fileprivate var cardHolderText:UILabel = UILabel(frame: .zero) 28 | fileprivate var cardHolder:UILabel = UILabel(frame: .zero) 29 | fileprivate var expireDate: AKMaskField = AKMaskField(frame: .zero) 30 | fileprivate var expireDateText: UILabel = UILabel(frame: .zero) 31 | fileprivate var backLine: UIView = UIView(frame: .zero) 32 | fileprivate var cvc: AKMaskField = AKMaskField(frame: .zero) 33 | fileprivate var chipImg: UIImageView = UIImageView(frame: .zero) 34 | fileprivate var cvcAmexImageView: UIImageView = UIImageView(frame: .zero) 35 | fileprivate var amexCVC: AKMaskField = AKMaskField(frame: .zero) 36 | fileprivate var colors = [Brands.DEFAULT.rawValue: [ 37 | UIColor.hexStr(hexStr: "363434", alpha: 1), 38 | UIColor.hexStr(hexStr: "363434", alpha: 1)] 39 | ] 40 | 41 | fileprivate var cardNumberCenterXConstraint = NSLayoutConstraint() 42 | fileprivate var amex = false { 43 | didSet { 44 | self.cardNumberCenterXConstraint.constant = (self.amex) ? -20 : 0.0 45 | self.cvcAmexImageView.isHidden = !self.amex 46 | self.amexCVC.isHidden = !self.amex 47 | UIView.animate(withDuration: 0.5) { 48 | self.cardView.layoutIfNeeded() 49 | } 50 | } 51 | } 52 | 53 | public var cardGradientColors = [String : [UIColor]]() 54 | 55 | @IBInspectable 56 | public var defaultCardColor: UIColor = UIColor.hexStr(hexStr: "363434", alpha: 1) { 57 | didSet { 58 | gradientLayer.colors = [defaultCardColor.cgColor, defaultCardColor.cgColor] 59 | backView.backgroundColor = defaultCardColor 60 | } 61 | } 62 | 63 | @IBInspectable 64 | public var cardHolderExpireDateTextColor: UIColor = UIColor.hexStr(hexStr: "#bdc3c7", alpha: 1) { 65 | didSet { 66 | cardHolderText.textColor = cardHolderExpireDateTextColor 67 | expireDateText.textColor = cardHolderExpireDateTextColor 68 | amexCVC.textColor = cardHolderExpireDateColor 69 | } 70 | } 71 | 72 | @IBInspectable 73 | public var cardHolderExpireDateColor: UIColor = .white { 74 | didSet { 75 | cardHolder.textColor = cardHolderExpireDateColor 76 | expireDate.textColor = cardHolderExpireDateColor 77 | cardNumber.textColor = cardHolderExpireDateColor 78 | } 79 | } 80 | 81 | @IBInspectable 82 | public var backLineColor: UIColor = .black { 83 | didSet { 84 | backLine.backgroundColor = backLineColor 85 | } 86 | } 87 | 88 | @IBInspectable 89 | public var chipImage = UIImage(named: "chip", in: Bundle.currentBundle(), compatibleWith: nil) { 90 | didSet { 91 | chipImg.image = chipImage 92 | } 93 | } 94 | 95 | @IBInspectable 96 | public var cvcAmexImageName = UIImage(named: "amexCvc", in: Bundle.currentBundle(), compatibleWith: nil) { 97 | didSet { 98 | cvcAmexImageView.image = cvcAmexImageName 99 | } 100 | } 101 | 102 | @IBInspectable 103 | public var cardHolderString = "----" { 104 | didSet { 105 | cardHolder.text = cardHolderString 106 | } 107 | } 108 | 109 | @IBInspectable 110 | public var cardHolderPlaceholderString = "CARD HOLDER" { 111 | didSet { 112 | cardHolderText.text = cardHolderPlaceholderString 113 | } 114 | } 115 | 116 | @IBInspectable 117 | public var expireDatePlaceholderText = "EXPIRY" { 118 | didSet { 119 | expireDateText.text = expireDatePlaceholderText 120 | } 121 | } 122 | 123 | @IBInspectable 124 | public var cardNumberMaskExpression = "{....} {....} {....} {....}" { 125 | didSet { 126 | cardNumber.maskExpression = cardNumberMaskExpression 127 | } 128 | } 129 | 130 | @IBInspectable 131 | public var cardNumberMaskTemplate = "**** **** **** ****" { 132 | didSet { 133 | cardNumber.maskTemplate = cardNumberMaskTemplate 134 | } 135 | } 136 | 137 | public var cardNumberFont: UIFont = UIFont(name: "HelveticaNeue", size: 20)! 138 | public var cardPlaceholdersFont: UIFont = UIFont(name: "HelveticaNeue", size: 10)! 139 | public var cardTextFont: UIFont = UIFont(name: "HelveticaNeue", size: 12)! 140 | 141 | public override init(frame: CGRect) { 142 | super.init(frame: frame) 143 | createViews() 144 | } 145 | 146 | required public init?(coder aDecoder: NSCoder) { 147 | super.init(coder: aDecoder) 148 | } 149 | 150 | public override func layoutSubviews() { 151 | super.layoutSubviews() 152 | createViews() 153 | } 154 | 155 | private func createViews() { 156 | frontView.isHidden = false 157 | backView.isHidden = true 158 | cardView.clipsToBounds = true 159 | 160 | if colors.count < 7 { 161 | setBrandColors() 162 | } 163 | 164 | createCardView() 165 | createFrontView() 166 | createbackImage() 167 | createBrandImageView() 168 | createCardNumber() 169 | createCardHolder() 170 | createCardHolderText() 171 | createExpireDate() 172 | createExpireDateText() 173 | createChipImage() 174 | createAmexCVC() 175 | createBackView() 176 | createBackLine() 177 | createCVC() 178 | } 179 | 180 | private func setGradientBackground(v: UIView, top: CGColor, bottom: CGColor) { 181 | let colorTop = top 182 | let colorBottom = bottom 183 | gradientLayer.colors = [ colorTop, colorBottom] 184 | gradientLayer.locations = [ 0.0, 1.0] 185 | gradientLayer.frame = v.bounds 186 | backView.backgroundColor = defaultCardColor 187 | v.layer.addSublayer(gradientLayer) 188 | } 189 | 190 | private func createCardView() { 191 | cardView.translatesAutoresizingMaskIntoConstraints = false 192 | cardView.layer.cornerRadius = 6 193 | cardView.backgroundColor = .clear 194 | self.addSubview(cardView) 195 | //CardView 196 | self.addConstraint(NSLayoutConstraint(item: cardView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0)); 197 | 198 | self.addConstraint(NSLayoutConstraint(item: cardView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0)); 199 | 200 | self.addConstraint(NSLayoutConstraint(item: cardView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.0, constant: 0.0)); 201 | 202 | self.addConstraint(NSLayoutConstraint(item: cardView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.0, constant: 0.0)); 203 | } 204 | 205 | private func createBackView() { 206 | backView.translatesAutoresizingMaskIntoConstraints = false 207 | backView.layer.cornerRadius = 6 208 | backView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) 209 | backView.autoresizingMask = [UIView.AutoresizingMask.flexibleLeftMargin, UIView.AutoresizingMask.flexibleRightMargin, UIView.AutoresizingMask.flexibleTopMargin, UIView.AutoresizingMask.flexibleBottomMargin] 210 | cardView.addSubview(backView) 211 | 212 | self.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0)); 213 | 214 | self.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0)); 215 | 216 | self.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.0, constant: 0.0)); 217 | 218 | self.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.0, constant: 0.0)); 219 | } 220 | 221 | private func createFrontView() { 222 | frontView.translatesAutoresizingMaskIntoConstraints = false 223 | frontView.layer.cornerRadius = 6 224 | frontView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) 225 | frontView.autoresizingMask = [UIView.AutoresizingMask.flexibleLeftMargin, UIView.AutoresizingMask.flexibleRightMargin, UIView.AutoresizingMask.flexibleTopMargin, UIView.AutoresizingMask.flexibleBottomMargin] 226 | cardView.addSubview(frontView) 227 | setGradientBackground(v: frontView, top: defaultCardColor.cgColor, bottom: defaultCardColor.cgColor) 228 | 229 | self.addConstraint(NSLayoutConstraint(item: frontView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0)); 230 | 231 | self.addConstraint(NSLayoutConstraint(item: frontView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0)); 232 | 233 | self.addConstraint(NSLayoutConstraint(item: frontView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.0, constant: 0.0)); 234 | 235 | self.addConstraint(NSLayoutConstraint(item: frontView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.0, constant: 0.0)); 236 | } 237 | 238 | private func createbackImage() { 239 | backImage.translatesAutoresizingMaskIntoConstraints = false 240 | backImage.image = UIImage(named: "back.jpg") 241 | backImage.contentMode = UIView.ContentMode.scaleAspectFill 242 | frontView.addSubview(backImage) 243 | 244 | self.addConstraint(NSLayoutConstraint(item: backImage, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0)); 245 | 246 | self.addConstraint(NSLayoutConstraint(item: backImage, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 0.0)); 247 | 248 | self.addConstraint(NSLayoutConstraint(item: backImage, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: 0.0)); 249 | 250 | self.addConstraint(NSLayoutConstraint(item: backImage, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 0.0)); 251 | } 252 | 253 | private func createBrandImageView() { 254 | //Card brand image 255 | brandImageView.translatesAutoresizingMaskIntoConstraints = false 256 | brandImageView.contentMode = UIView.ContentMode.scaleAspectFit 257 | frontView.addSubview(brandImageView) 258 | 259 | self.addConstraint(NSLayoutConstraint(item: brandImageView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 10)); 260 | 261 | self.addConstraint(NSLayoutConstraint(item: brandImageView, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -10)); 262 | 263 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==60)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": brandImageView])); 264 | 265 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==40)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": brandImageView])); 266 | } 267 | 268 | private func createCardNumber() { 269 | //Credit card number 270 | cardNumber.translatesAutoresizingMaskIntoConstraints = false 271 | cardNumber.maskExpression = cardNumberMaskExpression 272 | cardNumber.maskTemplate = cardNumberMaskTemplate 273 | cardNumber.textColor = cardHolderExpireDateColor 274 | cardNumber.isUserInteractionEnabled = false 275 | cardNumber.textAlignment = NSTextAlignment.center 276 | cardNumber.font = cardNumberFont 277 | frontView.addSubview(cardNumber) 278 | 279 | cardNumberCenterXConstraint = NSLayoutConstraint(item: cardNumber, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0) 280 | self.addConstraint(cardNumberCenterXConstraint); 281 | 282 | self.addConstraint(NSLayoutConstraint(item: cardNumber, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1.0, constant: 0.0)); 283 | 284 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==200)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cardNumber])); 285 | 286 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==30)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cardNumber])); 287 | } 288 | 289 | private func createCardHolder() { 290 | //Name 291 | cardHolder.translatesAutoresizingMaskIntoConstraints = false 292 | cardHolder.font = cardTextFont 293 | cardHolder.textColor = cardHolderExpireDateColor 294 | cardHolder.text = cardHolderString 295 | frontView.addSubview(cardHolder) 296 | 297 | self.addConstraint(NSLayoutConstraint(item: cardHolder, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: -20)); 298 | 299 | self.addConstraint(NSLayoutConstraint(item: cardHolder, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 15)); 300 | 301 | self.addConstraint(NSLayoutConstraint(item: cardHolder, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.0, constant: 20)); 302 | } 303 | 304 | private func createCardHolderText() { 305 | //Card holder uilabel 306 | cardHolderText.translatesAutoresizingMaskIntoConstraints = false 307 | cardHolderText.font = cardPlaceholdersFont 308 | cardHolderText.text = cardHolderPlaceholderString 309 | cardHolderText.textColor = cardHolderExpireDateTextColor 310 | frontView.addSubview(cardHolderText) 311 | 312 | self.addConstraint(NSLayoutConstraint(item: cardHolderText, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardHolder, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: -3)); 313 | 314 | self.addConstraint(NSLayoutConstraint(item: cardHolderText, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 15)); 315 | } 316 | 317 | private func createExpireDate() { 318 | //Expire Date 319 | expireDate = AKMaskField() 320 | expireDate.translatesAutoresizingMaskIntoConstraints = false 321 | expireDate.font = cardTextFont 322 | expireDate.maskExpression = "{..}/{..}" 323 | expireDate.text = "MM/YY" 324 | expireDate.textColor = cardHolderExpireDateColor 325 | frontView.addSubview(expireDate) 326 | 327 | self.addConstraint(NSLayoutConstraint(item: expireDate, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: -20)); 328 | 329 | self.addConstraint(NSLayoutConstraint(item: expireDate, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -55)); 330 | } 331 | 332 | private func createExpireDateText() { 333 | //Expire Date Text 334 | expireDateText.translatesAutoresizingMaskIntoConstraints = false 335 | expireDateText.font = cardPlaceholdersFont 336 | expireDateText.text = expireDatePlaceholderText 337 | expireDateText.textColor = cardHolderExpireDateTextColor 338 | frontView.addSubview(expireDateText) 339 | 340 | self.addConstraint(NSLayoutConstraint(item: expireDateText, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: expireDate, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: -3)); 341 | 342 | self.addConstraint(NSLayoutConstraint(item: expireDateText, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -58)); 343 | } 344 | 345 | private func createAmexCVC() { 346 | 347 | //Create Amex card cvc 348 | amexCVC = AKMaskField() 349 | amexCVC.translatesAutoresizingMaskIntoConstraints = false 350 | amexCVC.font = cardTextFont 351 | amexCVC.text = expireDatePlaceholderText 352 | amexCVC.maskExpression = "{....}" 353 | amexCVC.text = "***" 354 | amexCVC.isHidden = true 355 | frontView.addSubview(amexCVC) 356 | 357 | self.addConstraint(NSLayoutConstraint(item: amexCVC, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -23)); 358 | 359 | self.addConstraint(NSLayoutConstraint(item: amexCVC, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardNumber, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1.0, constant: 15)); 360 | 361 | self.addConstraint(NSLayoutConstraint(item: amexCVC, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.0, constant: 27)); 362 | 363 | // Create amex cvc image 364 | cvcAmexImageView.translatesAutoresizingMaskIntoConstraints = false 365 | cvcAmexImageView.image = cvcAmexImageName 366 | cvcAmexImageView.contentMode = ContentMode.scaleAspectFit 367 | cvcAmexImageView.isHidden = true 368 | frontView.addSubview(cvcAmexImageView) 369 | 370 | self.addConstraint(NSLayoutConstraint(item: cvcAmexImageView, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: amexCVC, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: -5)); 371 | 372 | self.addConstraint(NSLayoutConstraint(item: cvcAmexImageView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: amexCVC, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1.0, constant: 0)); 373 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==15)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cvcAmexImageView])); 374 | 375 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==15)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cvcAmexImageView])); 376 | 377 | } 378 | 379 | private func createChipImage() { 380 | //Chip image 381 | chipImg.translatesAutoresizingMaskIntoConstraints = false 382 | chipImg.alpha = 0.5 383 | chipImg.image = chipImage 384 | frontView.addSubview(chipImg) 385 | 386 | self.addConstraint(NSLayoutConstraint(item: chipImg, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 15)); 387 | 388 | self.addConstraint(NSLayoutConstraint(item: chipImg, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cardView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 15)); 389 | 390 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==45)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": chipImg])); 391 | 392 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==30)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": chipImg])); 393 | } 394 | 395 | private func createBackLine() { 396 | //BackLine 397 | backLine.translatesAutoresizingMaskIntoConstraints = false 398 | backLine.backgroundColor = backLineColor 399 | backView.addSubview(backLine) 400 | 401 | self.addConstraint(NSLayoutConstraint(item: backLine, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: backView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 20)); 402 | 403 | self.addConstraint(NSLayoutConstraint(item: backLine, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: backView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0)); 404 | 405 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==300)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": backLine])); 406 | 407 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==50)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": backLine])); 408 | } 409 | 410 | private func createCVC() { 411 | //CVC textfield 412 | cvc.translatesAutoresizingMaskIntoConstraints = false 413 | cvc.maskExpression = "..." 414 | cvc.text = "CVC" 415 | cvc.backgroundColor = .white 416 | cvc.textAlignment = NSTextAlignment.center 417 | cvc.isUserInteractionEnabled = false 418 | if #available(iOS 13.0, *) { 419 | cvc.backgroundColor = UIColor.systemGray3 420 | } 421 | backView.addSubview(cvc) 422 | 423 | self.addConstraint(NSLayoutConstraint(item: cvc, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: backLine, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 10)); 424 | 425 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[view(==50)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cvc])); 426 | 427 | self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[view(==25)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: ["view": cvc])); 428 | 429 | self.addConstraint(NSLayoutConstraint(item: cvc, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: backView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -10)); 430 | } 431 | 432 | private func setType(colors: [UIColor], alpha: CGFloat, back: UIColor) { 433 | UIView.animate(withDuration: 2, animations: { () -> Void in 434 | self.gradientLayer.colors = [colors[0].cgColor, colors[1].cgColor] 435 | }) 436 | self.backView.backgroundColor = back 437 | self.chipImg.alpha = alpha 438 | } 439 | 440 | private func flip() { 441 | var showingSide = frontView 442 | var hiddenSide = backView 443 | if showingBack { 444 | (showingSide, hiddenSide) = (backView, frontView) 445 | } 446 | 447 | UIView.transition(from:showingSide, 448 | to: hiddenSide, 449 | duration: 0.7, 450 | options: [UIView.AnimationOptions.transitionFlipFromRight, UIView.AnimationOptions.showHideTransitionViews], 451 | completion: nil) 452 | } 453 | 454 | public func isAmex() -> Bool { 455 | return self.amex 456 | } 457 | 458 | public func paymentCardTextFieldDidChange(cardNumber: String? = "", expirationYear: UInt?, expirationMonth: UInt?, cvc: String? = "") { 459 | self.cardNumber.text = cardNumber 460 | 461 | if let expireMonth = expirationMonth, let expireYear = expirationYear { 462 | self.expireDate.text = NSString(format: "%02ld", expireMonth) as String + "/" + (NSString(format: "%02ld", expireYear) as String) 463 | } 464 | 465 | if expirationMonth == 0 { 466 | expireDate.text = "MM/YY" 467 | } 468 | 469 | let v = CreditCardValidator() 470 | self.cvc.text = cvc 471 | self.amexCVC.text = cvc 472 | 473 | guard let cardN = cardNumber else { 474 | return 475 | } 476 | 477 | if (cardN.count == 0) 478 | { 479 | self.cardNumber.maskExpression = "{....} {....} {....} {....}" 480 | } 481 | if (cardN.count >= 7 || cardN.count < 4) { 482 | amex = false 483 | guard let type = v.type(from: "\(cardN as String?)") else { 484 | self.brandImageView.image = nil 485 | if let name = colors["NONE"] { 486 | setType(colors: [name[0], name[1]], alpha: 0.5, back: name[0]) 487 | } 488 | return 489 | } 490 | 491 | // Visa, Mastercard, Amex etc. 492 | if let name = colors[type.name] { 493 | if(type.name.lowercased() == "amex".lowercased()){ 494 | if !amex { 495 | self.cardNumber.maskExpression = "{....} {....} {....} {...}" 496 | self.cardNumber.text = cardNumber 497 | amex = true 498 | } 499 | } 500 | self.brandImageView.image = UIImage(named: type.name, in: Bundle.currentBundle(), compatibleWith: nil) 501 | setType(colors: [name[0], name[1]], alpha: 1, back: name[0]) 502 | } else { 503 | setType(colors: [self.colors["DEFAULT"]![0], self.colors["DEFAULT"]![0]], alpha: 1, back: self.colors["DEFAULT"]![0]) 504 | } 505 | } 506 | } 507 | 508 | public func paymentCardTextFieldDidEndEditingExpiration(expirationYear: UInt) { 509 | if "\(expirationYear)".count <= 1 { 510 | expireDate.text = "MM/YY" 511 | } 512 | } 513 | 514 | public func paymentCardTextFieldDidBeginEditingCVC() { 515 | if !showingBack { 516 | if !amex { 517 | flip() 518 | showingBack = true 519 | } 520 | } 521 | } 522 | 523 | public func paymentCardTextFieldDidEndEditingCVC() { 524 | if showingBack { 525 | flip() 526 | showingBack = false 527 | } 528 | } 529 | 530 | } 531 | 532 | //: CardColors 533 | extension CreditCardFormView { 534 | 535 | fileprivate func setBrandColors() { 536 | colors[Brands.NONE.rawValue] = [defaultCardColor, defaultCardColor] 537 | colors[Brands.Visa.rawValue] = [UIColor.hexStr(hexStr: "#5D8BF2", alpha: 1), UIColor.hexStr(hexStr: "#3545AE", alpha: 1)] 538 | colors[Brands.MasterCard.rawValue] = [UIColor.hexStr(hexStr: "#ED495A", alpha: 1), UIColor.hexStr(hexStr: "#8B1A2B", alpha: 1)] 539 | colors[Brands.UnionPay.rawValue] = [UIColor.hexStr(hexStr: "#987c00", alpha: 1), UIColor.hexStr(hexStr: "#826a01", alpha: 1)] 540 | colors[Brands.Amex.rawValue] = [UIColor.hexStr(hexStr: "#005B9D", alpha: 1), UIColor.hexStr(hexStr: "#132972", alpha: 1)] 541 | colors[Brands.JCB.rawValue] = [UIColor.hexStr(hexStr: "#265797", alpha: 1), UIColor.hexStr(hexStr: "#3d6eaa", alpha: 1)] 542 | colors["Diners Club"] = [UIColor.hexStr(hexStr: "#5b99d8", alpha: 1), UIColor.hexStr(hexStr: "#4186CD", alpha: 1)] 543 | colors[Brands.Discover.rawValue] = [UIColor.hexStr(hexStr: "#e8a258", alpha: 1), UIColor.hexStr(hexStr: "#D97B16", alpha: 1)] 544 | colors[Brands.DEFAULT.rawValue] = [UIColor.hexStr(hexStr: "#5D8BF2", alpha: 1), UIColor.hexStr(hexStr: "#3545AE", alpha: 1)] 545 | 546 | if cardGradientColors.count > 0 { 547 | for (_, value) in cardGradientColors.enumerated() { 548 | colors[value.key] = value.value 549 | } 550 | } 551 | } 552 | } 553 | 554 | 555 | --------------------------------------------------------------------------------