-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Public Release 1.6.1.
- Loading branch information
Showing
115 changed files
with
3,816 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// | ||
// Calendar+extension.swift | ||
// VGSCollectSDK | ||
// | ||
// Created by Dima on 22.07.2020. | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
internal extension Calendar { | ||
|
||
/// For card numbers we should use `gregorian` calendar. Note: Callendar.current could retern different calendars!!! | ||
static var currentMonth: Int { | ||
return Calendar(identifier: .gregorian).component(.month, from: Date()) | ||
} | ||
|
||
static var currentYear: Int { | ||
return Calendar(identifier: .gregorian).component(.year, from: Date()) | ||
} | ||
|
||
static var currentYearShort: Int { | ||
return Calendar(identifier: .gregorian).component(.year, from: Date()) - 2000 | ||
} | ||
} |
151 changes: 151 additions & 0 deletions
151
Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import UIKit | ||
|
||
/// An object that displays an editable text area. Can be use instead of a `VGSTextField` when need to show picker view with Card Number Expiration Month and Year. | ||
public final class VGSExpDateTextField: VGSTextField { | ||
|
||
// MARK: - Enums | ||
/// Available Month Label formats in `UIPickerView` | ||
public enum MonthFormat { | ||
/// Short month name, e.g.: `Jan` | ||
case shortSymbols | ||
/// Long month name, e.g.: `January` | ||
case longSymbols | ||
/// Month number: e.g.: `01` | ||
case numbers | ||
} | ||
|
||
/// Available Year Label formats in `UIPickerView` | ||
public enum YearFormat { | ||
/// Two digits year format, e.g.: `21` | ||
case short | ||
/// Four digits year format:, e.g.:`2021` | ||
case long | ||
} | ||
|
||
// MARK: - Attributes | ||
/// UIPickerView Month Label format | ||
public var monthPickerFormat: MonthFormat = .longSymbols { | ||
didSet { | ||
updateMonthsDataSource() | ||
} | ||
} | ||
|
||
/// UIPickerView Year Label format | ||
public var yearPickeFormat: YearFormat = .long { | ||
didSet { | ||
updateYearsDataSource() | ||
} | ||
} | ||
|
||
///:nodoc: | ||
public override var configuration: VGSConfiguration? { | ||
didSet { | ||
fieldType = .expDate | ||
} | ||
} | ||
|
||
/// Visual month data source | ||
internal var monthsDataSource = [String]() | ||
/// Visual year data source | ||
internal var yearsDataSource = [String]() | ||
/// Valid months range | ||
internal lazy var months = Array(1...12) | ||
/// Valid years range | ||
internal lazy var years: [Int] = { | ||
let current = Calendar.currentYear | ||
return Array(current...(current + validYearsCount)) | ||
}() | ||
internal let monthPickerComponent = 0 | ||
internal let yearPickerComponent = 1 | ||
internal let validYearsCount = 20 | ||
internal lazy var picker = self.makePicker() | ||
|
||
// MARK: - Initialization | ||
|
||
override func mainInitialization() { | ||
super.mainInitialization() | ||
textField.inputView = picker | ||
updateYearsDataSource() | ||
updateMonthsDataSource() | ||
scrollToCurrentMonth(animated: false) | ||
textField.inputAccessoryView = UIView() | ||
} | ||
|
||
private func updateTextField() { | ||
let month = months[picker.selectedRow(inComponent: monthPickerComponent)] | ||
let year = years[picker.selectedRow(inComponent: yearPickerComponent)] | ||
let format = textField.formatPattern.components(separatedBy: "/").last ?? FieldType.expDate.defaultFormatPattern | ||
let yearString = (format.count == 4) ? String(year) : String(year - 2000) | ||
let monthString = String(format: "%02d", month) | ||
self.setText("\(monthString)\(yearString)") | ||
} | ||
} | ||
|
||
extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource { | ||
public func numberOfComponents(in pickerView: UIPickerView) -> Int { | ||
return 2 | ||
} | ||
|
||
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { | ||
switch component { | ||
case monthPickerComponent: | ||
return monthsDataSource.count | ||
default: | ||
return yearsDataSource.count | ||
} | ||
} | ||
|
||
public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { | ||
switch component { | ||
case monthPickerComponent: | ||
return monthsDataSource[row] | ||
default: | ||
return yearsDataSource[row] | ||
} | ||
} | ||
|
||
public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { | ||
/// check that date is not before current month | ||
let currentMonthIndex = Calendar(identifier: .gregorian).component(.month, from: Date()) - 1 | ||
if pickerView.selectedRow(inComponent: yearPickerComponent) == 0 && pickerView.selectedRow(inComponent: monthPickerComponent) < currentMonthIndex { | ||
pickerView.selectRow(currentMonthIndex, inComponent: monthPickerComponent, animated: true) | ||
} | ||
updateTextField() | ||
} | ||
} | ||
|
||
private extension VGSExpDateTextField { | ||
func makePicker() -> UIPickerView { | ||
let picker = UIPickerView() | ||
picker.delegate = self | ||
picker.dataSource = self | ||
return picker | ||
} | ||
|
||
func updateMonthsDataSource() { | ||
switch monthPickerFormat { | ||
case .shortSymbols: | ||
monthsDataSource = DateFormatter().shortMonthSymbols | ||
case .longSymbols: | ||
monthsDataSource = DateFormatter().monthSymbols | ||
case .numbers: | ||
monthsDataSource = months.map{ (String(format: "%02d", $0))} | ||
} | ||
} | ||
|
||
func updateYearsDataSource() { | ||
let suffixLength = yearPickeFormat == .short ? 2 : 4 | ||
yearsDataSource = years.map{ String(String($0).suffix(suffixLength))} | ||
} | ||
|
||
func scrollToCurrentMonth(animated: Bool) { | ||
let currentMonthIndex = Calendar.currentMonth - 1 | ||
picker.selectRow(currentMonthIndex, inComponent: monthPickerComponent, animated: animated) | ||
picker.selectRow(0, inComponent: yearPickerComponent, animated: animated) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
Tests/FrameworkTests/Text Fields Tests/ExpDateTextField.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// | ||
// ExpDateTextField.swift | ||
// FrameworkTests | ||
// | ||
// Created by Vitalii Obertynskyi on 17.06.2020. | ||
// Copyright © 2020 VGS. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import VGSCollectSDK | ||
|
||
class ExpDateTextField: XCTestCase { | ||
|
||
var collector: VGSCollect! | ||
var textField: VGSExpDateTextField! | ||
|
||
override func setUp() { | ||
collector = VGSCollect(id: "any") | ||
textField = VGSExpDateTextField() | ||
let config = VGSConfiguration(collector: collector, fieldName: "textField") | ||
config.formatPattern = "##/####" | ||
textField.configuration = config | ||
} | ||
|
||
override func tearDown() { | ||
collector = nil | ||
textField = nil | ||
} | ||
|
||
func testMonthFormat() { | ||
textField.monthPickerFormat = .longSymbols | ||
XCTAssertTrue(textField.monthsDataSource.first == "January") | ||
textField.monthPickerFormat = .shortSymbols | ||
XCTAssertTrue(textField.monthsDataSource.first == "Jan") | ||
textField.monthPickerFormat = .numbers | ||
XCTAssertTrue(textField.monthsDataSource.last == "12") | ||
} | ||
|
||
func testYearFormat() { | ||
textField.yearPickeFormat = .long | ||
XCTAssertTrue(textField.yearsDataSource.first == String(Calendar.currentYear)) | ||
textField.yearPickeFormat = .short | ||
XCTAssertTrue(textField.yearsDataSource.first == String(Calendar.currentYear - 2000)) | ||
} | ||
|
||
func testSelectDate() { | ||
let monthSelected = 10 | ||
let yearSelected = 5 | ||
textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) | ||
textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) | ||
textField.picker.selectRow(yearSelected, inComponent: 1, animated: false) | ||
textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 1) | ||
|
||
let currentValue = textField.textField.secureText | ||
let monthComponent = currentValue?.components(separatedBy: "/").first ?? "0" | ||
let yearComponent = currentValue?.components(separatedBy: "/").last ?? "0" | ||
|
||
XCTAssertTrue(Int(monthComponent) == monthSelected + 1) | ||
XCTAssertTrue(Int(yearComponent) == Calendar.currentYear + yearSelected) | ||
} | ||
|
||
func testSelectWrongDate() { | ||
textField.picker.selectRow(0, inComponent: 1, animated: false) | ||
textField.picker.selectRow(0, inComponent: 0, animated: false) | ||
textField.pickerView(textField.picker, didSelectRow: 0, inComponent: 0) | ||
let currentValue = textField.textField.secureText | ||
|
||
let currentMonth = Calendar.currentMonth | ||
let currentYear = Calendar.currentYear | ||
let monthComponent = currentValue?.components(separatedBy: "/").first ?? "0" | ||
let yearComponent = currentValue?.components(separatedBy: "/").last ?? "0" | ||
|
||
XCTAssertTrue(Int(monthComponent) == currentMonth) | ||
XCTAssertTrue(Int(yearComponent) == currentYear) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.