├── OTPFieldView
├── .DS_Store
├── OTPFieldView.h
├── Info.plist
├── OTPTextField.swift
└── OTPFieldView.swift
├── Screenshots
├── IMG_0198.PNG
├── IMG_0199.PNG
├── IMG_0200.PNG
├── IMG_0201.PNG
└── IMG_0202.PNG
├── OTPFieldView.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── vaibhavbhasin.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── vaibhavbhasin.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── OTPFieldViewTests
├── Info.plist
└── OTPFieldViewTests.swift
├── OTPFieldView.podspec
├── LICENSE
└── README.md
/OTPFieldView/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/OTPFieldView/.DS_Store
--------------------------------------------------------------------------------
/Screenshots/IMG_0198.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/Screenshots/IMG_0198.PNG
--------------------------------------------------------------------------------
/Screenshots/IMG_0199.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/Screenshots/IMG_0199.PNG
--------------------------------------------------------------------------------
/Screenshots/IMG_0200.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/Screenshots/IMG_0200.PNG
--------------------------------------------------------------------------------
/Screenshots/IMG_0201.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/Screenshots/IMG_0201.PNG
--------------------------------------------------------------------------------
/Screenshots/IMG_0202.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/Screenshots/IMG_0202.PNG
--------------------------------------------------------------------------------
/OTPFieldView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OTPFieldView.xcodeproj/project.xcworkspace/xcuserdata/vaibhavbhasin.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Root-vb/OTPFieldView/HEAD/OTPFieldView.xcodeproj/project.xcworkspace/xcuserdata/vaibhavbhasin.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/OTPFieldView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OTPFieldView/OTPFieldView.h:
--------------------------------------------------------------------------------
1 | //
2 | // OTPFieldView.h
3 | // OTPFieldView
4 | //
5 | // Created by Vaibhav Bhasin on 10/09/19.
6 | // Copyright © 2019 Vaibhav Bhasin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for OTPFieldView.
12 | FOUNDATION_EXPORT double OTPFieldViewVersionNumber;
13 |
14 | //! Project version string for OTPFieldView.
15 | FOUNDATION_EXPORT const unsigned char OTPFieldViewVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/OTPFieldView.xcodeproj/xcuserdata/vaibhavbhasin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | OTPFieldView.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | OTPFieldViewTests.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/OTPFieldViewTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OTPFieldView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.1
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OTPFieldView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 |
3 | spec.name = "OTPFieldView"
4 | spec.version = "1.0.1"
5 | spec.summary = "A CocoaPods library for One Time Password View written in Swift"
6 |
7 | spec.description = <<-DESC
8 | This library helps you create One-Time-Password view for iOS Applications
9 | DESC
10 |
11 | spec.homepage = "https://github.com/Root-vb/OTPFieldView"
12 | spec.license = { :type => "MIT", :file => "LICENSE" }
13 | spec.author = { "Vaibhav Bhasin" => "vaibhavbhasin15@gmail.com" }
14 |
15 | spec.ios.deployment_target = "10.3"
16 | spec.swift_version = "5.0"
17 |
18 | spec.source = { :git => "https://github.com/Root-vb/OTPFieldView.git", :tag => "#{spec.version}" }
19 | spec.source_files = "OTPFieldView/**/*.{h,m,swift}"
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/OTPFieldViewTests/OTPFieldViewTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OTPFieldViewTests.swift
3 | // OTPFieldViewTests
4 | //
5 | // Created by Vaibhav Bhasin on 10/09/19.
6 | // Copyright © 2019 Vaibhav Bhasin. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class OTPFieldViewTests: XCTestCase {
12 |
13 | override func setUp() {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDown() {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Vaibhav Bhasin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OTPFieldView
2 | One Time Password View for iOS. Built in Swift 5
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | ### Preview
11 |
12 | 
13 | 
14 | 
15 | 
16 | 
17 |
18 | ## Installation
19 |
20 | ### CocoaPods
21 |
22 | Add the following line to your Podfile:
23 |
24 | ```ruby
25 | pod 'OTPFieldView'
26 | ```
27 |
28 | Then run the following in the same directory as your Podfile:
29 | ```ruby
30 | pod install
31 | ```
32 |
33 | ## Usage
34 |
35 | ### Code
36 | ```swift
37 | @IBOutlet var otpTextFieldView: OTPFieldView!
38 |
39 | func setupOtpView(){
40 | self.otpTextFieldView.fieldsCount = 5
41 | self.otpTextFieldView.fieldBorderWidth = 2
42 | self.otpTextFieldView.defaultBorderColor = UIColor.black
43 | self.otpTextFieldView.filledBorderColor = UIColor.green
44 | self.otpTextFieldView.cursorColor = UIColor.red
45 | self.otpTextFieldView.displayType = .underlinedBottom
46 | self.otpTextFieldView.fieldSize = 40
47 | self.otpTextFieldView.separatorSpace = 8
48 | self.otpTextFieldView.shouldAllowIntermediateEditing = false
49 | self.otpTextFieldView.delegate = self
50 | self.otpTextFieldView.initializeUI()
51 | }
52 | ```
53 | The `becomeFirstResponderAtIndex` property sets the pinField at the specified index as the first responder.
54 | The `isContentTypeOneTimeCode` property sets the contentType of the first pinField to `.oneTimeCode` to leverage the iOS 12 feature where the passcode is directly fetched from the messages.
55 |
56 | #### Styles
57 | ```swift
58 | enum DisplayType: Int {
59 | case circular
60 | case roundedCorner
61 | case square
62 | case diamond
63 | case underlinedBottom
64 | }
65 | ```
66 |
67 | ### Delegate Methods
68 |
69 | ```swift
70 | extension OtpViewController: OTPFieldViewDelegate {
71 | func hasEnteredAllOTP(hasEnteredAll hasEntered: Bool) -> Bool {
72 | print("Has entered all OTP? \(hasEntered)")
73 | return false
74 | }
75 |
76 | func shouldBecomeFirstResponderForOTP(otpTextFieldIndex index: Int) -> Bool {
77 | return true
78 | }
79 |
80 | func enteredOTP(otp otpString: String) {
81 | print("OTPString: \(otpString)")
82 | }
83 | }
84 | ```
85 |
86 | - **hasEnteredAllOTP()**: Returns true when all text Fields are full.
87 | - **shouldBecomeFirstResponderForOTP()**: Show keyboard automatically.
88 | - **enteredOTP()**: Get entered pin.
89 |
90 | ### Properties
91 |
92 | - **.displayType**: Display type for Text Field.
93 | - **.fieldsCount**: Length of OTP.
94 | - **.otpInputType**: Input type for Text Field : numeric, alphabet, alphaNumeric.
95 |
96 | - **.fieldFont**: Font for Text Field.
97 | - **.secureEntry**: Shows • instead of text.
98 | - **.hideEnteredText**: Hides the text.
99 | - **.requireCursor**: Shows/Hides cursor.
100 | - **.cursorColor**: Color for Cursor.
101 | - **.fieldSize**: Size of Text Field.
102 | - **.separatorSpace**: Space between Text Fields.
103 | - **.fieldBorderWidth**: Border width for Text Fields.
104 | - **.shouldAllowIntermediateEditing**: Allow to edit from middle.
105 | - **.defaultBackgroundColor**: Empty text field background color.
106 | - **.filledBackgroundColor**: Filled text field background color.
107 | - **.defaultBorderColor**: Empty text field border color.
108 | - **.filledBorderColor**: Filled text field border color.
109 | - **.errorBorderColor**: Error text field border color.
110 | - **.delegate**: delegate.
111 |
112 | ## License
113 |
114 | OTPFieldView is available under the MIT license. See LICENSE for details.
115 |
--------------------------------------------------------------------------------
/OTPFieldView/OTPTextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OTPTextField.swift
3 | // OTPFieldView
4 | //
5 | // Created by Vaibhav Bhasin on 10/09/19.
6 | // Copyright © 2019 Vaibhav Bhasin. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2019 Vaibhav Bhasin
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import UIKit
32 |
33 |
34 | @objc class OTPTextField: UITextField {
35 | /// Border color info for field
36 | public var otpBorderColor: UIColor = UIColor.black
37 |
38 | /// Border width info for field
39 | public var otpBorderWidth: CGFloat = 2
40 |
41 | public var shapeLayer: CAShapeLayer!
42 |
43 | override func awakeFromNib() {
44 | super.awakeFromNib()
45 | }
46 |
47 | override init(frame: CGRect) {
48 | super.init(frame: frame)
49 | }
50 |
51 | required init?(coder aDecoder: NSCoder) {
52 | super.init(coder: aDecoder)
53 | }
54 |
55 | public func initalizeUI(forFieldType type: DisplayType) {
56 | switch type {
57 | case .circular:
58 | layer.cornerRadius = bounds.size.width / 2
59 | break
60 | case .roundedCorner:
61 | layer.cornerRadius = 4
62 | break
63 | case .square:
64 | layer.cornerRadius = 0
65 | break
66 | case .diamond:
67 | addDiamondMask()
68 | break
69 | case .underlinedBottom:
70 | addBottomView()
71 | break
72 | }
73 |
74 | // Basic UI setup
75 | if type != .diamond && type != .underlinedBottom {
76 | layer.borderColor = otpBorderColor.cgColor
77 | layer.borderWidth = otpBorderWidth
78 | }
79 |
80 | autocorrectionType = .no
81 | textAlignment = .center
82 | if #available(iOS 12.0, *) {
83 | textContentType = .oneTimeCode
84 | }
85 | }
86 |
87 | override func deleteBackward() {
88 | super.deleteBackward()
89 |
90 | _ = delegate?.textField?(self, shouldChangeCharactersIn: NSMakeRange(0, 0), replacementString: "")
91 | }
92 |
93 | // Helper function to create diamond view
94 | fileprivate func addDiamondMask() {
95 | let path = UIBezierPath()
96 | path.move(to: CGPoint(x: bounds.size.width / 2.0, y: 0))
97 | path.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height / 2.0))
98 | path.addLine(to: CGPoint(x: bounds.size.width / 2.0, y: bounds.size.height))
99 | path.addLine(to: CGPoint(x: 0, y: bounds.size.height / 2.0))
100 | path.close()
101 |
102 | let maskLayer = CAShapeLayer()
103 | maskLayer.path = path.cgPath
104 |
105 | layer.mask = maskLayer
106 |
107 | shapeLayer = CAShapeLayer()
108 | shapeLayer.path = path.cgPath
109 | shapeLayer.lineWidth = otpBorderWidth
110 | shapeLayer.fillColor = backgroundColor?.cgColor
111 | shapeLayer.strokeColor = otpBorderColor.cgColor
112 |
113 | layer.addSublayer(shapeLayer)
114 | }
115 |
116 | // Helper function to create a underlined bottom view
117 | fileprivate func addBottomView() {
118 | let path = UIBezierPath()
119 | path.move(to: CGPoint(x: 0, y: bounds.size.height))
120 | path.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
121 | path.close()
122 |
123 | shapeLayer = CAShapeLayer()
124 | shapeLayer.path = path.cgPath
125 | shapeLayer.lineWidth = otpBorderWidth
126 | shapeLayer.fillColor = backgroundColor?.cgColor
127 | shapeLayer.strokeColor = otpBorderColor.cgColor
128 |
129 | layer.addSublayer(shapeLayer)
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/OTPFieldView/OTPFieldView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OTPFieldView.swift
3 | // OTPFieldView
4 | //
5 | // Created by Vaibhav Bhasin on 10/09/19.
6 | // Copyright © 2019 Vaibhav Bhasin. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2019 Vaibhav Bhasin
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import UIKit
32 |
33 | @objc public protocol OTPFieldViewDelegate: class {
34 |
35 | func shouldBecomeFirstResponderForOTP(otpTextFieldIndex index: Int) -> Bool
36 | func enteredOTP(otp: String)
37 | func hasEnteredAllOTP(hasEnteredAll: Bool) -> Bool
38 | }
39 |
40 | @objc public enum DisplayType: Int {
41 | case circular
42 | case roundedCorner
43 | case square
44 | case diamond
45 | case underlinedBottom
46 | }
47 |
48 | /// Different input type for OTP fields.
49 | @objc public enum KeyboardType: Int {
50 | case numeric
51 | case alphabet
52 | case alphaNumeric
53 | }
54 |
55 | @objc public class OTPFieldView: UIView {
56 |
57 | /// Different display type for text fields.
58 |
59 |
60 | public var displayType: DisplayType = .circular
61 | public var fieldsCount: Int = 4
62 | public var otpInputType: KeyboardType = .numeric
63 | public var fieldFont: UIFont = UIFont.systemFont(ofSize: 20)
64 | public var secureEntry: Bool = false
65 | public var hideEnteredText: Bool = false
66 | public var requireCursor: Bool = true
67 | public var cursorColor: UIColor = UIColor.blue
68 | public var fieldSize: CGFloat = 60
69 | public var separatorSpace: CGFloat = 16
70 | public var fieldBorderWidth: CGFloat = 1
71 | public var shouldAllowIntermediateEditing: Bool = true
72 | public var defaultBackgroundColor: UIColor = UIColor.clear
73 | public var filledBackgroundColor: UIColor = UIColor.clear
74 | public var defaultBorderColor: UIColor = UIColor.gray
75 | public var filledBorderColor: UIColor = UIColor.clear
76 | public var errorBorderColor: UIColor?
77 |
78 | public weak var delegate: OTPFieldViewDelegate?
79 |
80 | fileprivate var secureEntryData = [String]()
81 |
82 | override public func awakeFromNib() {
83 | super.awakeFromNib()
84 | }
85 |
86 | public func initializeUI() {
87 | layer.masksToBounds = true
88 | layoutIfNeeded()
89 |
90 | initializeOTPFields()
91 |
92 | layoutIfNeeded()
93 |
94 | // Forcefully try to make first otp field as first responder
95 | (viewWithTag(1) as? OTPTextField)?.becomeFirstResponder()
96 | }
97 |
98 | fileprivate func initializeOTPFields() {
99 | secureEntryData.removeAll()
100 |
101 | for index in stride(from: 0, to: fieldsCount, by: 1) {
102 | let oldOtpField = viewWithTag(index + 1) as? OTPTextField
103 | oldOtpField?.removeFromSuperview()
104 |
105 | let otpField = getOTPField(forIndex: index)
106 | addSubview(otpField)
107 |
108 | secureEntryData.append("")
109 | }
110 | }
111 |
112 | fileprivate func getOTPField(forIndex index: Int) -> OTPTextField {
113 | let hasOddNumberOfFields = (fieldsCount % 2 == 1)
114 | var fieldFrame = CGRect(x: 0, y: 0, width: fieldSize, height: fieldSize)
115 |
116 | if hasOddNumberOfFields {
117 | // Calculate from middle each fields x and y values so as to align the entire view in center
118 | fieldFrame.origin.x = bounds.size.width / 2 - (CGFloat(fieldsCount / 2 - index) * (fieldSize + separatorSpace) + fieldSize / 2)
119 | }
120 | else {
121 | // Calculate from middle each fields x and y values so as to align the entire view in center
122 | fieldFrame.origin.x = bounds.size.width / 2 - (CGFloat(fieldsCount / 2 - index) * fieldSize + CGFloat(fieldsCount / 2 - index - 1) * separatorSpace + separatorSpace / 2)
123 | }
124 |
125 | fieldFrame.origin.y = (bounds.size.height - fieldSize) / 2
126 |
127 | let otpField = OTPTextField(frame: fieldFrame)
128 | otpField.delegate = self
129 | otpField.tag = index + 1
130 | otpField.font = fieldFont
131 |
132 | // Set input type for OTP fields
133 | switch otpInputType {
134 | case .numeric:
135 | otpField.keyboardType = .numberPad
136 | case .alphabet:
137 | otpField.keyboardType = .alphabet
138 | case .alphaNumeric:
139 | otpField.keyboardType = .namePhonePad
140 | }
141 |
142 | // Set the border values if needed
143 | otpField.otpBorderColor = defaultBorderColor
144 | otpField.otpBorderWidth = fieldBorderWidth
145 |
146 | if requireCursor {
147 | otpField.tintColor = cursorColor
148 | }
149 | else {
150 | otpField.tintColor = UIColor.clear
151 | }
152 |
153 | // Set the default background color when text not set
154 | otpField.backgroundColor = defaultBackgroundColor
155 |
156 | // Finally create the fields
157 | otpField.initalizeUI(forFieldType: displayType)
158 |
159 | return otpField
160 | }
161 |
162 | fileprivate func isPreviousFieldsEntered(forTextField textField: UITextField) -> Bool {
163 | var isTextFilled = true
164 | var nextOTPField: UITextField?
165 |
166 | // If intermediate editing is not allowed, then check for last filled field in forward direction.
167 | if !shouldAllowIntermediateEditing {
168 | for index in stride(from: 1, to: fieldsCount + 1, by: 1) {
169 | let tempNextOTPField = viewWithTag(index) as? UITextField
170 |
171 | if let tempNextOTPFieldText = tempNextOTPField?.text, tempNextOTPFieldText.isEmpty {
172 | nextOTPField = tempNextOTPField
173 |
174 | break
175 | }
176 | }
177 |
178 | if let nextOTPField = nextOTPField {
179 | isTextFilled = (nextOTPField == textField || (textField.tag) == (nextOTPField.tag - 1))
180 | }
181 | }
182 |
183 | return isTextFilled
184 | }
185 |
186 | // Helper function to get the OTP String entered
187 | fileprivate func calculateEnteredOTPSTring(isDeleted: Bool) {
188 | if isDeleted {
189 | _ = delegate?.hasEnteredAllOTP(hasEnteredAll: false)
190 |
191 | // Set the default enteres state for otp entry
192 | for index in stride(from: 0, to: fieldsCount, by: 1) {
193 | var otpField = viewWithTag(index + 1) as? OTPTextField
194 |
195 | if otpField == nil {
196 | otpField = getOTPField(forIndex: index)
197 | }
198 |
199 | let fieldBackgroundColor = (otpField?.text ?? "").isEmpty ? defaultBackgroundColor : filledBackgroundColor
200 | let fieldBorderColor = (otpField?.text ?? "").isEmpty ? defaultBorderColor : filledBorderColor
201 |
202 | if displayType == .diamond || displayType == .underlinedBottom {
203 | otpField?.shapeLayer.fillColor = fieldBackgroundColor.cgColor
204 | otpField?.shapeLayer.strokeColor = fieldBorderColor.cgColor
205 | } else {
206 | otpField?.backgroundColor = fieldBackgroundColor
207 | otpField?.layer.borderColor = fieldBorderColor.cgColor
208 | }
209 | }
210 | }
211 | else {
212 | var enteredOTPString = ""
213 |
214 | // Check for entered OTP
215 | for index in stride(from: 0, to: secureEntryData.count, by: 1) {
216 | if !secureEntryData[index].isEmpty {
217 | enteredOTPString.append(secureEntryData[index])
218 | }
219 | }
220 |
221 | if enteredOTPString.count == fieldsCount {
222 | delegate?.enteredOTP(otp: enteredOTPString)
223 |
224 | // Check if all OTP fields have been filled or not. Based on that call the 2 delegate methods.
225 | let isValid = delegate?.hasEnteredAllOTP(hasEnteredAll: (enteredOTPString.count == fieldsCount)) ?? false
226 |
227 | // Set the error state for invalid otp entry
228 | for index in stride(from: 0, to: fieldsCount, by: 1) {
229 | var otpField = viewWithTag(index + 1) as? OTPTextField
230 |
231 | if otpField == nil {
232 | otpField = getOTPField(forIndex: index)
233 | }
234 |
235 | if !isValid {
236 | // Set error border color if set, if not, set default border color
237 | otpField?.layer.borderColor = (errorBorderColor ?? filledBorderColor).cgColor
238 | }
239 | else {
240 | otpField?.layer.borderColor = filledBorderColor.cgColor
241 | }
242 | }
243 | }
244 | }
245 | }
246 |
247 | }
248 |
249 | extension OTPFieldView: UITextFieldDelegate {
250 | public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
251 | let shouldBeginEditing = delegate?.shouldBecomeFirstResponderForOTP(otpTextFieldIndex: (textField.tag - 1)) ?? true
252 | if shouldBeginEditing {
253 | return isPreviousFieldsEntered(forTextField: textField)
254 | }
255 |
256 | return shouldBeginEditing
257 | }
258 |
259 | public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
260 | let replacedText = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) ?? ""
261 |
262 | // Check since only alphabet keyboard is not available in iOS
263 | if !replacedText.isEmpty && otpInputType == .alphabet && replacedText.rangeOfCharacter(from: .letters) == nil {
264 | return false
265 | }
266 |
267 | if replacedText.count >= 1 {
268 | // If field has a text already, then replace the text and move to next field if present
269 | secureEntryData[textField.tag - 1] = string
270 |
271 | if hideEnteredText {
272 | textField.text = " "
273 | }
274 | else {
275 | if secureEntry {
276 | textField.text = "•"
277 | }
278 | else {
279 | textField.text = string
280 | }
281 | }
282 |
283 | if displayType == .diamond || displayType == .underlinedBottom {
284 | (textField as! OTPTextField).shapeLayer.fillColor = filledBackgroundColor.cgColor
285 | (textField as! OTPTextField).shapeLayer.strokeColor = filledBorderColor.cgColor
286 | }
287 | else {
288 | textField.backgroundColor = filledBackgroundColor
289 | textField.layer.borderColor = filledBorderColor.cgColor
290 | }
291 |
292 | let nextOTPField = viewWithTag(textField.tag + 1)
293 |
294 | if let nextOTPField = nextOTPField {
295 | nextOTPField.becomeFirstResponder()
296 | }
297 | else {
298 | textField.resignFirstResponder()
299 | }
300 |
301 | // Get the entered string
302 | calculateEnteredOTPSTring(isDeleted: false)
303 | }
304 | else {
305 | let currentText = textField.text ?? ""
306 |
307 | if textField.tag > 1 && currentText.isEmpty {
308 | if let prevOTPField = viewWithTag(textField.tag - 1) as? UITextField {
309 | deleteText(in: prevOTPField)
310 | }
311 | } else {
312 | deleteText(in: textField)
313 |
314 | if textField.tag > 1 {
315 | if let prevOTPField = viewWithTag(textField.tag - 1) as? UITextField {
316 | prevOTPField.becomeFirstResponder()
317 | }
318 | }
319 | }
320 | }
321 |
322 | return false
323 | }
324 |
325 | private func deleteText(in textField: UITextField) {
326 | // If deleting the text, then move to previous text field if present
327 | secureEntryData[textField.tag - 1] = ""
328 | textField.text = ""
329 |
330 | if displayType == .diamond || displayType == .underlinedBottom {
331 | (textField as! OTPTextField).shapeLayer.fillColor = defaultBackgroundColor.cgColor
332 | (textField as! OTPTextField).shapeLayer.strokeColor = defaultBorderColor.cgColor
333 | } else {
334 | textField.backgroundColor = defaultBackgroundColor
335 | textField.layer.borderColor = defaultBorderColor.cgColor
336 | }
337 |
338 | textField.becomeFirstResponder()
339 |
340 | // Get the entered string
341 | calculateEnteredOTPSTring(isDeleted: true)
342 | }
343 | }
344 |
--------------------------------------------------------------------------------
/OTPFieldView.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 13EDE57623278D8700B45FF6 /* OTPFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = 13EDE57423278D8700B45FF6 /* OTPFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 13EDE57D23278DC400B45FF6 /* OTPFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EDE57C23278DC400B45FF6 /* OTPFieldView.swift */; };
12 | 13EDE57F23278E9A00B45FF6 /* OTPTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EDE57E23278E9A00B45FF6 /* OTPTextField.swift */; };
13 | 13EDE5872327A8C400B45FF6 /* OTPFieldViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EDE5862327A8C400B45FF6 /* OTPFieldViewTests.swift */; };
14 | 13EDE5892327A8C400B45FF6 /* OTPFieldView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13EDE57123278D8700B45FF6 /* OTPFieldView.framework */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXContainerItemProxy section */
18 | 13EDE58A2327A8C400B45FF6 /* PBXContainerItemProxy */ = {
19 | isa = PBXContainerItemProxy;
20 | containerPortal = 13EDE56823278D8700B45FF6 /* Project object */;
21 | proxyType = 1;
22 | remoteGlobalIDString = 13EDE57023278D8700B45FF6;
23 | remoteInfo = OTPFieldView;
24 | };
25 | /* End PBXContainerItemProxy section */
26 |
27 | /* Begin PBXFileReference section */
28 | 13EDE57123278D8700B45FF6 /* OTPFieldView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OTPFieldView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29 | 13EDE57423278D8700B45FF6 /* OTPFieldView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPFieldView.h; sourceTree = ""; };
30 | 13EDE57523278D8700B45FF6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | 13EDE57C23278DC400B45FF6 /* OTPFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTPFieldView.swift; sourceTree = ""; };
32 | 13EDE57E23278E9A00B45FF6 /* OTPTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTPTextField.swift; sourceTree = ""; };
33 | 13EDE5842327A8C400B45FF6 /* OTPFieldViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OTPFieldViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 13EDE5862327A8C400B45FF6 /* OTPFieldViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTPFieldViewTests.swift; sourceTree = ""; };
35 | 13EDE5882327A8C400B45FF6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
36 | /* End PBXFileReference section */
37 |
38 | /* Begin PBXFrameworksBuildPhase section */
39 | 13EDE56E23278D8700B45FF6 /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | );
44 | runOnlyForDeploymentPostprocessing = 0;
45 | };
46 | 13EDE5812327A8C400B45FF6 /* Frameworks */ = {
47 | isa = PBXFrameworksBuildPhase;
48 | buildActionMask = 2147483647;
49 | files = (
50 | 13EDE5892327A8C400B45FF6 /* OTPFieldView.framework in Frameworks */,
51 | );
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXFrameworksBuildPhase section */
55 |
56 | /* Begin PBXGroup section */
57 | 13EDE56723278D8700B45FF6 = {
58 | isa = PBXGroup;
59 | children = (
60 | 13EDE57323278D8700B45FF6 /* OTPFieldView */,
61 | 13EDE5852327A8C400B45FF6 /* OTPFieldViewTests */,
62 | 13EDE57223278D8700B45FF6 /* Products */,
63 | );
64 | sourceTree = "";
65 | };
66 | 13EDE57223278D8700B45FF6 /* Products */ = {
67 | isa = PBXGroup;
68 | children = (
69 | 13EDE57123278D8700B45FF6 /* OTPFieldView.framework */,
70 | 13EDE5842327A8C400B45FF6 /* OTPFieldViewTests.xctest */,
71 | );
72 | name = Products;
73 | sourceTree = "";
74 | };
75 | 13EDE57323278D8700B45FF6 /* OTPFieldView */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 13EDE57423278D8700B45FF6 /* OTPFieldView.h */,
79 | 13EDE57523278D8700B45FF6 /* Info.plist */,
80 | 13EDE57C23278DC400B45FF6 /* OTPFieldView.swift */,
81 | 13EDE57E23278E9A00B45FF6 /* OTPTextField.swift */,
82 | );
83 | path = OTPFieldView;
84 | sourceTree = "";
85 | };
86 | 13EDE5852327A8C400B45FF6 /* OTPFieldViewTests */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 13EDE5862327A8C400B45FF6 /* OTPFieldViewTests.swift */,
90 | 13EDE5882327A8C400B45FF6 /* Info.plist */,
91 | );
92 | path = OTPFieldViewTests;
93 | sourceTree = "";
94 | };
95 | /* End PBXGroup section */
96 |
97 | /* Begin PBXHeadersBuildPhase section */
98 | 13EDE56C23278D8700B45FF6 /* Headers */ = {
99 | isa = PBXHeadersBuildPhase;
100 | buildActionMask = 2147483647;
101 | files = (
102 | 13EDE57623278D8700B45FF6 /* OTPFieldView.h in Headers */,
103 | );
104 | runOnlyForDeploymentPostprocessing = 0;
105 | };
106 | /* End PBXHeadersBuildPhase section */
107 |
108 | /* Begin PBXNativeTarget section */
109 | 13EDE57023278D8700B45FF6 /* OTPFieldView */ = {
110 | isa = PBXNativeTarget;
111 | buildConfigurationList = 13EDE57923278D8700B45FF6 /* Build configuration list for PBXNativeTarget "OTPFieldView" */;
112 | buildPhases = (
113 | 13EDE56C23278D8700B45FF6 /* Headers */,
114 | 13EDE56D23278D8700B45FF6 /* Sources */,
115 | 13EDE56E23278D8700B45FF6 /* Frameworks */,
116 | 13EDE56F23278D8700B45FF6 /* Resources */,
117 | );
118 | buildRules = (
119 | );
120 | dependencies = (
121 | );
122 | name = OTPFieldView;
123 | productName = OTPFieldView;
124 | productReference = 13EDE57123278D8700B45FF6 /* OTPFieldView.framework */;
125 | productType = "com.apple.product-type.framework";
126 | };
127 | 13EDE5832327A8C400B45FF6 /* OTPFieldViewTests */ = {
128 | isa = PBXNativeTarget;
129 | buildConfigurationList = 13EDE58C2327A8C400B45FF6 /* Build configuration list for PBXNativeTarget "OTPFieldViewTests" */;
130 | buildPhases = (
131 | 13EDE5802327A8C400B45FF6 /* Sources */,
132 | 13EDE5812327A8C400B45FF6 /* Frameworks */,
133 | 13EDE5822327A8C400B45FF6 /* Resources */,
134 | );
135 | buildRules = (
136 | );
137 | dependencies = (
138 | 13EDE58B2327A8C400B45FF6 /* PBXTargetDependency */,
139 | );
140 | name = OTPFieldViewTests;
141 | productName = OTPFieldViewTests;
142 | productReference = 13EDE5842327A8C400B45FF6 /* OTPFieldViewTests.xctest */;
143 | productType = "com.apple.product-type.bundle.unit-test";
144 | };
145 | /* End PBXNativeTarget section */
146 |
147 | /* Begin PBXProject section */
148 | 13EDE56823278D8700B45FF6 /* Project object */ = {
149 | isa = PBXProject;
150 | attributes = {
151 | LastSwiftUpdateCheck = 1030;
152 | LastUpgradeCheck = 1030;
153 | ORGANIZATIONNAME = "Vaibhav Bhasin";
154 | TargetAttributes = {
155 | 13EDE57023278D8700B45FF6 = {
156 | CreatedOnToolsVersion = 10.3;
157 | LastSwiftMigration = 1030;
158 | };
159 | 13EDE5832327A8C400B45FF6 = {
160 | CreatedOnToolsVersion = 10.3;
161 | };
162 | };
163 | };
164 | buildConfigurationList = 13EDE56B23278D8700B45FF6 /* Build configuration list for PBXProject "OTPFieldView" */;
165 | compatibilityVersion = "Xcode 9.3";
166 | developmentRegion = en;
167 | hasScannedForEncodings = 0;
168 | knownRegions = (
169 | en,
170 | );
171 | mainGroup = 13EDE56723278D8700B45FF6;
172 | productRefGroup = 13EDE57223278D8700B45FF6 /* Products */;
173 | projectDirPath = "";
174 | projectRoot = "";
175 | targets = (
176 | 13EDE57023278D8700B45FF6 /* OTPFieldView */,
177 | 13EDE5832327A8C400B45FF6 /* OTPFieldViewTests */,
178 | );
179 | };
180 | /* End PBXProject section */
181 |
182 | /* Begin PBXResourcesBuildPhase section */
183 | 13EDE56F23278D8700B45FF6 /* Resources */ = {
184 | isa = PBXResourcesBuildPhase;
185 | buildActionMask = 2147483647;
186 | files = (
187 | );
188 | runOnlyForDeploymentPostprocessing = 0;
189 | };
190 | 13EDE5822327A8C400B45FF6 /* Resources */ = {
191 | isa = PBXResourcesBuildPhase;
192 | buildActionMask = 2147483647;
193 | files = (
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | };
197 | /* End PBXResourcesBuildPhase section */
198 |
199 | /* Begin PBXSourcesBuildPhase section */
200 | 13EDE56D23278D8700B45FF6 /* Sources */ = {
201 | isa = PBXSourcesBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 13EDE57D23278DC400B45FF6 /* OTPFieldView.swift in Sources */,
205 | 13EDE57F23278E9A00B45FF6 /* OTPTextField.swift in Sources */,
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | 13EDE5802327A8C400B45FF6 /* Sources */ = {
210 | isa = PBXSourcesBuildPhase;
211 | buildActionMask = 2147483647;
212 | files = (
213 | 13EDE5872327A8C400B45FF6 /* OTPFieldViewTests.swift in Sources */,
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | /* End PBXSourcesBuildPhase section */
218 |
219 | /* Begin PBXTargetDependency section */
220 | 13EDE58B2327A8C400B45FF6 /* PBXTargetDependency */ = {
221 | isa = PBXTargetDependency;
222 | target = 13EDE57023278D8700B45FF6 /* OTPFieldView */;
223 | targetProxy = 13EDE58A2327A8C400B45FF6 /* PBXContainerItemProxy */;
224 | };
225 | /* End PBXTargetDependency section */
226 |
227 | /* Begin XCBuildConfiguration section */
228 | 13EDE57723278D8700B45FF6 /* Debug */ = {
229 | isa = XCBuildConfiguration;
230 | buildSettings = {
231 | ALWAYS_SEARCH_USER_PATHS = NO;
232 | CLANG_ANALYZER_NONNULL = YES;
233 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
235 | CLANG_CXX_LIBRARY = "libc++";
236 | CLANG_ENABLE_MODULES = YES;
237 | CLANG_ENABLE_OBJC_ARC = YES;
238 | CLANG_ENABLE_OBJC_WEAK = YES;
239 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
240 | CLANG_WARN_BOOL_CONVERSION = YES;
241 | CLANG_WARN_COMMA = YES;
242 | CLANG_WARN_CONSTANT_CONVERSION = YES;
243 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
244 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
245 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
246 | CLANG_WARN_EMPTY_BODY = YES;
247 | CLANG_WARN_ENUM_CONVERSION = YES;
248 | CLANG_WARN_INFINITE_RECURSION = YES;
249 | CLANG_WARN_INT_CONVERSION = YES;
250 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
251 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
252 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
253 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
254 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
255 | CLANG_WARN_STRICT_PROTOTYPES = YES;
256 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
257 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
258 | CLANG_WARN_UNREACHABLE_CODE = YES;
259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
260 | CODE_SIGN_IDENTITY = "iPhone Developer";
261 | COPY_PHASE_STRIP = NO;
262 | CURRENT_PROJECT_VERSION = 1;
263 | DEBUG_INFORMATION_FORMAT = dwarf;
264 | ENABLE_STRICT_OBJC_MSGSEND = YES;
265 | ENABLE_TESTABILITY = YES;
266 | GCC_C_LANGUAGE_STANDARD = gnu11;
267 | GCC_DYNAMIC_NO_PIC = NO;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_OPTIMIZATION_LEVEL = 0;
270 | GCC_PREPROCESSOR_DEFINITIONS = (
271 | "DEBUG=1",
272 | "$(inherited)",
273 | );
274 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
275 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
276 | GCC_WARN_UNDECLARED_SELECTOR = YES;
277 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
278 | GCC_WARN_UNUSED_FUNCTION = YES;
279 | GCC_WARN_UNUSED_VARIABLE = YES;
280 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
281 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
282 | MTL_FAST_MATH = YES;
283 | ONLY_ACTIVE_ARCH = YES;
284 | SDKROOT = iphoneos;
285 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
286 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
287 | VERSIONING_SYSTEM = "apple-generic";
288 | VERSION_INFO_PREFIX = "";
289 | };
290 | name = Debug;
291 | };
292 | 13EDE57823278D8700B45FF6 /* Release */ = {
293 | isa = XCBuildConfiguration;
294 | buildSettings = {
295 | ALWAYS_SEARCH_USER_PATHS = NO;
296 | CLANG_ANALYZER_NONNULL = YES;
297 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
298 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
299 | CLANG_CXX_LIBRARY = "libc++";
300 | CLANG_ENABLE_MODULES = YES;
301 | CLANG_ENABLE_OBJC_ARC = YES;
302 | CLANG_ENABLE_OBJC_WEAK = YES;
303 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
304 | CLANG_WARN_BOOL_CONVERSION = YES;
305 | CLANG_WARN_COMMA = YES;
306 | CLANG_WARN_CONSTANT_CONVERSION = YES;
307 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
309 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
310 | CLANG_WARN_EMPTY_BODY = YES;
311 | CLANG_WARN_ENUM_CONVERSION = YES;
312 | CLANG_WARN_INFINITE_RECURSION = YES;
313 | CLANG_WARN_INT_CONVERSION = YES;
314 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
315 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
316 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
317 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
318 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
319 | CLANG_WARN_STRICT_PROTOTYPES = YES;
320 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
321 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
322 | CLANG_WARN_UNREACHABLE_CODE = YES;
323 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
324 | CODE_SIGN_IDENTITY = "iPhone Developer";
325 | COPY_PHASE_STRIP = NO;
326 | CURRENT_PROJECT_VERSION = 1;
327 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
328 | ENABLE_NS_ASSERTIONS = NO;
329 | ENABLE_STRICT_OBJC_MSGSEND = YES;
330 | GCC_C_LANGUAGE_STANDARD = gnu11;
331 | GCC_NO_COMMON_BLOCKS = YES;
332 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
333 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
334 | GCC_WARN_UNDECLARED_SELECTOR = YES;
335 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
336 | GCC_WARN_UNUSED_FUNCTION = YES;
337 | GCC_WARN_UNUSED_VARIABLE = YES;
338 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
339 | MTL_ENABLE_DEBUG_INFO = NO;
340 | MTL_FAST_MATH = YES;
341 | SDKROOT = iphoneos;
342 | SWIFT_COMPILATION_MODE = wholemodule;
343 | SWIFT_OPTIMIZATION_LEVEL = "-O";
344 | VALIDATE_PRODUCT = YES;
345 | VERSIONING_SYSTEM = "apple-generic";
346 | VERSION_INFO_PREFIX = "";
347 | };
348 | name = Release;
349 | };
350 | 13EDE57A23278D8700B45FF6 /* Debug */ = {
351 | isa = XCBuildConfiguration;
352 | buildSettings = {
353 | CLANG_ENABLE_MODULES = YES;
354 | CODE_SIGN_IDENTITY = "";
355 | CODE_SIGN_STYLE = Automatic;
356 | DEFINES_MODULE = YES;
357 | DEVELOPMENT_TEAM = 7X5CB8QV9R;
358 | DYLIB_COMPATIBILITY_VERSION = 1;
359 | DYLIB_CURRENT_VERSION = 1;
360 | DYLIB_INSTALL_NAME_BASE = "@rpath";
361 | INFOPLIST_FILE = OTPFieldView/Info.plist;
362 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
363 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
364 | LD_RUNPATH_SEARCH_PATHS = (
365 | "$(inherited)",
366 | "@executable_path/Frameworks",
367 | "@loader_path/Frameworks",
368 | );
369 | PRODUCT_BUNDLE_IDENTIFIER = com.Vaibhav.OTPFieldView;
370 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
371 | SKIP_INSTALL = YES;
372 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
373 | SWIFT_VERSION = 5.0;
374 | TARGETED_DEVICE_FAMILY = "1,2";
375 | };
376 | name = Debug;
377 | };
378 | 13EDE57B23278D8700B45FF6 /* Release */ = {
379 | isa = XCBuildConfiguration;
380 | buildSettings = {
381 | CLANG_ENABLE_MODULES = YES;
382 | CODE_SIGN_IDENTITY = "";
383 | CODE_SIGN_STYLE = Automatic;
384 | DEFINES_MODULE = YES;
385 | DEVELOPMENT_TEAM = 7X5CB8QV9R;
386 | DYLIB_COMPATIBILITY_VERSION = 1;
387 | DYLIB_CURRENT_VERSION = 1;
388 | DYLIB_INSTALL_NAME_BASE = "@rpath";
389 | INFOPLIST_FILE = OTPFieldView/Info.plist;
390 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
391 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
392 | LD_RUNPATH_SEARCH_PATHS = (
393 | "$(inherited)",
394 | "@executable_path/Frameworks",
395 | "@loader_path/Frameworks",
396 | );
397 | PRODUCT_BUNDLE_IDENTIFIER = com.Vaibhav.OTPFieldView;
398 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
399 | SKIP_INSTALL = YES;
400 | SWIFT_VERSION = 5.0;
401 | TARGETED_DEVICE_FAMILY = "1,2";
402 | };
403 | name = Release;
404 | };
405 | 13EDE58D2327A8C400B45FF6 /* Debug */ = {
406 | isa = XCBuildConfiguration;
407 | buildSettings = {
408 | CODE_SIGN_STYLE = Automatic;
409 | DEVELOPMENT_TEAM = 7X5CB8QV9R;
410 | INFOPLIST_FILE = OTPFieldViewTests/Info.plist;
411 | LD_RUNPATH_SEARCH_PATHS = (
412 | "$(inherited)",
413 | "@executable_path/Frameworks",
414 | "@loader_path/Frameworks",
415 | );
416 | PRODUCT_BUNDLE_IDENTIFIER = com.Vaibhav.OTPFieldViewTests;
417 | PRODUCT_NAME = "$(TARGET_NAME)";
418 | SWIFT_VERSION = 5.0;
419 | TARGETED_DEVICE_FAMILY = "1,2";
420 | };
421 | name = Debug;
422 | };
423 | 13EDE58E2327A8C400B45FF6 /* Release */ = {
424 | isa = XCBuildConfiguration;
425 | buildSettings = {
426 | CODE_SIGN_STYLE = Automatic;
427 | DEVELOPMENT_TEAM = 7X5CB8QV9R;
428 | INFOPLIST_FILE = OTPFieldViewTests/Info.plist;
429 | LD_RUNPATH_SEARCH_PATHS = (
430 | "$(inherited)",
431 | "@executable_path/Frameworks",
432 | "@loader_path/Frameworks",
433 | );
434 | PRODUCT_BUNDLE_IDENTIFIER = com.Vaibhav.OTPFieldViewTests;
435 | PRODUCT_NAME = "$(TARGET_NAME)";
436 | SWIFT_VERSION = 5.0;
437 | TARGETED_DEVICE_FAMILY = "1,2";
438 | };
439 | name = Release;
440 | };
441 | /* End XCBuildConfiguration section */
442 |
443 | /* Begin XCConfigurationList section */
444 | 13EDE56B23278D8700B45FF6 /* Build configuration list for PBXProject "OTPFieldView" */ = {
445 | isa = XCConfigurationList;
446 | buildConfigurations = (
447 | 13EDE57723278D8700B45FF6 /* Debug */,
448 | 13EDE57823278D8700B45FF6 /* Release */,
449 | );
450 | defaultConfigurationIsVisible = 0;
451 | defaultConfigurationName = Release;
452 | };
453 | 13EDE57923278D8700B45FF6 /* Build configuration list for PBXNativeTarget "OTPFieldView" */ = {
454 | isa = XCConfigurationList;
455 | buildConfigurations = (
456 | 13EDE57A23278D8700B45FF6 /* Debug */,
457 | 13EDE57B23278D8700B45FF6 /* Release */,
458 | );
459 | defaultConfigurationIsVisible = 0;
460 | defaultConfigurationName = Release;
461 | };
462 | 13EDE58C2327A8C400B45FF6 /* Build configuration list for PBXNativeTarget "OTPFieldViewTests" */ = {
463 | isa = XCConfigurationList;
464 | buildConfigurations = (
465 | 13EDE58D2327A8C400B45FF6 /* Debug */,
466 | 13EDE58E2327A8C400B45FF6 /* Release */,
467 | );
468 | defaultConfigurationIsVisible = 0;
469 | defaultConfigurationName = Release;
470 | };
471 | /* End XCConfigurationList section */
472 | };
473 | rootObject = 13EDE56823278D8700B45FF6 /* Project object */;
474 | }
475 |
--------------------------------------------------------------------------------