initial refactor to split out FieldTypes

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-05-09 08:19:39 -05:00
parent 2d5f3d7652
commit 5672df7070
7 changed files with 346 additions and 183 deletions

View File

@ -141,6 +141,11 @@
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; };
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFEB632A26473700C4C106 /* NSAttributedString.swift */; };
EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */; };
EAC58C062BED000200BA39FA /* CreditCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58C052BED000200BA39FA /* CreditCard.swift */; };
EAC58C082BED002D00BA39FA /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58C072BED002D00BA39FA /* Date.swift */; };
EAC58C0A2BED004E00BA39FA /* FieldType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58C092BED004E00BA39FA /* FieldType.swift */; };
EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58C0B2BED01D500BA39FA /* Telephone.swift */; };
EAC58C0E2BED021600BA39FA /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58C0D2BED021600BA39FA /* Password.swift */; };
EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */; };
EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */; };
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; };
@ -337,6 +342,11 @@
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = "<group>"; };
EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTextColor.swift; sourceTree = "<group>"; };
EAC58C052BED000200BA39FA /* CreditCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCard.swift; sourceTree = "<group>"; };
EAC58C072BED002D00BA39FA /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
EAC58C092BED004E00BA39FA /* FieldType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldType.swift; sourceTree = "<group>"; };
EAC58C0B2BED01D500BA39FA /* Telephone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Telephone.swift; sourceTree = "<group>"; };
EAC58C0D2BED021600BA39FA /* Password.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Password.swift; sourceTree = "<group>"; };
EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
@ -875,6 +885,18 @@
path = Tooltip;
sourceTree = "<group>";
};
EAC58C042BECFFEA00BA39FA /* FieldTypes */ = {
isa = PBXGroup;
children = (
EAC58C092BED004E00BA39FA /* FieldType.swift */,
EAC58C052BED000200BA39FA /* CreditCard.swift */,
EAC58C072BED002D00BA39FA /* Date.swift */,
EAC58C0B2BED01D500BA39FA /* Telephone.swift */,
EAC58C0D2BED021600BA39FA /* Password.swift */,
);
path = FieldTypes;
sourceTree = "<group>";
};
EAC9257E29119B5D00091998 /* TextLink */ = {
isa = PBXGroup;
children = (
@ -907,6 +929,7 @@
EAC925862911C9DE00091998 /* InputField */ = {
isa = PBXGroup;
children = (
EAC58C042BECFFEA00BA39FA /* FieldTypes */,
EAC925872911C9DE00091998 /* InputField.swift */,
EA2DC9B32BE2C6FE004F58C5 /* TextField.swift */,
EA6642942BCEBF9500D81DC4 /* TextLinkModel.swift */,
@ -1142,6 +1165,7 @@
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */,
EAC58C082BED002D00BA39FA /* Date.swift in Sources */,
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */,
EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */,
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
@ -1195,12 +1219,14 @@
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
EAC58C0A2BED004E00BA39FA /* FieldType.swift in Sources */,
EA471F3A2A95587500CE9E58 /* LayoutConstraintable.swift in Sources */,
EAB1D2CF28ABEF2B00DAE764 /* Typography+Base.swift in Sources */,
EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */,
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */,
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */,
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
EAC58C0C2BED01D500BA39FA /* Telephone.swift in Sources */,
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */,
EA6F330E2B911E9000BACAB9 /* TextView.swift in Sources */,
@ -1214,6 +1240,7 @@
44604AD729CE196600E62B51 /* Line.swift in Sources */,
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */,
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
EAC58C062BED000200BA39FA /* CreditCard.swift in Sources */,
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */,
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
@ -1246,6 +1273,7 @@
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */,
EA3362302891EB4A0071C351 /* Font.swift in Sources */,
EAC58C0E2BED021600BA39FA /* Password.swift in Sources */,
EAF7F0AD289B142900B287F5 /* StrikeThroughLabelAttribute.swift in Sources */,
EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */,
EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */,

View File

@ -0,0 +1,103 @@
//
// CreditCard.swift
// VDS
//
// Created by Matt Bruce on 5/9/24.
//
import Foundation
import UIKit
extension InputField {
enum CreditCardType: CaseIterable {
case generic
case visa
case mastercard
case amex
case discover
case dinersClub
case jcb
case chinaUnionPay
var image: UIImage {
return BundleManager.shared.image(for: imageName)!
}
var imageName: String {
var imageName: String = "generic"
switch self {
case .visa: imageName = "visa"
case .mastercard: imageName = "mastercard"
case .amex: imageName = "amex"
case .discover: imageName = "discover"
case .dinersClub: imageName = "dinersClub"
case .jcb: imageName = "jcb"
default: imageName = "generic"
}
return imageName
}
internal var separatorIndices: [Int] {
switch self {
case .dinersClub:
return [4, 10]
default:
return [4, 8, 12]
}
}
internal var maxLength: Int {
switch self {
case .dinersClub: return 14
default: return 16
}
}
static func from(iin: Int) -> CreditCardType? {
switch iin {
case 4000...4999:
return .visa
case 5100...5599, 2221...2720:
return .mastercard
case 3400...3499, 3700...3799:
return .amex
case 6011, 6221...6229, 6440...6499, 6500...6599:
return .discover
case 3600...3699, 3800...3999:
return .dinersClub
case 3528...3589:
return .jcb
case 6200...6299, 6000...6010, 8100...8199:
return .chinaUnionPay
default:
return nil
}
}
}
internal func formatCreditCardNumber(_ number: String) -> String {
let formattedInput = number.filter { $0.isNumber } // Remove any existing slashes
return String.format(formattedInput, indices: creditCardType.separatorIndices, with: " ")
}
internal func updateCardTypeIcon(rawNumber: String) {
guard rawNumber.count >= 4,
let firstFourDigits = Int(String(rawNumber.prefix(4))),
let creditCardType = CreditCardType.from(iin: firstFourDigits) else {
leftImageView.image = BundleManager.shared.image(for: CreditCardType.generic.imageName)
creditCardType = .generic
return
}
self.creditCardType = creditCardType
}
internal func maskCreditCardNumber(_ number: String) -> String {
// Mask the first 12 characters if the length is 16
let rawNumber = number.filter { $0.isNumber }
guard rawNumber.count == creditCardType.maxLength else { return formatCreditCardNumber(number) }
let lastFourDigits = rawNumber.suffix(4)
let maskedSection = String(repeating: "", count: 12)
let formattedMaskSection = String.format(maskedSection, indices: creditCardType.separatorIndices, with: " ")
return formattedMaskSection + " " + lastFourDigits
}
}

View File

@ -0,0 +1,65 @@
//
// Date.swift
// VDS
//
// Created by Matt Bruce on 5/9/24.
//
import Foundation
extension InputField {
public enum DateFormat: String, CaseIterable {
case mmyy
case mmddyy
case mmddyyyy
public var placeholderText: String {
switch self {
case .mmyy: "MM/YY"
case .mmddyy: "MM/DD/YY"
case .mmddyyyy: "MM/DD/YYYY"
}
}
public var formatString: String {
switch self {
case .mmyy: "MM/yy"
case .mmddyy: "MM/dd/yy"
case .mmddyyyy: "MM/dd/yyyy"
}
}
public var maxLength: Int {
switch self {
case .mmyy: 5
case .mmddyy: 8
case .mmddyyyy: 10
}
}
internal var separatorIndices: [Int] {
switch self {
case .mmyy: [2]
case .mmddyy: [2,4]
case .mmddyyyy: [2,4]
}
}
}
internal func formatDate(_ input: String) -> String {
let formattedInput = input.filter { $0.isNumber } // Remove any existing slashes
var formattedString = ""
var currentIndex = formattedInput.startIndex
for index in 0..<formattedInput.count {
if dateFormat.separatorIndices.contains(index) {
formattedString.append("/")
}
formattedString.append(formattedInput[currentIndex])
currentIndex = formattedInput.index(after: currentIndex)
}
return formattedString
}
}

View File

@ -0,0 +1,32 @@
//
// FieldType.swift
// VDS
//
// Created by Matt Bruce on 5/9/24.
//
import Foundation
import UIKit
extension InputField {
public enum FieldType: String, CaseIterable {
case text, number, inlineAction, password, creditCard, tel, date, securityCode
public var keyboardType: UIKeyboardType {
switch self {
case .number:
.numberPad
case .tel:
.phonePad
case .creditCard:
.numberPad
case .date:
.numberPad
case .securityCode:
.numberPad
default:
.default
}
}
}
}

View File

@ -0,0 +1,20 @@
//
// Password.swift
// VDS
//
// Created by Matt Bruce on 5/9/24.
//
import Foundation
extension InputField {
enum PasswordAction {
case show, hide
func toggle() -> PasswordAction {
self == .hide ? .show : .hide
}
}
}

View File

@ -0,0 +1,43 @@
//
// Tel.swift
// VDS
//
// Created by Matt Bruce on 5/9/24.
//
import Foundation
extension InputField {
internal func formatUSNumber(_ number: String) -> String {
// Format the number in the style XXX-XXX-XXXX
let areaCodeLength = 3
let centralOfficeCodeLength = 3
let lineNumberLength = 4
var formattedNumber = ""
if number.count > 0 {
formattedNumber.append(contentsOf: number.prefix(areaCodeLength))
}
if number.count > areaCodeLength {
let startIndex = number.index(number.startIndex, offsetBy: areaCodeLength)
let endIndex = number.index(startIndex, offsetBy: min(centralOfficeCodeLength, number.count - areaCodeLength))
let centralOfficeCode = number[startIndex..<endIndex]
formattedNumber.append("-")
formattedNumber.append(contentsOf: centralOfficeCode)
}
if number.count > areaCodeLength + centralOfficeCodeLength {
let startIndex = number.index(number.startIndex, offsetBy: areaCodeLength + centralOfficeCodeLength)
let endIndex = number.index(startIndex, offsetBy: min(lineNumberLength, number.count - areaCodeLength - centralOfficeCodeLength))
let lineNumber = number[startIndex..<endIndex]
formattedNumber.append("-")
formattedNumber.append(contentsOf: lineNumber)
}
return formattedNumber
}
}

View File

@ -31,14 +31,6 @@ open class InputField: EntryFieldBase {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
/// Enum used to describe the input type.
public enum FieldType: String, CaseIterable {
case text, number, inlineAction, password, creditCard, tel, date, securityCode
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
@ -77,7 +69,7 @@ open class InputField: EntryFieldBase {
/// Representing the type of input.
open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } }
open var leftIcon: Icon = Icon().with { $0.size = .medium }
open var leftImageView = UIImageView().with { $0.height(21); $0.width(32) }
open var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) }
@ -165,7 +157,7 @@ open class InputField: EntryFieldBase {
controlContainerView.addSubview(controlStackView)
controlStackView.pinToSuperView()
controlStackView.addArrangedSubview(leftIcon)
controlStackView.addArrangedSubview(leftImageView)
controlStackView.addArrangedSubview(textField)
textField.heightAnchor.constraint(equalToConstant: 20).isActive = true
@ -266,7 +258,7 @@ open class InputField: EntryFieldBase {
open func updateFieldType() {
var minWidth: CGFloat = 40.0
var leftIconName: Icon.Name?
var leftImageName: String?
var actionModel: InputField.TextLinkModel?
var toolTipModel: Tooltip.TooltipModel? = tooltipModel
var isSecureTextEntry = false
@ -303,7 +295,7 @@ open class InputField: EntryFieldBase {
case .creditCard:
minWidth = 288.0
leftImageName = creditCardType.imageName
case .tel:
minWidth = 176.0
@ -319,10 +311,10 @@ open class InputField: EntryFieldBase {
textField.isSecureTextEntry = isSecureTextEntry
//leftIcon
leftIcon.surface = surface
leftIcon.color = iconColorConfiguration.getColor(self)
leftIcon.name = leftIconName
leftIcon.isHidden = leftIconName == nil
if let leftImageName {
leftImageView.image = BundleManager.shared.image(for: creditCardType.imageName)?.withTintColor(iconColorConfiguration.getColor(self))
}
leftImageView.isHidden = leftImageName == nil
//actionLink
actionTextLink.surface = surface
@ -362,7 +354,7 @@ open class InputField: EntryFieldBase {
case .creditCard:
if let text = textField.text, text.count > 0 {
let rule = CharacterCountRule().copyWith {
$0.maxLength = creditCardMaxLength
$0.maxLength = creditCardType.maxLength
$0.compareType = .equals
$0.errorMessage = "Enter a valid credit card."
}
@ -431,115 +423,9 @@ open class InputField: EntryFieldBase {
}
//--------------------------------------------------
// MARK: - Password
// MARK: - Private Methods
//--------------------------------------------------
enum PasswordAction {
case show, hide
func toggle() -> PasswordAction {
self == .hide ? .show : .hide
}
}
internal var passwordActionType: PasswordAction = .show { didSet { setNeedsUpdate() } }
open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } }
open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } }
//--------------------------------------------------
// MARK: - Date
//--------------------------------------------------
open var dateFormat: DateFormat = .mmddyy { didSet { setNeedsUpdate() } }
private func formatDate(_ input: String) -> String {
let formattedInput = input.filter { $0.isNumber } // Remove any existing slashes
var formattedString = ""
var currentIndex = formattedInput.startIndex
for index in 0..<formattedInput.count {
if dateFormat.separatorIndices.contains(index) {
formattedString.append("/")
}
formattedString.append(formattedInput[currentIndex])
currentIndex = formattedInput.index(after: currentIndex)
}
return formattedString
}
//---------------------------------------------------
// MARK: - Credit Card
//---------------------------------------------------
private var creditCardRawNumber: String = ""
private var creditCardMaxLength = 16
private func formatCreditCardNumber(_ number: String) -> String {
// Format the number in the style XXXX XXXX XXXX XXXX
var formattedNumber = ""
for (index, char) in number.enumerated() {
if index != 0 && index % 4 == 0 {
formattedNumber.append(" ")
}
formattedNumber.append(char)
}
return formattedNumber
}
private func updateCardTypeIcon(rawNumber: String) {
// let firstFourDigits = String(rawNumber.prefix(4))
// if let icon = cardTypeIcons[firstFourDigits] {
// cardTypeIconView.image = icon
// } else {
// cardTypeIconView.image = nil
// }
}
private func maskCreditCardNumber(_ number: String) -> String {
// Mask the first 12 characters if the length is 16
let rawNumber = number.filter { $0.isNumber }
guard rawNumber.count == creditCardMaxLength else { return formatCreditCardNumber(number) }
let lastFourDigits = rawNumber.suffix(4)
let maskedSection = String(repeating: "", count: 12)
let formattedMaskSection = formatCreditCardNumber(maskedSection)
return formattedMaskSection + " " + lastFourDigits
}
//---------------------------------------------------
// MARK: - Telephone
//---------------------------------------------------
private func formatUSNumber(_ number: String) -> String {
// Format the number in the style XXX-XXX-XXXX
let areaCodeLength = 3
let centralOfficeCodeLength = 3
let lineNumberLength = 4
var formattedNumber = ""
if number.count > 0 {
formattedNumber.append(contentsOf: number.prefix(areaCodeLength))
}
if number.count > areaCodeLength {
let startIndex = number.index(number.startIndex, offsetBy: areaCodeLength)
let endIndex = number.index(startIndex, offsetBy: min(centralOfficeCodeLength, number.count - areaCodeLength))
let centralOfficeCode = number[startIndex..<endIndex]
formattedNumber.append("-")
formattedNumber.append(contentsOf: centralOfficeCode)
}
if number.count > areaCodeLength + centralOfficeCodeLength {
let startIndex = number.index(number.startIndex, offsetBy: areaCodeLength + centralOfficeCodeLength)
let endIndex = number.index(startIndex, offsetBy: min(lineNumberLength, number.count - areaCodeLength - centralOfficeCodeLength))
let lineNumber = number[startIndex..<endIndex]
formattedNumber.append("-")
formattedNumber.append(contentsOf: lineNumber)
}
return formattedNumber
}
private func getTelCursorPosition(textField: UITextField, range: NSRange, replacementString string: String, rawNumber: String, formattedNumber: String) -> UITextPosition? {
internal func cursorPosition(textField: UITextField, range: NSRange, replacementString string: String, rawNumber: String, formattedNumber: String) -> UITextPosition? {
let start = range.location
let length = string.count
@ -560,6 +446,28 @@ open class InputField: EntryFieldBase {
return textField.position(from: textField.beginningOfDocument, offset: finalCursorLocation)
}
//--------------------------------------------------
// MARK: - Password
//--------------------------------------------------
internal var passwordActionType: PasswordAction = .show { didSet { setNeedsUpdate() } }
open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } }
open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } }
//--------------------------------------------------
// MARK: - Date
//--------------------------------------------------
open var dateFormat: DateFormat = .mmddyy { didSet { setNeedsUpdate() } }
//---------------------------------------------------
// MARK: - Credit Card
//---------------------------------------------------
internal var creditCardRawNumber: String = ""
internal var creditCardType: CreditCardType = .generic { didSet { setNeedsUpdate() } }
//---------------------------------------------------
// MARK: - Telephone
//---------------------------------------------------
}
extension InputField: UITextFieldDelegate {
@ -596,7 +504,7 @@ extension InputField: UITextFieldDelegate {
// Remove any existing formatting
let rawNumber = newText.filter { $0.isNumber }
if rawNumber.count > creditCardMaxLength {
if rawNumber.count > creditCardType.maxLength {
return false
}
@ -606,11 +514,16 @@ extension InputField: UITextFieldDelegate {
// Update the icon based on the first four digits
updateCardTypeIcon(rawNumber: rawNumber)
// Check again
if rawNumber.count > creditCardType.maxLength {
return false
}
// Set the formatted text
textField.text = formattedNumber
// Calculate the new cursor position
if let newPosition = getTelCursorPosition(textField: textField,
if let newPosition = cursorPosition(textField: textField,
range: range,
replacementString: string,
rawNumber: rawNumber,
@ -670,7 +583,7 @@ extension InputField: UITextFieldDelegate {
textField.text = formattedNumber
// Calculate the new cursor position
if let newPosition = getTelCursorPosition(textField: textField,
if let newPosition = cursorPosition(textField: textField,
range: range,
replacementString: string,
rawNumber: rawNumber,
@ -693,62 +606,21 @@ extension InputField: UITextFieldDelegate {
}
}
extension InputField.FieldType {
extension String {
public var keyboardType: UIKeyboardType {
switch self {
case .number:
.numberPad
case .tel:
.phonePad
case .creditCard:
.numberPad
case .date:
.numberPad
case .securityCode:
.numberPad
default:
.default
}
}
}
extension InputField {
public enum DateFormat: String, CaseIterable {
case mmyy
case mmddyy
case mmddyyyy
public var placeholderText: String {
switch self {
case .mmyy: "MM/YY"
case .mmddyy: "MM/DD/YY"
case .mmddyyyy: "MM/DD/YYYY"
}
}
public var formatString: String {
switch self {
case .mmyy: "MM/yy"
case .mmddyy: "MM/dd/yy"
case .mmddyyyy: "MM/dd/yyyy"
}
}
public var maxLength: Int {
switch self {
case .mmyy: 5
case .mmddyy: 8
case .mmddyyyy: 10
}
}
internal var separatorIndices: [Int] {
switch self {
case .mmyy: [2]
case .mmddyy: [2,4]
case .mmddyyyy: [2,4]
}
internal static func format(_ value: String, indices: [Int], with separator: String) -> String {
var formattedString = ""
var currentIndex = value.startIndex
for index in 0..<value.count {
if indices.contains(index) {
formattedString.append(separator)
}
formattedString.append(value[currentIndex])
currentIndex = value.index(after: currentIndex)
}
return formattedString
}
}