From 15be48e434e8da29e6a84fd1383c25800a7da602 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 28 Jul 2016 07:23:05 +0200 Subject: [PATCH 01/20] Initial conversion to Swift 3 syntax --- Caishen.xcodeproj/project.pbxproj | 12 +-- CaishenTests/CaishenTests.swift | 2 +- CaishenTests/CardNumberFormatterTests.swift | 2 +- CaishenTests/CardNumberValidatorTests.swift | 12 +-- CaishenTests/XCTAssertValidation.swift | 30 +++---- Example/Caishen/AppDelegate.swift | 12 +-- Example/Caishen/ViewController.swift | 30 ++++--- .../Caishen_Example.xcodeproj/project.pbxproj | 8 +- Pod/Classes/Cards/Card.swift | 4 +- Pod/Classes/Cards/CardType.swift | 36 ++++---- Pod/Classes/Cards/CardTypeRegister.swift | 16 ++-- .../Default Card Types/UnknownCardType.swift | 6 +- Pod/Classes/Cards/Expiry.swift | 46 +++++----- Pod/Classes/Format/CardNumberFormatter.swift | 44 +++++----- Pod/Classes/Localization.swift | 6 +- Pod/Classes/StringExtension.swift | 22 +++-- ...dTextField+CardInfoTextFieldDelegate.swift | 22 ++--- .../UI/CardTextField+InterfaceBuilder.swift | 6 +- .../UI/CardTextField+PrefillInformation.swift | 8 +- .../UI/CardTextField+ViewAnimations.swift | 36 ++++---- Pod/Classes/UI/CardTextField.swift | 88 +++++++++---------- Pod/Classes/UI/CardTextFieldDelegate.swift | 10 +-- Pod/Classes/UI/CardTypeImageStore.swift | 14 +-- Pod/Classes/UI/NumberInputTextField.swift | 24 ++--- .../UI/NumberInputTextFieldDelegate.swift | 4 +- Pod/Classes/UI/StylizedTextField.swift | 22 ++--- .../UI/Text Fields/CVCInputTextField.swift | 2 +- .../Delegates/CardInfoTextFieldDelegate.swift | 6 +- .../UI/Text Fields/DetailInputTextField.swift | 20 ++--- .../UI/Text Fields/MonthInputTextField.swift | 4 +- .../Protocols/AutoCompletingTextField.swift | 2 +- .../Protocols/TextFieldValidation.swift | 2 +- .../UI/Text Fields/YearInputTextField.swift | 4 +- .../Validation/CardValidationResult.swift | 22 ++--- 34 files changed, 292 insertions(+), 292 deletions(-) diff --git a/Caishen.xcodeproj/project.pbxproj b/Caishen.xcodeproj/project.pbxproj index 6bc6322..c13c9cd 100644 --- a/Caishen.xcodeproj/project.pbxproj +++ b/Caishen.xcodeproj/project.pbxproj @@ -98,7 +98,7 @@ 2FDD15481CC7B1AC0086CEAC /* CardTextField+InterfaceBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CardTextField+InterfaceBuilder.swift"; sourceTree = ""; }; 2FDD15491CC7B1AC0086CEAC /* CardTextField+PrefillInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CardTextField+PrefillInformation.swift"; sourceTree = ""; }; 2FDD154A1CC7B1AC0086CEAC /* CardTextField+ViewAnimations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CardTextField+ViewAnimations.swift"; sourceTree = ""; }; - 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardTextField.swift; sourceTree = ""; }; + 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CardTextField.swift; path = ../UI/CardTextField.swift; sourceTree = ""; }; 2FDD154C1CC7B1AC0086CEAC /* CardTextFieldDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardTextFieldDelegate.swift; sourceTree = ""; }; 2FDD154D1CC7B1AC0086CEAC /* CardTypeImageStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardTypeImageStore.swift; sourceTree = ""; }; 2FDD154E1CC7B1AC0086CEAC /* CardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CardView.xib; sourceTree = ""; }; @@ -242,6 +242,7 @@ 2FDD15431CC7B1AC0086CEAC /* Format */ = { isa = PBXGroup; children = ( + 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */, 2FDD15441CC7B1AC0086CEAC /* CardNumberFormatter.swift */, ); path = Format; @@ -254,7 +255,6 @@ 2FDD15481CC7B1AC0086CEAC /* CardTextField+InterfaceBuilder.swift */, 2FDD15491CC7B1AC0086CEAC /* CardTextField+PrefillInformation.swift */, 2FDD154A1CC7B1AC0086CEAC /* CardTextField+ViewAnimations.swift */, - 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */, 2FDD154C1CC7B1AC0086CEAC /* CardTextFieldDelegate.swift */, 2FDD154D1CC7B1AC0086CEAC /* CardTypeImageStore.swift */, 2FDD154E1CC7B1AC0086CEAC /* CardView.xib */, @@ -584,7 +584,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.Caishen; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -601,7 +601,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.Caishen; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -612,7 +612,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.CaishenTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -623,7 +623,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.CaishenTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/CaishenTests/CaishenTests.swift b/CaishenTests/CaishenTests.swift index 6fcc331..d3c5e6a 100644 --- a/CaishenTests/CaishenTests.swift +++ b/CaishenTests/CaishenTests.swift @@ -28,7 +28,7 @@ class CaishenTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock { + self.measure { // Put the code you want to measure the time of here. } } diff --git a/CaishenTests/CardNumberFormatterTests.swift b/CaishenTests/CardNumberFormatterTests.swift index 245c8e4..e8fc337 100644 --- a/CaishenTests/CardNumberFormatterTests.swift +++ b/CaishenTests/CardNumberFormatterTests.swift @@ -36,7 +36,7 @@ class CardNumberFormatterTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock { + self.measure { // Put the code you want to measure the time of here. } } diff --git a/CaishenTests/CardNumberValidatorTests.swift b/CaishenTests/CardNumberValidatorTests.swift index 9cad97a..29401ff 100644 --- a/CaishenTests/CardNumberValidatorTests.swift +++ b/CaishenTests/CardNumberValidatorTests.swift @@ -149,10 +149,10 @@ class CardNumberValidatorTests: XCTestCase { */ func testInvalidLuhnTest() { var allValidCardNumbers = validVisaNumbers - allValidCardNumbers.appendContentsOf(self.validAmexNumbers) - allValidCardNumbers.appendContentsOf(self.validDinersClubNumbers) - allValidCardNumbers.appendContentsOf(self.validDiscoverNumbers) - allValidCardNumbers.appendContentsOf(self.validJCBNumbers) + allValidCardNumbers.append(contentsOf: self.validAmexNumbers) + allValidCardNumbers.append(contentsOf: self.validDinersClubNumbers) + allValidCardNumbers.append(contentsOf: self.validDiscoverNumbers) + allValidCardNumbers.append(contentsOf: self.validJCBNumbers) let invalidLuhnTestVisa: [String] = allValidCardNumbers.map({ guard let intValue = Int64($0) else { @@ -160,12 +160,12 @@ class CardNumberValidatorTests: XCTestCase { return "" } - var randomNumber = random() % 10 + var randomNumber = arc4random() % 10 if randomNumber == 0 { randomNumber = 1 } - let changedLastDigit = (intValue + randomNumber) % 10 + let changedLastDigit = (intValue + Int64(randomNumber)) % 10 let invalidValue = intValue - (intValue % 10) + changedLastDigit return "\(invalidValue)" diff --git a/CaishenTests/XCTAssertValidation.swift b/CaishenTests/XCTAssertValidation.swift index 2b79d6c..5f204b2 100644 --- a/CaishenTests/XCTAssertValidation.swift +++ b/CaishenTests/XCTAssertValidation.swift @@ -10,34 +10,34 @@ import UIKit import XCTest import Caishen -func XCTAssertValid(validationResult: CardValidationResult) { +func XCTAssertValid(_ validationResult: CardValidationResult) { XCTAssertTrue(validationResult == CardValidationResult.Valid, "Expected the validation result to be true, but was \(validationResult.description)") } -func XCTAssertInvalidCVC(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.InvalidCVC), "Expected an invalid CVC, but got \(validationResult.description)") +func XCTAssertInvalidCVC(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.InvalidCVC), "Expected an invalid CVC, but got \(validationResult.description)") } -func XCTAssertIncompleteCVC(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.CVCIncomplete), "Expected an incomplete CVC, but got \(validationResult.description)") +func XCTAssertIncompleteCVC(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.CVCIncomplete), "Expected an incomplete CVC, but got \(validationResult.description)") } -func XCTAssertInvalidNumberForType(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.NumberTooLong), "Expected an invalid number for the credit card type, but got \(validationResult.description)") +func XCTAssertInvalidNumberForType(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.NumberTooLong), "Expected an invalid number for the credit card type, but got \(validationResult.description)") } -func XCTAssertIncompleteNumber(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.NumberIncomplete), "Expected an incomplete number for the credit card type, but got \(validationResult.description)") +func XCTAssertIncompleteNumber(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.NumberIncomplete), "Expected an incomplete number for the credit card type, but got \(validationResult.description)") } -func XCTAssertCardNotExpired(validationResult: CardValidationResult) { - XCTAssertFalse(validationResult.isSupersetOf(CardValidationResult.CardExpired), "Expected a not expired card, but got: \(validationResult.description)") +func XCTAssertCardNotExpired(_ validationResult: CardValidationResult) { + XCTAssertFalse(validationResult.isSuperset(of: CardValidationResult.CardExpired), "Expected a not expired card, but got: \(validationResult.description)") } -func XCTAssertCardExpired(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.CardExpired), "Expected an expired card, but got: \(validationResult.description)") +func XCTAssertCardExpired(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.CardExpired), "Expected an expired card, but got: \(validationResult.description)") } -func XCTAssertLuhnTestFailed(validationResult: CardValidationResult) { - XCTAssertTrue(validationResult.isSupersetOf(CardValidationResult.LuhnTestFailed), "Expected a Luhn test failure on validation, but got \(validationResult.description)") +func XCTAssertLuhnTestFailed(_ validationResult: CardValidationResult) { + XCTAssertTrue(validationResult.isSuperset(of: CardValidationResult.LuhnTestFailed), "Expected a Luhn test failure on validation, but got \(validationResult.description)") } diff --git a/Example/Caishen/AppDelegate.swift b/Example/Caishen/AppDelegate.swift index bcd2954..62cbe78 100644 --- a/Example/Caishen/AppDelegate.swift +++ b/Example/Caishen/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // 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. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // 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. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/Example/Caishen/ViewController.swift b/Example/Caishen/ViewController.swift index be0cf38..d066fdd 100644 --- a/Example/Caishen/ViewController.swift +++ b/Example/Caishen/ViewController.swift @@ -20,40 +20,42 @@ class ViewController: UIViewController, CardTextFieldDelegate, CardIOPaymentView cardNumberTextField.cardTextFieldDelegate = self } - @IBAction func buy(sender: AnyObject) { - dismissViewControllerAnimated(true, completion: nil) + @IBAction func buy(_ sender: AnyObject) { + dismiss(animated: true, completion: nil) } - @IBAction func cancel(sender: UIButton) { - dismissViewControllerAnimated(true, completion: nil) + @IBAction func cancel(_ sender: UIButton) { + dismiss(animated: true, completion: nil) } // MARK: - CardNumberTextField delegate methods // This method of `CardNumberTextFieldDelegate` will set the saveButton enabled or disabled, based on whether valid card information has been entered. - func cardTextField(cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { - buyButton?.enabled = validationResult == .Valid + func cardTextField(_ cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { + buyButton?.isEnabled = validationResult == .Valid } - func cardTextFieldShouldShowAccessoryImage(cardTextField: CardTextField) -> UIImage? { + func cardTextFieldShouldShowAccessoryImage(_ cardTextField: CardTextField) -> UIImage? { return UIImage(named: "camera") } - func cardTextFieldShouldProvideAccessoryAction(cardTextField: CardTextField) -> (() -> ())? { + func cardTextFieldShouldProvideAccessoryAction(_ cardTextField: CardTextField) -> (() -> ())? { return { [weak self] _ in - let cardIOViewController = CardIOPaymentViewController(paymentDelegate: self) - self?.presentViewController(cardIOViewController, animated: true, completion: nil) + guard let cardIOViewController = CardIOPaymentViewController(paymentDelegate: self) else { + return + } + self?.present(cardIOViewController, animated: true, completion: nil) } } // MARK: - Card.io delegate methods - func userDidCancelPaymentViewController(paymentViewController: CardIOPaymentViewController!) { - paymentViewController.dismissViewControllerAnimated(true, completion: nil) + func userDidCancel(_ paymentViewController: CardIOPaymentViewController!) { + paymentViewController.dismiss(animated: true, completion: nil) } - func userDidProvideCreditCardInfo(cardInfo: CardIOCreditCardInfo!, inPaymentViewController paymentViewController: CardIOPaymentViewController!) { + func userDidProvide(_ cardInfo: CardIOCreditCardInfo!, in paymentViewController: CardIOPaymentViewController!) { cardNumberTextField.prefillCardInformation(cardInfo.cardNumber, month: Int(cardInfo.expiryMonth), year: Int(cardInfo.expiryYear), cvc: cardInfo.cvv) - paymentViewController.dismissViewControllerAnimated(true, completion: nil) + paymentViewController.dismiss(animated: true, completion: nil) } } diff --git a/Example/Caishen_Example.xcodeproj/project.pbxproj b/Example/Caishen_Example.xcodeproj/project.pbxproj index 1507132..8375fe8 100644 --- a/Example/Caishen_Example.xcodeproj/project.pbxproj +++ b/Example/Caishen_Example.xcodeproj/project.pbxproj @@ -493,7 +493,7 @@ PROVISIONING_PROFILE = ""; SWIFT_OBJC_BRIDGING_HEADER = "Caishen/Caishen_Example-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -512,7 +512,7 @@ PRODUCT_NAME = Caishen_Example; PROVISIONING_PROFILE = ""; SWIFT_OBJC_BRIDGING_HEADER = "Caishen/Caishen_Example-Bridging-Header.h"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -533,7 +533,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Caishen_Example; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Caishen_Example.app/Caishen_Example"; }; name = Debug; @@ -551,7 +551,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Caishen_Example; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Caishen_Example.app/Caishen_Example"; }; name = Release; diff --git a/Pod/Classes/Cards/Card.swift b/Pod/Classes/Cards/Card.swift index 73a296d..b36c5f0 100644 --- a/Pod/Classes/Cards/Card.swift +++ b/Pod/Classes/Cards/Card.swift @@ -40,7 +40,7 @@ public struct Card { - returns: A card with the provided parameters. */ - public static func create(number: String, cardVerificationCode cvc: String, expiry: String) throws -> Card { + public static func create(_ number: String, cardVerificationCode cvc: String, expiry: String) throws -> Card { // Create card number, cvc and expiry with the arguments provided let cardNumber = Number(rawValue: number) let cardCVC = CVC(rawValue: cvc) @@ -62,4 +62,4 @@ public struct Card { self.expiryDate = expiryDate } -} \ No newline at end of file +} diff --git a/Pod/Classes/Cards/CardType.swift b/Pod/Classes/Cards/CardType.swift index b1fd483..74a22a8 100644 --- a/Pod/Classes/Cards/CardType.swift +++ b/Pod/Classes/Cards/CardType.swift @@ -59,7 +59,7 @@ public protocol CardType { - returns: The validation result for the CVC, taking the current card type into account, as different card issuers can provide CVCs in different formats. */ - func validateCVC(cvc: CVC) -> CardValidationResult + func validateCVC(_ cvc: CVC) -> CardValidationResult /** @@ -84,7 +84,7 @@ public protocol CardType { - returns: The result of the card number validation. */ - func validateNumber(number: Number) -> CardValidationResult + func validateNumber(_ number: Number) -> CardValidationResult /** Validates the card's expiry date, checking whether the card has expired or not. @@ -93,7 +93,7 @@ public protocol CardType { - returns: The result of the card expiration date validation. */ - func validateExpiry(expiry: Expiry) -> CardValidationResult + func validateExpiry(_ expiry: Expiry) -> CardValidationResult /** Returns whether or not `self` is equal to another `CardType`. @@ -102,12 +102,12 @@ public protocol CardType { - returns: Whether or not `self` is equal to the provided `cardType`. */ - func isEqualTo(cardType: CardType) -> Bool + func isEqualTo(_ cardType: CardType) -> Bool } extension CardType { - public func isEqualTo(cardType: CardType) -> Bool { + public func isEqualTo(_ cardType: CardType) -> Bool { return cardType.name == self.name } @@ -127,7 +127,7 @@ extension CardType { return numberGrouping.reduce(0) { $0 + $1 } } - public func validateCVC(cvc: CVC) -> CardValidationResult { + public func validateCVC(_ cvc: CVC) -> CardValidationResult { guard requiresCVC else { return .Valid @@ -146,13 +146,13 @@ extension CardType { return .Valid } - public func validateNumber(cardNumber: Number) -> CardValidationResult { + public func validateNumber(_ cardNumber: Number) -> CardValidationResult { return lengthMatchesType(cardNumber.length) .union(numberIsNumeric(cardNumber)) .union(numberIsValidLuhn(cardNumber)) } - public func validateExpiry(expiry: Expiry) -> CardValidationResult { + public func validateExpiry(_ expiry: Expiry) -> CardValidationResult { guard requiresExpiry else { return .Valid } @@ -161,7 +161,7 @@ extension CardType { return .InvalidExpiry } - let currentDate = NSDate() + let currentDate = Date() let expiryDate = expiry.rawValue if expiryDate.timeIntervalSince1970 < currentDate.timeIntervalSince1970 { @@ -185,7 +185,7 @@ extension CardType { - returns: True if the card number complies to the Luhn algorithm. False if it does not. */ - public func numberIsValidLuhn(number: Number) -> CardValidationResult { + public func numberIsValidLuhn(_ number: Number) -> CardValidationResult { var odd = true var sum = 0 let digits = NSMutableArray(capacity: number.length) @@ -194,7 +194,7 @@ extension CardType { guard let digit = number.description[i,i+1] else { return CardValidationResult.LuhnTestFailed } - digits.addObject(NSString(string: digit)) + digits.add(NSString(string: digit)) } for obj in digits.reverseObjectEnumerator() { let digitString = obj as! NSString @@ -225,17 +225,17 @@ extension CardType { - the card validation succeeded - or the card validation failed because of the Luhn test or insufficient card number length (both of which are irrelevant for incomplete card numbers). */ - public func checkCardNumberPartiallyValid(cardNumber: Number) -> CardValidationResult { + public func checkCardNumberPartiallyValid(_ cardNumber: Number) -> CardValidationResult { let validationResult = validateNumber(cardNumber) - let completeNumberButLuhnTestFailed = !validationResult.isSupersetOf(CardValidationResult.NumberIncomplete) && validationResult.isSupersetOf(CardValidationResult.LuhnTestFailed) + let completeNumberButLuhnTestFailed = !validationResult.isSuperset(of: CardValidationResult.NumberIncomplete) && validationResult.isSuperset(of: CardValidationResult.LuhnTestFailed) if completeNumberButLuhnTestFailed { return validationResult } else { return self.validateNumber(cardNumber) - .subtract(.NumberIncomplete) - .subtract(.LuhnTestFailed) + .subtracting(.NumberIncomplete) + .subtracting(.LuhnTestFailed) } } @@ -247,7 +247,7 @@ extension CardType { - returns: CardValidationResult.Valid if the lengths match, CardValidationResult.NumberDoesNotMatchType otherwise. */ - private func testLength(actualLength: Int, assumingLength expectedLength: Int) -> CardValidationResult { + private func testLength(_ actualLength: Int, assumingLength expectedLength: Int) -> CardValidationResult { if actualLength == expectedLength { return .Valid } else if actualLength < expectedLength { @@ -269,7 +269,7 @@ extension CardType { - `.NumberTooLong`: The card number is too long - `.NumberDoesNotMatchType`: The card number's Issuer Identification Number does not match `self` */ - public func lengthMatchesType(length: Int) -> CardValidationResult { + public func lengthMatchesType(_ length: Int) -> CardValidationResult { return testLength(length, assumingLength: expectedCardNumberLength()) } @@ -281,7 +281,7 @@ extension CardType { - returns: `CardValidationResult.Valid` if the card number contains only numeric characters. - `.NumberIsNotNumeric`: Otherwise. */ - public func numberIsNumeric(number: Number) -> CardValidationResult { + public func numberIsNumeric(_ number: Number) -> CardValidationResult { for c in number.description.characters { if !["0","1","2","3","4","5","6","7","8","9"].contains(c) { return CardValidationResult.NumberIsNotNumeric diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index 9466888..fb4a0f3 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -31,7 +31,7 @@ public class CardTypeRegister { - parameter registeredCardTypes: Any sequence of `CardType` that should be accepted by `self`. */ - public convenience init(registeredCardTypes: T) { + public convenience init(registeredCardTypes: T) { self.init() setRegisteredCardTypes(registeredCardTypes) } @@ -52,7 +52,7 @@ public class CardTypeRegister { - parameter cardType: The card type that should be contained in this card type register. */ - public func registerCardType(cardType: CardType) { + public func registerCardType(_ cardType: CardType) { if registeredCardTypes.contains({ $0.isEqualTo(cardType) }) { return } @@ -65,7 +65,7 @@ public class CardTypeRegister { - parameter cardType: The card type that should be removed from this card type register. */ - public func unregisterCardType(cardType: CardType) { + public func unregisterCardType(_ cardType: CardType) { registeredCardTypes = registeredCardTypes.filter { !$0.isEqualTo(cardType) } } @@ -74,9 +74,9 @@ public class CardTypeRegister { - parameter cardTypes: The new range of card types contained in this card type register. */ - public func setRegisteredCardTypes(cardTypes: T) { + public func setRegisteredCardTypes(_ cardTypes: T) { registeredCardTypes = [CardType]() - registeredCardTypes.appendContentsOf(cardTypes) + registeredCardTypes.append(contentsOf: cardTypes) } /** @@ -88,8 +88,8 @@ public class CardTypeRegister { - returns: An instance of UnknownCardType, if no card type matches the Issuer Identification Number of the provided card number or any other card type that matches the card number. */ - public func cardTypeForNumber(cardNumber: Number) -> CardType { - for i in (0...min(cardNumber.length, 6)).reverse() { + public func cardTypeForNumber(_ cardNumber: Number) -> CardType { + for i in (0...min(cardNumber.length, 6)).reversed() { if let substring = cardNumber.rawValue[0,i], let substringAsNumber = Int(substring) { if let firstMatchingCardType = registeredCardTypes.filter({ $0.identifyingDigits.contains(substringAsNumber) @@ -102,4 +102,4 @@ public class CardTypeRegister { return UnknownCardType() } -} \ No newline at end of file +} diff --git a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift index da21a98..1243357 100644 --- a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift +++ b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift @@ -15,18 +15,18 @@ public struct UnknownCardType: CardType { public let CVCLength = 0 public let identifyingDigits: Set = [] - public func validateNumber(cardNumber: Number) -> CardValidationResult { + public func validateNumber(_ cardNumber: Number) -> CardValidationResult { return CardValidationResult.UnknownType .union(lengthMatchesType(cardNumber.length)) .union(numberIsNumeric(cardNumber)) .union(numberIsValidLuhn(cardNumber)) } - public func validateCVC(cvc: CVC) -> CardValidationResult { + public func validateCVC(_ cvc: CVC) -> CardValidationResult { return .UnknownType } - public func validateExpiry(expiry: Expiry) -> CardValidationResult { + public func validateExpiry(_ expiry: Expiry) -> CardValidationResult { return .UnknownType } diff --git a/Pod/Classes/Cards/Expiry.swift b/Pod/Classes/Cards/Expiry.swift index bff7922..2bfc36d 100644 --- a/Pod/Classes/Cards/Expiry.swift +++ b/Pod/Classes/Cards/Expiry.swift @@ -8,7 +8,7 @@ import Foundation -private let gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! +private let gregorianCalendar = Calendar(calendarIdentifier: Calendar.Identifier.gregorian)! /** A Credit Card Expiry date. @@ -16,20 +16,20 @@ private let gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentif public struct Expiry: RawRepresentable { /// An invalid expiry date. This date is set to 1/1/1970 and therefor will be shown as `expired`. - public static let invalid = Expiry(rawValue: NSDate(timeIntervalSince1970: 0)) + public static let invalid = Expiry(rawValue: Date(timeIntervalSince1970: 0)) - public typealias RawValue = NSDate + public typealias RawValue = Date - public let rawValue: NSDate + public let rawValue: Date /// The month of the expiration date. public var month: UInt { - return UInt(components().month) + return UInt(components().month!) } /// The year of the expiration date. public var year: UInt { - return UInt(components().year) + return UInt(components().year!) } /** @@ -39,28 +39,28 @@ public struct Expiry: RawRepresentable { */ public init?(string: String) { // Make sure that there is only one non-numeric separation character in the entire string - guard string.stringByTrimmingCharactersInSet(NSCharacterSet.decimalDigitCharacterSet()).characters.count == 1 else { + guard string.trimmingCharacters(in: CharacterSet.decimalDigits).characters.count == 1 else { return nil } - let regex = try! NSRegularExpression(pattern: "^(\\d{1,2})[/|-](\\d{1,4})", options: .CaseInsensitive) + let regex = try! RegularExpression(pattern: "^(\\d{1,2})[/|-](\\d{1,4})", options: .caseInsensitive) var monthStr: String = "" var yearStr: String = "" - guard let match = regex.firstMatchInString(string, options: .ReportProgress, range: NSMakeRange(0, string.characters.count)) else { + guard let match = regex.firstMatch(in: string, options: .reportProgress, range: NSMakeRange(0, string.characters.count)) else { return nil } - let monthRange = match.rangeAtIndex(1) + let monthRange = match.range(at: 1) if monthRange.length > 0, let range = string.rangeFromNSRange(monthRange) { - monthStr = string.substringWithRange(range) + monthStr = string.substring(with: range) } else { return nil } - let yearRange = match.rangeAtIndex(2) + let yearRange = match.range(at: 2) if yearRange.length > 0, let range = string.rangeFromNSRange(yearRange) { - yearStr = string.substringWithRange(range) + yearStr = string.substring(with: range) } else { return nil } @@ -119,12 +119,12 @@ public struct Expiry: RawRepresentable { self.init(rawValue: date) } - public init(rawValue: NSDate) { + public init(rawValue: Date) { self.rawValue = rawValue } - private func components() -> NSDateComponents { - return gregorianCalendar.components([.Year, .Month], fromDate: rawValue) + private func components() -> DateComponents { + return gregorianCalendar.components([.year, .month], from: rawValue) } } @@ -144,22 +144,22 @@ extension Expiry: CustomStringConvertible { - returns: The date with month and year and time set to one minute before the following month. */ -private func toDate(month: UInt, year: UInt) -> NSDate? { - let dateComponents = NSDateComponents() +private func toDate(_ month: UInt, year: UInt) -> Date? { + var dateComponents = DateComponents() dateComponents.day = 1 dateComponents.month = Int(month) dateComponents.year = Int(year) - if let gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian), - let components = gregorianCalendar.dateFromComponents(dateComponents) { - let monthRange = gregorianCalendar.rangeOfUnit(NSCalendarUnit.Day, inUnit: NSCalendarUnit.Month, - forDate:components) + if let gregorianCalendar = Calendar(calendarIdentifier: Calendar.Identifier.gregorian), + let components = gregorianCalendar.date(from: dateComponents) { + let monthRange = gregorianCalendar.range(of: Calendar.Unit.day, in: Calendar.Unit.month, + for:components) dateComponents.day = monthRange.length dateComponents.hour = 23 dateComponents.minute = 59 - return gregorianCalendar.dateFromComponents(dateComponents) + return gregorianCalendar.date(from: dateComponents) } return nil diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 2dbe7f0..02460f8 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -36,8 +36,8 @@ public final class CardNumberFormatter { - returns: The unformatted card number string representation. */ - public func unformattedCardNumber(cardNumberString: String) -> String { - return cardNumberString.stringByReplacingOccurrencesOfString(self.separator, withString: "") + public func unformattedCardNumber(_ cardNumberString: String) -> String { + return cardNumberString.replacingOccurrences(of: self.separator, with: "") } /** @@ -47,8 +47,8 @@ public final class CardNumberFormatter { - returns: Formatted card number string. */ - public func formattedCardNumber(cardNumberString: String) -> String { - let regex: NSRegularExpression + public func formattedCardNumber(_ cardNumberString: String) -> String { + let regex: RegularExpression let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumberString)) do { @@ -62,12 +62,12 @@ public final class CardNumberFormatter { } first = false } - regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions()) + regex = try RegularExpression(pattern: pattern, options: RegularExpression.Options()) } catch { fatalError("Error when creating regular expression: \(error)") } - return NSArray(array: self.splitString(cardNumberString, withRegex: regex)).componentsJoinedByString(self.separator) + return NSArray(array: self.splitString(cardNumberString, withRegex: regex)).componentsJoined(by: self.separator) } /** @@ -77,16 +77,16 @@ public final class CardNumberFormatter { - returns: The index of the cursor position or nil, if no selected text was found. */ - public func cursorPositionAfterUnformattingText(text: String, inTextField textField: UITextField) -> Int? { + public func cursorPositionAfterUnformattingText(_ text: String, inTextField textField: UITextField) -> Int? { guard let selectedRange = textField.selectedTextRange else { return nil } let addedCharacters = text.characters.count - (textField.text ?? "").characters.count - let position = textField.offsetFromPosition(textField.beginningOfDocument, toPosition: selectedRange.start) + addedCharacters + let position = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) + addedCharacters let formattedString = text ?? "" - let components = formattedString.componentsSeparatedByString(self.separator) + let components = formattedString.components(separatedBy: self.separator) // Find the component that contains the cursor var componentContainingCursor = 0 @@ -113,10 +113,10 @@ public final class CardNumberFormatter { - returns: The index in an unformatted string that is equivalent to `index` in `formattedString`. */ - private func indexInUnformattedString(index: Int, formattedString: String) -> Int { + private func indexInUnformattedString(_ index: Int, formattedString: String) -> Int { var componentWithIndex = 0 var charCount = 0 - for component in formattedString.componentsSeparatedByString(self.separator) { + for component in formattedString.components(separatedBy: self.separator) { charCount += component.characters.count if charCount >= index { break @@ -139,11 +139,11 @@ public final class CardNumberFormatter { - returns: The index in a formatted string that is equivalent to `index` in `unformattedString`. */ - private func indexInFormattedString(index: Int, unformattedString: String) -> Int { + private func indexInFormattedString(_ index: Int, unformattedString: String) -> Int { var charIdx = 0 let formattedString = self.formattedCardNumber(unformattedString) - let groups = formattedString.componentsSeparatedByString(self.separator) + let groups = formattedString.components(separatedBy: self.separator) for i in 0.. [String] { - let matches = regex.matchesInString(string, options: NSMatchingOptions(), range: NSMakeRange(0, string.characters.count)) + private func splitString(_ string: String, withRegex regex: RegularExpression) -> [String] { + let matches = regex.matches(in: string, options: RegularExpression.MatchingOptions(), range: NSMakeRange(0, string.characters.count)) var result = [String]() matches.forEach { for i in 1..<$0.numberOfRanges { - let range = $0.rangeAtIndex(i) + let range = $0.range(at: i) if range.length > 0 { - result.append(NSString(string: string).substringWithRange(range)) + result.append(NSString(string: string).substring(with: range)) } } } diff --git a/Pod/Classes/Localization.swift b/Pod/Classes/Localization.swift index bcc8bcd..276bdfb 100644 --- a/Pod/Classes/Localization.swift +++ b/Pod/Classes/Localization.swift @@ -28,7 +28,7 @@ internal enum Localization: String { - returns: The accessibility label for the provided text field. */ - static func accessibilityLabelForTextField(textField: UITextField, comment: String? = nil) -> String? { + static func accessibilityLabelForTextField(_ textField: UITextField, comment: String? = nil) -> String? { switch textField { case is NumberInputTextField: return Localization.NumberInputTextFieldAccessibilityLabel.localizedStringWithComment(comment) @@ -48,10 +48,10 @@ internal enum Localization: String { - returns: The localized string for the raw value of `self` in the Caishen bundle. */ - func localizedStringWithComment(comment: String?) -> String { + func localizedStringWithComment(_ comment: String?) -> String { return NSLocalizedString(self.rawValue, tableName: Localization.StringsFileName.rawValue, - bundle: NSBundle(forClass: CardTextField.self), + bundle: Bundle(for: CardTextField.self), comment: comment ?? "") } } diff --git a/Pod/Classes/StringExtension.swift b/Pod/Classes/StringExtension.swift index ccf195f..4f35036 100644 --- a/Pod/Classes/StringExtension.swift +++ b/Pod/Classes/StringExtension.swift @@ -19,9 +19,13 @@ extension String { - returns: `nsRange` converted to Range or nil, if its start and/or end location are not within `self`. */ - func rangeFromNSRange(nsRange: NSRange) -> Range? { - let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex) - let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex) + func rangeFromNSRange(_ nsRange: NSRange) -> Range? { + guard let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex) else { + return nil + } + guard let to16 = utf16.index(from16, offsetBy: nsRange.length, limitedBy: utf16.endIndex) else { + return nil + } if let from = String.Index(from16, within: self), let to = String.Index(to16, within: self) { return from ..< to @@ -36,11 +40,11 @@ extension String { - returns: An NSRange object that is equivalent to `range`. */ - func NSRangeFromRange(range : Range) -> NSRange { + func NSRangeFromRange(_ range : Range) -> NSRange { let utf16view = self.utf16 - let from = String.UTF16View.Index(range.startIndex, within: utf16view) - let to = String.UTF16View.Index(range.endIndex, within: utf16view) - return NSMakeRange(utf16view.startIndex.distanceTo(from), from.distanceTo(to)) + let from = String.UTF16View.Index(range.lowerBound, within: utf16view) + let to = String.UTF16View.Index(range.upperBound, within: utf16view) + return NSMakeRange(utf16view.startIndex.distance(to: from), from.distance(to: to)) } /** @@ -55,7 +59,7 @@ extension String { if characters.count < toExclusively || fromInclusively >= toExclusively { return nil } - return self.substringWithRange((self.startIndex.advancedBy(fromInclusively).. 100 { @@ -43,9 +43,9 @@ public extension CardTextField { cvcTextField?.prefillInformation(cvc) } - NSOperationQueue().addOperationWithBlock({ - NSThread.sleepForTimeInterval(0.5) - NSOperationQueue.mainQueue().addOperationWithBlock({ [weak self] _ in + OperationQueue().addOperation({ + Thread.sleep(forTimeInterval: 0.5) + OperationQueue.main.addOperation({ [weak self] _ in self?.moveCardNumberOutAnimated() }) }) diff --git a/Pod/Classes/UI/CardTextField+ViewAnimations.swift b/Pod/Classes/UI/CardTextField+ViewAnimations.swift index 805054c..187c183 100644 --- a/Pod/Classes/UI/CardTextField+ViewAnimations.swift +++ b/Pod/Classes/UI/CardTextField+ViewAnimations.swift @@ -15,7 +15,7 @@ public extension CardTextField { Moves the card number input field to the left outside of the screen with an animation of the duration `viewAnimationDuration`, so that only the last group of the card number is visible. At the same time, the card detail (expiration month and year and CVC) slide in from the right. */ public func moveCardNumberOutAnimated() { - UIView.animateWithDuration(viewAnimationDuration, animations: { [weak self] _ in + UIView.animate(withDuration: viewAnimationDuration, animations: { [weak self] _ in self?.moveCardNumberOut() }) } @@ -24,7 +24,7 @@ public extension CardTextField { Moves the full card number input field to inside the screen with an animation of the duration `viewAnimationDuration`. At the same time, the card detail (expiration month and year and CVC) slide outside the view. */ public func moveCardNumberInAnimated() { - UIView.animateWithDuration(viewAnimationDuration, animations: { [weak self] _ in + UIView.animate(withDuration: viewAnimationDuration, animations: { [weak self] _ in self?.moveCardNumberIn() }) } @@ -45,7 +45,7 @@ public extension CardTextField { // which in turn will cause the number field to move to full display. This can cause animation issues. // In order to tackle these animation issues, check if the cardInfoView was previously fully displayed (and should therefor not be moved with an animation). var shouldMoveAnimated: Bool = true - if let transform = cardInfoView?.transform where CGAffineTransformIsIdentity(transform) { + if let transform = cardInfoView?.transform where transform.isIdentity { shouldMoveAnimated = false } UIView.performWithoutAnimation { [weak self] _ in @@ -57,18 +57,18 @@ public extension CardTextField { // Else: Move the number out of range, except for the last group. if isRightToLeftLanguage { let shapeLayer = CAShapeLayer() - let path = CGPathCreateWithRect(rect, nil) + let path = CGPath(rect: rect, transform: nil) shapeLayer.path = path numberInputTextField.layer.mask = shapeLayer - numberInputTextField?.transform = CGAffineTransformIdentity + numberInputTextField?.transform = CGAffineTransform.identity } else { if shouldMoveAnimated { numberInputTextField?.transform = - CGAffineTransformMakeTranslation(-rect.origin.x, 0) + CGAffineTransform(translationX: -rect.origin.x, y: 0) } else { UIView.performWithoutAnimation { [weak self] _ in self?.numberInputTextField?.transform = - CGAffineTransformMakeTranslation(-rect.origin.x, 0) + CGAffineTransform(translationX: -rect.origin.x, y: 0) } } } @@ -80,10 +80,10 @@ public extension CardTextField { self?.numberInputTextField?.resignFirstResponder() } if shouldMoveAnimated { - cardInfoView?.transform = CGAffineTransformIdentity + cardInfoView?.transform = CGAffineTransform.identity } else { UIView.performWithoutAnimation { [weak self] _ in - self?.cardInfoView?.transform = CGAffineTransformIdentity + self?.cardInfoView?.transform = CGAffineTransform.identity } } monthTextField.becomeFirstResponder() @@ -100,20 +100,14 @@ public extension CardTextField { // If card info view is moved with an animation, wait for it to finish before // showing the full card number to avoid overlapping on RTL language. if cardInfoView?.layer.animationKeys() != nil { - dispatch_after(dispatch_time( - DISPATCH_TIME_NOW, - Int64(viewAnimationDuration * Double(NSEC_PER_SEC))), - dispatch_get_main_queue()) { [weak self] _ in + DispatchQueue.main.after(when: DispatchTime.now() + Double(Int64(viewAnimationDuration * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { [weak self] _ in self?.numberInputTextField?.layer.mask = nil } // Let the number text field become first responder only after the animation has completed (left to right script) // or half way through the view animation (right to left script) let firstResponderDelay = isRightToLeftLanguage ? viewAnimationDuration / 2.0 : viewAnimationDuration - dispatch_after(dispatch_time( - DISPATCH_TIME_NOW, - Int64(firstResponderDelay * Double(NSEC_PER_SEC))), - dispatch_get_main_queue()) { + DispatchQueue.main.after(when: DispatchTime.now() + Double(Int64(firstResponderDelay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { infoTextFields.forEach({$0?.resignFirstResponder()}) self.numberInputTextField.becomeFirstResponder() } @@ -128,15 +122,15 @@ public extension CardTextField { if isRightToLeftLanguage { UIView.performWithoutAnimation { self.numberInputTextField?.alpha = 1 - self.numberInputTextField?.transform = CGAffineTransformIdentity + self.numberInputTextField?.transform = CGAffineTransform.identity } } else { numberInputTextField?.alpha = 1 - numberInputTextField?.transform = CGAffineTransformIdentity + numberInputTextField?.transform = CGAffineTransform.identity } // Move card info view let offset = isRightToLeftLanguage ? -bounds.width : bounds.width - cardInfoView?.transform = CGAffineTransformMakeTranslation(offset, 0) + cardInfoView?.transform = CGAffineTransform(translationX: offset, y: 0) } -} \ No newline at end of file +} diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index 957b18f..83962fb 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -63,7 +63,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { @IBOutlet public weak var cardInfoView: UIView? /// The image store for the card number text field. - public var cardTypeImageStore: CardTypeImageStore = NSBundle(forClass: CardTextField.self) + public var cardTypeImageStore: CardTypeImageStore = Bundle(for: CardTextField.self) public var cardTextFieldDelegate: CardTextFieldDelegate? { didSet { @@ -185,7 +185,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { } #endif - public override var attributedPlaceholder: NSAttributedString? { + public override var attributedPlaceholder: AttributedString? { didSet { numberInputTextField?.attributedPlaceholder = attributedPlaceholder super.attributedPlaceholder = nil @@ -205,25 +205,25 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { internal var hideExpiryTextFields: Bool = false { didSet { - monthTextField.hidden = hideExpiryTextFields - yearTextField.hidden = hideExpiryTextFields - slashLabel.hidden = hideExpiryTextFields + monthTextField.isHidden = hideExpiryTextFields + yearTextField.isHidden = hideExpiryTextFields + slashLabel.isHidden = hideExpiryTextFields } } internal var hideCVCTextField: Bool = false { didSet { - cvcTextField.hidden = hideCVCTextField + cvcTextField.isHidden = hideCVCTextField } } /// Computed variable that returns whether or not the view should use right to left layout design. On iOS 9 and newer, this will be based on the interface layout of `self`, whereas this property is not available on older versions of iOS and therefor uses the character direction of the device language. internal var isRightToLeftLanguage: Bool { if #available(iOS 9.0, *) { - return UIView.userInterfaceLayoutDirectionForSemanticContentAttribute(semanticContentAttribute) == .RightToLeft + return UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft } else { - let isoCode = NSLocale.autoupdatingCurrentLocale().objectForKey(NSLocaleLanguageCode) as? String ?? "" - return NSLocale.characterDirectionForLanguage(isoCode) == NSLocaleLanguageDirection.RightToLeft + let isoCode = Locale.autoupdatingCurrent.object(forKey: Locale.Key.languageCode) as? String ?? "" + return Locale.characterDirection(forLanguage: isoCode) == Locale.LanguageDirection.rightToLeft } } @@ -231,7 +231,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.localeDidChange), name: NSCurrentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.localeDidChange), name: Locale.currentLocaleDidChangeNotification, object: nil) #if !TARGET_INTERFACE_BUILDER setupView() #endif @@ -239,14 +239,14 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { public override init(frame: CGRect) { super.init(frame: frame) - NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.localeDidChange), name: NSCurrentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.localeDidChange), name: Locale.currentLocaleDidChangeNotification, object: nil) #if !TARGET_INTERFACE_BUILDER setupView() #endif } deinit { - NSNotificationCenter.defaultCenter().removeObserver(self, name: NSCurrentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: Locale.currentLocaleDidChangeNotification, object: nil) } /** @@ -264,7 +264,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { fatalError("The nib is expected to contain a UIView as root element.") } - numberInputTextField.contentMode = UIViewContentMode.Redraw + numberInputTextField.contentMode = UIViewContentMode.redraw clipsToBounds = true @@ -275,7 +275,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { cardImageView?.image = cardTypeImageStore.imageForCardType(UnknownCardType()) cardImageView?.layer.cornerRadius = 5.0 - cardImageView?.layer.shadowColor = UIColor.blackColor().CGColor + cardImageView?.layer.shadowColor = UIColor.black().cgColor cardImageView?.layer.shadowRadius = 2 cardImageView?.layer.shadowOffset = CGSize(width: 0, height: 0) cardImageView?.layer.shadowOpacity = 0.2 @@ -289,12 +289,12 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { [firstObjectInNib, cardInfoView].forEach({$0?.gestureRecognizers = []}) let hideCardNumberSwipeRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(moveCardNumberOutAnimated)) - hideCardNumberSwipeRecognizer.direction = isRightToLeftLanguage ? .Right : .Left + hideCardNumberSwipeRecognizer.direction = isRightToLeftLanguage ? .right : .left firstObjectInNib.addGestureRecognizer(hideCardNumberSwipeRecognizer) [firstObjectInNib, cardInfoView].forEach({ let showCardNumberSwipeRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(moveCardNumberInAnimated)) - showCardNumberSwipeRecognizer.direction = isRightToLeftLanguage ? .Left : .Right + showCardNumberSwipeRecognizer.direction = isRightToLeftLanguage ? .left : .right $0?.addGestureRecognizer(showCardNumberSwipeRecognizer) }) @@ -341,23 +341,23 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { // counterpart to `right` (in a left-to-right script) that changes based on localization // and can be set in a Nib. if isRightToLeftLanguage { - cvcTextField.textAlignment = .Left - monthTextField.textAlignment = .Left + cvcTextField.textAlignment = .left + monthTextField.textAlignment = .left } else { - cvcTextField.textAlignment = .Right - monthTextField.textAlignment = .Right + cvcTextField.textAlignment = .right + monthTextField.textAlignment = .right } let textFields: [UITextField?] = [numberInputTextField, cvcTextField, monthTextField, yearTextField] textFields.forEach({ - $0?.keyboardType = .NumberPad + $0?.keyboardType = .numberPad $0?.textColor = textColor $0?.font = font $0?.keyboardAppearance = keyboardAppearance - $0?.secureTextEntry = secureTextEntry + $0?.isSecureTextEntry = isSecureTextEntry }) - super.textColor = UIColor.clearColor() + super.textColor = UIColor.clear() super.placeholder = nil } @@ -376,7 +376,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { - parameter textField: a text field that needs support for voice over accessibility */ - private func setupAccessibilityLabelForTextField(textField: UITextField) { + private func setupAccessibilityLabelForTextField(_ textField: UITextField) { textField.accessibilityLabel = Localization.accessibilityLabelForTextField(textField, comment: "Accessibility label for \(String(textField))") } @@ -386,12 +386,12 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ private func setupTargetsForEditinBegin() { // Show the full number text field, if editing began on it - numberInputTextField?.addTarget(self, action: #selector(moveCardNumberInAnimated), forControlEvents: UIControlEvents.EditingDidBegin) + numberInputTextField?.addTarget(self, action: #selector(moveCardNumberInAnimated), for: UIControlEvents.editingDidBegin) // Show CVC image if the cvcTextField is selected, show card image otherwise let nonCVCTextFields: [UITextField?] = [numberInputTextField, monthTextField, yearTextField] - nonCVCTextFields.forEach({$0?.addTarget(self, action: #selector(showCardImage), forControlEvents: .EditingDidBegin)}) - cvcTextField?.addTarget(self, action: #selector(showCVCImage), forControlEvents: .EditingDidBegin) + nonCVCTextFields.forEach({$0?.addTarget(self, action: #selector(showCardImage), for: .editingDidBegin)}) + cvcTextField?.addTarget(self, action: #selector(showCVCImage), for: .editingDidBegin) } /** @@ -409,14 +409,14 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { accessoryButton?.alpha = 0 return } - accessoryButton?.addTarget(self, action: #selector(buttonReceivedAction), forControlEvents: .TouchUpInside) + accessoryButton?.addTarget(self, action: #selector(buttonReceivedAction), for: .touchUpInside) accessoryButton?.alpha = 1.0 - accessoryButton?.imageView?.contentMode = .ScaleAspectFit + accessoryButton?.imageView?.contentMode = .scaleAspectFit if let buttonImage = cardTextFieldDelegate?.cardTextFieldShouldShowAccessoryImage(self) { - let scaledImage = buttonImage.resizableImageWithCapInsets(UIEdgeInsetsZero, resizingMode: .Stretch) + let scaledImage = buttonImage.resizableImage(withCapInsets: UIEdgeInsetsZero, resizingMode: .stretch) accessoryButton?.titleLabel?.text = nil - accessoryButton?.setImage(scaledImage, forState: .Normal) + accessoryButton?.setImage(scaledImage, for: UIControlState()) accessoryButton?.tintColor = numberInputTextField?.textColor } @@ -425,8 +425,8 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { // MARK: - View lifecycle - public override func willMoveToSuperview(newSuperview: UIView?) { - super.willMoveToSuperview(newSuperview) + public override func willMove(toSuperview newSuperview: UIView?) { + super.willMove(toSuperview: newSuperview) if let secondaryView = cardInfoView { if secondaryView.superview != superview { superview?.addSubview(secondaryView) @@ -453,8 +453,8 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { /** You can override this function to provide the NSBundle for your own Nib. If you do so, please override 'getNibName' as well to provide the right Nib to load the nib file. */ - public func getNibBundle() -> NSBundle { - return NSBundle(forClass: CardTextField.self) + public func getNibBundle() -> Bundle { + return Bundle(for: CardTextField.self) } // MARK: - CardNumberInputTextFieldDelegate @@ -478,14 +478,14 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { withValidationResult: result) } - @objc public func numberInputTextFieldDidChangeText(numberInputTextField: NumberInputTextField) { + @objc public func numberInputTextFieldDidChangeText(_ numberInputTextField: NumberInputTextField) { showCardImage() notifyDelegate() hideExpiryTextFields = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresExpiry hideCVCTextField = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresCVC } - public func numberInputTextFieldDidComplete(numberInputTextField: NumberInputTextField) { + public func numberInputTextFieldDidComplete(_ numberInputTextField: NumberInputTextField) { moveCardNumberOutAnimated() notifyDelegate() @@ -529,18 +529,18 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { super.layoutSubviews() // If moving to a larger screen size and not showing the detail view, make sure that it is outside the view. - if let transform = cardInfoView?.transform where !CGAffineTransformIsIdentity(transform) { + if let transform = cardInfoView?.transform where !transform.isIdentity { translateCardNumberIn() } } - public override func touchesEnded(touches: Set, withEvent event: UIEvent?) { + public override func touchesEnded(_ touches: Set, with event: UIEvent?) { // Detect touches in card number text field as long as the detail view is on top of it touches.forEach({ touch -> () in - let point = touch.locationInView(numberInputTextField) - if (numberInputTextField?.pointInside(point, withEvent: event) ?? false) && [monthTextField,yearTextField,cvcTextField, slashLabel].reduce(true, combine: { (currentValue: Bool, view: UIView?) -> Bool in - let pointInView = touch.locationInView(view) - return currentValue && !(view?.pointInside(pointInView, withEvent: event) ?? false) + let point = touch.location(in: numberInputTextField) + if (numberInputTextField?.point(inside: point, with: event) ?? false) && [monthTextField,yearTextField,cvcTextField, slashLabel].reduce(true, combine: { (currentValue: Bool, view: UIView?) -> Bool in + let pointInView = touch.location(in: view) + return currentValue && !(view?.point(inside: pointInView, with: event) ?? false) }) { numberInputTextField?.becomeFirstResponder() } @@ -567,7 +567,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { - returns: The accessibility element at the specified index, or nil if none exists */ - public override func accessibilityElementAtIndex(index: Int) -> AnyObject? { + public override func accessibilityElement(at index: Int) -> AnyObject? { switch index { case 0: return numberInputTextField diff --git a/Pod/Classes/UI/CardTextFieldDelegate.swift b/Pod/Classes/UI/CardTextFieldDelegate.swift index 74097b0..8f8dc70 100644 --- a/Pod/Classes/UI/CardTextFieldDelegate.swift +++ b/Pod/Classes/UI/CardTextFieldDelegate.swift @@ -17,7 +17,7 @@ public protocol CardTextFieldDelegate { - parameter information: The Card information which has been entered in the CardTextField or nil, if one or more of the CardTextField's text fields are empty or incomplete. - parameter validationResult: The result for the card validation of `information` or nil, if one or more of the CardTextField's text fields are empty or incomplete. */ - func cardTextField(cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) + func cardTextField(_ cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) /** Callback for a CardTextField, which is called to update the image for its accessory button. @@ -25,7 +25,7 @@ public protocol CardTextFieldDelegate { - parameter CardTextField: The card number text field requesting an image for its accessory button. - returns: An image for the CardTextField's accessory button. */ - func cardTextFieldShouldShowAccessoryImage(cardTextField: CardTextField) -> UIImage? + func cardTextFieldShouldShowAccessoryImage(_ cardTextField: CardTextField) -> UIImage? /** Callback for a CardTextField, which is used to check whether an accessory button should be provided. @@ -34,7 +34,7 @@ public protocol CardTextFieldDelegate { - parameter CardTextField: The text field requesting an action for its accessory button. - returns: Any action that is performed when the accessory button is tapped or nil, if no accessory button should be displayed in the text field. */ - func cardTextFieldShouldProvideAccessoryAction(cardTextField: CardTextField) -> (() -> ())? + func cardTextFieldShouldProvideAccessoryAction(_ cardTextField: CardTextField) -> (() -> ())? /** Callback for a CardTextField, which is called to update the accessibility label of the accessory button @@ -42,11 +42,11 @@ public protocol CardTextFieldDelegate { - parameter cardTextField: The text field requesting a accessibility label for its accessory button. - returns: The accessibility label for its accessory button */ - func cardTextFieldShouldProvideAccessoryButtonAccessibilityLabel(cardTextField: CardTextField) -> String? + func cardTextFieldShouldProvideAccessoryButtonAccessibilityLabel(_ cardTextField: CardTextField) -> String? } public extension CardTextFieldDelegate { - public func cardTextFieldShouldProvideAccessoryButtonAccessibilityLabel(cardTextField: CardTextField) -> String? { + public func cardTextFieldShouldProvideAccessoryButtonAccessibilityLabel(_ cardTextField: CardTextField) -> String? { return Localization.AccessoryButtonAccessibilityLabel.localizedStringWithComment("Accessibility label for accessory button") } } diff --git a/Pod/Classes/UI/CardTypeImageStore.swift b/Pod/Classes/UI/CardTypeImageStore.swift index a8a5387..f853677 100644 --- a/Pod/Classes/UI/CardTypeImageStore.swift +++ b/Pod/Classes/UI/CardTypeImageStore.swift @@ -18,7 +18,7 @@ public protocol CardTypeImageStore { - returns: The image for the specified card type or nil, if no image was provided for this card type. */ - func imageForCardType(cardType: CardType) -> UIImage? + func imageForCardType(_ cardType: CardType) -> UIImage? /** Provides an image for the CVC of a specific card type. The position of a CVC on a card may vary based on the card issuer, so that different card types may provide different images to indicate the location of the CVC on the card. This image will be shown in a `CardTextField`'s image view once the user starts entering the CVC. @@ -27,17 +27,17 @@ public protocol CardTypeImageStore { - returns: The image for the CVC of the specified card type or nil, if no image was provided for this card type. */ - func cvcImageForCardType(cardType: CardType) -> UIImage? + func cvcImageForCardType(_ cardType: CardType) -> UIImage? } -extension NSBundle: CardTypeImageStore { +extension Bundle: CardTypeImageStore { - public func imageForCardType(cardType: CardType) -> UIImage? { - return UIImage(named: cardType.name, inBundle: self, compatibleWithTraitCollection: nil) + public func imageForCardType(_ cardType: CardType) -> UIImage? { + return UIImage(named: cardType.name, in: self, compatibleWith: nil) } - public func cvcImageForCardType(cardType: CardType) -> UIImage? { + public func cvcImageForCardType(_ cardType: CardType) -> UIImage? { let cvcImageName: String if cardType.isEqualTo(AmericanExpress()) { cvcImageName = "AmexCVC" @@ -45,7 +45,7 @@ extension NSBundle: CardTypeImageStore { cvcImageName = "CVC" } - return UIImage(named: cvcImageName, inBundle: self, compatibleWithTraitCollection: nil) + return UIImage(named: cvcImageName, in: self, compatibleWith: nil) } } diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index 1486a46..faf16cf 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -89,11 +89,11 @@ public class NumberInputTextField: StylizedTextField { // MARK: - UITextFieldDelegate - public override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { + public override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Current text in text field, formatted and unformatted: let textFieldTextFormatted = NSString(string: textField.text ?? "") // Text in text field after applying changes, formatted and unformatted: - let newTextFormatted = textFieldTextFormatted.stringByReplacingCharactersInRange(range, withString: string) + let newTextFormatted = textFieldTextFormatted.replacingCharacters(in: range, with: string) let newTextUnformatted = cardNumberFormatter.unformattedCardNumber(newTextFormatted) // Set the text color to invalid - this will be changed to `validTextColor` later in this method if the input was valid @@ -144,7 +144,7 @@ public class NumberInputTextField: StylizedTextField { - parameter cardNumber: The card number which should be displayed in `self`. */ - public func prefillInformation(cardNumber: String) { + public func prefillInformation(_ cardNumber: String) { let unformattedCardNumber = String(cardNumber.characters.filter({$0.isNumeric()})) let cardNumber = Number(rawValue: unformattedCardNumber) let type = cardTypeRegister.cardTypeForNumber(cardNumber) @@ -170,18 +170,18 @@ public class NumberInputTextField: StylizedTextField { - returns: A rect indicating the location and bounds of the text within the text field, or nil, if an invalid range has been entered. */ - private func rectForTextRange(range: NSRange, inTextField textField: UITextField) -> CGRect? { - guard let rangeStart = textField.positionFromPosition(textField.beginningOfDocument, offset: range.location) else { + private func rectForTextRange(_ range: NSRange, inTextField textField: UITextField) -> CGRect? { + guard let rangeStart = textField.position(from: textField.beginningOfDocument, offset: range.location) else { return nil } - guard let rangeEnd = textField.positionFromPosition(rangeStart, offset: range.length) else { + guard let rangeEnd = textField.position(from: rangeStart, offset: range.length) else { return nil } - guard let textRange = textField.textRangeFromPosition(rangeStart, toPosition: rangeEnd) else { + guard let textRange = textField.textRange(from: rangeStart, to: rangeEnd) else { return nil } - return textField.firstRectForRange(textRange) + return textField.firstRect(for: textRange) } /** @@ -190,7 +190,7 @@ public class NumberInputTextField: StylizedTextField { - returns: The CGRect in `self` that contains the last group of the card number. */ public func rectForLastGroup() -> CGRect? { - guard let lastGroupLength = text?.componentsSeparatedByString(cardNumberFormatter.separator).last?.characters.count else { + guard let lastGroupLength = text?.components(separatedBy: cardNumberFormatter.separator).last?.characters.count else { return nil } guard let textLength = text?.characters.count else { @@ -211,9 +211,9 @@ public class NumberInputTextField: StylizedTextField { posted here. Thus we need to listen to the notification from the system first, wait until it is finished, and post ours afterwards. */ private func addNumberInvalidityObserver() { - NSNotificationCenter.defaultCenter().addObserver(self, + NotificationCenter.default.addObserver(self, selector: #selector(notifyNumberInvalidity), - name: UIAccessibilityAnnouncementDidFinishNotification, + name: NSNotification.Name.UIAccessibilityAnnouncementDidFinish, object: nil) } @@ -223,6 +223,6 @@ public class NumberInputTextField: StylizedTextField { @objc private func notifyNumberInvalidity() { let localizedString = Localization.InvalidCardNumber.localizedStringWithComment("The expiration date entered is not valid") UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, localizedString) - NSNotificationCenter.defaultCenter().removeObserver(self) + NotificationCenter.default.removeObserver(self) } } diff --git a/Pod/Classes/UI/NumberInputTextFieldDelegate.swift b/Pod/Classes/UI/NumberInputTextFieldDelegate.swift index 49be913..92cde4f 100644 --- a/Pod/Classes/UI/NumberInputTextFieldDelegate.swift +++ b/Pod/Classes/UI/NumberInputTextFieldDelegate.swift @@ -16,12 +16,12 @@ public protocol NumberInputTextFieldDelegate { - parameter numberInputTextField: The `NumberInputTextField` that was used to enter a card number. */ - func numberInputTextFieldDidComplete(numberInputTextField: NumberInputTextField) + func numberInputTextFieldDidComplete(_ numberInputTextField: NumberInputTextField) /** Called when the user changed the text in the `NumberInputTextField`. - parameter numberInputTextField: The `NumberInputTextField` whose text was changed. */ - func numberInputTextFieldDidChangeText(numberInputTextField: NumberInputTextField) + func numberInputTextFieldDidChangeText(_ numberInputTextField: NumberInputTextField) } diff --git a/Pod/Classes/UI/StylizedTextField.swift b/Pod/Classes/UI/StylizedTextField.swift index 14f0a58..a2e0e78 100644 --- a/Pod/Classes/UI/StylizedTextField.swift +++ b/Pod/Classes/UI/StylizedTextField.swift @@ -19,10 +19,10 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { public var borderWidth: CGFloat = 0 { didSet { if borderWidth >= 0 { - self.borderStyle = .None + self.borderStyle = .none self.layer.borderWidth = CGFloat(borderWidth) } else { - self.borderStyle = .RoundedRect + self.borderStyle = .roundedRect self.layer.borderWidth = 0 } } @@ -44,9 +44,9 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { If `borderWidth` has been set, changes to this parameter change the color of the border of `self`. */ @IBInspectable - public var borderColor: UIColor = UIColor.blackColor() { + public var borderColor: UIColor = UIColor.black() { didSet { - self.layer.borderColor = self.borderColor.CGColor + self.layer.borderColor = self.borderColor.cgColor } } @@ -60,7 +60,7 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { if (text ?? "").isEmpty { deleteBackwardCallback?(self) } else if text == UITextField.emptyTextFieldCharacter { - drawPlaceholderInRect(textInputView.bounds) + drawPlaceholder(in: textInputView.bounds) } setNeedsDisplay() } @@ -69,7 +69,7 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { /** The color in which text flashes, when the user is about to enter an invalid card number. */ - @IBInspectable public var invalidInputColor: UIColor = UIColor.redColor() + @IBInspectable public var invalidInputColor: UIColor = UIColor.red() public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) @@ -96,19 +96,19 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { return super.becomeFirstResponder() } - public override func drawRect(rect: CGRect) { + public override func draw(_ rect: CGRect) { if text == "" || text == UITextField.emptyTextFieldCharacter { - super.drawPlaceholderInRect(rect) + super.drawPlaceholder(in: rect) } else { - super.drawRect(rect) + super.draw(rect) } } - public override func drawPlaceholderInRect(rect: CGRect) { + public override func drawPlaceholder(in rect: CGRect) { } - public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { + public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return true } } diff --git a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift index fa41ff6..790194e 100644 --- a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift @@ -23,7 +23,7 @@ public class CVCInputTextField: DetailInputTextField { - returns: True, if the card validation code is valid. */ - internal override func isInputValid(cvcString: String, partiallyValid: Bool) -> Bool { + internal override func isInputValid(_ cvcString: String, partiallyValid: Bool) -> Bool { if cvcString.characters.count == 0 && partiallyValid { return true } diff --git a/Pod/Classes/UI/Text Fields/Delegates/CardInfoTextFieldDelegate.swift b/Pod/Classes/UI/Text Fields/Delegates/CardInfoTextFieldDelegate.swift index be30e79..7bbcb57 100644 --- a/Pod/Classes/UI/Text Fields/Delegates/CardInfoTextFieldDelegate.swift +++ b/Pod/Classes/UI/Text Fields/Delegates/CardInfoTextFieldDelegate.swift @@ -20,7 +20,7 @@ public protocol CardInfoTextFieldDelegate { - parameter textField: The text field whose information was updated and is valid. - parameter didEnterValidInfo: The valid information that was entered into `textField`. */ - func textField(textField: UITextField, didEnterValidInfo: String) + func textField(_ textField: UITextField, didEnterValidInfo: String) /** Called whenever partially valid information was entered into `textField`. @@ -28,7 +28,7 @@ public protocol CardInfoTextFieldDelegate { - parameter textField: The text field whose information was updated and is partially valid. - parameter didEnterPartiallyValidInfo: The partially valid information that was entered. */ - func textField(textField: UITextField, didEnterPartiallyValidInfo: String) + func textField(_ textField: UITextField, didEnterPartiallyValidInfo: String) /** Called whenever more text was entered into `textField` than necessary. This can be used to provide this overflow as text in the next text field in the responder chain. @@ -36,5 +36,5 @@ public protocol CardInfoTextFieldDelegate { - parameter textField: The text field which received more information than required. - parameter overFlowDigits: The overflow of text which does not fit into `textField` and might be entered into the next receiver in the responder chain. */ - func textField(textField: UITextField, didEnterOverflowInfo overFlowDigits: String) + func textField(_ textField: UITextField, didEnterOverflowInfo overFlowDigits: String) } diff --git a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift index 806fc43..28f0e42 100644 --- a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift @@ -17,14 +17,14 @@ public class DetailInputTextField: StylizedTextField { public var cardInfoTextFieldDelegate: CardInfoTextFieldDelegate? - public func textFieldDidBeginEditing(textField: UITextField) { + public func textFieldDidBeginEditing(_ textField: UITextField) { if (textField.text ?? "").isEmpty { textField.text = UITextField.emptyTextFieldCharacter } } - public override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { - let newText = NSString(string: (textField.text ?? "")).stringByReplacingCharactersInRange(range, withString: string).stringByReplacingOccurrencesOfString(UITextField.emptyTextFieldCharacter, withString: "") + public override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + let newText = NSString(string: (textField.text ?? "")).replacingCharacters(in: range, with: string).replacingOccurrences(of: UITextField.emptyTextFieldCharacter, with: "") let deletingLastCharacter = !(textField.text ?? "").isEmpty && textField.text != UITextField.emptyTextFieldCharacter && newText.isEmpty if deletingLastCharacter { @@ -53,7 +53,7 @@ public class DetailInputTextField: StylizedTextField { return false } - public func prefillInformation(info: String) { + public func prefillInformation(_ info: String) { if isInputValid(info, partiallyValid: false) { text = info cardInfoTextFieldDelegate?.textField(self, didEnterValidInfo: info) @@ -63,18 +63,18 @@ public class DetailInputTextField: StylizedTextField { } } - private func splitText(text: String) -> (currentText: String, overflowText: String) { + private func splitText(_ text: String) -> (currentText: String, overflowText: String) { let hasOverflow = text.characters.count > expectedInputLength let index = (hasOverflow) ? - text.startIndex.advancedBy(expectedInputLength) : - text.startIndex.advancedBy(text.characters.count) - return (text.substringToIndex(index), text.substringFromIndex(index)) + text.characters.index(text.startIndex, offsetBy: expectedInputLength) : + text.characters.index(text.startIndex, offsetBy: text.characters.count) + return (text.substring(to: index), text.substring(from: index)) } } extension DetailInputTextField: AutoCompletingTextField { - func autocompleteText(text: String) -> String { + func autocompleteText(_ text: String) -> String { return text } } @@ -87,7 +87,7 @@ extension DetailInputTextField: TextFieldValidation { return 2 } - func isInputValid(input: String, partiallyValid: Bool) -> Bool { + func isInputValid(_ input: String, partiallyValid: Bool) -> Bool { return true } } diff --git a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift index 06f2a8c..65b5571 100644 --- a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift @@ -16,7 +16,7 @@ public class MonthInputTextField: DetailInputTextField { - returns: True, if the month is valid. */ - internal override func isInputValid(month: String, partiallyValid: Bool) -> Bool { + internal override func isInputValid(_ month: String, partiallyValid: Bool) -> Bool { let length = month.characters.count if partiallyValid && length == 0 { return true @@ -42,7 +42,7 @@ public class MonthInputTextField: DetailInputTextField { - returns: Auto-completed string. */ - internal override func autocompleteText(month: String) -> String { + internal override func autocompleteText(_ month: String) -> String { let length = month.characters.count if length != 1 { return month diff --git a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift index 80f4466..bd3d8a4 100644 --- a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift +++ b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift @@ -22,5 +22,5 @@ protocol AutoCompletingTextField { - returns: Auto-completed string. */ - func autocompleteText(text: String) -> String + func autocompleteText(_ text: String) -> String } diff --git a/Pod/Classes/UI/Text Fields/Protocols/TextFieldValidation.swift b/Pod/Classes/UI/Text Fields/Protocols/TextFieldValidation.swift index f5d103d..c9d4542 100644 --- a/Pod/Classes/UI/Text Fields/Protocols/TextFieldValidation.swift +++ b/Pod/Classes/UI/Text Fields/Protocols/TextFieldValidation.swift @@ -24,5 +24,5 @@ internal protocol TextFieldValidation { - returns: True, if the input is valid. */ - func isInputValid(input: String, partiallyValid: Bool) -> Bool + func isInputValid(_ input: String, partiallyValid: Bool) -> Bool } diff --git a/Pod/Classes/UI/Text Fields/YearInputTextField.swift b/Pod/Classes/UI/Text Fields/YearInputTextField.swift index 4107d05..3a1511e 100644 --- a/Pod/Classes/UI/Text Fields/YearInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/YearInputTextField.swift @@ -16,7 +16,7 @@ public class YearInputTextField: DetailInputTextField { - returns: True, if the year is valid. */ - internal override func isInputValid(year: String, partiallyValid: Bool) -> Bool { + internal override func isInputValid(_ year: String, partiallyValid: Bool) -> Bool { if partiallyValid && year.characters.count == 0 { return true } @@ -29,4 +29,4 @@ public class YearInputTextField: DetailInputTextField { yearInt < 100 && (partiallyValid || year.characters.count == 2) } -} \ No newline at end of file +} diff --git a/Pod/Classes/Validation/CardValidationResult.swift b/Pod/Classes/Validation/CardValidationResult.swift index 57246f0..d4405e7 100644 --- a/Pod/Classes/Validation/CardValidationResult.swift +++ b/Pod/Classes/Validation/CardValidationResult.swift @@ -18,7 +18,7 @@ import UIKit ```` let result = CardValidationResult.NumberDoesNotMatchType.union(CardValidationResult.CardExpired) */ -public struct CardValidationResult: OptionSetType { +public struct CardValidationResult: OptionSet { public let rawValue: UInt64 public init(rawValue: UInt64) { @@ -87,43 +87,43 @@ extension CardValidationResult: CustomStringConvertible { strings.append("Valid") } - if isSupersetOf(.NumberDoesNotMatchType) { + if isSuperset(of: .NumberDoesNotMatchType) { strings.append("Number does not match type") } - if isSupersetOf(.CVCIncomplete) { + if isSuperset(of: .CVCIncomplete) { strings.append("CVC is too short") } - if isSupersetOf(.InvalidCVC) { + if isSuperset(of: .InvalidCVC) { strings.append("CVC is invalid") } - if isSupersetOf(.CardExpired) { + if isSuperset(of: .CardExpired) { strings.append("Card has expired") } - if isSupersetOf(.InvalidExpiry) { + if isSuperset(of: .InvalidExpiry) { strings.append("Expiration date is not valid") } - if isSupersetOf(.NumberIsNotNumeric) { + if isSuperset(of: .NumberIsNotNumeric) { strings.append("Card number is not numeric") } - if isSupersetOf(.LuhnTestFailed) { + if isSuperset(of: .LuhnTestFailed) { strings.append("Luhn test failed for card number") } - if isSupersetOf(.NumberIncomplete) { + if isSuperset(of: .NumberIncomplete) { strings.append("Card number seems to be incomplete") } - if isSupersetOf(.UnknownType) { + if isSuperset(of: .UnknownType) { strings.append("Card type could not be inferred") } - if isSupersetOf(.NumberTooLong) { + if isSuperset(of: .NumberTooLong) { strings.append("Card number is too long") } From 5577f410274109a12294bc18c14abd300d601a70 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 28 Jul 2016 09:29:52 +0200 Subject: [PATCH 02/20] Updates to function signatures to be more "Swift 3" --- CaishenTests/CardCVCValidatorTests.swift | 16 +++---- CaishenTests/CardExpiryValidatorTests.swift | 8 ++-- CaishenTests/CardNumberFormatterTests.swift | 2 +- CaishenTests/CardNumberValidatorTests.swift | 42 +++++++++---------- Example/Caishen/ViewController.swift | 2 +- Example/Podfile.lock | 2 +- Pod/Classes/Cards/Card.swift | 2 +- Pod/Classes/Cards/CardType.swift | 26 ++++++------ Pod/Classes/Cards/CardTypeRegister.swift | 4 +- .../Default Card Types/UnknownCardType.swift | 12 +++--- Pod/Classes/Cards/Expiry.swift | 8 ++-- Pod/Classes/Format/CardNumberFormatter.swift | 22 +++++----- Pod/Classes/StringExtension.swift | 4 +- ...dTextField+CardInfoTextFieldDelegate.swift | 8 ++-- .../UI/CardTextField+PrefillInformation.swift | 12 +++--- .../UI/CardTextField+ViewAnimations.swift | 2 +- Pod/Classes/UI/CardTextField.swift | 22 +++++----- Pod/Classes/UI/CardTypeImageStore.swift | 10 ++--- Pod/Classes/UI/NumberInputTextField.swift | 12 +++--- .../UI/Text Fields/CVCInputTextField.swift | 2 +- .../UI/Text Fields/DetailInputTextField.swift | 20 ++++----- .../UI/Text Fields/MonthInputTextField.swift | 12 +++--- .../Protocols/AutoCompletingTextField.swift | 2 +- 23 files changed, 125 insertions(+), 127 deletions(-) diff --git a/CaishenTests/CardCVCValidatorTests.swift b/CaishenTests/CardCVCValidatorTests.swift index dec912b..49e6acb 100644 --- a/CaishenTests/CardCVCValidatorTests.swift +++ b/CaishenTests/CardCVCValidatorTests.swift @@ -16,11 +16,11 @@ class CardCVCValidatorTests: XCTestCase { let invalidLengthObject1 = CVC(rawValue: "23") let invalidLengthObject2 = CVC(rawValue: "2345") - XCTAssertValid(Visa().validateCVC(validObject)) - XCTAssertValid(AmericanExpress().validateCVC(invalidLengthObject2)) - XCTAssertIncompleteCVC(AmericanExpress().validateCVC(validObject)) - XCTAssertIncompleteCVC(Visa().validateCVC(invalidLengthObject1)) - XCTAssertInvalidCVC(Visa().validateCVC(invalidLengthObject2)) + XCTAssertValid(Visa().validate(cvc: validObject)) + XCTAssertValid(AmericanExpress().validate(cvc: invalidLengthObject2)) + XCTAssertIncompleteCVC(AmericanExpress().validate(cvc: validObject)) + XCTAssertIncompleteCVC(Visa().validate(cvc: invalidLengthObject1)) + XCTAssertInvalidCVC(Visa().validate(cvc: invalidLengthObject2)) } func testValidateCharacters() { @@ -28,9 +28,9 @@ class CardCVCValidatorTests: XCTestCase { let invalidCharacterObject1 = CVC(rawValue: "23a") let invalidCharacterObject2 = CVC(rawValue: "2.5") - XCTAssertValid(Visa().validateCVC(validObject)) - XCTAssertInvalidCVC(Visa().validateCVC(invalidCharacterObject1)) - XCTAssertInvalidCVC(Visa().validateCVC(invalidCharacterObject2)) + XCTAssertValid(Visa().validate(cvc: validObject)) + XCTAssertInvalidCVC(Visa().validate(cvc: invalidCharacterObject1)) + XCTAssertInvalidCVC(Visa().validate(cvc: invalidCharacterObject2)) } } diff --git a/CaishenTests/CardExpiryValidatorTests.swift b/CaishenTests/CardExpiryValidatorTests.swift index 72210e5..1677284 100644 --- a/CaishenTests/CardExpiryValidatorTests.swift +++ b/CaishenTests/CardExpiryValidatorTests.swift @@ -23,8 +23,8 @@ class CardExpiryValidatorTests: XCTestCase { let lastYear = Expiry(month: 01, year: 2015)! let future = Expiry(month: 12, year: 2115)! - XCTAssertValid(cardType.validateExpiry(future)) - XCTAssertCardExpired(cardType.validateExpiry(lastYear)) + XCTAssertValid(cardType.validate(expiry: future)) + XCTAssertCardExpired(cardType.validate(expiry: lastYear)) } func testInvalidExpiryCreation() { @@ -62,7 +62,7 @@ class CardExpiryValidatorTests: XCTestCase { XCTAssertNotNil(obj, "Object \(i) should not be nil, but is") XCTAssertEqual(obj?.description, "02/2006") if let obj = obj { - XCTAssertCardExpired(cardType.validateExpiry(obj)) + XCTAssertCardExpired(cardType.validate(expiry: obj)) } } @@ -71,7 +71,7 @@ class CardExpiryValidatorTests: XCTestCase { XCTAssertNotNil(obj, "Object \(i) should not be nil, but is") XCTAssertEqual(obj?.description, "02/2096") if let obj = obj { - XCTAssertCardNotExpired(cardType.validateExpiry(obj)) + XCTAssertCardNotExpired(cardType.validate(expiry: obj)) } } } diff --git a/CaishenTests/CardNumberFormatterTests.swift b/CaishenTests/CardNumberFormatterTests.swift index e8fc337..543ecab 100644 --- a/CaishenTests/CardNumberFormatterTests.swift +++ b/CaishenTests/CardNumberFormatterTests.swift @@ -29,7 +29,7 @@ class CardNumberFormatterTests: XCTestCase { func testCorrectSeparator() { let testNumber = Number(rawValue: "4123123412341234") - let formattedTestNumber = self.formatter.formattedCardNumber(testNumber.description) + let formattedTestNumber = self.formatter.format(cardNumber: testNumber.description) XCTAssertEqual(formattedTestNumber, "4123-1234-1234-1234") } diff --git a/CaishenTests/CardNumberValidatorTests.swift b/CaishenTests/CardNumberValidatorTests.swift index 29401ff..776b39d 100644 --- a/CaishenTests/CardNumberValidatorTests.swift +++ b/CaishenTests/CardNumberValidatorTests.swift @@ -76,37 +76,37 @@ class CardNumberValidatorTests: XCTestCase { print("Validate Visa") self.validVisaNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, Visa().name) - XCTAssertValid(Visa().validateNumber(Number(rawValue: $0))) + XCTAssertValid(Visa().validate(number: Number(rawValue: $0))) }) print("Validate Amex") self.validAmexNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, AmericanExpress().name) - XCTAssertValid(AmericanExpress().validateNumber(Number(rawValue: $0))) + XCTAssertValid(AmericanExpress().validate(number: Number(rawValue: $0))) }) print("Validate China UnionPay") self.validChinaUnionPayNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, ChinaUnionPay().name) - XCTAssertValid(ChinaUnionPay().validateNumber(Number(rawValue: $0))) + XCTAssertValid(ChinaUnionPay().validate(number: Number(rawValue: $0))) }) print("Validate Diners Club") self.validDinersClubNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, DinersClub().name) - XCTAssertValid(DinersClub().validateNumber(Number(rawValue: $0))) + XCTAssertValid(DinersClub().validate(number: Number(rawValue: $0))) }) print("Validate Discover") self.validDiscoverNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, Discover().name) - XCTAssertValid(Discover().validateNumber(Number(rawValue: $0))) + XCTAssertValid(Discover().validate(number: Number(rawValue: $0))) }) print("Validate JCB") self.validJCBNumbers.forEach({ XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeForNumber(Number(rawValue: $0)).name, JCB().name, "Card number was interpreted as wrong kind: \($0)") - XCTAssertValid(JCB().validateNumber(Number(rawValue: $0))) + XCTAssertValid(JCB().validate(number: Number(rawValue: $0))) }) } @@ -127,21 +127,21 @@ class CardNumberValidatorTests: XCTestCase { let tooLongMasterCard = "55555555555544444" let tooLongChinaUnionPay = "62812636660717755" - XCTAssertIncompleteNumber(Visa().validateNumber(Number(rawValue: tooShortVisa))) - XCTAssertIncompleteNumber(AmericanExpress().validateNumber(Number(rawValue: tooShortAmex))) - XCTAssertIncompleteNumber(DinersClub().validateNumber(Number(rawValue: tooShortDiners))) - XCTAssertIncompleteNumber(Discover().validateNumber(Number(rawValue: tooShortDiscover))) - XCTAssertIncompleteNumber(JCB().validateNumber(Number(rawValue: tooShortJCB))) - XCTAssertIncompleteNumber(MasterCard().validateNumber(Number(rawValue: tooShortMasterCard))) - XCTAssertIncompleteNumber(ChinaUnionPay().validateNumber(Number(rawValue: tooShortChinaUnionPay))) + XCTAssertIncompleteNumber(Visa().validate(number: Number(rawValue: tooShortVisa))) + XCTAssertIncompleteNumber(AmericanExpress().validate(number: Number(rawValue: tooShortAmex))) + XCTAssertIncompleteNumber(DinersClub().validate(number: Number(rawValue: tooShortDiners))) + XCTAssertIncompleteNumber(Discover().validate(number: Number(rawValue: tooShortDiscover))) + XCTAssertIncompleteNumber(JCB().validate(number: Number(rawValue: tooShortJCB))) + XCTAssertIncompleteNumber(MasterCard().validate(number: Number(rawValue: tooShortMasterCard))) + XCTAssertIncompleteNumber(ChinaUnionPay().validate(number: Number(rawValue: tooShortChinaUnionPay))) - XCTAssertInvalidNumberForType(Visa().validateNumber(Number(rawValue: tooLongVisa))) - XCTAssertInvalidNumberForType(AmericanExpress().validateNumber(Number(rawValue: tooLongAmex))) - XCTAssertInvalidNumberForType(DinersClub().validateNumber(Number(rawValue: tooLongDiners))) - XCTAssertInvalidNumberForType(Discover().validateNumber(Number(rawValue: tooLongDiscover))) - XCTAssertInvalidNumberForType(JCB().validateNumber(Number(rawValue: tooLongJCB))) - XCTAssertInvalidNumberForType(MasterCard().validateNumber(Number(rawValue: tooLongMasterCard))) - XCTAssertInvalidNumberForType(ChinaUnionPay().validateNumber(Number(rawValue: tooLongChinaUnionPay))) + XCTAssertInvalidNumberForType(Visa().validate(number: Number(rawValue: tooLongVisa))) + XCTAssertInvalidNumberForType(AmericanExpress().validate(number: Number(rawValue: tooLongAmex))) + XCTAssertInvalidNumberForType(DinersClub().validate(number: Number(rawValue: tooLongDiners))) + XCTAssertInvalidNumberForType(Discover().validate(number: Number(rawValue: tooLongDiscover))) + XCTAssertInvalidNumberForType(JCB().validate(number: Number(rawValue: tooLongJCB))) + XCTAssertInvalidNumberForType(MasterCard().validate(number: Number(rawValue: tooLongMasterCard))) + XCTAssertInvalidNumberForType(ChinaUnionPay().validate(number: Number(rawValue: tooLongChinaUnionPay))) } /** @@ -173,7 +173,7 @@ class CardNumberValidatorTests: XCTestCase { invalidLuhnTestVisa.forEach({ - XCTAssertLuhnTestFailed(Visa().validateNumber(Number(rawValue: $0))) + XCTAssertLuhnTestFailed(Visa().validate(number: Number(rawValue: $0))) }) } diff --git a/Example/Caishen/ViewController.swift b/Example/Caishen/ViewController.swift index d066fdd..07c5574 100644 --- a/Example/Caishen/ViewController.swift +++ b/Example/Caishen/ViewController.swift @@ -54,7 +54,7 @@ class ViewController: UIViewController, CardTextFieldDelegate, CardIOPaymentView } func userDidProvide(_ cardInfo: CardIOCreditCardInfo!, in paymentViewController: CardIOPaymentViewController!) { - cardNumberTextField.prefillCardInformation(cardInfo.cardNumber, month: Int(cardInfo.expiryMonth), year: Int(cardInfo.expiryYear), cvc: cardInfo.cvv) + cardNumberTextField.prefill(number: cardInfo.cardNumber, month: Int(cardInfo.expiryMonth), year: Int(cardInfo.expiryYear), cvc: cardInfo.cvv) paymentViewController.dismiss(animated: true, completion: nil) } diff --git a/Example/Podfile.lock b/Example/Podfile.lock index cb2b4b0..11eed2e 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -11,7 +11,7 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - Caishen: 19c73df58634c898c8cab66b870b9159d60ce9e2 + Caishen: c0c7050eaaefac2df5196ea2c2451b79978cd617 CardIO: 92c45caef0d986c4a303a7afba0c9b76ff2b1f6e PODFILE CHECKSUM: 171ac2de78bae9fd3012144f2669334669aef0d6 diff --git a/Pod/Classes/Cards/Card.swift b/Pod/Classes/Cards/Card.swift index b36c5f0..838aa2e 100644 --- a/Pod/Classes/Cards/Card.swift +++ b/Pod/Classes/Cards/Card.swift @@ -40,7 +40,7 @@ public struct Card { - returns: A card with the provided parameters. */ - public static func create(_ number: String, cardVerificationCode cvc: String, expiry: String) throws -> Card { + public static func create(number: String, cardVerificationCode cvc: String, expiry: String) throws -> Card { // Create card number, cvc and expiry with the arguments provided let cardNumber = Number(rawValue: number) let cardCVC = CVC(rawValue: cvc) diff --git a/Pod/Classes/Cards/CardType.swift b/Pod/Classes/Cards/CardType.swift index 74a22a8..188cccf 100644 --- a/Pod/Classes/Cards/CardType.swift +++ b/Pod/Classes/Cards/CardType.swift @@ -59,7 +59,7 @@ public protocol CardType { - returns: The validation result for the CVC, taking the current card type into account, as different card issuers can provide CVCs in different formats. */ - func validateCVC(_ cvc: CVC) -> CardValidationResult + func validate(cvc: CVC) -> CardValidationResult /** @@ -84,7 +84,7 @@ public protocol CardType { - returns: The result of the card number validation. */ - func validateNumber(_ number: Number) -> CardValidationResult + func validate(number: Number) -> CardValidationResult /** Validates the card's expiry date, checking whether the card has expired or not. @@ -93,7 +93,7 @@ public protocol CardType { - returns: The result of the card expiration date validation. */ - func validateExpiry(_ expiry: Expiry) -> CardValidationResult + func validate(expiry: Expiry) -> CardValidationResult /** Returns whether or not `self` is equal to another `CardType`. @@ -102,12 +102,12 @@ public protocol CardType { - returns: Whether or not `self` is equal to the provided `cardType`. */ - func isEqualTo(_ cardType: CardType) -> Bool + func isEqual(to cardType: CardType) -> Bool } extension CardType { - public func isEqualTo(_ cardType: CardType) -> Bool { + public func isEqual(to cardType: CardType) -> Bool { return cardType.name == self.name } @@ -127,7 +127,7 @@ extension CardType { return numberGrouping.reduce(0) { $0 + $1 } } - public func validateCVC(_ cvc: CVC) -> CardValidationResult { + public func validate(cvc: CVC) -> CardValidationResult { guard requiresCVC else { return .Valid @@ -146,13 +146,13 @@ extension CardType { return .Valid } - public func validateNumber(_ cardNumber: Number) -> CardValidationResult { - return lengthMatchesType(cardNumber.length) - .union(numberIsNumeric(cardNumber)) - .union(numberIsValidLuhn(cardNumber)) + public func validate(number: Number) -> CardValidationResult { + return lengthMatchesType(number.length) + .union(numberIsNumeric(number)) + .union(numberIsValidLuhn(number)) } - public func validateExpiry(_ expiry: Expiry) -> CardValidationResult { + public func validate(expiry: Expiry) -> CardValidationResult { guard requiresExpiry else { return .Valid } @@ -226,14 +226,14 @@ extension CardType { - or the card validation failed because of the Luhn test or insufficient card number length (both of which are irrelevant for incomplete card numbers). */ public func checkCardNumberPartiallyValid(_ cardNumber: Number) -> CardValidationResult { - let validationResult = validateNumber(cardNumber) + let validationResult = validate(number: cardNumber) let completeNumberButLuhnTestFailed = !validationResult.isSuperset(of: CardValidationResult.NumberIncomplete) && validationResult.isSuperset(of: CardValidationResult.LuhnTestFailed) if completeNumberButLuhnTestFailed { return validationResult } else { return - self.validateNumber(cardNumber) + self.validate(number: cardNumber) .subtracting(.NumberIncomplete) .subtracting(.LuhnTestFailed) } diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index fb4a0f3..f8b45b3 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -53,7 +53,7 @@ public class CardTypeRegister { - parameter cardType: The card type that should be contained in this card type register. */ public func registerCardType(_ cardType: CardType) { - if registeredCardTypes.contains({ $0.isEqualTo(cardType) }) { + if registeredCardTypes.contains({ $0.isEqual(to: cardType) }) { return } @@ -66,7 +66,7 @@ public class CardTypeRegister { - parameter cardType: The card type that should be removed from this card type register. */ public func unregisterCardType(_ cardType: CardType) { - registeredCardTypes = registeredCardTypes.filter { !$0.isEqualTo(cardType) } + registeredCardTypes = registeredCardTypes.filter { !$0.isEqual(to: cardType) } } /** diff --git a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift index 1243357..3440ac7 100644 --- a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift +++ b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift @@ -15,18 +15,18 @@ public struct UnknownCardType: CardType { public let CVCLength = 0 public let identifyingDigits: Set = [] - public func validateNumber(_ cardNumber: Number) -> CardValidationResult { + public func validate(number: Number) -> CardValidationResult { return CardValidationResult.UnknownType - .union(lengthMatchesType(cardNumber.length)) - .union(numberIsNumeric(cardNumber)) - .union(numberIsValidLuhn(cardNumber)) + .union(lengthMatchesType(number.length)) + .union(numberIsNumeric(number)) + .union(numberIsValidLuhn(number)) } - public func validateCVC(_ cvc: CVC) -> CardValidationResult { + public func validate(cvc: CVC) -> CardValidationResult { return .UnknownType } - public func validateExpiry(_ expiry: Expiry) -> CardValidationResult { + public func validate(expiry: Expiry) -> CardValidationResult { return .UnknownType } diff --git a/Pod/Classes/Cards/Expiry.swift b/Pod/Classes/Cards/Expiry.swift index 2bfc36d..898de0b 100644 --- a/Pod/Classes/Cards/Expiry.swift +++ b/Pod/Classes/Cards/Expiry.swift @@ -52,14 +52,14 @@ public struct Expiry: RawRepresentable { } let monthRange = match.range(at: 1) - if monthRange.length > 0, let range = string.rangeFromNSRange(monthRange) { + if monthRange.length > 0, let range = string.rangeFrom(nsRange: monthRange) { monthStr = string.substring(with: range) } else { return nil } let yearRange = match.range(at: 2) - if yearRange.length > 0, let range = string.rangeFromNSRange(yearRange) { + if yearRange.length > 0, let range = string.rangeFrom(nsRange: yearRange) { yearStr = string.substring(with: range) } else { return nil @@ -112,7 +112,7 @@ public struct Expiry: RawRepresentable { return nil } - guard let date = toDate(month, year: yearValue) else { + guard let date = toDate(month: month, year: yearValue) else { return nil } @@ -144,7 +144,7 @@ extension Expiry: CustomStringConvertible { - returns: The date with month and year and time set to one minute before the following month. */ -private func toDate(_ month: UInt, year: UInt) -> Date? { +private func toDate(month: UInt, year: UInt) -> Date? { var dateComponents = DateComponents() dateComponents.day = 1 dateComponents.month = Int(month) diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 02460f8..844d790 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -47,10 +47,10 @@ public final class CardNumberFormatter { - returns: Formatted card number string. */ - public func formattedCardNumber(_ cardNumberString: String) -> String { + public func format(cardNumber: String) -> String { let regex: RegularExpression - let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumberString)) + let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumber)) do { let groups = cardType.numberGrouping var pattern = "" @@ -67,7 +67,7 @@ public final class CardNumberFormatter { fatalError("Error when creating regular expression: \(error)") } - return NSArray(array: self.splitString(cardNumberString, withRegex: regex)).componentsJoined(by: self.separator) + return NSArray(array: self.splitString(cardNumber, withRegex: regex)).componentsJoined(by: self.separator) } /** @@ -77,7 +77,7 @@ public final class CardNumberFormatter { - returns: The index of the cursor position or nil, if no selected text was found. */ - public func cursorPositionAfterUnformattingText(_ text: String, inTextField textField: UITextField) -> Int? { + public func cursorPositionAfterUnformatting(text: String, in textField: UITextField) -> Int? { guard let selectedRange = textField.selectedTextRange else { return nil } @@ -113,12 +113,12 @@ public final class CardNumberFormatter { - returns: The index in an unformatted string that is equivalent to `index` in `formattedString`. */ - private func indexInUnformattedString(_ index: Int, formattedString: String) -> Int { + private func indexInUnformattedString(indexInFormattedString: Int, formattedString: String) -> Int { var componentWithIndex = 0 var charCount = 0 for component in formattedString.components(separatedBy: self.separator) { charCount += component.characters.count - if charCount >= index { + if charCount >= indexInFormattedString { break } else { componentWithIndex += 1 @@ -126,7 +126,7 @@ public final class CardNumberFormatter { } } - return index - componentWithIndex * self.separator.characters.count + return indexInFormattedString - componentWithIndex * self.separator.characters.count } /** @@ -141,7 +141,7 @@ public final class CardNumberFormatter { */ private func indexInFormattedString(_ index: Int, unformattedString: String) -> Int { var charIdx = 0 - let formattedString = self.formattedCardNumber(unformattedString) + let formattedString = self.format(cardNumber: unformattedString) let groups = formattedString.components(separatedBy: self.separator) @@ -168,15 +168,15 @@ public final class CardNumberFormatter { let newValueUnformatted = self.unformattedCardNumber(NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)) let oldValueUnformatted = self.unformattedCardNumber(textField.text ?? "") - let newValue = self.formattedCardNumber(newValueUnformatted) + let newValue = format(cardNumber: newValueUnformatted) let oldValue = textField.text ?? "" var position: UITextPosition? if let start = textField.selectedTextRange?.start { let oldCursorPosition = textField.offset(from: textField.beginningOfDocument, to: start) - let oldCursorPositionUnformatted = self.indexInUnformattedString(oldCursorPosition, formattedString: oldValue) + let oldCursorPositionUnformatted = indexInUnformattedString(indexInFormattedString: oldCursorPosition, formattedString: oldValue) let newCursorPositionUnformatted = oldCursorPositionUnformatted + (newValueUnformatted.characters.count - oldValueUnformatted.characters.count) - let newCursorPositionFormatted = self.indexInFormattedString(newCursorPositionUnformatted, unformattedString: newValueUnformatted) + let newCursorPositionFormatted = indexInFormattedString(newCursorPositionUnformatted, unformattedString: newValueUnformatted) position = textField.position(from: textField.beginningOfDocument, offset: newCursorPositionFormatted) } diff --git a/Pod/Classes/StringExtension.swift b/Pod/Classes/StringExtension.swift index 4f35036..7eadea7 100644 --- a/Pod/Classes/StringExtension.swift +++ b/Pod/Classes/StringExtension.swift @@ -19,7 +19,7 @@ extension String { - returns: `nsRange` converted to Range or nil, if its start and/or end location are not within `self`. */ - func rangeFromNSRange(_ nsRange: NSRange) -> Range? { + func rangeFrom(nsRange: NSRange) -> Range? { guard let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex) else { return nil } @@ -40,7 +40,7 @@ extension String { - returns: An NSRange object that is equivalent to `range`. */ - func NSRangeFromRange(_ range : Range) -> NSRange { + func NSRangeFrom(range : Range) -> NSRange { let utf16view = self.utf16 let from = String.UTF16View.Index(range.lowerBound, within: utf16view) let to = String.UTF16View.Index(range.upperBound, within: utf16view) diff --git a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift index 2cc5fa8..9c6240a 100644 --- a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift +++ b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift @@ -14,7 +14,7 @@ extension CardTextField: CardInfoTextFieldDelegate { updateNumberColor() notifyDelegate() if expirationDateIsValid() { - selectNextTextField(textField, prefillText: nil) + select(textField: textField, prefillText: nil) } } @@ -25,14 +25,14 @@ extension CardTextField: CardInfoTextFieldDelegate { public func textField(_ textField: UITextField, didEnterOverflowInfo overFlowDigits: String) { updateNumberColor() - selectNextTextField(textField, prefillText: overFlowDigits) + select(textField: textField, prefillText: overFlowDigits) } - private func selectNextTextField(_ textField: UITextField, prefillText: String?) { + private func select(textField: UITextField, prefillText: String?) { var nextTextField: UITextField? if textField == monthTextField { if hideExpiryTextFields { - selectNextTextField(yearTextField, prefillText: prefillText) + select(textField: yearTextField, prefillText: prefillText) } else { nextTextField = yearTextField } diff --git a/Pod/Classes/UI/CardTextField+PrefillInformation.swift b/Pod/Classes/UI/CardTextField+PrefillInformation.swift index a317e1c..66c571f 100644 --- a/Pod/Classes/UI/CardTextField+PrefillInformation.swift +++ b/Pod/Classes/UI/CardTextField+PrefillInformation.swift @@ -18,29 +18,29 @@ public extension CardTextField { - parameter year: The year that should be shown in the year input field. - parameter cvc: The CVC that should be shown in the CVC input field. */ - public func prefillCardInformation(_ cardNumber: String?, month: Int?, year: Int?, cvc: String?) { + public func prefill(number: String?, month: Int?, year: Int?, cvc: String?) { if let year = year { var trimmedYear = year if year > 100 { trimmedYear = year % 100 } - yearTextField?.prefillInformation(String(format: "%02i", arguments: [trimmedYear])) + yearTextField?.prefill(text: String(format: "%02i", arguments: [trimmedYear])) } if let month = month { - monthTextField?.prefillInformation(String(format: "%02i", arguments: [month])) + monthTextField?.prefill(text: String(format: "%02i", arguments: [month])) } - if let cardNumber = cardNumber, let numberInputTextField = numberInputTextField { - numberInputTextField.prefillInformation(cardNumber) + if let cardNumber = number, let numberInputTextField = numberInputTextField { + numberInputTextField.prefill(text: cardNumber) // With a new card number comes a new card type - pass this card type to `cvcTextField` cvcTextField?.cardType = cardType } if let cvc = cvc { - cvcTextField?.prefillInformation(cvc) + cvcTextField?.prefill(text: cvc) } OperationQueue().addOperation({ diff --git a/Pod/Classes/UI/CardTextField+ViewAnimations.swift b/Pod/Classes/UI/CardTextField+ViewAnimations.swift index 187c183..a9f8106 100644 --- a/Pod/Classes/UI/CardTextField+ViewAnimations.swift +++ b/Pod/Classes/UI/CardTextField+ViewAnimations.swift @@ -34,7 +34,7 @@ public extension CardTextField { */ public func moveCardNumberOut() { // If the card number is invalid, do not allow to move to the card detail - if cardType?.validateNumber(card.bankCardNumber) != .Valid { + if cardType?.validate(number: card.bankCardNumber) != .Valid { return } // If neither expiry nor cvc are required, also do not allow to move to the detail diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index 83962fb..5820652 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -273,7 +273,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { firstObjectInNib.frame = bounds addSubview(firstObjectInNib) - cardImageView?.image = cardTypeImageStore.imageForCardType(UnknownCardType()) + cardImageView?.image = cardTypeImageStore.imageFor(cardType: UnknownCardType()) cardImageView?.layer.cornerRadius = 5.0 cardImageView?.layer.shadowColor = UIColor.black().cgColor cardImageView?.layer.shadowRadius = 2 @@ -365,10 +365,10 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Adds voice over accessibility support for all text fields */ private func setupAccessibilityLabels() { - setupAccessibilityLabelForTextField(numberInputTextField) - setupAccessibilityLabelForTextField(cvcTextField) - setupAccessibilityLabelForTextField(monthTextField) - setupAccessibilityLabelForTextField(yearTextField) + setupAccessibilityLabelFor(textField: numberInputTextField) + setupAccessibilityLabelFor(textField: cvcTextField) + setupAccessibilityLabelFor(textField: monthTextField) + setupAccessibilityLabelFor(textField: yearTextField) } /** @@ -376,7 +376,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { - parameter textField: a text field that needs support for voice over accessibility */ - private func setupAccessibilityLabelForTextField(_ textField: UITextField) { + private func setupAccessibilityLabelFor(textField: UITextField) { textField.accessibilityLabel = Localization.accessibilityLabelForTextField(textField, comment: "Accessibility label for \(String(textField))") } @@ -468,9 +468,9 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { return .UnknownType } - return cardType.validateNumber(self.card.bankCardNumber) - .union(cardType.validateCVC(self.card.cardVerificationCode)) - .union(cardType.validateExpiry(self.card.expiryDate)) + return cardType.validate(number: self.card.bankCardNumber) + .union(cardType.validate(cvc: self.card.cardVerificationCode)) + .union(cardType.validate(expiry: self.card.expiryDate)) }() cardTextFieldDelegate?.cardTextField(self, @@ -507,7 +507,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ internal func showCardImage() { let cardType = cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber) - let cardTypeImage = cardTypeImageStore.imageForCardType(cardType) + let cardTypeImage = cardTypeImageStore.imageFor(cardType: cardType) cardImageView?.image = cardTypeImage } @@ -517,7 +517,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ internal func showCVCImage() { let cardType = cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber) - let cvcImage = cardTypeImageStore.cvcImageForCardType(cardType) + let cvcImage = cardTypeImageStore.cvcImageFor(cardType: cardType) cardImageView?.image = cvcImage cvcTextField?.cardType = cardType diff --git a/Pod/Classes/UI/CardTypeImageStore.swift b/Pod/Classes/UI/CardTypeImageStore.swift index f853677..7bec865 100644 --- a/Pod/Classes/UI/CardTypeImageStore.swift +++ b/Pod/Classes/UI/CardTypeImageStore.swift @@ -18,7 +18,7 @@ public protocol CardTypeImageStore { - returns: The image for the specified card type or nil, if no image was provided for this card type. */ - func imageForCardType(_ cardType: CardType) -> UIImage? + func imageFor(cardType: CardType) -> UIImage? /** Provides an image for the CVC of a specific card type. The position of a CVC on a card may vary based on the card issuer, so that different card types may provide different images to indicate the location of the CVC on the card. This image will be shown in a `CardTextField`'s image view once the user starts entering the CVC. @@ -27,19 +27,19 @@ public protocol CardTypeImageStore { - returns: The image for the CVC of the specified card type or nil, if no image was provided for this card type. */ - func cvcImageForCardType(_ cardType: CardType) -> UIImage? + func cvcImageFor(cardType: CardType) -> UIImage? } extension Bundle: CardTypeImageStore { - public func imageForCardType(_ cardType: CardType) -> UIImage? { + public func imageFor(cardType: CardType) -> UIImage? { return UIImage(named: cardType.name, in: self, compatibleWith: nil) } - public func cvcImageForCardType(_ cardType: CardType) -> UIImage? { + public func cvcImageFor(cardType: CardType) -> UIImage? { let cvcImageName: String - if cardType.isEqualTo(AmericanExpress()) { + if cardType.isEqual(to: AmericanExpress()) { cvcImageName = "AmexCVC" } else { cvcImageName = "CVC" diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index faf16cf..96fa6a9 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -104,9 +104,9 @@ public class NumberInputTextField: StylizedTextField { } let parsedCardNumber = Number(rawValue: newTextUnformatted) - let oldValidation = cardTypeRegister.cardTypeForNumber(cardNumber).validateNumber(cardNumber) + let oldValidation = cardTypeRegister.cardTypeForNumber(cardNumber).validate(number: cardNumber) let newValidation = - cardTypeRegister.cardTypeForNumber(parsedCardNumber).validateNumber(parsedCardNumber) + cardTypeRegister.cardTypeForNumber(parsedCardNumber).validate(number: parsedCardNumber) if !newValidation.contains(.NumberTooLong) { cardNumberFormatter.replaceRangeFormatted(range, inTextField: textField, withString: string) @@ -144,8 +144,8 @@ public class NumberInputTextField: StylizedTextField { - parameter cardNumber: The card number which should be displayed in `self`. */ - public func prefillInformation(_ cardNumber: String) { - let unformattedCardNumber = String(cardNumber.characters.filter({$0.isNumeric()})) + public func prefill(text: String) { + let unformattedCardNumber = String(text.characters.filter({$0.isNumeric()})) let cardNumber = Number(rawValue: unformattedCardNumber) let type = cardTypeRegister.cardTypeForNumber(cardNumber) let numberPartiallyValid = type.checkCardNumberPartiallyValid(cardNumber) == .Valid @@ -170,7 +170,7 @@ public class NumberInputTextField: StylizedTextField { - returns: A rect indicating the location and bounds of the text within the text field, or nil, if an invalid range has been entered. */ - private func rectForTextRange(_ range: NSRange, inTextField textField: UITextField) -> CGRect? { + private func rectFor(range: NSRange, in textField: UITextField) -> CGRect? { guard let rangeStart = textField.position(from: textField.beginningOfDocument, offset: range.location) else { return nil } @@ -197,7 +197,7 @@ public class NumberInputTextField: StylizedTextField { return nil } - return rectForTextRange(NSMakeRange(textLength - lastGroupLength, lastGroupLength), inTextField: self) + return rectFor(range: NSMakeRange(textLength - lastGroupLength, lastGroupLength), in: self) } // MARK: Accessibility diff --git a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift index 790194e..e8ec5c0 100644 --- a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift @@ -29,6 +29,6 @@ public class CVCInputTextField: DetailInputTextField { } let cvc = CVC(rawValue: cvcString) - return (cardType?.validateCVC(cvc) == .Valid) ?? false || partiallyValid && (cardType?.validateCVC(cvc) == .CVCIncomplete) ?? false + return (cardType?.validate(cvc: cvc) == .Valid) ?? false || partiallyValid && (cardType?.validate(cvc: cvc) == .CVCIncomplete) ?? false } } diff --git a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift index 28f0e42..2cf46ea 100644 --- a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift @@ -33,9 +33,9 @@ public class DetailInputTextField: StylizedTextField { return false } - let autoCompletedNewText = autocompleteText(newText) + let autoCompletedNewText = autocomplete(text: newText) - let (currentTextFieldText, overflowTextFieldText) = splitText(autoCompletedNewText) + let (currentTextFieldText, overflowTextFieldText) = split(text: autoCompletedNewText) if isInputValid(currentTextFieldText, partiallyValid: true) { textField.text = currentTextFieldText @@ -53,17 +53,15 @@ public class DetailInputTextField: StylizedTextField { return false } - public func prefillInformation(_ info: String) { - if isInputValid(info, partiallyValid: false) { - text = info - cardInfoTextFieldDelegate?.textField(self, didEnterValidInfo: info) - } else if isInputValid(info, partiallyValid: true) { - text = info - cardInfoTextFieldDelegate?.textField(self, didEnterPartiallyValidInfo: info) + public func prefill(text: String) { + if isInputValid(text, partiallyValid: false) { + cardInfoTextFieldDelegate?.textField(self, didEnterValidInfo: text) + } else if isInputValid(text, partiallyValid: true) { + cardInfoTextFieldDelegate?.textField(self, didEnterPartiallyValidInfo: text) } } - private func splitText(_ text: String) -> (currentText: String, overflowText: String) { + private func split(text: String) -> (currentText: String, overflowText: String) { let hasOverflow = text.characters.count > expectedInputLength let index = (hasOverflow) ? text.characters.index(text.startIndex, offsetBy: expectedInputLength) : @@ -74,7 +72,7 @@ public class DetailInputTextField: StylizedTextField { extension DetailInputTextField: AutoCompletingTextField { - func autocompleteText(_ text: String) -> String { + func autocomplete(text: String) -> String { return text } } diff --git a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift index 65b5571..c6c2588 100644 --- a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift @@ -42,17 +42,17 @@ public class MonthInputTextField: DetailInputTextField { - returns: Auto-completed string. */ - internal override func autocompleteText(_ month: String) -> String { - let length = month.characters.count + internal override func autocomplete(text: String) -> String { + let length = text.characters.count if length != 1 { - return month + return text } - let monthNumber = Int(month) + let monthNumber = Int(text) if monthNumber > 1 { - return "0" + month + return "0" + text } - return month + return text } } diff --git a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift index bd3d8a4..9e137a4 100644 --- a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift +++ b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift @@ -22,5 +22,5 @@ protocol AutoCompletingTextField { - returns: Auto-completed string. */ - func autocompleteText(_ text: String) -> String + func autocomplete(text: String) -> String } From 99b98fb31b752c2b3c07ae01b88a572794173981 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 28 Jul 2016 10:03:55 +0200 Subject: [PATCH 03/20] Updated readme and more method signatures --- Pod/Classes/Cards/Card.swift | 12 ++--- Pod/Classes/Cards/CardTypeRegister.swift | 6 +-- Pod/Classes/Format/CardNumberFormatter.swift | 2 +- Pod/Classes/UI/CardTextField.swift | 16 +++---- Pod/Classes/UI/NumberInputTextField.swift | 10 ++-- README.md | 50 ++++++++++---------- 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Pod/Classes/Cards/Card.swift b/Pod/Classes/Cards/Card.swift index 838aa2e..e9ba9dd 100644 --- a/Pod/Classes/Cards/Card.swift +++ b/Pod/Classes/Cards/Card.swift @@ -40,13 +40,13 @@ public struct Card { - returns: A card with the provided parameters. */ - public static func create(number: String, cardVerificationCode cvc: String, expiry: String) throws -> Card { + public static func create(number: String, cvc: String, expiry: String) throws -> Card { // Create card number, cvc and expiry with the arguments provided let cardNumber = Number(rawValue: number) let cardCVC = CVC(rawValue: cvc) let cardExpiry = Expiry(string: expiry) ?? Expiry.invalid - return Card(bankCardNumber: cardNumber, cardVerificationCode: cardCVC, expiryDate: cardExpiry) + return Card(number: cardNumber, cvc: cardCVC, expiry: cardExpiry) } /** @@ -56,10 +56,10 @@ public struct Card { - parameter cardVerificationCode: The card verification code as indicated on the user's payment card. - parameter expiryDate: The expiration date as indicated on the user's payment card */ - public init(bankCardNumber: Number, cardVerificationCode: CVC, expiryDate: Expiry) { - self.bankCardNumber = bankCardNumber - self.cardVerificationCode = cardVerificationCode - self.expiryDate = expiryDate + public init(number: Number, cvc: CVC, expiry: Expiry) { + self.bankCardNumber = number + self.cardVerificationCode = cvc + self.expiryDate = expiry } } diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index f8b45b3..7144c46 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -88,9 +88,9 @@ public class CardTypeRegister { - returns: An instance of UnknownCardType, if no card type matches the Issuer Identification Number of the provided card number or any other card type that matches the card number. */ - public func cardTypeForNumber(_ cardNumber: Number) -> CardType { - for i in (0...min(cardNumber.length, 6)).reversed() { - if let substring = cardNumber.rawValue[0,i], let substringAsNumber = Int(substring) { + public func cardTypeFor(number: Number) -> CardType { + for i in (0...min(number.length, 6)).reversed() { + if let substring = number.rawValue[0,i], let substringAsNumber = Int(substring) { if let firstMatchingCardType = registeredCardTypes.filter({ $0.identifyingDigits.contains(substringAsNumber) }).first { diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 844d790..25a79c3 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -50,7 +50,7 @@ public final class CardNumberFormatter { public func format(cardNumber: String) -> String { let regex: RegularExpression - let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumber)) + let cardType = cardTypeRegister.cardTypeFor(number: Number(rawValue: cardNumber)) do { let groups = cardType.numberGrouping var pattern = "" diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index 5820652..526371d 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -162,7 +162,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Expiry(month: monthTextField.text ?? "", year: yearTextField.text ?? "") ?? Expiry.invalid - return Card(bankCardNumber: cardNumber, cardVerificationCode: cardCVC, expiryDate: cardExpiry) + return Card(number: cardNumber, cvc: cardCVC, expiry: cardExpiry) } } @@ -200,7 +200,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { return nil } - return cardTypeRegister.cardTypeForNumber(number) + return cardTypeRegister.cardTypeFor(number: number) } internal var hideExpiryTextFields: Bool = false { @@ -481,16 +481,16 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { @objc public func numberInputTextFieldDidChangeText(_ numberInputTextField: NumberInputTextField) { showCardImage() notifyDelegate() - hideExpiryTextFields = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresExpiry - hideCVCTextField = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresCVC + hideExpiryTextFields = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresExpiry + hideCVCTextField = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresCVC } public func numberInputTextFieldDidComplete(_ numberInputTextField: NumberInputTextField) { moveCardNumberOutAnimated() notifyDelegate() - hideExpiryTextFields = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresExpiry - hideCVCTextField = !cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber).requiresCVC + hideExpiryTextFields = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresExpiry + hideCVCTextField = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresCVC if hideExpiryTextFields && hideCVCTextField { return } else if hideExpiryTextFields { @@ -506,7 +506,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Displays the card image for the currently detected card type in the card text field's `cardImageView`. */ internal func showCardImage() { - let cardType = cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber) + let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) let cardTypeImage = cardTypeImageStore.imageFor(cardType: cardType) cardImageView?.image = cardTypeImage @@ -516,7 +516,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Displays the CVC image for the currently detected card type in the card text field's `cardImageView`. */ internal func showCVCImage() { - let cardType = cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber) + let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) let cvcImage = cardTypeImageStore.cvcImageFor(cardType: cardType) cardImageView?.image = cvcImage diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index 96fa6a9..bc44abf 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -56,7 +56,7 @@ public class NumberInputTextField: StylizedTextField { + ". " + Localization.CardType.localizedStringWithComment("Description for detected card type.") + ": " - + cardTypeRegister.cardTypeForNumber(cardNumber).name + + cardTypeRegister.cardTypeFor(number: cardNumber).name } set { } @@ -104,9 +104,9 @@ public class NumberInputTextField: StylizedTextField { } let parsedCardNumber = Number(rawValue: newTextUnformatted) - let oldValidation = cardTypeRegister.cardTypeForNumber(cardNumber).validate(number: cardNumber) + let oldValidation = cardTypeRegister.cardTypeFor(number: cardNumber).validate(number: cardNumber) let newValidation = - cardTypeRegister.cardTypeForNumber(parsedCardNumber).validate(number: parsedCardNumber) + cardTypeRegister.cardTypeFor(number: parsedCardNumber).validate(number: parsedCardNumber) if !newValidation.contains(.NumberTooLong) { cardNumberFormatter.replaceRangeFormatted(range, inTextField: textField, withString: string) @@ -122,7 +122,7 @@ public class NumberInputTextField: StylizedTextField { } let newLengthComplete = - parsedCardNumber.length == cardTypeRegister.cardTypeForNumber(parsedCardNumber).maxLength + parsedCardNumber.length == cardTypeRegister.cardTypeFor(number: parsedCardNumber).maxLength if newLengthComplete && newValidation != .Valid { addNumberInvalidityObserver() @@ -147,7 +147,7 @@ public class NumberInputTextField: StylizedTextField { public func prefill(text: String) { let unformattedCardNumber = String(text.characters.filter({$0.isNumeric()})) let cardNumber = Number(rawValue: unformattedCardNumber) - let type = cardTypeRegister.cardTypeForNumber(cardNumber) + let type = cardTypeRegister.cardTypeFor(number: cardNumber) let numberPartiallyValid = type.checkCardNumberPartiallyValid(cardNumber) == .Valid if numberPartiallyValid { diff --git a/README.md b/README.md index 9e64cec..8b6df30 100644 --- a/README.md +++ b/README.md @@ -67,19 +67,19 @@ class MyViewController: UIViewController, CardTextFieldDelegate { ... } - func cardTextField(cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { - // A valid card has been entered, if information is not nil and validationResult == CardValidationResult.Valid - } - - func cardTextFieldShouldShowAccessoryImage(cardTextField: CardTextField) -> UIImage? { - // You can return an image which will be used on cardTextField's accessory button - // If you return nil but provide an accessory button action, the unicode character "⇤" is displayed instead of an image to indicate an action that affects the text field. - } - - func cardTextFieldShouldProvideAccessoryAction(cardTextField: CardTextField) -> (() -> ())? { - // You can return a callback function which will be called if a user tapped on cardTextField's accessory button - // If you return nil, cardTextField won't display an accessory button at all. - } + func cardTextField(_ cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { + // A valid card has been entered, if validationResult == CardValidationResult.Valid + } + + func cardTextFieldShouldShowAccessoryImage(_ cardTextField: CardTextField) -> UIImage? { + // You can return an image which will be used on cardTextField's accessory button + // If you return nil but provide an accessory button action, the unicode character "⇤" is displayed instead of an image to indicate an action that affects the text field. + } + + func cardTextFieldShouldProvideAccessoryAction(_ cardTextField: CardTextField) -> (() -> ())? { + // You can return a callback function which will be called if a user tapped on cardTextField's accessory button + // If you return nil, cardTextField won't display an accessory button at all. + } ... ``` @@ -122,19 +122,19 @@ class ViewController: UIViewController, CardTextFieldDelegate, CardIOPaymentView ... // MARK: - CardTextFieldDelegate - func cardTextField(cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { + func cardTextField(_ cardTextField: CardTextField, didEnterCardInformation information: Card, withValidationResult validationResult: CardValidationResult) { if validationResult == .Valid { // A valid payment card has been manually entered or CardIO was used to scan one. } } // 2. Optionally provide an image for the CardIO button - func cardTextFieldShouldShowAccessoryImage(cardTextField: CardTextField) -> UIImage? { + func cardTextFieldShouldShowAccessoryImage(_ cardTextField: CardTextField) -> UIImage? { return UIImage(named: "cardIOIcon") } // 3. Set the action for the accessoryButton to open CardIO: - func cardTextFieldShouldProvideAccessoryAction(cardTextField: CardTextField) -> (() -> ())? { + func cardTextFieldShouldProvideAccessoryAction(_ cardTextField: CardTextField) -> (() -> ())? { return { [weak self] _ in let cardIOViewController = CardIOPaymentViewController(paymentDelegate: self) self?.presentViewController(cardIOViewController, animated: true, completion: nil) @@ -245,9 +245,9 @@ class ViewController: UIViewController, NumberInputTextFieldDelegate, CardInfoTe let expiry = Expiry(month: monthInputTextField.text ?? "", year: yearInputTextField.text ?? "") ?? Expiry.invalid - let cardType = cardNumberTextField.cardTypeRegister.cardTypeForNumber(cardNumberTextField.cardNumber) - if cardType.validateCVC(cvc).union(cardType.validateExpiry(expiry)).union(cardType.validateNumber(number)) == .Valid { - return Card(bankCardNumber: number, cardVerificationCode: cvc, expiryDate: expiry) + let cardType = cardNumberTextField.cardTypeRegister.cardTypeFor(number: cardNumberTextField.cardNumber) + if cardType.validate(cvc: cvc).union(cardType.validate(expiry: expiry)).union(cardType.validate(number: number)) == .Valid { + return Card(number: number, cvc: cvc, expiry: expiry) } else { return nil } @@ -268,18 +268,18 @@ class ViewController: UIViewController, NumberInputTextFieldDelegate, CardInfoTe cvcInputTextField.deleteBackwardCallback = { _ in self.yearInputTextField.becomeFirstResponder() } } - func numberInputTextFieldDidComplete(numberInputTextField: NumberInputTextField) { - cvcInputTextField.cardType = numberInputTextField.cardTypeRegister.cardTypeForNumber(numberInputTextField.cardNumber) + func numberInputTextFieldDidComplete(_ numberInputTextField: NumberInputTextField) { + cvcInputTextField.cardType = numberInputTextField.cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) print("Card number: \(numberInputTextField.cardNumber)") print(card) monthInputTextField.becomeFirstResponder() } - func numberInputTextFieldDidChangeText(numberInputTextField: NumberInputTextField) { + func numberInputTextFieldDidChangeText(_ numberInputTextField: NumberInputTextField) { } - func textField(textField: UITextField, didEnterValidInfo: String) { + func textField(_ textField: UITextField, didEnterValidInfo: String) { switch textField { case is MonthInputTextField: print("Month: \(didEnterValidInfo)") @@ -295,12 +295,12 @@ class ViewController: UIViewController, NumberInputTextFieldDelegate, CardInfoTe print(card) } - func textField(textField: UITextField, didEnterPartiallyValidInfo: String) { + func textField(_ textField: UITextField, didEnterPartiallyValidInfo: String) { // The user entered information that is not valid but might become valid on further input. // Example: Entering "1" for the CVC is partially valid, while entering "a" is not. } - func textField(textField: UITextField, didEnterOverflowInfo overFlowDigits: String) { + func textField(_ textField: UITextField, didEnterOverflowInfo overFlowDigits: String) { // This function is used in a CardTextField to carry digits to the next text field. // Example: A user entered "02/20" as expiry and now tries to append "5" to the month. // On a card text field, the year will be replaced with "5" - the overflow digit. From 83d8461773b58a9b917de76d5419ac0853e81275 Mon Sep 17 00:00:00 2001 From: klein-thibault Date: Wed, 10 Aug 2016 12:50:28 +0200 Subject: [PATCH 04/20] Updated code to compile on Xcode 8 beta 4 --- Caishen.xcodeproj/project.pbxproj | 8 +- .../xcshareddata/xcschemes/Caishen.xcscheme | 2 +- .../xcschemes/CaishenTests.xcscheme | 2 +- CaishenTests/CardNumberValidatorTests.swift | 12 +- Example/Caishen/ViewController.swift | 2 +- .../Caishen_Example.xcodeproj/project.pbxproj | 109 ++++++++++-------- Example/Podfile | 8 +- Example/Podfile.lock | 4 +- Pod/Classes/Cards/CardType.swift | 4 +- Pod/Classes/Cards/CardTypeRegister.swift | 4 +- .../Default Card Types/UnknownCardType.swift | 6 +- Pod/Classes/Cards/Expiry.swift | 33 +++--- Pod/Classes/Format/CardNumberFormatter.swift | 18 +-- Pod/Classes/StringExtension.swift | 6 +- ...dTextField+CardInfoTextFieldDelegate.swift | 16 +-- .../UI/CardTextField+PrefillInformation.swift | 8 +- .../UI/CardTextField+ViewAnimations.swift | 12 +- Pod/Classes/UI/CardTextField.swift | 64 +++++----- Pod/Classes/UI/CardTypeImageStore.swift | 8 +- Pod/Classes/UI/StylizedTextField.swift | 4 +- .../UI/Text Fields/DetailInputTextField.swift | 10 +- .../UI/Text Fields/MonthInputTextField.swift | 2 +- .../Protocols/AutoCompletingTextField.swift | 2 +- 23 files changed, 185 insertions(+), 159 deletions(-) diff --git a/Caishen.xcodeproj/project.pbxproj b/Caishen.xcodeproj/project.pbxproj index c13c9cd..a03b36f 100644 --- a/Caishen.xcodeproj/project.pbxproj +++ b/Caishen.xcodeproj/project.pbxproj @@ -361,7 +361,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Prolific Interactive"; TargetAttributes = { 2FDD150F1CC7B0B90086CEAC = { @@ -494,8 +494,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -543,8 +545,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -601,6 +605,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.Caishen; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; name = Release; @@ -623,6 +628,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.prolificinteractive.CaishenTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; name = Release; diff --git a/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme b/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme index 2fde38f..8a66643 100644 --- a/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme +++ b/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme @@ -1,6 +1,6 @@ /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"; showEnvVarsInLog = 0; }; - 539FB51F6DF3B1CC6D25DDEB /* [CP] Copy Pods Resources */ = { + B83A566C7F23BC329E14B52B /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "[CP] Copy Pods Resources"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Caishen_Example/Pods-Caishen_Example-resources.sh\"\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 89C44B98C2EC16EB8CC248EF /* [CP] Check Pods Manifest.lock */ = { + C96374A808E4C8DA4E904C77 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -327,7 +327,7 @@ 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"; showEnvVarsInLog = 0; }; - EF1D231BE23959118EB04EEF /* [CP] Embed Pods Frameworks */ = { + F250CCBCDDD5DA61BD004F32 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -339,7 +339,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Caishen_Example/Pods-Caishen_Example-frameworks.sh\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Caishen_Tests/Pods-Caishen_Tests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -399,6 +399,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -408,8 +409,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -444,6 +447,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -453,8 +457,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -479,8 +485,9 @@ }; 607FACF01AFB9204008FA782 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CE358C157BD84C44391BA0B8 /* Pods-Caishen_Example.debug.xcconfig */; + baseConfigurationReference = 01B1F5731BF07579B0F8303E /* Pods-Caishen_Example.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -499,8 +506,9 @@ }; 607FACF11AFB9204008FA782 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4F1D2B9E0E07343B5D68E2A2 /* Pods-Caishen_Example.release.xcconfig */; + baseConfigurationReference = 2F5F9CCA6140D64E65AE55BC /* Pods-Caishen_Example.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -512,14 +520,16 @@ PRODUCT_NAME = Caishen_Example; PROVISIONING_PROFILE = ""; SWIFT_OBJC_BRIDGING_HEADER = "Caishen/Caishen_Example-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; name = Release; }; 607FACF31AFB9204008FA782 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 01466240EB0F8DBD9846D92D /* Pods-Caishen_Tests.debug.xcconfig */; + baseConfigurationReference = AFDA4A6398F7CBDF670ACC8A /* Pods-Caishen_Tests.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", @@ -540,8 +550,9 @@ }; 607FACF41AFB9204008FA782 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 36D12A2E02DC0EB09CD0A671 /* Pods-Caishen_Tests.release.xcconfig */; + baseConfigurationReference = 890F5CA910E8A5F9D55DA251 /* Pods-Caishen_Tests.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", diff --git a/Example/Podfile b/Example/Podfile index 8c2ab1c..814e8bb 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -8,8 +8,14 @@ end target 'Caishen_Tests' do pod 'Caishen', :path => '../' +end - +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['SWIFT_VERSION'] = '3.0' + end + end end post_install do |installer| diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 11eed2e..4751a99 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -14,6 +14,6 @@ SPEC CHECKSUMS: Caishen: c0c7050eaaefac2df5196ea2c2451b79978cd617 CardIO: 92c45caef0d986c4a303a7afba0c9b76ff2b1f6e -PODFILE CHECKSUM: 171ac2de78bae9fd3012144f2669334669aef0d6 +PODFILE CHECKSUM: 6ef97acedda52c92ab765cecef83077de5e22385 -COCOAPODS: 1.1.1 +COCOAPODS: 1.0.1 diff --git a/Pod/Classes/Cards/CardType.swift b/Pod/Classes/Cards/CardType.swift index 188cccf..e251a88 100644 --- a/Pod/Classes/Cards/CardType.swift +++ b/Pod/Classes/Cards/CardType.swift @@ -177,7 +177,7 @@ extension CardType { - returns: The number of digits that are contained in a card number of card type `self`. */ public func expectedCardNumberLength() -> Int { - return numberGrouping.reduce(0, combine: {$0 + $1}) + return numberGrouping.reduce(0, {$0 + $1}) } /** @@ -203,7 +203,7 @@ extension CardType { if odd { digit = digit * 2 } - if digit > 9 {3 + if digit > 9 { digit = digit - 9 } sum += digit diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index 7144c46..6cd8e8e 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -52,8 +52,8 @@ public class CardTypeRegister { - parameter cardType: The card type that should be contained in this card type register. */ - public func registerCardType(_ cardType: CardType) { - if registeredCardTypes.contains({ $0.isEqual(to: cardType) }) { + public func register(cardType: CardType) { + if registeredCardTypes.contains(where: { $0.isEqual(to: cardType) }) { return } diff --git a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift index 3440ac7..a945a28 100644 --- a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift +++ b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift @@ -15,18 +15,18 @@ public struct UnknownCardType: CardType { public let CVCLength = 0 public let identifyingDigits: Set = [] - public func validate(number: Number) -> CardValidationResult { + public func validate(_ number: Number) -> CardValidationResult { return CardValidationResult.UnknownType .union(lengthMatchesType(number.length)) .union(numberIsNumeric(number)) .union(numberIsValidLuhn(number)) } - public func validate(cvc: CVC) -> CardValidationResult { + public func validate(_ cvc: CVC) -> CardValidationResult { return .UnknownType } - public func validate(expiry: Expiry) -> CardValidationResult { + public func validate(_ expiry: Expiry) -> CardValidationResult { return .UnknownType } diff --git a/Pod/Classes/Cards/Expiry.swift b/Pod/Classes/Cards/Expiry.swift index 898de0b..d131d17 100644 --- a/Pod/Classes/Cards/Expiry.swift +++ b/Pod/Classes/Cards/Expiry.swift @@ -8,7 +8,7 @@ import Foundation -private let gregorianCalendar = Calendar(calendarIdentifier: Calendar.Identifier.gregorian)! +private let gregorianCalendar = Calendar(identifier: Calendar.Identifier.gregorian) /** A Credit Card Expiry date. @@ -43,7 +43,7 @@ public struct Expiry: RawRepresentable { return nil } - let regex = try! RegularExpression(pattern: "^(\\d{1,2})[/|-](\\d{1,4})", options: .caseInsensitive) + let regex = try! NSRegularExpression(pattern: "^(\\d{1,2})[/|-](\\d{1,4})", options: .caseInsensitive) var monthStr: String = "" var yearStr: String = "" @@ -51,15 +51,15 @@ public struct Expiry: RawRepresentable { return nil } - let monthRange = match.range(at: 1) - if monthRange.length > 0, let range = string.rangeFrom(nsRange: monthRange) { + let monthRange = match.rangeAt(1) + if monthRange.length > 0, let range = string.rangeFrom(monthRange) { monthStr = string.substring(with: range) } else { return nil } - let yearRange = match.range(at: 2) - if yearRange.length > 0, let range = string.rangeFrom(nsRange: yearRange) { + let yearRange = match.rangeAt(2) + if yearRange.length > 0, let range = string.rangeFrom(yearRange) { yearStr = string.substring(with: range) } else { return nil @@ -77,10 +77,10 @@ public struct Expiry: RawRepresentable { - returns: `nil`, if the expiration date could not be created because of invalid month or year strings. */ public init?(month: String, year: String) { - guard let monthVal = UInt(month), yearVal = UInt(year) where year.characters.count >= 2 else { + guard let monthVal = UInt(month), let yearVal = UInt(year), year.characters.count >= 2 else { return nil } - + self.init(month: monthVal, year: yearVal) } @@ -112,7 +112,7 @@ public struct Expiry: RawRepresentable { return nil } - guard let date = toDate(month: month, year: yearValue) else { + guard let date = dateWith(month: month, year: yearValue) else { return nil } @@ -124,7 +124,7 @@ public struct Expiry: RawRepresentable { } private func components() -> DateComponents { - return gregorianCalendar.components([.year, .month], from: rawValue) + return gregorianCalendar.dateComponents([.year, .month], from: rawValue) } } @@ -144,18 +144,19 @@ extension Expiry: CustomStringConvertible { - returns: The date with month and year and time set to one minute before the following month. */ -private func toDate(month: UInt, year: UInt) -> Date? { +private func dateWith(month: UInt, year: UInt) -> Date? { var dateComponents = DateComponents() dateComponents.day = 1 dateComponents.month = Int(month) dateComponents.year = Int(year) - if let gregorianCalendar = Calendar(calendarIdentifier: Calendar.Identifier.gregorian), - let components = gregorianCalendar.date(from: dateComponents) { - let monthRange = gregorianCalendar.range(of: Calendar.Unit.day, in: Calendar.Unit.month, - for:components) + let gregorianCalendar = Calendar(identifier: Calendar.Identifier.gregorian) + if let components = gregorianCalendar.date(from: dateComponents) { + let monthRange = gregorianCalendar.range(of: Calendar.Component.day, + in: Calendar.Component.month, + for:components) - dateComponents.day = monthRange.length + dateComponents.day = monthRange?.count dateComponents.hour = 23 dateComponents.minute = 59 diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 25a79c3..2acb58b 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -48,7 +48,7 @@ public final class CardNumberFormatter { - returns: Formatted card number string. */ public func format(cardNumber: String) -> String { - let regex: RegularExpression + let regex: NSRegularExpression let cardType = cardTypeRegister.cardTypeFor(number: Number(rawValue: cardNumber)) do { @@ -62,7 +62,7 @@ public final class CardNumberFormatter { } first = false } - regex = try RegularExpression(pattern: pattern, options: RegularExpression.Options()) + regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options()) } catch { fatalError("Error when creating regular expression: \(error)") } @@ -77,7 +77,7 @@ public final class CardNumberFormatter { - returns: The index of the cursor position or nil, if no selected text was found. */ - public func cursorPositionAfterUnformatting(text: String, in textField: UITextField) -> Int? { + public func cursorPositionAfterUnformatting(_ text: String, in textField: UITextField) -> Int? { guard let selectedRange = textField.selectedTextRange else { return nil } @@ -85,7 +85,7 @@ public final class CardNumberFormatter { let position = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) + addedCharacters - let formattedString = text ?? "" + let formattedString = text let components = formattedString.components(separatedBy: self.separator) // Find the component that contains the cursor @@ -113,7 +113,7 @@ public final class CardNumberFormatter { - returns: The index in an unformatted string that is equivalent to `index` in `formattedString`. */ - private func indexInUnformattedString(indexInFormattedString: Int, formattedString: String) -> Int { + private func indexInUnformattedString(_ indexInFormattedString: Int, formattedString: String) -> Int { var componentWithIndex = 0 var charCount = 0 for component in formattedString.components(separatedBy: self.separator) { @@ -174,7 +174,7 @@ public final class CardNumberFormatter { var position: UITextPosition? if let start = textField.selectedTextRange?.start { let oldCursorPosition = textField.offset(from: textField.beginningOfDocument, to: start) - let oldCursorPositionUnformatted = indexInUnformattedString(indexInFormattedString: oldCursorPosition, formattedString: oldValue) + let oldCursorPositionUnformatted = indexInUnformattedString(oldCursorPosition, formattedString: oldValue) let newCursorPositionUnformatted = oldCursorPositionUnformatted + (newValueUnformatted.characters.count - oldValueUnformatted.characters.count) let newCursorPositionFormatted = indexInFormattedString(newCursorPositionUnformatted, unformattedString: newValueUnformatted) @@ -195,13 +195,13 @@ public final class CardNumberFormatter { - returns: An array of all matches found in string for `regex`. */ - private func splitString(_ string: String, withRegex regex: RegularExpression) -> [String] { - let matches = regex.matches(in: string, options: RegularExpression.MatchingOptions(), range: NSMakeRange(0, string.characters.count)) + private func splitString(_ string: String, withRegex regex: NSRegularExpression) -> [String] { + let matches = regex.matches(in: string, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, string.characters.count)) var result = [String]() matches.forEach { for i in 1..<$0.numberOfRanges { - let range = $0.range(at: i) + let range = $0.rangeAt(i) if range.length > 0 { result.append(NSString(string: string).substring(with: range)) diff --git a/Pod/Classes/StringExtension.swift b/Pod/Classes/StringExtension.swift index 7eadea7..bb218aa 100644 --- a/Pod/Classes/StringExtension.swift +++ b/Pod/Classes/StringExtension.swift @@ -19,7 +19,7 @@ extension String { - returns: `nsRange` converted to Range or nil, if its start and/or end location are not within `self`. */ - func rangeFrom(nsRange: NSRange) -> Range? { + func rangeFrom(_ nsRange: NSRange) -> Range? { guard let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex) else { return nil } @@ -40,7 +40,7 @@ extension String { - returns: An NSRange object that is equivalent to `range`. */ - func NSRangeFrom(range : Range) -> NSRange { + func NSRangeFrom(_ range : Range) -> NSRange { let utf16view = self.utf16 let from = String.UTF16View.Index(range.lowerBound, within: utf16view) let to = String.UTF16View.Index(range.upperBound, within: utf16view) @@ -66,7 +66,7 @@ extension String { - returns: True if this string contains only digits. */ func isNumeric() -> Bool { - return characters.reduce(true, combine: { (result, value) in + return characters.reduce(true, { (result, value) in let string = String(value) guard let firstChar = string.utf16.first else { return result diff --git a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift index 9c6240a..4f01043 100644 --- a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift +++ b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift @@ -14,7 +14,7 @@ extension CardTextField: CardInfoTextFieldDelegate { updateNumberColor() notifyDelegate() if expirationDateIsValid() { - select(textField: textField, prefillText: nil) + select(textField, prefillText: nil) } } @@ -25,14 +25,14 @@ extension CardTextField: CardInfoTextFieldDelegate { public func textField(_ textField: UITextField, didEnterOverflowInfo overFlowDigits: String) { updateNumberColor() - select(textField: textField, prefillText: overFlowDigits) + select(textField, prefillText: overFlowDigits) } - private func select(textField: UITextField, prefillText: String?) { + private func select(_ textField: UITextField, prefillText: String?) { var nextTextField: UITextField? if textField == monthTextField { if hideExpiryTextFields { - select(textField: yearTextField, prefillText: prefillText) + select(yearTextField, prefillText: prefillText) } else { nextTextField = yearTextField } @@ -48,7 +48,7 @@ extension CardTextField: CardInfoTextFieldDelegate { return } - nextTextField?.delegate?.textField?(nextTextField!, shouldChangeCharactersIn: NSMakeRange(0, (nextTextField?.text ?? "").characters.count), replacementString: prefillText) + _ = nextTextField?.delegate?.textField?(nextTextField!, shouldChangeCharactersIn: NSMakeRange(0, (nextTextField?.text ?? "").characters.count), replacementString: prefillText) } /** @@ -57,7 +57,7 @@ extension CardTextField: CardInfoTextFieldDelegate { private func updateNumberColor() { // if the expiration date is not valid, set the text color for the date to `invalidNumberColor` if !expirationDateIsValid() { - let invalidInputColor = self.invalidInputColor ?? UIColor.red() + let invalidInputColor = self.invalidInputColor ?? UIColor.red // if the expiration date text fields haven't been assigned invalid input color if monthTextField?.textColor != invalidInputColor && yearTextField?.textColor != invalidInputColor { monthTextField?.textColor = invalidInputColor @@ -66,8 +66,8 @@ extension CardTextField: CardInfoTextFieldDelegate { addDateInvalidityObserver() } } else { - monthTextField?.textColor = numberInputTextField?.textColor ?? UIColor.black() - yearTextField?.textColor = numberInputTextField?.textColor ?? UIColor.black() + monthTextField?.textColor = numberInputTextField?.textColor ?? UIColor.black + yearTextField?.textColor = numberInputTextField?.textColor ?? UIColor.black } } diff --git a/Pod/Classes/UI/CardTextField+PrefillInformation.swift b/Pod/Classes/UI/CardTextField+PrefillInformation.swift index 66c571f..40d5940 100644 --- a/Pod/Classes/UI/CardTextField+PrefillInformation.swift +++ b/Pod/Classes/UI/CardTextField+PrefillInformation.swift @@ -18,18 +18,18 @@ public extension CardTextField { - parameter year: The year that should be shown in the year input field. - parameter cvc: The CVC that should be shown in the CVC input field. */ - public func prefill(number: String?, month: Int?, year: Int?, cvc: String?) { + public func prefill(_ number: String?, month: Int?, year: Int?, cvc: String?) { if let year = year { var trimmedYear = year if year > 100 { trimmedYear = year % 100 } - yearTextField?.prefill(text: String(format: "%02i", arguments: [trimmedYear])) + yearTextField?.prefill(String(format: "%02i", arguments: [trimmedYear])) } if let month = month { - monthTextField?.prefill(text: String(format: "%02i", arguments: [month])) + monthTextField?.prefill(String(format: "%02i", arguments: [month])) } if let cardNumber = number, let numberInputTextField = numberInputTextField { @@ -40,7 +40,7 @@ public extension CardTextField { } if let cvc = cvc { - cvcTextField?.prefill(text: cvc) + cvcTextField?.prefill(cvc) } OperationQueue().addOperation({ diff --git a/Pod/Classes/UI/CardTextField+ViewAnimations.swift b/Pod/Classes/UI/CardTextField+ViewAnimations.swift index a9f8106..b5b8d97 100644 --- a/Pod/Classes/UI/CardTextField+ViewAnimations.swift +++ b/Pod/Classes/UI/CardTextField+ViewAnimations.swift @@ -45,7 +45,7 @@ public extension CardTextField { // which in turn will cause the number field to move to full display. This can cause animation issues. // In order to tackle these animation issues, check if the cardInfoView was previously fully displayed (and should therefor not be moved with an animation). var shouldMoveAnimated: Bool = true - if let transform = cardInfoView?.transform where transform.isIdentity { + if let transform = cardInfoView?.transform, transform.isIdentity { shouldMoveAnimated = false } UIView.performWithoutAnimation { [weak self] _ in @@ -100,17 +100,17 @@ public extension CardTextField { // If card info view is moved with an animation, wait for it to finish before // showing the full card number to avoid overlapping on RTL language. if cardInfoView?.layer.animationKeys() != nil { - DispatchQueue.main.after(when: DispatchTime.now() + Double(Int64(viewAnimationDuration * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { [weak self] _ in + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(viewAnimationDuration * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: { [weak self] _ in self?.numberInputTextField?.layer.mask = nil - } - + }) + // Let the number text field become first responder only after the animation has completed (left to right script) // or half way through the view animation (right to left script) let firstResponderDelay = isRightToLeftLanguage ? viewAnimationDuration / 2.0 : viewAnimationDuration - DispatchQueue.main.after(when: DispatchTime.now() + Double(Int64(firstResponderDelay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(firstResponderDelay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: { infoTextFields.forEach({$0?.resignFirstResponder()}) self.numberInputTextField.becomeFirstResponder() - } + }) } else { numberInputTextField?.layer.mask = nil infoTextFields.forEach({$0?.resignFirstResponder()}) diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index 526371d..51ab7ff 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -184,14 +184,21 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { } } #endif - - public override var attributedPlaceholder: AttributedString? { + + public override var attributedPlaceholder: NSAttributedString? { didSet { numberInputTextField?.attributedPlaceholder = attributedPlaceholder super.attributedPlaceholder = nil } } - + + public override var isFirstResponder: Bool { + // Return true if any of `self`'s subviews is the current first responder. + return [numberInputTextField,monthTextField,yearTextField,cvcTextField] + .filter({$0.isFirstResponder}) + .isEmpty == false + } + /** The card type for the entered card number or nil, if no card type has been detected with the given input. */ @@ -222,7 +229,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { if #available(iOS 9.0, *) { return UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft } else { - let isoCode = Locale.autoupdatingCurrent.object(forKey: Locale.Key.languageCode) as? String ?? "" + let isoCode = Locale.autoupdatingCurrent.languageCode ?? "" return Locale.characterDirection(forLanguage: isoCode) == Locale.LanguageDirection.rightToLeft } } @@ -231,7 +238,10 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - NotificationCenter.default.addObserver(self, selector: #selector(self.localeDidChange), name: Locale.currentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, + selector: #selector(self.localeDidChange), + name: NSLocale.currentLocaleDidChangeNotification, + object: nil) #if !TARGET_INTERFACE_BUILDER setupView() #endif @@ -239,14 +249,19 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { public override init(frame: CGRect) { super.init(frame: frame) - NotificationCenter.default.addObserver(self, selector: #selector(self.localeDidChange), name: Locale.currentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, + selector: #selector(self.localeDidChange), + name: NSLocale.currentLocaleDidChangeNotification, + object: nil) #if !TARGET_INTERFACE_BUILDER setupView() #endif } deinit { - NotificationCenter.default.removeObserver(self, name: Locale.currentLocaleDidChangeNotification, object: nil) + NotificationCenter.default.removeObserver(self, + name: NSLocale.currentLocaleDidChangeNotification, + object: nil) } /** @@ -273,9 +288,9 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { firstObjectInNib.frame = bounds addSubview(firstObjectInNib) - cardImageView?.image = cardTypeImageStore.imageFor(cardType: UnknownCardType()) + cardImageView?.image = cardTypeImageStore.imageFor(UnknownCardType()) cardImageView?.layer.cornerRadius = 5.0 - cardImageView?.layer.shadowColor = UIColor.black().cgColor + cardImageView?.layer.shadowColor = UIColor.black.cgColor cardImageView?.layer.shadowRadius = 2 cardImageView?.layer.shadowOffset = CGSize(width: 0, height: 0) cardImageView?.layer.shadowOpacity = 0.2 @@ -357,7 +372,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { $0?.isSecureTextEntry = isSecureTextEntry }) - super.textColor = UIColor.clear() + super.textColor = UIColor.clear super.placeholder = nil } @@ -414,7 +429,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { accessoryButton?.imageView?.contentMode = .scaleAspectFit if let buttonImage = cardTextFieldDelegate?.cardTextFieldShouldShowAccessoryImage(self) { - let scaledImage = buttonImage.resizableImage(withCapInsets: UIEdgeInsetsZero, resizingMode: .stretch) + let scaledImage = buttonImage.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch) accessoryButton?.titleLabel?.text = nil accessoryButton?.setImage(scaledImage, for: UIControlState()) accessoryButton?.tintColor = numberInputTextField?.textColor @@ -507,7 +522,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ internal func showCardImage() { let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) - let cardTypeImage = cardTypeImageStore.imageFor(cardType: cardType) + let cardTypeImage = cardTypeImageStore.imageFor(cardType) cardImageView?.image = cardTypeImage } @@ -517,7 +532,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ internal func showCVCImage() { let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) - let cvcImage = cardTypeImageStore.cvcImageFor(cardType: cardType) + let cvcImage = cardTypeImageStore.cvcImageFor(cardType) cardImageView?.image = cvcImage cvcTextField?.cardType = cardType @@ -529,7 +544,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { super.layoutSubviews() // If moving to a larger screen size and not showing the detail view, make sure that it is outside the view. - if let transform = cardInfoView?.transform where !transform.isIdentity { + if let transform = cardInfoView?.transform, !transform.isIdentity { translateCardNumberIn() } } @@ -538,7 +553,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { // Detect touches in card number text field as long as the detail view is on top of it touches.forEach({ touch -> () in let point = touch.location(in: numberInputTextField) - if (numberInputTextField?.point(inside: point, with: event) ?? false) && [monthTextField,yearTextField,cvcTextField, slashLabel].reduce(true, combine: { (currentValue: Bool, view: UIView?) -> Bool in + if (numberInputTextField?.point(inside: point, with: event) ?? false) && [monthTextField,yearTextField,cvcTextField, slashLabel].reduce(true, { (currentValue: Bool, view: UIView?) -> Bool in let pointInView = touch.location(in: view) return currentValue && !(view?.point(inside: pointInView, with: event) ?? false) }) { @@ -588,30 +603,17 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { // Return false if any of this text field's subviews is already first responder. // Otherwise let `numberInputTextField` become the first responder. if [numberInputTextField,monthTextField,yearTextField,cvcTextField] - .flatMap({return $0.isFirstResponder()}) - .reduce(true, combine: {$0 && $1}) { + .flatMap({return $0.isFirstResponder}) + .reduce(true, {$0 && $1}) { return false } return numberInputTextField.becomeFirstResponder() } - public override func isFirstResponder() -> Bool { - // Return true if any of `self`'s subviews is the current first responder. - // Needs to unwrap the IBOutlets otherwise IBInspectable is crashing when using CardTextField because IBOutlets - // are not initialized yet when IBInspectable engine runs. - guard let numberInputTextField = numberInputTextField, monthTextField = monthTextField, yearTextField = yearTextField, cvcTextField = cvcTextField else { - return false - } - - return [numberInputTextField, monthTextField, yearTextField, cvcTextField] - .filter({$0.isFirstResponder()}) - .isEmpty == false - } - public override func resignFirstResponder() -> Bool { // If any of `self`'s subviews is first responder, resign first responder status. return [numberInputTextField,monthTextField,yearTextField,cvcTextField] - .filter({$0.isFirstResponder()}) + .filter({$0.isFirstResponder}) .first? .resignFirstResponder() ?? true } diff --git a/Pod/Classes/UI/CardTypeImageStore.swift b/Pod/Classes/UI/CardTypeImageStore.swift index 7bec865..7e4e192 100644 --- a/Pod/Classes/UI/CardTypeImageStore.swift +++ b/Pod/Classes/UI/CardTypeImageStore.swift @@ -18,7 +18,7 @@ public protocol CardTypeImageStore { - returns: The image for the specified card type or nil, if no image was provided for this card type. */ - func imageFor(cardType: CardType) -> UIImage? + func imageFor(_ cardType: CardType) -> UIImage? /** Provides an image for the CVC of a specific card type. The position of a CVC on a card may vary based on the card issuer, so that different card types may provide different images to indicate the location of the CVC on the card. This image will be shown in a `CardTextField`'s image view once the user starts entering the CVC. @@ -27,17 +27,17 @@ public protocol CardTypeImageStore { - returns: The image for the CVC of the specified card type or nil, if no image was provided for this card type. */ - func cvcImageFor(cardType: CardType) -> UIImage? + func cvcImageFor(_ cardType: CardType) -> UIImage? } extension Bundle: CardTypeImageStore { - public func imageFor(cardType: CardType) -> UIImage? { + public func imageFor(_ cardType: CardType) -> UIImage? { return UIImage(named: cardType.name, in: self, compatibleWith: nil) } - public func cvcImageFor(cardType: CardType) -> UIImage? { + public func cvcImageFor(_ cardType: CardType) -> UIImage? { let cvcImageName: String if cardType.isEqual(to: AmericanExpress()) { cvcImageName = "AmexCVC" diff --git a/Pod/Classes/UI/StylizedTextField.swift b/Pod/Classes/UI/StylizedTextField.swift index a2e0e78..dd39801 100644 --- a/Pod/Classes/UI/StylizedTextField.swift +++ b/Pod/Classes/UI/StylizedTextField.swift @@ -44,7 +44,7 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { If `borderWidth` has been set, changes to this parameter change the color of the border of `self`. */ @IBInspectable - public var borderColor: UIColor = UIColor.black() { + public var borderColor: UIColor = UIColor.black { didSet { self.layer.borderColor = self.borderColor.cgColor } @@ -69,7 +69,7 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { /** The color in which text flashes, when the user is about to enter an invalid card number. */ - @IBInspectable public var invalidInputColor: UIColor = UIColor.red() + @IBInspectable public var invalidInputColor: UIColor = UIColor.red public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) diff --git a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift index 2cf46ea..6df7af8 100644 --- a/Pod/Classes/UI/Text Fields/DetailInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/DetailInputTextField.swift @@ -33,9 +33,9 @@ public class DetailInputTextField: StylizedTextField { return false } - let autoCompletedNewText = autocomplete(text: newText) + let autoCompletedNewText = autocomplete(newText) - let (currentTextFieldText, overflowTextFieldText) = split(text: autoCompletedNewText) + let (currentTextFieldText, overflowTextFieldText) = split(autoCompletedNewText) if isInputValid(currentTextFieldText, partiallyValid: true) { textField.text = currentTextFieldText @@ -53,7 +53,7 @@ public class DetailInputTextField: StylizedTextField { return false } - public func prefill(text: String) { + public func prefill(_ text: String) { if isInputValid(text, partiallyValid: false) { cardInfoTextFieldDelegate?.textField(self, didEnterValidInfo: text) } else if isInputValid(text, partiallyValid: true) { @@ -61,7 +61,7 @@ public class DetailInputTextField: StylizedTextField { } } - private func split(text: String) -> (currentText: String, overflowText: String) { + private func split(_ text: String) -> (currentText: String, overflowText: String) { let hasOverflow = text.characters.count > expectedInputLength let index = (hasOverflow) ? text.characters.index(text.startIndex, offsetBy: expectedInputLength) : @@ -72,7 +72,7 @@ public class DetailInputTextField: StylizedTextField { extension DetailInputTextField: AutoCompletingTextField { - func autocomplete(text: String) -> String { + func autocomplete(_ text: String) -> String { return text } } diff --git a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift index c6c2588..d15b332 100644 --- a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift @@ -42,7 +42,7 @@ public class MonthInputTextField: DetailInputTextField { - returns: Auto-completed string. */ - internal override func autocomplete(text: String) -> String { + internal override func autocomplete(_ text: String) -> String { let length = text.characters.count if length != 1 { return text diff --git a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift index 9e137a4..cff3042 100644 --- a/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift +++ b/Pod/Classes/UI/Text Fields/Protocols/AutoCompletingTextField.swift @@ -22,5 +22,5 @@ protocol AutoCompletingTextField { - returns: Auto-completed string. */ - func autocomplete(text: String) -> String + func autocomplete(_ text: String) -> String } From 3a4cb21560ded7b0c972745f62fe811145b61e95 Mon Sep 17 00:00:00 2001 From: klein-thibault Date: Wed, 14 Sep 2016 17:36:57 +0200 Subject: [PATCH 05/20] Updated Caishen to Swift 3 GM --- .travis.yml | 2 +- Example/Caishen/AppDelegate.swift | 29 ------------------- Example/Podfile.lock | 2 +- Pod/Classes/Cards/CardTypeRegister.swift | 4 +-- Pod/Classes/Format/CardNumberFormatter.swift | 6 ++-- Pod/Classes/StringExtension.swift | 2 +- Pod/Classes/UI/CardTextField.swift | 6 ++-- Pod/Classes/UI/StylizedTextField.swift | 1 + .../UI/Text Fields/CVCInputTextField.swift | 4 ++- .../UI/Text Fields/MonthInputTextField.swift | 2 +- 10 files changed, 15 insertions(+), 43 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34aee05..c271b83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ # * https://github.com/supermarin/xcpretty#usage language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 # cache: cocoapods # podfile: Example/Podfile # before_install: diff --git a/Example/Caishen/AppDelegate.swift b/Example/Caishen/AppDelegate.swift index 62cbe78..9ee1868 100644 --- a/Example/Caishen/AppDelegate.swift +++ b/Example/Caishen/AppDelegate.swift @@ -13,34 +13,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // 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. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // 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. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // 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. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - } diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 4751a99..4e1bbd9 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -11,7 +11,7 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - Caishen: c0c7050eaaefac2df5196ea2c2451b79978cd617 + Caishen: 4203013fd59dfbd1c7dad8d631b096dcbf6a2081 CardIO: 92c45caef0d986c4a303a7afba0c9b76ff2b1f6e PODFILE CHECKSUM: 6ef97acedda52c92ab765cecef83077de5e22385 diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index 6cd8e8e..6ea7fdb 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -31,7 +31,7 @@ public class CardTypeRegister { - parameter registeredCardTypes: Any sequence of `CardType` that should be accepted by `self`. */ - public convenience init(registeredCardTypes: T) { + public convenience init(registeredCardTypes: T) where T.Iterator.Element == CardType { self.init() setRegisteredCardTypes(registeredCardTypes) } @@ -74,7 +74,7 @@ public class CardTypeRegister { - parameter cardTypes: The new range of card types contained in this card type register. */ - public func setRegisteredCardTypes(_ cardTypes: T) { + public func setRegisteredCardTypes(_ cardTypes: T) where T.Iterator.Element == CardType { registeredCardTypes = [CardType]() registeredCardTypes.append(contentsOf: cardTypes) } diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 2acb58b..0dadb81 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -81,12 +81,10 @@ public final class CardNumberFormatter { guard let selectedRange = textField.selectedTextRange else { return nil } + let addedCharacters = text.characters.count - (textField.text ?? "").characters.count - let position = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) + addedCharacters - - let formattedString = text - let components = formattedString.components(separatedBy: self.separator) + let components = text.components(separatedBy: self.separator) // Find the component that contains the cursor var componentContainingCursor = 0 diff --git a/Pod/Classes/StringExtension.swift b/Pod/Classes/StringExtension.swift index bb218aa..82e6f84 100644 --- a/Pod/Classes/StringExtension.swift +++ b/Pod/Classes/StringExtension.swift @@ -71,7 +71,7 @@ extension String { guard let firstChar = string.utf16.first else { return result } - return result && CharacterSet.decimalDigits.contains(UnicodeScalar(firstChar))} + return result && CharacterSet.decimalDigits.contains(UnicodeScalar(firstChar)!)} ) } } diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index 51ab7ff..ea4b533 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -393,7 +393,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { */ private func setupAccessibilityLabelFor(textField: UITextField) { textField.accessibilityLabel = Localization.accessibilityLabelForTextField(textField, - comment: "Accessibility label for \(String(textField))") + comment: "Accessibility label for \(String(describing: textField))") } /** @@ -574,7 +574,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { public override func accessibilityElementCount() -> Int { return 5 } - + /** Returns the accessibility element at the specified index @@ -582,7 +582,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { - returns: The accessibility element at the specified index, or nil if none exists */ - public override func accessibilityElement(at index: Int) -> AnyObject? { + public override func accessibilityElement(at index: Int) -> Any? { switch index { case 0: return numberInputTextField diff --git a/Pod/Classes/UI/StylizedTextField.swift b/Pod/Classes/UI/StylizedTextField.swift index dd39801..0d72666 100644 --- a/Pod/Classes/UI/StylizedTextField.swift +++ b/Pod/Classes/UI/StylizedTextField.swift @@ -91,6 +91,7 @@ public class StylizedTextField: UITextField, UITextFieldDelegate { } } + @discardableResult override public func becomeFirstResponder() -> Bool { UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self) return super.becomeFirstResponder() diff --git a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift index e8ec5c0..cde2c8e 100644 --- a/Pod/Classes/UI/Text Fields/CVCInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/CVCInputTextField.swift @@ -29,6 +29,8 @@ public class CVCInputTextField: DetailInputTextField { } let cvc = CVC(rawValue: cvcString) - return (cardType?.validate(cvc: cvc) == .Valid) ?? false || partiallyValid && (cardType?.validate(cvc: cvc) == .CVCIncomplete) ?? false + return (cardType?.validate(cvc: cvc) == .Valid) + || partiallyValid && (cardType?.validate(cvc: cvc) == .CVCIncomplete) } + } diff --git a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift index d15b332..72646dc 100644 --- a/Pod/Classes/UI/Text Fields/MonthInputTextField.swift +++ b/Pod/Classes/UI/Text Fields/MonthInputTextField.swift @@ -48,7 +48,7 @@ public class MonthInputTextField: DetailInputTextField { return text } - let monthNumber = Int(text) + let monthNumber = Int(text) ?? 0 if monthNumber > 1 { return "0" + text } From 78e6afbe2a3f517b021cf6480e29b5b98f8adafd Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Wed, 14 Sep 2016 09:56:07 -0700 Subject: [PATCH 06/20] Added simulator environment variable --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index c271b83..daa4c8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,3 +12,7 @@ osx_image: xcode8 script: - set -o pipefail && xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty - pod lib lint + +env: + global: + - IOS_SDK=iphonesimulator10.0 \ No newline at end of file From b09097d357fe3baf8d3d7abee24ff8fc2495eab4 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Wed, 14 Sep 2016 10:07:58 -0700 Subject: [PATCH 07/20] Added additional options for Travis --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index daa4c8c..d3b6a2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,12 @@ script: env: global: - - IOS_SDK=iphonesimulator10.0 \ No newline at end of file + - LC_CTYPE=en_US.UTF-8 + - LANG=en_US.UTF-8 + - WORKSPACE=Caishen.xcworkspace + - IOS_FRAMEWORK_SCHEME="Caishen" + - IOS_SDK=iphonesimulator10.0 + - OSX_SDK=macosx10.12 + - TVOS_SDK=appletvsimulator10.0 + - WATCHOS_SDK=watchsimulator3.0 + - EXAMPLE_SCHEME="Caishen_Example" \ No newline at end of file From 7b14434cfcdb480e0d96c6bb05005c83dc334162 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Wed, 14 Sep 2016 10:11:41 -0700 Subject: [PATCH 08/20] Travis YAML formatting --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3b6a2f..51acccd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,13 @@ script: - pod lib lint env: - global: - - LC_CTYPE=en_US.UTF-8 - - LANG=en_US.UTF-8 - - WORKSPACE=Caishen.xcworkspace - - IOS_FRAMEWORK_SCHEME="Caishen" - - IOS_SDK=iphonesimulator10.0 - - OSX_SDK=macosx10.12 - - TVOS_SDK=appletvsimulator10.0 - - WATCHOS_SDK=watchsimulator3.0 - - EXAMPLE_SCHEME="Caishen_Example" \ No newline at end of file + global: + - LC_CTYPE=en_US.UTF-8 + - LANG=en_US.UTF-8 + - WORKSPACE=Caishen.xcworkspace + - IOS_FRAMEWORK_SCHEME="Caishen" + - IOS_SDK=iphonesimulator10.0 + - OSX_SDK=macosx10.12 + - TVOS_SDK=appletvsimulator10.0 + - WATCHOS_SDK=watchsimulator3.0 + - EXAMPLE_SCHEME="Caishen_Example" From ea256980454abfceebd5b9986a52b06116bf2faa Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Wed, 14 Sep 2016 11:05:06 -0700 Subject: [PATCH 09/20] Added pre-install action for travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 51acccd..3cee5b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,3 +24,5 @@ env: - TVOS_SDK=appletvsimulator10.0 - WATCHOS_SDK=watchsimulator3.0 - EXAMPLE_SCHEME="Caishen_Example" +before_install: + - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet \ No newline at end of file From 0854530c2dd9581ec177f2f033daa2c87e32f609 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 15 Sep 2016 09:13:13 -0700 Subject: [PATCH 10/20] Added .swift-version and Gemfile --- .swift-version | 1 + Gemfile | 1 + 2 files changed, 2 insertions(+) create mode 100644 .swift-version create mode 100644 Gemfile diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..9f55b2c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..a48b065 --- /dev/null +++ b/Gemfile @@ -0,0 +1 @@ +gem 'cocoapods', '1.1.0.rc.2' From 848f29083e331c5e01d7d2aed50b529f2ddd5fed Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 15 Sep 2016 09:49:38 -0700 Subject: [PATCH 11/20] Changed build destination for Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3cee5b5..a963705 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ osx_image: xcode8 # - gem install cocoapods # Since Travis is not always on latest version # - pod install --project-directory=Example script: -- set -o pipefail && xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty +- set -o pipefail && xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' | xcpretty - pod lib lint env: From f25a80a845f348ddb3a62b8f61dd0d35bd0fdb37 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 15 Sep 2016 10:07:36 -0700 Subject: [PATCH 12/20] Removed unused environment variables --- .travis.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index a963705..7bda9de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,16 +13,5 @@ script: - set -o pipefail && xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' | xcpretty - pod lib lint -env: - global: - - LC_CTYPE=en_US.UTF-8 - - LANG=en_US.UTF-8 - - WORKSPACE=Caishen.xcworkspace - - IOS_FRAMEWORK_SCHEME="Caishen" - - IOS_SDK=iphonesimulator10.0 - - OSX_SDK=macosx10.12 - - TVOS_SDK=appletvsimulator10.0 - - WATCHOS_SDK=watchsimulator3.0 - - EXAMPLE_SCHEME="Caishen_Example" before_install: - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet \ No newline at end of file From 71149c49faf111002e32518dfc0004b8f27cc5cc Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Tue, 18 Oct 2016 12:41:32 -0700 Subject: [PATCH 13/20] Fixed the Gemfile to use the latest stable release client version of Cocoapods Travis is currently failing, missing Cocoapods version 1.1.0 rc 2. This should point to the latest release client version (rc 3) and be compatible with future releases of this. --- Gemfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index a48b065..9f77c0f 100644 --- a/Gemfile +++ b/Gemfile @@ -1 +1,3 @@ -gem 'cocoapods', '1.1.0.rc.2' +source 'https://rubygems.org' + +gem 'cocoapods', :git => 'https://github.com/CocoaPods/CocoaPods.git', :tag => '1-1-stable' \ No newline at end of file From c88f253665369c50592d6f71edea35b7a4625fbc Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Mon, 24 Oct 2016 19:02:25 -0700 Subject: [PATCH 14/20] Updated Gemfile to use the final version of Cocoapods 1.1.x (making use of .swift-version) --- .../Caishen_Example.xcodeproj/project.pbxproj | 4 ++-- Example/Podfile | 16 ---------------- Example/Podfile.lock | 6 +++--- Gemfile | 2 +- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Example/Caishen_Example.xcodeproj/project.pbxproj b/Example/Caishen_Example.xcodeproj/project.pbxproj index 75701ce..771fba9 100644 --- a/Example/Caishen_Example.xcodeproj/project.pbxproj +++ b/Example/Caishen_Example.xcodeproj/project.pbxproj @@ -309,7 +309,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + 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"; showEnvVarsInLog = 0; }; C96374A808E4C8DA4E904C77 /* [CP] Copy Pods Resources */ = { @@ -324,7 +324,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - 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"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Caishen_Tests/Pods-Caishen_Tests-resources.sh\"\n"; showEnvVarsInLog = 0; }; F250CCBCDDD5DA61BD004F32 /* [CP] Embed Pods Frameworks */ = { diff --git a/Example/Podfile b/Example/Podfile index 814e8bb..dfba9fc 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -9,19 +9,3 @@ end target 'Caishen_Tests' do pod 'Caishen', :path => '../' end - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '3.0' - end - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '2.3' - end - end -end \ No newline at end of file diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 4e1bbd9..7781628 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -11,9 +11,9 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - Caishen: 4203013fd59dfbd1c7dad8d631b096dcbf6a2081 + Caishen: 19c73df58634c898c8cab66b870b9159d60ce9e2 CardIO: 92c45caef0d986c4a303a7afba0c9b76ff2b1f6e -PODFILE CHECKSUM: 6ef97acedda52c92ab765cecef83077de5e22385 +PODFILE CHECKSUM: 1514fd4fa58ab9e1f9e1ed14ec4c0220e09f13d1 -COCOAPODS: 1.0.1 +COCOAPODS: 1.1.1 diff --git a/Gemfile b/Gemfile index 9f77c0f..0da8ec0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source 'https://rubygems.org' -gem 'cocoapods', :git => 'https://github.com/CocoaPods/CocoaPods.git', :tag => '1-1-stable' \ No newline at end of file +gem 'cocoapods' \ No newline at end of file From cfef1115a2bb51e3e9a2158baf8014c16dce4824 Mon Sep 17 00:00:00 2001 From: ThibaultKlein Date: Thu, 3 Nov 2016 10:47:59 -0400 Subject: [PATCH 15/20] Updated Swift 3 syntax based on the pull request feedback --- CaishenTests/CardNumberValidatorTests.swift | 12 +-- Gemfile | 2 +- Gemfile.lock | 73 +++++++++++++++++++ Pod/Classes/Cards/CardTypeRegister.swift | 6 +- .../Default Card Types/UnknownCardType.swift | 6 +- Pod/Classes/Format/CardNumberFormatter.swift | 22 +++--- Pod/Classes/Localization.swift | 2 +- ...dTextField+CardInfoTextFieldDelegate.swift | 12 +-- .../UI/CardTextField+PrefillInformation.swift | 2 +- Pod/Classes/UI/CardTextField.swift | 36 ++++----- Pod/Classes/UI/CardTypeImageStore.swift | 10 +-- Pod/Classes/UI/NumberInputTextField.swift | 18 ++--- 12 files changed, 137 insertions(+), 64 deletions(-) create mode 100644 Gemfile.lock diff --git a/CaishenTests/CardNumberValidatorTests.swift b/CaishenTests/CardNumberValidatorTests.swift index c8cb0c3..5658bc5 100644 --- a/CaishenTests/CardNumberValidatorTests.swift +++ b/CaishenTests/CardNumberValidatorTests.swift @@ -75,37 +75,37 @@ class CardNumberValidatorTests: XCTestCase { func testValidCards() { print("Validate Visa") self.validVisaNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, Visa().name) + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, Visa().name) XCTAssertValid(Visa().validate(number: Number(rawValue: $0))) }) print("Validate Amex") self.validAmexNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, AmericanExpress().name) + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, AmericanExpress().name) XCTAssertValid(AmericanExpress().validate(number: Number(rawValue: $0))) }) print("Validate China UnionPay") self.validChinaUnionPayNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, ChinaUnionPay().name) + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, ChinaUnionPay().name) XCTAssertValid(ChinaUnionPay().validate(number: Number(rawValue: $0))) }) print("Validate Diners Club") self.validDinersClubNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, DinersClub().name) + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, DinersClub().name) XCTAssertValid(DinersClub().validate(number: Number(rawValue: $0))) }) print("Validate Discover") self.validDiscoverNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, Discover().name) + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, Discover().name) XCTAssertValid(Discover().validate(number: Number(rawValue: $0))) }) print("Validate JCB") self.validJCBNumbers.forEach({ - XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardTypeFor(number: Number(rawValue: $0)).name, JCB().name, "Card number was interpreted as wrong kind: \($0)") + XCTAssertEqual(CardTypeRegister.sharedCardTypeRegister.cardType(for: Number(rawValue: $0)).name, JCB().name, "Card number was interpreted as wrong kind: \($0)") XCTAssertValid(JCB().validate(number: Number(rawValue: $0))) }) } diff --git a/Gemfile b/Gemfile index 0da8ec0..94a11c3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source 'https://rubygems.org' -gem 'cocoapods' \ No newline at end of file +gem 'cocoapods', '1.1.1' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..1cb58f6 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,73 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (2.3.3) + activesupport (4.2.7.1) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + claide (1.0.1) + cocoapods (1.1.1) + activesupport (>= 4.0.2, < 5) + claide (>= 1.0.1, < 2.0) + cocoapods-core (= 1.1.1) + cocoapods-deintegrate (>= 1.0.1, < 2.0) + cocoapods-downloader (>= 1.1.2, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-stats (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.1.1, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored (~> 1.2) + escape (~> 0.0.4) + fourflusher (~> 2.0.1) + gh_inspector (~> 1.0) + molinillo (~> 0.5.1) + nap (~> 1.0) + xcodeproj (>= 1.3.3, < 2.0) + cocoapods-core (1.1.1) + activesupport (>= 4.0.2, < 5) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + cocoapods-deintegrate (1.0.1) + cocoapods-downloader (1.1.2) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.0) + cocoapods-stats (1.0.0) + cocoapods-trunk (1.1.1) + nap (>= 0.8, < 2.0) + netrc (= 0.7.8) + cocoapods-try (1.1.0) + colored (1.2) + escape (0.0.4) + fourflusher (2.0.1) + fuzzy_match (2.0.4) + gh_inspector (1.0.2) + i18n (0.7.0) + json (1.8.3) + minitest (5.9.1) + molinillo (0.5.3) + nanaimo (0.2.0) + nap (1.1.0) + netrc (0.7.8) + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + xcodeproj (1.4.1) + CFPropertyList (~> 2.3.3) + activesupport (>= 3) + claide (>= 1.0.1, < 2.0) + colored (~> 1.2) + nanaimo (~> 0.2.0) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods (= 1.1.1) + +BUNDLED WITH + 1.13.6 diff --git a/Pod/Classes/Cards/CardTypeRegister.swift b/Pod/Classes/Cards/CardTypeRegister.swift index 6ea7fdb..a30c066 100644 --- a/Pod/Classes/Cards/CardTypeRegister.swift +++ b/Pod/Classes/Cards/CardTypeRegister.swift @@ -65,7 +65,7 @@ public class CardTypeRegister { - parameter cardType: The card type that should be removed from this card type register. */ - public func unregisterCardType(_ cardType: CardType) { + public func unregister(cardType: CardType) { registeredCardTypes = registeredCardTypes.filter { !$0.isEqual(to: cardType) } } @@ -84,11 +84,11 @@ public class CardTypeRegister { - important: When creating custom card types, you should make sure, that there are no conflicts in the Issuer Identification Numbers you provide. For example, using [309] to detect a Diners Club card and using [3096] to detect a JCB card will not cause issues as IINs are parsed with the highest numbers first, i.e. the numbers that provide the most context possible, which will return a JCB card in this case. However, no two card types should provide the exact same number (like [309] to detect both a Diners Club card and a JCB card)! - - parameter cardNumber: The card number whose CardType should be determined + - parameter number: The card number whose CardType should be determined - returns: An instance of UnknownCardType, if no card type matches the Issuer Identification Number of the provided card number or any other card type that matches the card number. */ - public func cardTypeFor(number: Number) -> CardType { + public func cardType(for number: Number) -> CardType { for i in (0...min(number.length, 6)).reversed() { if let substring = number.rawValue[0,i], let substringAsNumber = Int(substring) { if let firstMatchingCardType = registeredCardTypes.filter({ diff --git a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift index a945a28..3440ac7 100644 --- a/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift +++ b/Pod/Classes/Cards/Default Card Types/UnknownCardType.swift @@ -15,18 +15,18 @@ public struct UnknownCardType: CardType { public let CVCLength = 0 public let identifyingDigits: Set = [] - public func validate(_ number: Number) -> CardValidationResult { + public func validate(number: Number) -> CardValidationResult { return CardValidationResult.UnknownType .union(lengthMatchesType(number.length)) .union(numberIsNumeric(number)) .union(numberIsValidLuhn(number)) } - public func validate(_ cvc: CVC) -> CardValidationResult { + public func validate(cvc: CVC) -> CardValidationResult { return .UnknownType } - public func validate(_ expiry: Expiry) -> CardValidationResult { + public func validate(expiry: Expiry) -> CardValidationResult { return .UnknownType } diff --git a/Pod/Classes/Format/CardNumberFormatter.swift b/Pod/Classes/Format/CardNumberFormatter.swift index 0dadb81..0dd18ba 100644 --- a/Pod/Classes/Format/CardNumberFormatter.swift +++ b/Pod/Classes/Format/CardNumberFormatter.swift @@ -36,10 +36,10 @@ public final class CardNumberFormatter { - returns: The unformatted card number string representation. */ - public func unformattedCardNumber(_ cardNumberString: String) -> String { - return cardNumberString.replacingOccurrences(of: self.separator, with: "") + public func unformat(cardNumber: String) -> String { + return cardNumber.replacingOccurrences(of: self.separator, with: "") } - + /** Formats the given card number string based on the detected card type. @@ -49,8 +49,8 @@ public final class CardNumberFormatter { */ public func format(cardNumber: String) -> String { let regex: NSRegularExpression - - let cardType = cardTypeRegister.cardTypeFor(number: Number(rawValue: cardNumber)) + + let cardType = cardTypeRegister.cardType(for: Number(rawValue: cardNumber)) do { let groups = cardType.numberGrouping var pattern = "" @@ -67,7 +67,7 @@ public final class CardNumberFormatter { fatalError("Error when creating regular expression: \(error)") } - return NSArray(array: self.splitString(cardNumber, withRegex: regex)).componentsJoined(by: self.separator) + return NSArray(array: split(string: cardNumber, with: regex)).componentsJoined(by: self.separator) } /** @@ -162,10 +162,10 @@ public final class CardNumberFormatter { - parameter textField: The text field whose text should be changed. - parameter string: The new string. This might be unformatted or badly formatted and will be formatted properly before being inserted into `textField`. */ - public func replaceRangeFormatted(_ range: NSRange, inTextField textField: UITextField, withString string: String) { - let newValueUnformatted = self.unformattedCardNumber(NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)) - let oldValueUnformatted = self.unformattedCardNumber(textField.text ?? "") - + public func format(range: NSRange, inTextField textField: UITextField, andReplaceWith string: String) { + let newValueUnformatted = unformat(cardNumber: NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)) + let oldValueUnformatted = unformat(cardNumber: textField.text ?? "") + let newValue = format(cardNumber: newValueUnformatted) let oldValue = textField.text ?? "" @@ -193,7 +193,7 @@ public final class CardNumberFormatter { - returns: An array of all matches found in string for `regex`. */ - private func splitString(_ string: String, withRegex regex: NSRegularExpression) -> [String] { + private func split(string: String, with regex: NSRegularExpression) -> [String] { let matches = regex.matches(in: string, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, string.characters.count)) var result = [String]() diff --git a/Pod/Classes/Localization.swift b/Pod/Classes/Localization.swift index 276bdfb..94d33fa 100644 --- a/Pod/Classes/Localization.swift +++ b/Pod/Classes/Localization.swift @@ -28,7 +28,7 @@ internal enum Localization: String { - returns: The accessibility label for the provided text field. */ - static func accessibilityLabelForTextField(_ textField: UITextField, comment: String? = nil) -> String? { + static func accessibilityLabel(for textField: UITextField, with comment: String? = nil) -> String? { switch textField { case is NumberInputTextField: return Localization.NumberInputTextFieldAccessibilityLabel.localizedStringWithComment(comment) diff --git a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift index 4f01043..25668f5 100644 --- a/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift +++ b/Pod/Classes/UI/CardTextField+CardInfoTextFieldDelegate.swift @@ -89,20 +89,20 @@ extension CardTextField: CardInfoTextFieldDelegate { } // MARK: Accessibility - + /** Add an observer to listen to the event of UIAccessibilityAnnouncementDidFinishNotification, and then post an accessibility notification to user that the entered expiration date has already expired. - + The reason why can't we just post an accessbility notification is that only the last accessibility notification would be read to users. - As each time users input something there will be an accessibility notification from the system which will always replace what we have + As each time users input something there will be an accessibility notification from the system which will always replace what we have posted here. Thus we need to listen to the notification from the system first, wait until it is finished, and post ours afterwards. */ private func addDateInvalidityObserver() { NotificationCenter.default.addObserver(self, - selector: #selector(notifyExpiryInvalidity), - name: NSNotification.Name.UIAccessibilityAnnouncementDidFinish, - object: nil) + selector: #selector(notifyExpiryInvalidity), + name: NSNotification.Name.UIAccessibilityAnnouncementDidFinish, + object: nil) } /** diff --git a/Pod/Classes/UI/CardTextField+PrefillInformation.swift b/Pod/Classes/UI/CardTextField+PrefillInformation.swift index 40d5940..f290dfe 100644 --- a/Pod/Classes/UI/CardTextField+PrefillInformation.swift +++ b/Pod/Classes/UI/CardTextField+PrefillInformation.swift @@ -33,7 +33,7 @@ public extension CardTextField { } if let cardNumber = number, let numberInputTextField = numberInputTextField { - numberInputTextField.prefill(text: cardNumber) + numberInputTextField.prefill(cardNumber) // With a new card number comes a new card type - pass this card type to `cvcTextField` cvcTextField?.cardType = cardType diff --git a/Pod/Classes/UI/CardTextField.swift b/Pod/Classes/UI/CardTextField.swift index ea4b533..7db0f04 100644 --- a/Pod/Classes/UI/CardTextField.swift +++ b/Pod/Classes/UI/CardTextField.swift @@ -207,7 +207,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { return nil } - return cardTypeRegister.cardTypeFor(number: number) + return cardTypeRegister.cardType(for: number) } internal var hideExpiryTextFields: Bool = false { @@ -288,7 +288,7 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { firstObjectInNib.frame = bounds addSubview(firstObjectInNib) - cardImageView?.image = cardTypeImageStore.imageFor(UnknownCardType()) + cardImageView?.image = cardTypeImageStore.image(for: UnknownCardType()) cardImageView?.layer.cornerRadius = 5.0 cardImageView?.layer.shadowColor = UIColor.black.cgColor cardImageView?.layer.shadowRadius = 2 @@ -380,20 +380,20 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Adds voice over accessibility support for all text fields */ private func setupAccessibilityLabels() { - setupAccessibilityLabelFor(textField: numberInputTextField) - setupAccessibilityLabelFor(textField: cvcTextField) - setupAccessibilityLabelFor(textField: monthTextField) - setupAccessibilityLabelFor(textField: yearTextField) + setupAccessibilityLabel(for: numberInputTextField) + setupAccessibilityLabel(for: cvcTextField) + setupAccessibilityLabel(for: monthTextField) + setupAccessibilityLabel(for: yearTextField) } - + /** Adds voice over accessibility support for a particular text fields - parameter textField: a text field that needs support for voice over accessibility */ - private func setupAccessibilityLabelFor(textField: UITextField) { - textField.accessibilityLabel = Localization.accessibilityLabelForTextField(textField, - comment: "Accessibility label for \(String(describing: textField))") + private func setupAccessibilityLabel(for textField: UITextField) { + textField.accessibilityLabel = Localization.accessibilityLabel(for: textField, + with: "Accessibility label for \(String(describing: textField))") } /** @@ -496,16 +496,16 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { @objc public func numberInputTextFieldDidChangeText(_ numberInputTextField: NumberInputTextField) { showCardImage() notifyDelegate() - hideExpiryTextFields = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresExpiry - hideCVCTextField = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresCVC + hideExpiryTextFields = !cardTypeRegister.cardType(for: numberInputTextField.cardNumber).requiresExpiry + hideCVCTextField = !cardTypeRegister.cardType(for: numberInputTextField.cardNumber).requiresCVC } public func numberInputTextFieldDidComplete(_ numberInputTextField: NumberInputTextField) { moveCardNumberOutAnimated() notifyDelegate() - hideExpiryTextFields = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresExpiry - hideCVCTextField = !cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber).requiresCVC + hideExpiryTextFields = !cardTypeRegister.cardType(for: numberInputTextField.cardNumber).requiresExpiry + hideCVCTextField = !cardTypeRegister.cardType(for: numberInputTextField.cardNumber).requiresCVC if hideExpiryTextFields && hideCVCTextField { return } else if hideExpiryTextFields { @@ -521,8 +521,8 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Displays the card image for the currently detected card type in the card text field's `cardImageView`. */ internal func showCardImage() { - let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) - let cardTypeImage = cardTypeImageStore.imageFor(cardType) + let cardType = cardTypeRegister.cardType(for: numberInputTextField.cardNumber) + let cardTypeImage = cardTypeImageStore.image(for: cardType) cardImageView?.image = cardTypeImage } @@ -531,8 +531,8 @@ public class CardTextField: UITextField, NumberInputTextFieldDelegate { Displays the CVC image for the currently detected card type in the card text field's `cardImageView`. */ internal func showCVCImage() { - let cardType = cardTypeRegister.cardTypeFor(number: numberInputTextField.cardNumber) - let cvcImage = cardTypeImageStore.cvcImageFor(cardType) + let cardType = cardTypeRegister.cardType(for: numberInputTextField.cardNumber) + let cvcImage = cardTypeImageStore.cvcImage(for: cardType) cardImageView?.image = cvcImage cvcTextField?.cardType = cardType diff --git a/Pod/Classes/UI/CardTypeImageStore.swift b/Pod/Classes/UI/CardTypeImageStore.swift index 7e4e192..3f5bff5 100644 --- a/Pod/Classes/UI/CardTypeImageStore.swift +++ b/Pod/Classes/UI/CardTypeImageStore.swift @@ -18,7 +18,7 @@ public protocol CardTypeImageStore { - returns: The image for the specified card type or nil, if no image was provided for this card type. */ - func imageFor(_ cardType: CardType) -> UIImage? + func image(for cardType: CardType) -> UIImage? /** Provides an image for the CVC of a specific card type. The position of a CVC on a card may vary based on the card issuer, so that different card types may provide different images to indicate the location of the CVC on the card. This image will be shown in a `CardTextField`'s image view once the user starts entering the CVC. @@ -27,17 +27,17 @@ public protocol CardTypeImageStore { - returns: The image for the CVC of the specified card type or nil, if no image was provided for this card type. */ - func cvcImageFor(_ cardType: CardType) -> UIImage? + func cvcImage(for cardType: CardType) -> UIImage? } extension Bundle: CardTypeImageStore { - - public func imageFor(_ cardType: CardType) -> UIImage? { + + public func image(for cardType: CardType) -> UIImage? { return UIImage(named: cardType.name, in: self, compatibleWith: nil) } - public func cvcImageFor(_ cardType: CardType) -> UIImage? { + public func cvcImage(for cardType: CardType) -> UIImage? { let cvcImageName: String if cardType.isEqual(to: AmericanExpress()) { cvcImageName = "AmexCVC" diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index bc44abf..84f7cd0 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -22,7 +22,7 @@ public class NumberInputTextField: StylizedTextField { - note: This card number may be incomplete and invalid while the user is entering a card number. Be sure to validate it against a proper card type before assuming it is valid. */ public var cardNumber: Number { - let textFieldTextUnformatted = cardNumberFormatter.unformattedCardNumber(text ?? "") + let textFieldTextUnformatted = cardNumberFormatter.unformat(cardNumber: text ?? "") return Number(rawValue: textFieldTextUnformatted) } @@ -56,7 +56,7 @@ public class NumberInputTextField: StylizedTextField { + ". " + Localization.CardType.localizedStringWithComment("Description for detected card type.") + ": " - + cardTypeRegister.cardTypeFor(number: cardNumber).name + + cardTypeRegister.cardType(for: cardNumber).name } set { } @@ -94,7 +94,7 @@ public class NumberInputTextField: StylizedTextField { let textFieldTextFormatted = NSString(string: textField.text ?? "") // Text in text field after applying changes, formatted and unformatted: let newTextFormatted = textFieldTextFormatted.replacingCharacters(in: range, with: string) - let newTextUnformatted = cardNumberFormatter.unformattedCardNumber(newTextFormatted) + let newTextUnformatted = cardNumberFormatter.unformat(cardNumber: newTextFormatted) // Set the text color to invalid - this will be changed to `validTextColor` later in this method if the input was valid super.textColor = invalidInputColor @@ -104,12 +104,12 @@ public class NumberInputTextField: StylizedTextField { } let parsedCardNumber = Number(rawValue: newTextUnformatted) - let oldValidation = cardTypeRegister.cardTypeFor(number: cardNumber).validate(number: cardNumber) + let oldValidation = cardTypeRegister.cardType(for: cardNumber).validate(number: cardNumber) let newValidation = - cardTypeRegister.cardTypeFor(number: parsedCardNumber).validate(number: parsedCardNumber) + cardTypeRegister.cardType(for: parsedCardNumber).validate(number: parsedCardNumber) if !newValidation.contains(.NumberTooLong) { - cardNumberFormatter.replaceRangeFormatted(range, inTextField: textField, withString: string) + cardNumberFormatter.format(range: range, inTextField: textField, andReplaceWith: string) numberInputTextFieldDelegate?.numberInputTextFieldDidChangeText(self) } else if oldValidation == .Valid { // If the card number is already valid, should call numberInputTextFieldDidComplete on delegate @@ -122,7 +122,7 @@ public class NumberInputTextField: StylizedTextField { } let newLengthComplete = - parsedCardNumber.length == cardTypeRegister.cardTypeFor(number: parsedCardNumber).maxLength + parsedCardNumber.length == cardTypeRegister.cardType(for: parsedCardNumber).maxLength if newLengthComplete && newValidation != .Valid { addNumberInvalidityObserver() @@ -144,10 +144,10 @@ public class NumberInputTextField: StylizedTextField { - parameter cardNumber: The card number which should be displayed in `self`. */ - public func prefill(text: String) { + public func prefill(_ text: String) { let unformattedCardNumber = String(text.characters.filter({$0.isNumeric()})) let cardNumber = Number(rawValue: unformattedCardNumber) - let type = cardTypeRegister.cardTypeFor(number: cardNumber) + let type = cardTypeRegister.cardType(for: cardNumber) let numberPartiallyValid = type.checkCardNumberPartiallyValid(cardNumber) == .Valid if numberPartiallyValid { From 69b709703ed83cfe0785afe768cd75054bba449a Mon Sep 17 00:00:00 2001 From: ThibaultKlein Date: Thu, 3 Nov 2016 10:51:35 -0400 Subject: [PATCH 16/20] Fixed project settings after cocoapods update to 1.1.1 --- .travis.yml | 4 +++- Caishen.xcodeproj/project.pbxproj | 4 +++- .../xcshareddata/xcschemes/Caishen.xcscheme | 2 +- .../xcshareddata/xcschemes/CaishenTests.xcscheme | 2 +- .../Images.xcassets/AppIcon.appiconset/Contents.json | 12 +++++++++++- Example/Caishen_Example.xcodeproj/project.pbxproj | 3 ++- Gemfile | 2 -- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7bda9de..928a121 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,6 @@ script: - pod lib lint before_install: - - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet \ No newline at end of file +- rvm install ruby-2.3.1 && rvm use 2.3.1 +- gem install bundler +- gem install cocoapods --no-rdoc --no-ri --no-document --quiet \ No newline at end of file diff --git a/Caishen.xcodeproj/project.pbxproj b/Caishen.xcodeproj/project.pbxproj index a03b36f..490e481 100644 --- a/Caishen.xcodeproj/project.pbxproj +++ b/Caishen.xcodeproj/project.pbxproj @@ -361,7 +361,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Prolific Interactive"; TargetAttributes = { 2FDD150F1CC7B0B90086CEAC = { @@ -578,6 +578,7 @@ 2FDD15251CC7B0B90086CEAC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -595,6 +596,7 @@ 2FDD15261CC7B0B90086CEAC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; diff --git a/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme b/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme index 8a66643..84a3d19 100644 --- a/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme +++ b/Caishen.xcodeproj/xcshareddata/xcschemes/Caishen.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 29 Nov 2016 10:19:24 -0800 Subject: [PATCH 17/20] Fixed some rebase issues --- Caishen.xcodeproj/project.pbxproj | 2 +- Example/Caishen_Example.xcodeproj/project.pbxproj | 4 ---- Gemfile | 2 ++ Pod/Classes/UI/NumberInputTextField.swift | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Caishen.xcodeproj/project.pbxproj b/Caishen.xcodeproj/project.pbxproj index 490e481..a3fe87a 100644 --- a/Caishen.xcodeproj/project.pbxproj +++ b/Caishen.xcodeproj/project.pbxproj @@ -242,7 +242,6 @@ 2FDD15431CC7B1AC0086CEAC /* Format */ = { isa = PBXGroup; children = ( - 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */, 2FDD15441CC7B1AC0086CEAC /* CardNumberFormatter.swift */, ); path = Format; @@ -251,6 +250,7 @@ 2FDD15461CC7B1AC0086CEAC /* UI */ = { isa = PBXGroup; children = ( + 2FDD154B1CC7B1AC0086CEAC /* CardTextField.swift */, 2FDD15471CC7B1AC0086CEAC /* CardTextField+CardInfoTextFieldDelegate.swift */, 2FDD15481CC7B1AC0086CEAC /* CardTextField+InterfaceBuilder.swift */, 2FDD15491CC7B1AC0086CEAC /* CardTextField+PrefillInformation.swift */, diff --git a/Example/Caishen_Example.xcodeproj/project.pbxproj b/Example/Caishen_Example.xcodeproj/project.pbxproj index 0d73304..6f39a90 100644 --- a/Example/Caishen_Example.xcodeproj/project.pbxproj +++ b/Example/Caishen_Example.xcodeproj/project.pbxproj @@ -488,7 +488,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 01B1F5731BF07579B0F8303E /* Pods-Caishen_Example.debug.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -509,7 +508,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2F5F9CCA6140D64E65AE55BC /* Pods-Caishen_Example.release.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -530,7 +528,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = AFDA4A6398F7CBDF670ACC8A /* Pods-Caishen_Tests.debug.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", @@ -553,7 +550,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 890F5CA910E8A5F9D55DA251 /* Pods-Caishen_Tests.release.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", diff --git a/Gemfile b/Gemfile index 2e4664d..94a11c3 100644 --- a/Gemfile +++ b/Gemfile @@ -1 +1,3 @@ +source 'https://rubygems.org' + gem 'cocoapods', '1.1.1' diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index 84f7cd0..e9216a6 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -153,7 +153,7 @@ public class NumberInputTextField: StylizedTextField { if numberPartiallyValid { // Set text and apply text color changes if the prefilled card type is unknown textField(self, - shouldChangeCharactersInRange: NSRange(location: 0, length: text?.characters.count ?? 0), + shouldChangeCharactersIn: NSRange(location: 0, length: text.characters.count ?? 0), replacementString: cardNumber.rawValue) } } From 16172e8dc4491b8541ae37e01f9e9d8f9b572bea Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Wed, 7 Dec 2016 15:31:01 -0800 Subject: [PATCH 18/20] Fixed warnings that caused Travis CI to fail. --- Pod/Classes/UI/NumberInputTextField.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pod/Classes/UI/NumberInputTextField.swift b/Pod/Classes/UI/NumberInputTextField.swift index e9216a6..82cdf31 100644 --- a/Pod/Classes/UI/NumberInputTextField.swift +++ b/Pod/Classes/UI/NumberInputTextField.swift @@ -152,9 +152,9 @@ public class NumberInputTextField: StylizedTextField { if numberPartiallyValid { // Set text and apply text color changes if the prefilled card type is unknown - textField(self, - shouldChangeCharactersIn: NSRange(location: 0, length: text.characters.count ?? 0), - replacementString: cardNumber.rawValue) + _ = textField(self, + shouldChangeCharactersIn: NSRange(location: 0, length: text.characters.count), + replacementString: cardNumber.rawValue) } } From 7240a031af0b6c1c6f320b1cfe56663710a9875c Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 8 Dec 2016 10:05:36 -0800 Subject: [PATCH 19/20] Fixed Travis CI. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 928a121..72fe3ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,10 +10,10 @@ osx_image: xcode8 # - gem install cocoapods # Since Travis is not always on latest version # - pod install --project-directory=Example script: -- set -o pipefail && xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' | xcpretty -- pod lib lint +- xcodebuild test -project Caishen.xcodeproj -scheme CaishenTests -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' +- pod lib lint --quick before_install: - rvm install ruby-2.3.1 && rvm use 2.3.1 - gem install bundler -- gem install cocoapods --no-rdoc --no-ri --no-document --quiet \ No newline at end of file +- gem install cocoapods --no-rdoc --no-ri --no-document --quiet From 2005f51cc926604bf432d062947b171618b604c3 Mon Sep 17 00:00:00 2001 From: Daniel Vancura Date: Thu, 8 Dec 2016 12:00:58 -0800 Subject: [PATCH 20/20] Bumped pod version --- Caishen.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caishen.podspec b/Caishen.podspec index eed4803..b2e996c 100644 --- a/Caishen.podspec +++ b/Caishen.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "Caishen" - s.version = "1.5.0" + s.version = "2.0.0" s.summary = "A Payment Card UI & Validator for iOS" # This description is used to generate tags and improve search results.