├── .gitignore
├── LICENSE.md
├── Package.swift
├── README.md
├── ScreenShots
├── demo.gif
├── demo.mp4
└── screenShot1.png
├── Sources
└── TFManager
│ ├── TFManager.swift
│ ├── TextRules.swift
│ ├── TextRulesRepo.swift
│ ├── Validatable.swift
│ ├── ValidatableField.swift
│ └── ValidationResult.swift
├── TFManager.podspec
├── TFManagerDemo
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Headers
│ │ └── Public
│ │ │ └── TFManager
│ │ │ ├── TFManager-umbrella.h
│ │ │ └── TFManager.modulemap
│ ├── Local Podspecs
│ │ └── TFManager.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ └── project.pbxproj
│ └── Target Support Files
│ │ ├── Pods-TFManagerDemo
│ │ ├── Pods-TFManagerDemo-acknowledgements.markdown
│ │ ├── Pods-TFManagerDemo-acknowledgements.plist
│ │ ├── Pods-TFManagerDemo-dummy.m
│ │ ├── Pods-TFManagerDemo-umbrella.h
│ │ ├── Pods-TFManagerDemo.debug.xcconfig
│ │ ├── Pods-TFManagerDemo.modulemap
│ │ └── Pods-TFManagerDemo.release.xcconfig
│ │ └── TFManager
│ │ ├── TFManager-dummy.m
│ │ ├── TFManager-prefix.pch
│ │ ├── TFManager-umbrella.h
│ │ ├── TFManager.debug.xcconfig
│ │ ├── TFManager.modulemap
│ │ └── TFManager.release.xcconfig
├── TFManagerDemo.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── TFManagerDemo.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── TFManagerDemo
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── CustomValidatableField.swift
│ ├── Info.plist
│ └── ViewController.swift
└── Tests
└── TFManagerTests
└── TFManagerTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022
2 | Permission is hereby granted, free of charge, to any person obtaining a copy
3 | of this software and associated documentation files (the "Software"), to deal
4 | in the Software without restriction, including without limitation the rights
5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6 | copies of the Software, and to permit persons to whom the Software is
7 | furnished to do so, subject to the following conditions:
8 | The above copyright notice and this permission notice shall be included in
9 | all copies or substantial portions of the Software.
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 | THE SOFTWARE.
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.5
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "TFManager",
8 | platforms: [
9 | .iOS(.v11),
10 | ],
11 | products: [
12 | // Products define the executables and libraries a package produces, and make them visible to other packages.
13 | .library(
14 | name: "TFManager",
15 | targets: ["TFManager"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
24 | .target(
25 | name: "TFManager",
26 | dependencies: []),
27 | .testTarget(
28 | name: "TFManagerTests",
29 | dependencies: ["TFManager"]),
30 | ],
31 | swiftLanguageVersions: [.v5]
32 | )
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # TFManager
6 |
7 | Let's say you have multiple `UITextField`s to get data from users. You need to handle each field keyboard's return key and add an accessory view to the keyboard for navigating through fields. TFManager will do this for you in just one line of code!
8 | And if you want more you can add validation rules to the text fields and check if they're valid or not.
9 |
10 | [](https://developer.apple.com/iOS)
11 | [](https://developer.apple.com/documentation/swift_packages/package/)
12 | [](https://opensource.org/licenses/MIT)
13 |
14 | ## Navigate
15 |
16 | - [Installation](#installation)
17 | - [Swift Package Manager](#swift-package-manager)
18 | - [CocoaPods](#cocoapods)
19 | - [Manually](#manually)
20 | - [Basic Usage](#basic-usage)
21 | - [Validate All Fields](#validate-all-fields)
22 | - [Rules](#rules)
23 | - [Contact](#contact)
24 | - [License](#license)
25 |
26 | ## Installation
27 |
28 | Ready for use on iOS and iPadOS 11+.
29 |
30 | ### Swift Package Manager
31 |
32 | The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.
33 |
34 | Once you have your Swift package set up, adding as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
35 |
36 | ```swift
37 | dependencies: [
38 | .package(url: "https://github.com/abspr/TFManager", .upToNextMajor(from: "1.1.0"))
39 | ]
40 | ```
41 |
42 | ### CocoaPods:
43 |
44 | [CocoaPods](https://cocoapods.org) is a dependency manager. For usage and installation instructions, visit their website. To integrate using CocoaPods, specify it in your `Podfile`:
45 |
46 | ```ruby
47 | pod 'TFManager'
48 | ```
49 |
50 | ### Manually
51 |
52 | If you prefer not to use any of dependency managers, you can integrate manually. Put `Sources/TFManager` folder in your Xcode project. Make sure to enable `Copy items if needed` and `Create groups`.
53 |
54 | ## Basic Usage
55 |
56 | 1. Create an instance of TFManager in your `viewController`
57 | ```swift
58 | var fieldsManager = TFManager()
59 | ```
60 | 2. Add your `textFields` to it:
61 | ```swift
62 | fieldsManager.add([nameField, mailField, ageField])
63 | ```
64 | 3. There is no more steps 😯
65 |
66 | ## Validate All Fields
67 | You can add rules to your `UITextField`s and ask `TFManager` to apply validation to all of child fields:
68 |
69 | 1. Change your textField class to `ValidatableField`.
70 |
71 |
72 | 2. Then you can call `validate()` method on your `TFManager` instance.
73 | ```swift
74 | let result = fieldsManager.validate()
75 | result.forEach { (invalidField, validationResult) in
76 | invalidField.textColor = .systemRed
77 | print(validationResult.message)
78 | }
79 | ```
80 |
81 | 💡 You can set `TFManager`'s delegate and use its methods to get notified which textField is become active or its text is changing:
82 | ```swift
83 | fieldsManager.delegate = self
84 |
85 | extension ViewController: TFManagerDelegate {
86 | func textDidChange(_ textField: UITextField, validationResult: ValidationResult?) {
87 | guard let validationResult = validationResult else { return }
88 | textField.textColor = validationResult.isValid ? .label : .systemRed
89 | }
90 | }
91 | ```
92 |
93 | 💡 You also can subclass `ValidatableField` and customize your textField.
94 | Override `didFailValidation(_:)` and `didPass()` methods to handle valid/invalid states (eg: show/hide the error label)
95 |
96 | ## Rules
97 | `TFManager` comes with set of rules (`TextRulesSet`) and you can add them to any `ValidatableField`:
98 | ```swift
99 | ageField.rulesRepo.add(TextRulesSet.numbersOnly())
100 | ageField.rulesRepo.add(TextRulesSet.minLenght(1))
101 | ageField.rulesRepo.add(TextRulesSet.maxLenght(2))
102 | ```
103 |
104 | 💡 You can have your own rules too. Just create a `struct` and implement `TextRule`:
105 |
106 | ```swift
107 | struct YourRule: TextRule {
108 | var message: String
109 |
110 | func validate(_ text: String) -> Bool {
111 | // code
112 | }
113 | }
114 | ```
115 |
116 | ## Contact
117 | email : [hosein@me.com](mailto:hosein@me.com)
118 |
119 | ## License
120 | TFManager is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
121 |
--------------------------------------------------------------------------------
/ScreenShots/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abspr/TFManager/31c969fdbc515274c029cfa17b570c9260b7de7f/ScreenShots/demo.gif
--------------------------------------------------------------------------------
/ScreenShots/demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abspr/TFManager/31c969fdbc515274c029cfa17b570c9260b7de7f/ScreenShots/demo.mp4
--------------------------------------------------------------------------------
/ScreenShots/screenShot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abspr/TFManager/31c969fdbc515274c029cfa17b570c9260b7de7f/ScreenShots/screenShot1.png
--------------------------------------------------------------------------------
/Sources/TFManager/TFManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Form.swift
3 | // TFManager
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Sets of methods you can use to notify how users are interacting with the textFields.
11 | public protocol TFManagerDelegate: AnyObject {
12 |
13 | /// to notify which `UITextField` was last responder.
14 | func focusChanged(from textField: UITextField)
15 |
16 | /// to notify which `UITextField` became first responder.
17 | func focusChanged(to textField: UITextField)
18 |
19 | /// Will call when text changed from a `UITextField` with its validation result.
20 | func textDidChange(_ textField: UITextField, validationResult: ValidationResult?)
21 |
22 | /// Will call when no more `UITextField` is first responder.
23 | func didEndEditing(_ manager: TFManager)
24 | }
25 |
26 | public extension TFManagerDelegate {
27 | func focusChanged(from textField: UITextField) { }
28 | func focusChanged(to textField: UITextField) { }
29 | func textDidChange(_ textField: UITextField, validationResult: ValidationResult?) { }
30 | func didEndEditing(_ manager: TFManager) { }
31 | }
32 |
33 |
34 | /// Groups textFields together and handle their navigation.
35 | open class TFManager: NSObject {
36 |
37 |
38 | /// Use this to get notified how users are interacting with the textFields
39 | public weak var delegate: TFManagerDelegate?
40 |
41 | private var items: [UITextField] = []
42 |
43 | private lazy var prevButton: UIBarButtonItem = {
44 | let button = UIBarButtonItem()
45 | button.style = .plain
46 | button.target = self
47 | button.action = #selector(goToPreviousField)
48 | if #available(iOS 13.0, *) {
49 | button.image = UIImage(systemName: "chevron.backward")
50 | } else {
51 | button.title = "Previous"
52 | }
53 | return button
54 | }()
55 |
56 | private lazy var nextButton: UIBarButtonItem = {
57 | let button = UIBarButtonItem()
58 | button.style = .plain
59 | button.target = self
60 | if #available(iOS 13.0, *) {
61 | button.image = UIImage(systemName: "chevron.right")
62 | } else {
63 | button.title = "Next"
64 | }
65 | button.action = #selector(goToNextField)
66 | return button
67 | }()
68 |
69 | private lazy var doneButton: UIBarButtonItem = {
70 | let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneAction))
71 | return button
72 | }()
73 |
74 | private lazy var toolbar = UIToolbar()
75 | private var activeField: UITextField?
76 | private var hasToolbar: Bool = true
77 |
78 | // MARK: - Init and setup
79 |
80 | public override init() {
81 | super.init()
82 | }
83 |
84 | private func setupToolbar() {
85 | let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
86 | toolbar.setItems([prevButton, nextButton, space, doneButton], animated: false)
87 | toolbar.sizeToFit()
88 | }
89 |
90 | private func configFields() {
91 | for (index, field) in items.enumerated() {
92 | field.addTarget(self, action: #selector(fieldTextChanged(_:)), for: .editingChanged)
93 | field.addTarget(self, action: #selector(fieldBeginEditing(_:)), for: .editingDidBegin)
94 | field.addTarget(self, action: #selector(returnDidPress(_:)), for: .editingDidEndOnExit)
95 | field.addTarget(self, action: #selector(fieldEndsEditing(_:)), for: .editingDidEnd)
96 | let isLastField = index == items.count - 1
97 | field.returnKeyType = isLastField ? .done : .next
98 | }
99 | }
100 |
101 | // MARK: - Public
102 |
103 |
104 | /// Adds array of textFields in order of their appearance.
105 | /// - Parameters:
106 | /// - fields: Array of `UITextFields` or `Validable` field.
107 | /// - includesBar: Whether keyboard should have accessory bar or not.
108 | open func add(_ fields: [UITextField], includesBar: Bool = true) {
109 | items = fields
110 | hasToolbar = includesBar
111 | configFields()
112 | if hasToolbar { setupToolbar() }
113 | }
114 |
115 | // MARK: - Actions
116 |
117 | @objc
118 | private func goToNextField() {
119 | guard let activeField = activeField else { return }
120 | guard let lastField = items.last, activeField != lastField else { return }
121 | guard let activeFieldIndex = items.firstIndex(where: { $0 == activeField }) else { return }
122 | if items.indices.contains(activeFieldIndex + 1) {
123 | items[activeFieldIndex + 1].becomeFirstResponder()
124 | }
125 | }
126 |
127 | @objc
128 | private func goToPreviousField() {
129 | guard let activeField = activeField else { return }
130 | guard let firstField = items.first, activeField != firstField else { return }
131 | guard let activeFieldIndex = items.firstIndex(where: { $0 == activeField }) else { return }
132 | if items.indices.contains(activeFieldIndex - 1) {
133 | items[activeFieldIndex - 1].becomeFirstResponder()
134 | }
135 | }
136 |
137 | @objc
138 | private func doneAction() {
139 | activeField?.resignFirstResponder()
140 | delegate?.didEndEditing(self)
141 | }
142 |
143 | @objc
144 | private func fieldTextChanged(_ textField: UITextField) {
145 | delegate?.textDidChange(textField, validationResult: (textField as? ValidatableField)?.validate())
146 | }
147 |
148 | @objc
149 | private func fieldBeginEditing(_ textField: UITextField) {
150 | activeField = textField
151 | delegate?.focusChanged(to: textField)
152 | guard hasToolbar else { return }
153 | activeField?.inputAccessoryView = toolbar
154 | nextButton.isEnabled = !(textField == items.last)
155 | prevButton.isEnabled = !(textField == items.first)
156 | }
157 |
158 | @objc
159 | private func fieldEndsEditing(_ textField: UITextField) {
160 | delegate?.focusChanged(from: textField)
161 | }
162 |
163 | @objc
164 | private func returnDidPress(_ textField: UITextField) {
165 | if textField == items.last {
166 | doneAction()
167 | } else {
168 | goToNextField()
169 | }
170 | }
171 |
172 | // MARK: -
173 |
174 | /// Loop through all textFields in the manager and returns the result.
175 | /// - Returns: Array of tuples containing textFields and validation result.
176 | public func validate() -> [(textField: UITextField, result: ValidationResult)] {
177 | var validationResult = [(textField: UITextField, result: ValidationResult)]()
178 | for item in items {
179 | guard let validatableItem = item as? Validatable else { continue }
180 | let result = validatableItem.validate()
181 | if !result.isValid {
182 | validationResult.append((item, result))
183 | }
184 | }
185 | return validationResult
186 | }
187 |
188 |
189 |
190 | }
191 |
--------------------------------------------------------------------------------
/Sources/TFManager/TextRules.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationRules.swift
3 | // MyKuyaClient
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Conform to this if you want to make your own rules beside `RulesSet`
11 | public protocol TextRule {
12 |
13 | /// Message that will be returned if any `Validatable` field does not pass validation.
14 | var message: String { get set }
15 |
16 | /// Implement this for your rule logic
17 | /// - Returns: `true` if `text` is valid.
18 | func validate(_ text: String) -> Bool
19 | }
20 |
21 | /// Set of rules. You can use them in any `Validable` field.
22 | public struct TextRulesSet {
23 |
24 | /// Email validation. If you don't set `errorMessage` default error message will be returned.
25 | public static func mail(_ errorMessage: String? = nil) -> TextRule {
26 | if let message = errorMessage { return Mail(message) }
27 | else { return Mail(RulesErrorMessages.mail) }
28 | }
29 |
30 | /// Zipcode validation. If you don't set `errorMessage` default error message will be returned.
31 | public static func zipcode(_ errorMessage: String? = nil) -> TextRule {
32 | if let message = errorMessage { return ZipCode(message) }
33 | else { return ZipCode(RulesErrorMessages.zipCode) }
34 | }
35 |
36 | /// Characters count validation. If you don't set `errorMessage` default error message will be returned.
37 | public static func exactLenght(_ lenght: Int, _ errorMessage: String? = nil) -> TextRule {
38 | if let message = errorMessage { return ExactLenght(lenght: lenght, message) }
39 | else { return ExactLenght(lenght: lenght, RulesErrorMessages.exactLenght(lenght)) }
40 | }
41 |
42 | /// Minimum characters count validation. If you don't set `errorMessage` default error message will be returned.
43 | public static func minLenght(_ lenght: Int, _ errorMessage: String? = nil) -> TextRule {
44 | if let message = errorMessage { return MinLenght(minLenght: lenght, message) }
45 | else { return MinLenght(minLenght: lenght, RulesErrorMessages.minLenght(lenght)) }
46 | }
47 |
48 | /// Maximum characters count validation. If you don't set `errorMessage` default error message will be returned.
49 | public static func maxLenght(_ lenght: Int, _ errorMessage: String? = nil) -> TextRule {
50 | if let message = errorMessage { return MaxLenght(maxLenght: lenght, message) }
51 | else { return MaxLenght(maxLenght: lenght, RulesErrorMessages.maxLenght(lenght)) }
52 | }
53 |
54 | /// If text is only white spaces will not pass validation. If you don't set `errorMessage` default error message will be returned.
55 | public static func notEmpty(_ errorMessage: String? = nil) -> TextRule {
56 | if let message = errorMessage { return notEmpty(message) }
57 | else { return NotEmpty(RulesErrorMessages.notEmpty) }
58 | }
59 |
60 | /// Validates if text cotains only numbers. If you don't set `errorMessage` default error message will be returned.
61 | public static func numbersOnly(_ errorMessage: String? = nil) -> TextRule {
62 | if let message = errorMessage { return NumbersOnly(message) }
63 | else { return NumbersOnly(RulesErrorMessages.numbersOnly) }
64 | }
65 |
66 | }
67 |
68 | /// Implement this on your object and pass the regex and use `validate(_:)` for validation.
69 | public protocol RegexRuleInterface {
70 | var regex: String { get }
71 | func validate(_ text: String) -> Bool
72 | }
73 |
74 | extension RegexRuleInterface {
75 | func validate(_ text: String) -> Bool {
76 | let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
77 | return predicate.evaluate(with: text)
78 | }
79 | }
80 |
81 | fileprivate struct RulesErrorMessages {
82 | static var mail: String = "Email is not valid."
83 | static var zipCode: String = "Zipcode is not valid."
84 | static var notEmpty: String = "Space only text is not valid."
85 | static var numbersOnly: String = "You must enter only numbers."
86 | static func exactLenght(_ lenght: Int) -> String { "Must be exactly \(lenght) characters long." }
87 | static func minLenght(_ lenght: Int) -> String { "Must be at least \(lenght) characters long." }
88 | static func maxLenght(_ lenght: Int) -> String { "Must be maximum of \(lenght) characters long." }
89 | }
90 |
91 | fileprivate struct Mail: TextRule, RegexRuleInterface {
92 | var regex: String { "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" }
93 | var message: String
94 |
95 | init(_ errorMessage: String) { message = errorMessage }
96 | }
97 |
98 | fileprivate struct ZipCode: TextRule, RegexRuleInterface {
99 | var regex: String { "\\d{5}(-\\d{4})?" }
100 | var message: String
101 |
102 | init(_ errorMessage: String) { message = errorMessage }
103 | }
104 |
105 | fileprivate struct ExactLenght: TextRule {
106 | var message: String
107 | var lenght: Int
108 |
109 | init(lenght: Int, _ errorMessage: String) {
110 | self.lenght = lenght
111 | message = errorMessage
112 | }
113 |
114 | func validate(_ text: String) -> Bool {
115 | text.count == lenght
116 | }
117 | }
118 |
119 | fileprivate struct MinLenght: TextRule {
120 | var message: String
121 | var min: Int
122 |
123 | init(minLenght: Int, _ errorMessage: String) {
124 | self.min = minLenght
125 | message = errorMessage
126 | }
127 |
128 | func validate(_ text: String) -> Bool {
129 | text.count >= min
130 | }
131 | }
132 |
133 | fileprivate struct MaxLenght: TextRule {
134 | var message: String
135 | var max: Int
136 |
137 | init(maxLenght: Int, _ errorMessage: String) {
138 | self.max = maxLenght
139 | message = errorMessage
140 | }
141 |
142 | func validate(_ text: String) -> Bool {
143 | text.count <= max
144 | }
145 | }
146 |
147 |
148 | fileprivate struct NotEmpty: TextRule {
149 | var message: String
150 |
151 | init(_ errorMessage: String) {
152 | message = errorMessage
153 | }
154 |
155 | func validate(_ text: String) -> Bool {
156 | text.trimmingCharacters(in: .whitespacesAndNewlines).count > 0
157 | }
158 | }
159 |
160 | fileprivate struct NumbersOnly: TextRule {
161 | var message: String
162 |
163 | init(_ errorMessage: String) {
164 | message = errorMessage
165 | }
166 |
167 | func validate(_ text: String) -> Bool {
168 | var isValid = true
169 | text.unicodeScalars.forEach { scalar in
170 | if !CharacterSet.decimalDigits.contains(scalar) {
171 | isValid = false
172 | return
173 | }
174 | }
175 | return isValid
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/Sources/TFManager/TextRulesRepo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RulesRepo.swift
3 | // TFManager
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An object holds all rules.
11 | public class TextRulesRepo: NSObject {
12 |
13 | /// Array of rules
14 | public var rules: [TextRule] = []
15 |
16 | /// If sets to `true` it will pass validation if `text` is `nil`
17 | public var ignoreNil: Bool = false
18 |
19 | /// Add rule using this. You can use `RulesSet` for preset rules.
20 | /// - Parameter rule: Use `RulesSet` for preset or extent it for your own rules.
21 | public func add(_ rule: TextRule) {
22 | rules.append(rule)
23 | }
24 |
25 | /// Remove all rules set before using `add(_:)` method.
26 | public func removeAllRules() {
27 | rules.removeAll()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/TFManager/Validatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Validatable.swift
3 | // TFManager
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Adds validation to any object using `TextRulesSet` or any `TextRule`.
11 | public protocol Validatable: AnyObject {
12 |
13 | /// Set `TextRulesRepo()` to it.
14 | var rulesRepo: TextRulesRepo { get set }
15 |
16 | /// Return `text` that will be validated.
17 | var textToValidate: String? { get }
18 |
19 | /// Don't implement this unless you know what you're doing.
20 | /// - Returns: Result of validation
21 | func validate() -> ValidationResult
22 |
23 | /// Will call when validation fails.
24 | func validationDidFail(_ rule: TextRule)
25 |
26 | /// Will call when validation pass.
27 | func validationDidPass()
28 | }
29 |
30 | public extension Validatable {
31 | func validate() -> ValidationResult {
32 | if rulesRepo.ignoreNil && textToValidate?.isEmpty ?? true {
33 | validationDidPass()
34 | return ValidationResult(isValid: true, message: nil)
35 | }
36 | for rule in rulesRepo.rules {
37 | if !rule.validate(textToValidate!) {
38 | validationDidFail(rule)
39 | return ValidationResult(isValid: false, message: rule.message)
40 | }
41 | }
42 | validationDidPass()
43 | return ValidationResult(isValid: true, message: nil)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/TFManager/ValidatableField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidatableField.swift
3 | // MyKuyaClient
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import UIKit
9 |
10 | /// A subclass of `UITextField` supports validation.
11 | ///
12 | /// You can add rules like this:
13 | /// ```swift
14 | /// yourField.rulesRepo.add(TextRulesSet.mail)
15 | /// ```
16 | /// ---
17 | /// If you use your custom `UITextField` make sure subclass from `ValidatableField` and if you have a custom `UIControl` it should conforms to `Validatable` protocol.
18 | ///
19 | open class ValidatableField: UITextField, Validatable {
20 |
21 | /// You add or remove rules using this property. Use `RulesSet` for some default rules or add your own using `Rule` protocol.
22 | public var rulesRepo = TextRulesRepo()
23 |
24 | /// Returns `text` property of `UITextField`
25 | public var textToValidate: String? { text }
26 |
27 | /// Will call when validation pass. Override this if you want adjust the UI.
28 | open func validationDidPass() { }
29 |
30 | /// Will call when validation fails. Override this if you want adjust the UI.
31 | open func validationDidFail(_ rule: TextRule) { }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/TFManager/ValidationResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationResult.swift
3 | // TFManager
4 | //
5 | // Created by Hosein Abbaspour on 4/17/22.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Result object used in `Validatable` and `TFManager`
11 | public struct ValidationResult {
12 |
13 | /// Boolean determines whether validatoin did pass or not.
14 | public var isValid: Bool
15 |
16 | /// holds error message.
17 | public var message: String?
18 | }
19 |
--------------------------------------------------------------------------------
/TFManager.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'TFManager'
3 | s.version = '1.1.0'
4 | s.summary = 'Add validations to your text fields, Group them together and navigate through them via return button and accessory view.'
5 | s.homepage = 'https://github.com/abspr/TFManager'
6 | s.license = { :type => 'MIT', :file => 'LICENSE.md' }
7 | s.author = { 'Hosein Abbaspour' => 'hosein@me.com' }
8 | s.source = { :git => 'https://github.com/abspr/TFManager.git', :tag => s.version.to_s }
9 | s.ios.deployment_target = '11.0'
10 | s.swift_version = '5.0'
11 | s.source_files = 'Sources/TFManager/**/*'
12 | end
13 |
--------------------------------------------------------------------------------
/TFManagerDemo/Podfile:
--------------------------------------------------------------------------------
1 | # platform :ios, '11.0'
2 |
3 | target 'TFManagerDemo' do
4 | pod 'TFManager', :path => '../'
5 | end
6 |
--------------------------------------------------------------------------------
/TFManagerDemo/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - TFManager (1.0.0)
3 |
4 | DEPENDENCIES:
5 | - TFManager (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | TFManager:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | TFManager: 55ad13b1da90fd1b20a0619141b78597a1aff028
13 |
14 | PODFILE CHECKSUM: e7b52e5382700e488554835ce8f8e75061a770d4
15 |
16 | COCOAPODS: 1.11.2
17 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Headers/Public/TFManager/TFManager-umbrella.h:
--------------------------------------------------------------------------------
1 | ../../../Target Support Files/TFManager/TFManager-umbrella.h
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Headers/Public/TFManager/TFManager.modulemap:
--------------------------------------------------------------------------------
1 | ../../../Target Support Files/TFManager/TFManager.modulemap
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Local Podspecs/TFManager.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "TFManager",
3 | "version": "1.0.0",
4 | "summary": "Add validations to your text fields, Group them together and navigate through them via return button and its bar.",
5 | "homepage": "https://github.com/abspr/TFManager",
6 | "license": {
7 | "type": "MIT",
8 | "file": "LICENSE.md"
9 | },
10 | "authors": {
11 | "Hosein Abbaspour": "hosein@me.com"
12 | },
13 | "source": {
14 | "git": "https://github.com/abspr/TFManager.git",
15 | "tag": "1.0.0"
16 | },
17 | "platforms": {
18 | "ios": "11.0"
19 | },
20 | "swift_versions": "5.0",
21 | "source_files": "Sources/TFManager/**/*",
22 | "swift_version": "5.0"
23 | }
24 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - TFManager (1.0.0)
3 |
4 | DEPENDENCIES:
5 | - TFManager (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | TFManager:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | TFManager: 55ad13b1da90fd1b20a0619141b78597a1aff028
13 |
14 | PODFILE CHECKSUM: e7b52e5382700e488554835ce8f8e75061a770d4
15 |
16 | COCOAPODS: 1.11.2
17 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Pods.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2E4E1BC0FA2B16A54BE9892CD00B0189 /* Pods-TFManagerDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = DB62B4016E95F19040951C337E29B0CD /* Pods-TFManagerDemo-dummy.m */; };
11 | 3BE6A74A55EED856490FC04B3EBE7D79 /* TFManager-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 783144D7FF8526824A8F0C0344187A30 /* TFManager-dummy.m */; };
12 | 99A0010E1EA47E10C4BA60B276858626 /* Pods-TFManagerDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BAB75F19DDF145D3916826DD31904B2F /* Pods-TFManagerDemo-umbrella.h */; settings = {ATTRIBUTES = (Project, ); }; };
13 | F728198398EE72E7D208D7EBC52D453B /* TFManager-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB1782F0FD82901074E3C0BC896AB07 /* TFManager-umbrella.h */; settings = {ATTRIBUTES = (Project, ); }; };
14 | FEED888A280C1A13003CC779 /* TextRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8886280C1A13003CC779 /* TextRules.swift */; };
15 | FEED888D280C1A13003CC779 /* ValidatableField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8889280C1A13003CC779 /* ValidatableField.swift */; };
16 | FEED8893280C42A8003CC779 /* ValidationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8892280C42A8003CC779 /* ValidationResult.swift */; };
17 | FEED889A280C651D003CC779 /* TextRulesRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8898280C651D003CC779 /* TextRulesRepo.swift */; };
18 | FEED889B280C651D003CC779 /* Validatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8899280C651D003CC779 /* Validatable.swift */; };
19 | FEED889D280C6A94003CC779 /* TFManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED889C280C6A94003CC779 /* TFManager.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXContainerItemProxy section */
23 | 7EFC3569592A10DF350B01597190F899 /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = CD81A75480014BFEDC9DFC4E65A6E7F3;
28 | remoteInfo = TFManager;
29 | };
30 | /* End PBXContainerItemProxy section */
31 |
32 | /* Begin PBXFileReference section */
33 | 0B23AD29F011DD9A864681BCC078692D /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
34 | 1A86B28083A75235F332EEDA3E152644 /* TFManager-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "TFManager-prefix.pch"; sourceTree = ""; };
35 | 238CF0E6F5C6A27680C5414BD4BD3DBC /* LICENSE.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; };
36 | 23C082F039C9DFE23D7681F4DDE0E01B /* TFManager.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = TFManager.release.xcconfig; sourceTree = ""; };
37 | 2F1BF0EEE5A38CDDD4780F8CA0A417B7 /* Pods-TFManagerDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-TFManagerDemo-acknowledgements.plist"; sourceTree = ""; };
38 | 4BB1782F0FD82901074E3C0BC896AB07 /* TFManager-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "TFManager-umbrella.h"; sourceTree = ""; };
39 | 783144D7FF8526824A8F0C0344187A30 /* TFManager-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "TFManager-dummy.m"; sourceTree = ""; };
40 | 8935851A1BBEBA808373A73581C8982C /* Pods-TFManagerDemo */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "Pods-TFManagerDemo"; path = "libPods-TFManagerDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
42 | 9E1B2F49A7163041CA9EE1D4861697A7 /* TFManager.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = TFManager.modulemap; sourceTree = ""; };
43 | A462A73D57E94F85C299E1066173F374 /* Pods-TFManagerDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-TFManagerDemo.modulemap"; sourceTree = ""; };
44 | B9514A8AF6538723F3C370A67FBD05D3 /* Pods-TFManagerDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-TFManagerDemo.release.xcconfig"; sourceTree = ""; };
45 | BAB75F19DDF145D3916826DD31904B2F /* Pods-TFManagerDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-TFManagerDemo-umbrella.h"; sourceTree = ""; };
46 | BAC1E02C753EF0BF3EFAEBBCB8BA2B90 /* TFManager */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = TFManager; path = libTFManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
47 | BB344007B48900F883DB2A88EA751FE2 /* TFManager.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = TFManager.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
48 | DB62B4016E95F19040951C337E29B0CD /* Pods-TFManagerDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-TFManagerDemo-dummy.m"; sourceTree = ""; };
49 | EA0E5F5FE9090A11B99650864B7B5826 /* TFManager.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = TFManager.debug.xcconfig; sourceTree = ""; };
50 | F04B090EC8CD990ECF6998F6EBFAE897 /* Pods-TFManagerDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-TFManagerDemo.debug.xcconfig"; sourceTree = ""; };
51 | F9D7432D264BD371F5E6DC5DD81A061C /* Pods-TFManagerDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-TFManagerDemo-acknowledgements.markdown"; sourceTree = ""; };
52 | FEED8886280C1A13003CC779 /* TextRules.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextRules.swift; path = Sources/TFManager/TextRules.swift; sourceTree = ""; };
53 | FEED8889280C1A13003CC779 /* ValidatableField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ValidatableField.swift; path = Sources/TFManager/ValidatableField.swift; sourceTree = ""; };
54 | FEED8892280C42A8003CC779 /* ValidationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ValidationResult.swift; path = Sources/TFManager/ValidationResult.swift; sourceTree = ""; };
55 | FEED8898280C651D003CC779 /* TextRulesRepo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextRulesRepo.swift; path = Sources/TFManager/TextRulesRepo.swift; sourceTree = ""; };
56 | FEED8899280C651D003CC779 /* Validatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Validatable.swift; path = Sources/TFManager/Validatable.swift; sourceTree = ""; };
57 | FEED889C280C6A94003CC779 /* TFManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TFManager.swift; path = Sources/TFManager/TFManager.swift; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 2CE49C43812EE1203A87E2FDB022DB71 /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | F9904E3A0ECCF773F3D1F9D091EC0EDE /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 124D8A1E5CA26A4FC17963685B4A959B /* TFManager */ = {
79 | isa = PBXGroup;
80 | children = (
81 | FEED8889280C1A13003CC779 /* ValidatableField.swift */,
82 | FEED8886280C1A13003CC779 /* TextRules.swift */,
83 | FEED8898280C651D003CC779 /* TextRulesRepo.swift */,
84 | FEED8899280C651D003CC779 /* Validatable.swift */,
85 | FEED8892280C42A8003CC779 /* ValidationResult.swift */,
86 | FEED889C280C6A94003CC779 /* TFManager.swift */,
87 | 20D4CA4A69957CBEECA7A0C8A311B69B /* Pod */,
88 | 85375CAA6D558A5246C4E25201021A44 /* Support Files */,
89 | );
90 | name = TFManager;
91 | path = ../..;
92 | sourceTree = "";
93 | };
94 | 20D4CA4A69957CBEECA7A0C8A311B69B /* Pod */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 238CF0E6F5C6A27680C5414BD4BD3DBC /* LICENSE.md */,
98 | 0B23AD29F011DD9A864681BCC078692D /* README.md */,
99 | BB344007B48900F883DB2A88EA751FE2 /* TFManager.podspec */,
100 | );
101 | name = Pod;
102 | sourceTree = "";
103 | };
104 | 85375CAA6D558A5246C4E25201021A44 /* Support Files */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 9E1B2F49A7163041CA9EE1D4861697A7 /* TFManager.modulemap */,
108 | 783144D7FF8526824A8F0C0344187A30 /* TFManager-dummy.m */,
109 | 1A86B28083A75235F332EEDA3E152644 /* TFManager-prefix.pch */,
110 | 4BB1782F0FD82901074E3C0BC896AB07 /* TFManager-umbrella.h */,
111 | EA0E5F5FE9090A11B99650864B7B5826 /* TFManager.debug.xcconfig */,
112 | 23C082F039C9DFE23D7681F4DDE0E01B /* TFManager.release.xcconfig */,
113 | );
114 | name = "Support Files";
115 | path = "TFManagerDemo/Pods/Target Support Files/TFManager";
116 | sourceTree = "";
117 | };
118 | 956431126E9404B4A162D19EE4482FE4 /* Targets Support Files */ = {
119 | isa = PBXGroup;
120 | children = (
121 | D9FB1881AFBCFFC41657F780F485B27F /* Pods-TFManagerDemo */,
122 | );
123 | name = "Targets Support Files";
124 | sourceTree = "";
125 | };
126 | C89C0E7E224E221A0B0BDE79D6867B06 /* Products */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 8935851A1BBEBA808373A73581C8982C /* Pods-TFManagerDemo */,
130 | BAC1E02C753EF0BF3EFAEBBCB8BA2B90 /* TFManager */,
131 | );
132 | name = Products;
133 | sourceTree = "";
134 | };
135 | CF1408CF629C7361332E53B88F7BD30C = {
136 | isa = PBXGroup;
137 | children = (
138 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
139 | E431F6A4C69B86FCDEF8B4A4B1AEC85B /* Development Pods */,
140 | D89477F20FB1DE18A04690586D7808C4 /* Frameworks */,
141 | C89C0E7E224E221A0B0BDE79D6867B06 /* Products */,
142 | 956431126E9404B4A162D19EE4482FE4 /* Targets Support Files */,
143 | );
144 | sourceTree = "";
145 | };
146 | D89477F20FB1DE18A04690586D7808C4 /* Frameworks */ = {
147 | isa = PBXGroup;
148 | children = (
149 | );
150 | name = Frameworks;
151 | sourceTree = "";
152 | };
153 | D9FB1881AFBCFFC41657F780F485B27F /* Pods-TFManagerDemo */ = {
154 | isa = PBXGroup;
155 | children = (
156 | A462A73D57E94F85C299E1066173F374 /* Pods-TFManagerDemo.modulemap */,
157 | F9D7432D264BD371F5E6DC5DD81A061C /* Pods-TFManagerDemo-acknowledgements.markdown */,
158 | 2F1BF0EEE5A38CDDD4780F8CA0A417B7 /* Pods-TFManagerDemo-acknowledgements.plist */,
159 | DB62B4016E95F19040951C337E29B0CD /* Pods-TFManagerDemo-dummy.m */,
160 | BAB75F19DDF145D3916826DD31904B2F /* Pods-TFManagerDemo-umbrella.h */,
161 | F04B090EC8CD990ECF6998F6EBFAE897 /* Pods-TFManagerDemo.debug.xcconfig */,
162 | B9514A8AF6538723F3C370A67FBD05D3 /* Pods-TFManagerDemo.release.xcconfig */,
163 | );
164 | name = "Pods-TFManagerDemo";
165 | path = "Target Support Files/Pods-TFManagerDemo";
166 | sourceTree = "";
167 | };
168 | E431F6A4C69B86FCDEF8B4A4B1AEC85B /* Development Pods */ = {
169 | isa = PBXGroup;
170 | children = (
171 | 124D8A1E5CA26A4FC17963685B4A959B /* TFManager */,
172 | );
173 | name = "Development Pods";
174 | sourceTree = "";
175 | };
176 | /* End PBXGroup section */
177 |
178 | /* Begin PBXHeadersBuildPhase section */
179 | 0BB1D660B5AEB21312AB76207BD47C49 /* Headers */ = {
180 | isa = PBXHeadersBuildPhase;
181 | buildActionMask = 2147483647;
182 | files = (
183 | F728198398EE72E7D208D7EBC52D453B /* TFManager-umbrella.h in Headers */,
184 | );
185 | runOnlyForDeploymentPostprocessing = 0;
186 | };
187 | E5EFE24AA39012EDEC3379615784EEFE /* Headers */ = {
188 | isa = PBXHeadersBuildPhase;
189 | buildActionMask = 2147483647;
190 | files = (
191 | 99A0010E1EA47E10C4BA60B276858626 /* Pods-TFManagerDemo-umbrella.h in Headers */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | /* End PBXHeadersBuildPhase section */
196 |
197 | /* Begin PBXNativeTarget section */
198 | 4B7845337CCC99A5EFDE1A7FCD68657B /* Pods-TFManagerDemo */ = {
199 | isa = PBXNativeTarget;
200 | buildConfigurationList = 9A3BF051BED8F224F60D7A71BD297391 /* Build configuration list for PBXNativeTarget "Pods-TFManagerDemo" */;
201 | buildPhases = (
202 | E5EFE24AA39012EDEC3379615784EEFE /* Headers */,
203 | 6CC364AA7191348DADAD58CD03B1FB9E /* Sources */,
204 | F9904E3A0ECCF773F3D1F9D091EC0EDE /* Frameworks */,
205 | );
206 | buildRules = (
207 | );
208 | dependencies = (
209 | E672C2FE2E613CBBCB4A593BF0F82CB5 /* PBXTargetDependency */,
210 | );
211 | name = "Pods-TFManagerDemo";
212 | productName = "Pods-TFManagerDemo";
213 | productReference = 8935851A1BBEBA808373A73581C8982C /* Pods-TFManagerDemo */;
214 | productType = "com.apple.product-type.library.static";
215 | };
216 | CD81A75480014BFEDC9DFC4E65A6E7F3 /* TFManager */ = {
217 | isa = PBXNativeTarget;
218 | buildConfigurationList = 5B5492EFB9DAE9B6F311C5090CFC5FBD /* Build configuration list for PBXNativeTarget "TFManager" */;
219 | buildPhases = (
220 | 0BB1D660B5AEB21312AB76207BD47C49 /* Headers */,
221 | 57A21997667930B0551D17E0B51A8A36 /* Sources */,
222 | 2CE49C43812EE1203A87E2FDB022DB71 /* Frameworks */,
223 | 5B4CA9C8C45F5997EACDDED3BAB25C1C /* Copy generated compatibility header */,
224 | );
225 | buildRules = (
226 | );
227 | dependencies = (
228 | );
229 | name = TFManager;
230 | productName = TFManager;
231 | productReference = BAC1E02C753EF0BF3EFAEBBCB8BA2B90 /* TFManager */;
232 | productType = "com.apple.product-type.library.static";
233 | };
234 | /* End PBXNativeTarget section */
235 |
236 | /* Begin PBXProject section */
237 | BFDFE7DC352907FC980B868725387E98 /* Project object */ = {
238 | isa = PBXProject;
239 | attributes = {
240 | LastSwiftUpdateCheck = 1240;
241 | LastUpgradeCheck = 1240;
242 | };
243 | buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
244 | compatibilityVersion = "Xcode 13.0";
245 | developmentRegion = en;
246 | hasScannedForEncodings = 0;
247 | knownRegions = (
248 | Base,
249 | en,
250 | );
251 | mainGroup = CF1408CF629C7361332E53B88F7BD30C;
252 | productRefGroup = C89C0E7E224E221A0B0BDE79D6867B06 /* Products */;
253 | projectDirPath = "";
254 | projectRoot = "";
255 | targets = (
256 | 4B7845337CCC99A5EFDE1A7FCD68657B /* Pods-TFManagerDemo */,
257 | CD81A75480014BFEDC9DFC4E65A6E7F3 /* TFManager */,
258 | );
259 | };
260 | /* End PBXProject section */
261 |
262 | /* Begin PBXShellScriptBuildPhase section */
263 | 5B4CA9C8C45F5997EACDDED3BAB25C1C /* Copy generated compatibility header */ = {
264 | isa = PBXShellScriptBuildPhase;
265 | buildActionMask = 2147483647;
266 | files = (
267 | );
268 | inputFileListPaths = (
269 | );
270 | inputPaths = (
271 | "${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h",
272 | "${PODS_ROOT}/Headers/Public/TFManager/TFManager.modulemap",
273 | "${PODS_ROOT}/Headers/Public/TFManager/TFManager-umbrella.h",
274 | );
275 | name = "Copy generated compatibility header";
276 | outputFileListPaths = (
277 | );
278 | outputPaths = (
279 | "${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap",
280 | "${BUILT_PRODUCTS_DIR}/TFManager-umbrella.h",
281 | "${BUILT_PRODUCTS_DIR}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h",
282 | );
283 | runOnlyForDeploymentPostprocessing = 0;
284 | shellPath = /bin/sh;
285 | shellScript = "COMPATIBILITY_HEADER_PATH=\"${BUILT_PRODUCTS_DIR}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h\"\nMODULE_MAP_PATH=\"${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap\"\n\nditto \"${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h\" \"${COMPATIBILITY_HEADER_PATH}\"\nditto \"${PODS_ROOT}/Headers/Public/TFManager/TFManager.modulemap\" \"${MODULE_MAP_PATH}\"\nditto \"${PODS_ROOT}/Headers/Public/TFManager/TFManager-umbrella.h\" \"${BUILT_PRODUCTS_DIR}\"\nprintf \"\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\\"${COMPATIBILITY_HEADER_PATH}\\\"\\n requires objc\\n}\\n\" >> \"${MODULE_MAP_PATH}\"\n";
286 | };
287 | /* End PBXShellScriptBuildPhase section */
288 |
289 | /* Begin PBXSourcesBuildPhase section */
290 | 57A21997667930B0551D17E0B51A8A36 /* Sources */ = {
291 | isa = PBXSourcesBuildPhase;
292 | buildActionMask = 2147483647;
293 | files = (
294 | FEED888A280C1A13003CC779 /* TextRules.swift in Sources */,
295 | FEED888D280C1A13003CC779 /* ValidatableField.swift in Sources */,
296 | FEED8893280C42A8003CC779 /* ValidationResult.swift in Sources */,
297 | FEED889A280C651D003CC779 /* TextRulesRepo.swift in Sources */,
298 | FEED889B280C651D003CC779 /* Validatable.swift in Sources */,
299 | 3BE6A74A55EED856490FC04B3EBE7D79 /* TFManager-dummy.m in Sources */,
300 | FEED889D280C6A94003CC779 /* TFManager.swift in Sources */,
301 | );
302 | runOnlyForDeploymentPostprocessing = 0;
303 | };
304 | 6CC364AA7191348DADAD58CD03B1FB9E /* Sources */ = {
305 | isa = PBXSourcesBuildPhase;
306 | buildActionMask = 2147483647;
307 | files = (
308 | 2E4E1BC0FA2B16A54BE9892CD00B0189 /* Pods-TFManagerDemo-dummy.m in Sources */,
309 | );
310 | runOnlyForDeploymentPostprocessing = 0;
311 | };
312 | /* End PBXSourcesBuildPhase section */
313 |
314 | /* Begin PBXTargetDependency section */
315 | E672C2FE2E613CBBCB4A593BF0F82CB5 /* PBXTargetDependency */ = {
316 | isa = PBXTargetDependency;
317 | name = TFManager;
318 | target = CD81A75480014BFEDC9DFC4E65A6E7F3 /* TFManager */;
319 | targetProxy = 7EFC3569592A10DF350B01597190F899 /* PBXContainerItemProxy */;
320 | };
321 | /* End PBXTargetDependency section */
322 |
323 | /* Begin XCBuildConfiguration section */
324 | 659406831D93AF04D72954803296B5EF /* Release */ = {
325 | isa = XCBuildConfiguration;
326 | baseConfigurationReference = 23C082F039C9DFE23D7681F4DDE0E01B /* TFManager.release.xcconfig */;
327 | buildSettings = {
328 | CLANG_ENABLE_OBJC_WEAK = NO;
329 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
331 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
332 | GCC_PREFIX_HEADER = "Target Support Files/TFManager/TFManager-prefix.pch";
333 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
334 | MODULEMAP_FILE = Headers/Public/TFManager/TFManager.modulemap;
335 | OTHER_LDFLAGS = "";
336 | OTHER_LIBTOOLFLAGS = "";
337 | PRIVATE_HEADERS_FOLDER_PATH = "";
338 | PRODUCT_MODULE_NAME = TFManager;
339 | PRODUCT_NAME = TFManager;
340 | PUBLIC_HEADERS_FOLDER_PATH = "";
341 | SDKROOT = iphoneos;
342 | SKIP_INSTALL = YES;
343 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
344 | SWIFT_VERSION = 5.0;
345 | TARGETED_DEVICE_FAMILY = "1,2";
346 | VALIDATE_PRODUCT = YES;
347 | };
348 | name = Release;
349 | };
350 | 70FF5C2B6ED61B9672378BDFCC7CDBBE /* Debug */ = {
351 | isa = XCBuildConfiguration;
352 | baseConfigurationReference = F04B090EC8CD990ECF6998F6EBFAE897 /* Pods-TFManagerDemo.debug.xcconfig */;
353 | buildSettings = {
354 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
355 | CLANG_ENABLE_OBJC_WEAK = NO;
356 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
358 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
359 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
360 | MACH_O_TYPE = staticlib;
361 | MODULEMAP_FILE = "Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.modulemap";
362 | OTHER_LDFLAGS = "";
363 | OTHER_LIBTOOLFLAGS = "";
364 | PODS_ROOT = "$(SRCROOT)";
365 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
366 | SDKROOT = iphoneos;
367 | SKIP_INSTALL = YES;
368 | TARGETED_DEVICE_FAMILY = "1,2";
369 | };
370 | name = Debug;
371 | };
372 | 903A0004D3E6651EFD5D2E16214D101B /* Release */ = {
373 | isa = XCBuildConfiguration;
374 | buildSettings = {
375 | ALWAYS_SEARCH_USER_PATHS = NO;
376 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
377 | CLANG_ANALYZER_NONNULL = YES;
378 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
380 | CLANG_CXX_LIBRARY = "libc++";
381 | CLANG_ENABLE_MODULES = YES;
382 | CLANG_ENABLE_OBJC_ARC = YES;
383 | CLANG_ENABLE_OBJC_WEAK = YES;
384 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
385 | CLANG_WARN_BOOL_CONVERSION = YES;
386 | CLANG_WARN_COMMA = YES;
387 | CLANG_WARN_CONSTANT_CONVERSION = YES;
388 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
390 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
391 | CLANG_WARN_EMPTY_BODY = YES;
392 | CLANG_WARN_ENUM_CONVERSION = YES;
393 | CLANG_WARN_INFINITE_RECURSION = YES;
394 | CLANG_WARN_INT_CONVERSION = YES;
395 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
396 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
397 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
398 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
399 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
400 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
401 | CLANG_WARN_STRICT_PROTOTYPES = YES;
402 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
403 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
404 | CLANG_WARN_UNREACHABLE_CODE = YES;
405 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
406 | COPY_PHASE_STRIP = NO;
407 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
408 | ENABLE_NS_ASSERTIONS = NO;
409 | ENABLE_STRICT_OBJC_MSGSEND = YES;
410 | GCC_C_LANGUAGE_STANDARD = gnu11;
411 | GCC_NO_COMMON_BLOCKS = YES;
412 | GCC_PREPROCESSOR_DEFINITIONS = (
413 | "POD_CONFIGURATION_RELEASE=1",
414 | "$(inherited)",
415 | );
416 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
417 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
418 | GCC_WARN_UNDECLARED_SELECTOR = YES;
419 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
420 | GCC_WARN_UNUSED_FUNCTION = YES;
421 | GCC_WARN_UNUSED_VARIABLE = YES;
422 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
423 | MTL_ENABLE_DEBUG_INFO = NO;
424 | MTL_FAST_MATH = YES;
425 | PRODUCT_NAME = "$(TARGET_NAME)";
426 | STRIP_INSTALLED_PRODUCT = NO;
427 | SWIFT_COMPILATION_MODE = wholemodule;
428 | SWIFT_OPTIMIZATION_LEVEL = "-O";
429 | SWIFT_VERSION = 5.0;
430 | SYMROOT = "${SRCROOT}/../build";
431 | };
432 | name = Release;
433 | };
434 | B4EFE046ACF8F37157F6E322C7FCFC28 /* Debug */ = {
435 | isa = XCBuildConfiguration;
436 | buildSettings = {
437 | ALWAYS_SEARCH_USER_PATHS = NO;
438 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
439 | CLANG_ANALYZER_NONNULL = YES;
440 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
442 | CLANG_CXX_LIBRARY = "libc++";
443 | CLANG_ENABLE_MODULES = YES;
444 | CLANG_ENABLE_OBJC_ARC = YES;
445 | CLANG_ENABLE_OBJC_WEAK = YES;
446 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
447 | CLANG_WARN_BOOL_CONVERSION = YES;
448 | CLANG_WARN_COMMA = YES;
449 | CLANG_WARN_CONSTANT_CONVERSION = YES;
450 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
451 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
452 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
453 | CLANG_WARN_EMPTY_BODY = YES;
454 | CLANG_WARN_ENUM_CONVERSION = YES;
455 | CLANG_WARN_INFINITE_RECURSION = YES;
456 | CLANG_WARN_INT_CONVERSION = YES;
457 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
458 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
459 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
461 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
462 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
463 | CLANG_WARN_STRICT_PROTOTYPES = YES;
464 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
465 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
466 | CLANG_WARN_UNREACHABLE_CODE = YES;
467 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
468 | COPY_PHASE_STRIP = NO;
469 | DEBUG_INFORMATION_FORMAT = dwarf;
470 | ENABLE_STRICT_OBJC_MSGSEND = YES;
471 | ENABLE_TESTABILITY = YES;
472 | GCC_C_LANGUAGE_STANDARD = gnu11;
473 | GCC_DYNAMIC_NO_PIC = NO;
474 | GCC_NO_COMMON_BLOCKS = YES;
475 | GCC_OPTIMIZATION_LEVEL = 0;
476 | GCC_PREPROCESSOR_DEFINITIONS = (
477 | "POD_CONFIGURATION_DEBUG=1",
478 | "DEBUG=1",
479 | "$(inherited)",
480 | );
481 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
482 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
483 | GCC_WARN_UNDECLARED_SELECTOR = YES;
484 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
485 | GCC_WARN_UNUSED_FUNCTION = YES;
486 | GCC_WARN_UNUSED_VARIABLE = YES;
487 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
488 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
489 | MTL_FAST_MATH = YES;
490 | ONLY_ACTIVE_ARCH = YES;
491 | PRODUCT_NAME = "$(TARGET_NAME)";
492 | STRIP_INSTALLED_PRODUCT = NO;
493 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
494 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
495 | SWIFT_VERSION = 5.0;
496 | SYMROOT = "${SRCROOT}/../build";
497 | };
498 | name = Debug;
499 | };
500 | E494B44C036E414DB15F3B033A3E0A4C /* Release */ = {
501 | isa = XCBuildConfiguration;
502 | baseConfigurationReference = B9514A8AF6538723F3C370A67FBD05D3 /* Pods-TFManagerDemo.release.xcconfig */;
503 | buildSettings = {
504 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
505 | CLANG_ENABLE_OBJC_WEAK = NO;
506 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
507 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
508 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
509 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
510 | MACH_O_TYPE = staticlib;
511 | MODULEMAP_FILE = "Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.modulemap";
512 | OTHER_LDFLAGS = "";
513 | OTHER_LIBTOOLFLAGS = "";
514 | PODS_ROOT = "$(SRCROOT)";
515 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
516 | SDKROOT = iphoneos;
517 | SKIP_INSTALL = YES;
518 | TARGETED_DEVICE_FAMILY = "1,2";
519 | VALIDATE_PRODUCT = YES;
520 | };
521 | name = Release;
522 | };
523 | FBAD7089A6BB07D69093E449DA8F4FC3 /* Debug */ = {
524 | isa = XCBuildConfiguration;
525 | baseConfigurationReference = EA0E5F5FE9090A11B99650864B7B5826 /* TFManager.debug.xcconfig */;
526 | buildSettings = {
527 | CLANG_ENABLE_OBJC_WEAK = NO;
528 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
529 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
530 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
531 | GCC_PREFIX_HEADER = "Target Support Files/TFManager/TFManager-prefix.pch";
532 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
533 | MODULEMAP_FILE = Headers/Public/TFManager/TFManager.modulemap;
534 | OTHER_LDFLAGS = "";
535 | OTHER_LIBTOOLFLAGS = "";
536 | PRIVATE_HEADERS_FOLDER_PATH = "";
537 | PRODUCT_MODULE_NAME = TFManager;
538 | PRODUCT_NAME = TFManager;
539 | PUBLIC_HEADERS_FOLDER_PATH = "";
540 | SDKROOT = iphoneos;
541 | SKIP_INSTALL = YES;
542 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
543 | SWIFT_VERSION = 5.0;
544 | TARGETED_DEVICE_FAMILY = "1,2";
545 | };
546 | name = Debug;
547 | };
548 | /* End XCBuildConfiguration section */
549 |
550 | /* Begin XCConfigurationList section */
551 | 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
552 | isa = XCConfigurationList;
553 | buildConfigurations = (
554 | B4EFE046ACF8F37157F6E322C7FCFC28 /* Debug */,
555 | 903A0004D3E6651EFD5D2E16214D101B /* Release */,
556 | );
557 | defaultConfigurationIsVisible = 0;
558 | defaultConfigurationName = Release;
559 | };
560 | 5B5492EFB9DAE9B6F311C5090CFC5FBD /* Build configuration list for PBXNativeTarget "TFManager" */ = {
561 | isa = XCConfigurationList;
562 | buildConfigurations = (
563 | FBAD7089A6BB07D69093E449DA8F4FC3 /* Debug */,
564 | 659406831D93AF04D72954803296B5EF /* Release */,
565 | );
566 | defaultConfigurationIsVisible = 0;
567 | defaultConfigurationName = Release;
568 | };
569 | 9A3BF051BED8F224F60D7A71BD297391 /* Build configuration list for PBXNativeTarget "Pods-TFManagerDemo" */ = {
570 | isa = XCConfigurationList;
571 | buildConfigurations = (
572 | 70FF5C2B6ED61B9672378BDFCC7CDBBE /* Debug */,
573 | E494B44C036E414DB15F3B033A3E0A4C /* Release */,
574 | );
575 | defaultConfigurationIsVisible = 0;
576 | defaultConfigurationName = Release;
577 | };
578 | /* End XCConfigurationList section */
579 | };
580 | rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */;
581 | }
582 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## TFManager
5 |
6 | Copyright (c) 2022
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
23 | Generated by CocoaPods - https://cocoapods.org
24 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2022
18 | Permission is hereby granted, free of charge, to any person obtaining a copy
19 | of this software and associated documentation files (the "Software"), to deal
20 | in the Software without restriction, including without limitation the rights
21 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 | copies of the Software, and to permit persons to whom the Software is
23 | furnished to do so, subject to the following conditions:
24 | The above copyright notice and this permission notice shall be included in
25 | all copies or substantial portions of the Software.
26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 | THE SOFTWARE.
33 |
34 | License
35 | MIT
36 | Title
37 | TFManager
38 | Type
39 | PSGroupSpecifier
40 |
41 |
42 | FooterText
43 | Generated by CocoaPods - https://cocoapods.org
44 | Title
45 |
46 | Type
47 | PSGroupSpecifier
48 |
49 |
50 | StringsTable
51 | Acknowledgements
52 | Title
53 | Acknowledgements
54 |
55 |
56 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_TFManagerDemo : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_TFManagerDemo
5 | @end
6 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_TFManagerDemoVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_TFManagerDemoVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" "${PODS_CONFIGURATION_BUILD_DIR}/TFManager" /usr/lib/swift
5 | OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/TFManager/TFManager.modulemap"
6 | OTHER_LDFLAGS = $(inherited) -ObjC -l"TFManager"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/TFManager/TFManager.modulemap"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | SWIFT_INCLUDE_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TFManager"
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.modulemap:
--------------------------------------------------------------------------------
1 | module Pods_TFManagerDemo {
2 | umbrella header "Pods-TFManagerDemo-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" "${PODS_CONFIGURATION_BUILD_DIR}/TFManager" /usr/lib/swift
5 | OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/TFManager/TFManager.modulemap"
6 | OTHER_LDFLAGS = $(inherited) -ObjC -l"TFManager"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/TFManager/TFManager.modulemap"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | SWIFT_INCLUDE_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TFManager"
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_TFManager : NSObject
3 | @end
4 | @implementation PodsDummy_TFManager
5 | @end
6 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double TFManagerVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char TFManagerVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/TFManager
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -import-underlying-module -Xcc -fmodule-map-file="${SRCROOT}/${MODULEMAP_FILE}"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager.modulemap:
--------------------------------------------------------------------------------
1 | module TFManager {
2 | umbrella header "TFManager-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/TFManagerDemo/Pods/Target Support Files/TFManager/TFManager.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/TFManager
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -import-underlying-module -Xcc -fmodule-map-file="${SRCROOT}/${MODULEMAP_FILE}"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4467FBC4BFD7879C607F2372 /* libPods-TFManagerDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 90B17154B1F770548A212660 /* libPods-TFManagerDemo.a */; };
11 | FEE3EC64281575F700869C74 /* CustomValidatableField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE3EC63281575F700869C74 /* CustomValidatableField.swift */; };
12 | FEED8866280AC68B003CC779 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8865280AC68B003CC779 /* AppDelegate.swift */; };
13 | FEED886A280AC68B003CC779 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEED8869280AC68B003CC779 /* ViewController.swift */; };
14 | FEED886D280AC68B003CC779 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEED886B280AC68B003CC779 /* Main.storyboard */; };
15 | FEED886F280AC68C003CC779 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FEED886E280AC68C003CC779 /* Assets.xcassets */; };
16 | FEED8872280AC68C003CC779 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEED8870280AC68C003CC779 /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 65B12019D66E3DDA0B5D9DA9 /* Pods-TFManagerDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TFManagerDemo.debug.xcconfig"; path = "Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.debug.xcconfig"; sourceTree = ""; };
21 | 90B17154B1F770548A212660 /* libPods-TFManagerDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TFManagerDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
22 | 933BA34010181A29A6C41E45 /* Pods-TFManagerDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TFManagerDemo.release.xcconfig"; path = "Target Support Files/Pods-TFManagerDemo/Pods-TFManagerDemo.release.xcconfig"; sourceTree = ""; };
23 | FEE3EC63281575F700869C74 /* CustomValidatableField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomValidatableField.swift; sourceTree = ""; };
24 | FEED8862280AC68B003CC779 /* TFManagerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TFManagerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | FEED8865280AC68B003CC779 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
26 | FEED8869280AC68B003CC779 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | FEED886C280AC68B003CC779 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | FEED886E280AC68C003CC779 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | FEED8871280AC68C003CC779 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
30 | FEED8873280AC68C003CC779 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | FEED885F280AC68B003CC779 /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | 4467FBC4BFD7879C607F2372 /* libPods-TFManagerDemo.a in Frameworks */,
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | 447EB5A4D91C507AF4C9625D /* Frameworks */ = {
46 | isa = PBXGroup;
47 | children = (
48 | 90B17154B1F770548A212660 /* libPods-TFManagerDemo.a */,
49 | );
50 | name = Frameworks;
51 | sourceTree = "";
52 | };
53 | AA3A5136B78AB5C490EC7E9F /* Pods */ = {
54 | isa = PBXGroup;
55 | children = (
56 | 65B12019D66E3DDA0B5D9DA9 /* Pods-TFManagerDemo.debug.xcconfig */,
57 | 933BA34010181A29A6C41E45 /* Pods-TFManagerDemo.release.xcconfig */,
58 | );
59 | path = Pods;
60 | sourceTree = "";
61 | };
62 | FEED8859280AC68B003CC779 = {
63 | isa = PBXGroup;
64 | children = (
65 | FEED8864280AC68B003CC779 /* TFManagerDemo */,
66 | FEED8863280AC68B003CC779 /* Products */,
67 | AA3A5136B78AB5C490EC7E9F /* Pods */,
68 | 447EB5A4D91C507AF4C9625D /* Frameworks */,
69 | );
70 | sourceTree = "";
71 | };
72 | FEED8863280AC68B003CC779 /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | FEED8862280AC68B003CC779 /* TFManagerDemo.app */,
76 | );
77 | name = Products;
78 | sourceTree = "";
79 | };
80 | FEED8864280AC68B003CC779 /* TFManagerDemo */ = {
81 | isa = PBXGroup;
82 | children = (
83 | FEED8865280AC68B003CC779 /* AppDelegate.swift */,
84 | FEED8869280AC68B003CC779 /* ViewController.swift */,
85 | FEE3EC63281575F700869C74 /* CustomValidatableField.swift */,
86 | FEED886B280AC68B003CC779 /* Main.storyboard */,
87 | FEED886E280AC68C003CC779 /* Assets.xcassets */,
88 | FEED8870280AC68C003CC779 /* LaunchScreen.storyboard */,
89 | FEED8873280AC68C003CC779 /* Info.plist */,
90 | );
91 | path = TFManagerDemo;
92 | sourceTree = "";
93 | };
94 | /* End PBXGroup section */
95 |
96 | /* Begin PBXNativeTarget section */
97 | FEED8861280AC68B003CC779 /* TFManagerDemo */ = {
98 | isa = PBXNativeTarget;
99 | buildConfigurationList = FEED8876280AC68C003CC779 /* Build configuration list for PBXNativeTarget "TFManagerDemo" */;
100 | buildPhases = (
101 | 4F28EE05C8229C6798CC27AE /* [CP] Check Pods Manifest.lock */,
102 | FEED885E280AC68B003CC779 /* Sources */,
103 | FEED885F280AC68B003CC779 /* Frameworks */,
104 | FEED8860280AC68B003CC779 /* Resources */,
105 | );
106 | buildRules = (
107 | );
108 | dependencies = (
109 | );
110 | name = TFManagerDemo;
111 | productName = TFManagerDemo;
112 | productReference = FEED8862280AC68B003CC779 /* TFManagerDemo.app */;
113 | productType = "com.apple.product-type.application";
114 | };
115 | /* End PBXNativeTarget section */
116 |
117 | /* Begin PBXProject section */
118 | FEED885A280AC68B003CC779 /* Project object */ = {
119 | isa = PBXProject;
120 | attributes = {
121 | BuildIndependentTargetsInParallel = 1;
122 | LastSwiftUpdateCheck = 1320;
123 | LastUpgradeCheck = 1320;
124 | TargetAttributes = {
125 | FEED8861280AC68B003CC779 = {
126 | CreatedOnToolsVersion = 13.2.1;
127 | };
128 | };
129 | };
130 | buildConfigurationList = FEED885D280AC68B003CC779 /* Build configuration list for PBXProject "TFManagerDemo" */;
131 | compatibilityVersion = "Xcode 13.0";
132 | developmentRegion = en;
133 | hasScannedForEncodings = 0;
134 | knownRegions = (
135 | en,
136 | Base,
137 | );
138 | mainGroup = FEED8859280AC68B003CC779;
139 | productRefGroup = FEED8863280AC68B003CC779 /* Products */;
140 | projectDirPath = "";
141 | projectRoot = "";
142 | targets = (
143 | FEED8861280AC68B003CC779 /* TFManagerDemo */,
144 | );
145 | };
146 | /* End PBXProject section */
147 |
148 | /* Begin PBXResourcesBuildPhase section */
149 | FEED8860280AC68B003CC779 /* Resources */ = {
150 | isa = PBXResourcesBuildPhase;
151 | buildActionMask = 2147483647;
152 | files = (
153 | FEED8872280AC68C003CC779 /* LaunchScreen.storyboard in Resources */,
154 | FEED886F280AC68C003CC779 /* Assets.xcassets in Resources */,
155 | FEED886D280AC68B003CC779 /* Main.storyboard in Resources */,
156 | );
157 | runOnlyForDeploymentPostprocessing = 0;
158 | };
159 | /* End PBXResourcesBuildPhase section */
160 |
161 | /* Begin PBXShellScriptBuildPhase section */
162 | 4F28EE05C8229C6798CC27AE /* [CP] Check Pods Manifest.lock */ = {
163 | isa = PBXShellScriptBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | );
167 | inputFileListPaths = (
168 | );
169 | inputPaths = (
170 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
171 | "${PODS_ROOT}/Manifest.lock",
172 | );
173 | name = "[CP] Check Pods Manifest.lock";
174 | outputFileListPaths = (
175 | );
176 | outputPaths = (
177 | "$(DERIVED_FILE_DIR)/Pods-TFManagerDemo-checkManifestLockResult.txt",
178 | );
179 | runOnlyForDeploymentPostprocessing = 0;
180 | shellPath = /bin/sh;
181 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
182 | showEnvVarsInLog = 0;
183 | };
184 | /* End PBXShellScriptBuildPhase section */
185 |
186 | /* Begin PBXSourcesBuildPhase section */
187 | FEED885E280AC68B003CC779 /* Sources */ = {
188 | isa = PBXSourcesBuildPhase;
189 | buildActionMask = 2147483647;
190 | files = (
191 | FEED886A280AC68B003CC779 /* ViewController.swift in Sources */,
192 | FEED8866280AC68B003CC779 /* AppDelegate.swift in Sources */,
193 | FEE3EC64281575F700869C74 /* CustomValidatableField.swift in Sources */,
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | };
197 | /* End PBXSourcesBuildPhase section */
198 |
199 | /* Begin PBXVariantGroup section */
200 | FEED886B280AC68B003CC779 /* Main.storyboard */ = {
201 | isa = PBXVariantGroup;
202 | children = (
203 | FEED886C280AC68B003CC779 /* Base */,
204 | );
205 | name = Main.storyboard;
206 | sourceTree = "";
207 | };
208 | FEED8870280AC68C003CC779 /* LaunchScreen.storyboard */ = {
209 | isa = PBXVariantGroup;
210 | children = (
211 | FEED8871280AC68C003CC779 /* Base */,
212 | );
213 | name = LaunchScreen.storyboard;
214 | sourceTree = "";
215 | };
216 | /* End PBXVariantGroup section */
217 |
218 | /* Begin XCBuildConfiguration section */
219 | FEED8874280AC68C003CC779 /* Debug */ = {
220 | isa = XCBuildConfiguration;
221 | buildSettings = {
222 | ALWAYS_SEARCH_USER_PATHS = NO;
223 | CLANG_ANALYZER_NONNULL = YES;
224 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
226 | CLANG_CXX_LIBRARY = "libc++";
227 | CLANG_ENABLE_MODULES = YES;
228 | CLANG_ENABLE_OBJC_ARC = YES;
229 | CLANG_ENABLE_OBJC_WEAK = YES;
230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
231 | CLANG_WARN_BOOL_CONVERSION = YES;
232 | CLANG_WARN_COMMA = YES;
233 | CLANG_WARN_CONSTANT_CONVERSION = YES;
234 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
236 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
237 | CLANG_WARN_EMPTY_BODY = YES;
238 | CLANG_WARN_ENUM_CONVERSION = YES;
239 | CLANG_WARN_INFINITE_RECURSION = YES;
240 | CLANG_WARN_INT_CONVERSION = YES;
241 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
242 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
243 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
245 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
246 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
247 | CLANG_WARN_STRICT_PROTOTYPES = YES;
248 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
249 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
250 | CLANG_WARN_UNREACHABLE_CODE = YES;
251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
252 | COPY_PHASE_STRIP = NO;
253 | DEBUG_INFORMATION_FORMAT = dwarf;
254 | ENABLE_STRICT_OBJC_MSGSEND = YES;
255 | ENABLE_TESTABILITY = YES;
256 | GCC_C_LANGUAGE_STANDARD = gnu11;
257 | GCC_DYNAMIC_NO_PIC = NO;
258 | GCC_NO_COMMON_BLOCKS = YES;
259 | GCC_OPTIMIZATION_LEVEL = 0;
260 | GCC_PREPROCESSOR_DEFINITIONS = (
261 | "DEBUG=1",
262 | "$(inherited)",
263 | );
264 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
265 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
266 | GCC_WARN_UNDECLARED_SELECTOR = YES;
267 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
268 | GCC_WARN_UNUSED_FUNCTION = YES;
269 | GCC_WARN_UNUSED_VARIABLE = YES;
270 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
271 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
272 | MTL_FAST_MATH = YES;
273 | ONLY_ACTIVE_ARCH = YES;
274 | SDKROOT = iphoneos;
275 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
276 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
277 | };
278 | name = Debug;
279 | };
280 | FEED8875280AC68C003CC779 /* Release */ = {
281 | isa = XCBuildConfiguration;
282 | buildSettings = {
283 | ALWAYS_SEARCH_USER_PATHS = NO;
284 | CLANG_ANALYZER_NONNULL = YES;
285 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
286 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
287 | CLANG_CXX_LIBRARY = "libc++";
288 | CLANG_ENABLE_MODULES = YES;
289 | CLANG_ENABLE_OBJC_ARC = YES;
290 | CLANG_ENABLE_OBJC_WEAK = YES;
291 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
292 | CLANG_WARN_BOOL_CONVERSION = YES;
293 | CLANG_WARN_COMMA = YES;
294 | CLANG_WARN_CONSTANT_CONVERSION = YES;
295 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
296 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
297 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
298 | CLANG_WARN_EMPTY_BODY = YES;
299 | CLANG_WARN_ENUM_CONVERSION = YES;
300 | CLANG_WARN_INFINITE_RECURSION = YES;
301 | CLANG_WARN_INT_CONVERSION = YES;
302 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
303 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
304 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
305 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
306 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
308 | CLANG_WARN_STRICT_PROTOTYPES = YES;
309 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
310 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
311 | CLANG_WARN_UNREACHABLE_CODE = YES;
312 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
313 | COPY_PHASE_STRIP = NO;
314 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
315 | ENABLE_NS_ASSERTIONS = NO;
316 | ENABLE_STRICT_OBJC_MSGSEND = YES;
317 | GCC_C_LANGUAGE_STANDARD = gnu11;
318 | GCC_NO_COMMON_BLOCKS = YES;
319 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
320 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
321 | GCC_WARN_UNDECLARED_SELECTOR = YES;
322 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
323 | GCC_WARN_UNUSED_FUNCTION = YES;
324 | GCC_WARN_UNUSED_VARIABLE = YES;
325 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
326 | MTL_ENABLE_DEBUG_INFO = NO;
327 | MTL_FAST_MATH = YES;
328 | SDKROOT = iphoneos;
329 | SWIFT_COMPILATION_MODE = wholemodule;
330 | SWIFT_OPTIMIZATION_LEVEL = "-O";
331 | VALIDATE_PRODUCT = YES;
332 | };
333 | name = Release;
334 | };
335 | FEED8877280AC68C003CC779 /* Debug */ = {
336 | isa = XCBuildConfiguration;
337 | baseConfigurationReference = 65B12019D66E3DDA0B5D9DA9 /* Pods-TFManagerDemo.debug.xcconfig */;
338 | buildSettings = {
339 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
340 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
341 | CODE_SIGN_STYLE = Automatic;
342 | CURRENT_PROJECT_VERSION = 1;
343 | GENERATE_INFOPLIST_FILE = YES;
344 | INFOPLIST_FILE = TFManagerDemo/Info.plist;
345 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
346 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
347 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
348 | INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
349 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
350 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
351 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
352 | LD_RUNPATH_SEARCH_PATHS = (
353 | "$(inherited)",
354 | "@executable_path/Frameworks",
355 | );
356 | MARKETING_VERSION = 1.0;
357 | PRODUCT_BUNDLE_IDENTIFIER = com.abspr.TFManagerDemo;
358 | PRODUCT_NAME = "$(TARGET_NAME)";
359 | SWIFT_EMIT_LOC_STRINGS = YES;
360 | SWIFT_VERSION = 5.0;
361 | TARGETED_DEVICE_FAMILY = 1;
362 | };
363 | name = Debug;
364 | };
365 | FEED8878280AC68C003CC779 /* Release */ = {
366 | isa = XCBuildConfiguration;
367 | baseConfigurationReference = 933BA34010181A29A6C41E45 /* Pods-TFManagerDemo.release.xcconfig */;
368 | buildSettings = {
369 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
370 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
371 | CODE_SIGN_STYLE = Automatic;
372 | CURRENT_PROJECT_VERSION = 1;
373 | GENERATE_INFOPLIST_FILE = YES;
374 | INFOPLIST_FILE = TFManagerDemo/Info.plist;
375 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
376 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
377 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
378 | INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
379 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
380 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
381 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
382 | LD_RUNPATH_SEARCH_PATHS = (
383 | "$(inherited)",
384 | "@executable_path/Frameworks",
385 | );
386 | MARKETING_VERSION = 1.0;
387 | PRODUCT_BUNDLE_IDENTIFIER = com.abspr.TFManagerDemo;
388 | PRODUCT_NAME = "$(TARGET_NAME)";
389 | SWIFT_EMIT_LOC_STRINGS = YES;
390 | SWIFT_VERSION = 5.0;
391 | TARGETED_DEVICE_FAMILY = 1;
392 | };
393 | name = Release;
394 | };
395 | /* End XCBuildConfiguration section */
396 |
397 | /* Begin XCConfigurationList section */
398 | FEED885D280AC68B003CC779 /* Build configuration list for PBXProject "TFManagerDemo" */ = {
399 | isa = XCConfigurationList;
400 | buildConfigurations = (
401 | FEED8874280AC68C003CC779 /* Debug */,
402 | FEED8875280AC68C003CC779 /* Release */,
403 | );
404 | defaultConfigurationIsVisible = 0;
405 | defaultConfigurationName = Release;
406 | };
407 | FEED8876280AC68C003CC779 /* Build configuration list for PBXNativeTarget "TFManagerDemo" */ = {
408 | isa = XCConfigurationList;
409 | buildConfigurations = (
410 | FEED8877280AC68C003CC779 /* Debug */,
411 | FEED8878280AC68C003CC779 /* Release */,
412 | );
413 | defaultConfigurationIsVisible = 0;
414 | defaultConfigurationName = Release;
415 | };
416 | /* End XCConfigurationList section */
417 | };
418 | rootObject = FEED885A280AC68B003CC779 /* Project object */;
419 | }
420 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TFManagerDemo
4 | //
5 | // Created by Hosein Abbaspour on 4/16/22.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | return true
17 | }
18 |
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/CustomValidatableField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomValidatableField.swift
3 | // TFManagerDemo
4 | //
5 | // Created by Hosein Abbaspour on 4/24/22.
6 | //
7 |
8 | import TFManager
9 |
10 | class CustomValidatableField: ValidatableField {
11 |
12 | private lazy var errorImageView: UIImageView = {
13 | let view = UIImageView()
14 | view.tintColor = .systemRed
15 | return view
16 | }()
17 |
18 | required init?(coder: NSCoder) {
19 | super.init(coder: coder)
20 | commonInit()
21 | }
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: frame)
25 | commonInit()
26 | }
27 |
28 | private func commonInit() {
29 | rightViewMode = .always
30 | rightView = errorImageView
31 | }
32 |
33 | // from Validatable protocol:
34 |
35 | override func validationDidPass() {
36 | errorImageView.image = nil
37 | }
38 |
39 | override func validationDidFail(_ rule: TextRule) {
40 | errorImageView.image = UIImage(systemName: "exclamationmark.circle")
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TFManagerDemo/TFManagerDemo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // TFManagerDemo
4 | //
5 | // Created by Hosein Abbaspour on 4/16/22.
6 | //
7 |
8 | import UIKit
9 | import TFManager
10 |
11 | class ViewController: UITableViewController {
12 |
13 | var fieldsManager = TFManager()
14 |
15 | @IBOutlet weak var nameField: UITextField!
16 |
17 | @IBOutlet weak var mailField: ValidatableField! {
18 | didSet {
19 | mailField.rulesRepo.add(TextRulesSet.mail())
20 | }
21 | }
22 |
23 | @IBOutlet weak var ageField: CustomValidatableField! {
24 | didSet {
25 | ageField.rulesRepo.ignoreNil = true
26 | ageField.rulesRepo.add(TextRulesSet.numbersOnly())
27 | ageField.rulesRepo.add(TextRulesSet.minLenght(1))
28 | ageField.rulesRepo.add(TextRulesSet.maxLenght(2))
29 | }
30 | }
31 |
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 | fieldsManager.add([nameField, mailField, ageField])
35 | fieldsManager.delegate = self
36 | }
37 |
38 | }
39 |
40 | extension ViewController: TFManagerDelegate {
41 |
42 | func textDidChange(_ textField: UITextField, validationResult: ValidationResult?) {
43 | guard let validationResult = validationResult, textField == mailField else { return }
44 | textField.textColor = validationResult.isValid ? .label : .systemRed
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/Tests/TFManagerTests/TFManagerTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import TFManager
3 |
4 | final class TFManagerTests: XCTestCase {
5 | func testExample() throws {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(TFManager().text, "Hello, World!")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------