) -> Self {
310 | var config = self
311 | config.inputAccessoryViewContent = content
312 | return config
313 | }
314 | }
315 |
316 | // extra configuration
317 | public extension UIKitTextField.Configuration {
318 | func configure(handler: @escaping (_ uiTextField: UITextFieldType) -> Void) -> Self {
319 | var config = self
320 | config.configureHandler = handler
321 | return config
322 | }
323 | }
324 |
325 | #endif
326 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | # uikit-textfield
11 |
12 | `uikit-textfield` offers `UIKitTextField` which makes using `UITextField` in SwiftUI a breeze.
13 |
14 | From data binding, focus binding, handling callbacks from `UITextFieldDelegate`,
15 | custom `UITextField` subclass, horizontal/vertical stretching, `inputView`/`inputAccessoryView`,
16 | to extra configuration, `UIKitTextField` is the complete solution.
17 |
18 | - [Installation](#installation)
19 | - [Usage](#usage)
20 | - [Data Binding](#data-binding)
21 | - [Text](#text)
22 | - [Formatted Value](#formatted-value)
23 | - [Custom Data Binding](#custom-data-binding)
24 | - [Placeholder](#placeholder)
25 | - [Font](#font)
26 | - [Text Color](#text-color)
27 | - [Clear on Begin Editing](#clear-on-begin-editing)
28 | - [Clear on Insertion](#clear-on-insertion)
29 | - [Clear Button Mode](#clear-button-mode)
30 | - [Focus Binding](#focus-binding)
31 | - [Bool](#bool)
32 | - [Hashable](#hashable)
33 | - [Stretching](#stretching)
34 | - [Input View / Input Accessory View](#input-view--input-accessory-view)
35 | - [Custom Text Field Class](#custom-text-field-class)
36 | - [Extra Configuration](#extra-configuration)
37 | - [UITextFieldDelegate](#uitextfielddelegate)
38 | - [UITextInputTraits](#uitextinputtraits)
39 | - [Examples](#examples)
40 | - [Additional Notes](#additional-notes)
41 |
42 |
43 | ## Installation
44 |
45 | To install through Xcode, follow the [official guide](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) to add the following your Xcode project
46 | ```
47 | https://github.com/vinceplusplus/uikit-textfield.git
48 | ```
49 |
50 | To install through Swift Package Manager, add the following as package dependency and target dependency respectively
51 | ```
52 | .package(url: "https://github.com/vinceplusplus/uikit-textfield.git", from: "2.0")
53 | ```
54 | ```
55 | .product(name: "UIKitTextField", package: "uikit-textfield")
56 | ```
57 |
58 | ## Usage
59 |
60 | All configurations are done using `UIKitTextField.Configuration` and are in turn passed to
61 | `UIKitTextField`'s `.init(config: )`
62 |
63 | ### Data binding
64 |
65 | #### Text
66 |
67 | ```swift
68 | func value(text: Binding) -> Self
69 | ```
70 |
71 | ```swift
72 | @State var name: String = ""
73 |
74 | var body: some View {
75 | VStack(alignment: .leading) {
76 | UIKitTextField(
77 | config: .init()
78 | .value(text: $name)
79 | )
80 | .border(Color.black)
81 | Text("\(name.isEmpty ? "Please enter your name above" : "Hello \(name)")")
82 | }
83 | .padding()
84 | }
85 | ```
86 |
87 |
88 |
89 | #### Formatted value
90 |
91 | ```swift
92 | @available(iOS 15.0, *)
93 | func value(value: Binding, format: F) -> Self
94 | where
95 | F: ParseableFormatStyle,
96 | F.FormatOutput == String
97 |
98 | @available(iOS 15.0, *)
99 | func value(value: Binding, format: F) -> Self
100 | where
101 | F: ParseableFormatStyle,
102 | F.FormatOutput == String
103 |
104 | func value(value: Binding, formatter: Formatter) -> Self
105 |
106 | func value(value: Binding, formatter: Formatter) -> Self
107 | ```
108 |
109 | When the text field is not the first responder, it will take value from the binding and display in the specified formatted way
110 |
111 | When the text field is the first responder, every change will try to update the binding. If it's a binding of a non optional value,
112 | an invalid input will preserve the last value. If it's a binding of an optional value, an invalid input will set the value to `nil`.
113 |
114 | ```swift
115 | @State var value: Int = 0
116 |
117 | // ...
118 |
119 | Text("Enter a number:")
120 |
121 | UIKitTextField(
122 | config: .init()
123 | .value(value: $value, format: .number)
124 | //.value(value: $value, formatter: NumberFormatter())
125 | )
126 | .border(Color.black)
127 |
128 | // NOTE: avoiding the formatting behavior which comes from Text()
129 | Text("Your input: \("\(value)")")
130 | ```
131 |
132 |
133 |
134 | #### Custom Data Binding
135 |
136 | ```swift
137 | func value(
138 | updateViewValue: @escaping (_ textField: UITextFieldType) -> Void,
139 | onViewValueChanged: @escaping (_ textField: UITextFieldType) -> Void
140 | ) -> Self
141 | ```
142 |
143 | ### Placeholder
144 |
145 | ```swift
146 | func placeholder(_ placeholder: String?) -> Self
147 | ```
148 |
149 | ```swift
150 | UIKitTextField(
151 | config: .init()
152 | .placeholder("some placeholder...")
153 | )
154 | ```
155 |
156 | ### Font
157 |
158 | ```swift
159 | func font(_ font: UIFont?) -> Self
160 | ```
161 |
162 | Note that since there are no ways to convert back from a `Font` to `UIFont`, the configuration
163 | can only take a `UIFont`
164 |
165 | ```swift
166 | UIKitTextField(
167 | config: .init()
168 | .font(.systemFont(ofSize: 16))
169 | )
170 | ```
171 |
172 | ### Text Color
173 |
174 | ```swift
175 | func textColor(_ color: Color?) -> Self
176 | ```
177 |
178 | ```swift
179 | UIKitTextField(
180 | config: .init()
181 | .textColor(.red)
182 | )
183 | ```
184 |
185 | ### Text Alignment
186 |
187 | ```swift
188 | func textAlignment(_ textAlignment: NSTextAlignment?) -> Self
189 | ```
190 |
191 | ```swift
192 | UIKitTextField(
193 | config: .init()
194 | .textAlignment(.center)
195 | )
196 | ```
197 |
198 | ### Clear on Begin Editing
199 |
200 | ```swift
201 | func clearsOnBeginEditing(_ clearsOnBeginEditing: Bool?) -> Self
202 | ```
203 |
204 | ```swift
205 | UIKitTextField(
206 | config: .init()
207 | .clearsOnBeginEditing(true)
208 | )
209 | ```
210 |
211 | ### Clear on Insertion
212 |
213 | ```swift
214 | func clearsOnInsertion(_ clearsOnInsertion: Bool?) -> Self
215 | ```
216 |
217 | ```swift
218 | UIKitTextField(
219 | config: .init()
220 | .clearsOnInsertion(true)
221 | )
222 | ```
223 |
224 | ### Clear Button Mode
225 |
226 | ```swift
227 | func clearButtonMode(_ clearButtonMode: UITextField.ViewMode?) -> Self
228 | ```
229 |
230 | ```swift
231 | UIKitTextField(
232 | config: .init()
233 | .clearButtonMode(.always)
234 | )
235 | ```
236 |
237 | ### Focus Binding
238 |
239 | Similar to `@FocusState`, we could use an orindary `@State` to do a 2 way focus binding
240 |
241 | #### Bool
242 |
243 | ```swift
244 | func focused(_ binding: Binding) -> Self
245 | ```
246 |
247 | ```swift
248 | @State var name = ""
249 | @State var isFocused = false
250 |
251 | VStack {
252 | Text("Your name:")
253 | UIKitTextField(
254 | config: .init()
255 | .value(text: $name)
256 | .focused($isFocused)
257 | )
258 | Button {
259 | if name.isEmpty {
260 | isFocused = true
261 | } else {
262 | isFocused = false
263 | }
264 | } label: {
265 | Text("Submit")
266 | }
267 | }
268 | ```
269 |
270 | #### Hashable
271 |
272 | ```swift
273 | func focused(_ binding: Binding, equals value: Value?) -> Self where Value: Hashable
274 | ```
275 |
276 | ```swift
277 | enum Field {
278 | case firstName
279 | case lastName
280 | }
281 |
282 | @State var firstName = ""
283 | @State var lastName = ""
284 | @State var focusedField: Field?
285 |
286 | VStack {
287 | Text("First Name:")
288 | UIKitTextField(
289 | config: .init()
290 | .value(text: $firstName)
291 | .focused(focusedField, equals: .firstName)
292 | )
293 | Text("Last Name:")
294 | UIKitTextField(
295 | config: .init()
296 | .value(text: $lastName)
297 | .focused(focusedField, equals: .lastName)
298 | )
299 | Button {
300 | if firstName.isEmpty {
301 | focusedField = .firstName
302 | } else if lastName.isEmpty {
303 | focusedField = .lastName
304 | } else {
305 | focusedField = nil
306 | }
307 | } label: {
308 | Text("Submit")
309 | }
310 | }
311 | ```
312 |
313 | ### Stretching
314 |
315 | By default, `UIKitTextField` will stretch horizontally but not vertically
316 |
317 | ```swift
318 | func stretches(horizontal: Bool, vertical: Bool) -> Self
319 | ```
320 |
321 | ```swift
322 | UIKitTextField(
323 | config: .init {
324 | PaddedTextField()
325 | }
326 | .stretches(horizontal: true, vertical: false)
327 | )
328 | .border(Color.black)
329 | ```
330 |
331 | Note that `PaddedTextField` is just a simple internally padded `UITextField`, see more in custom init
332 |
333 |
334 |
335 | ```swift
336 | UIKitTextField(
337 | config: .init {
338 | PaddedTextField()
339 | }
340 | .stretches(horizontal: false, vertical: false)
341 | )
342 | .border(Color.black)
343 | ```
344 |
345 |
346 |
347 | ### Input View / Input Accessory View
348 |
349 | Supporting `UITextField.inputView` and `UITextField.inputAccessoryView` by accepting a user defined `SwiftUI` view for each of them
350 |
351 | ```swift
352 | func inputView(content: InputViewContent) -> Self
353 |
354 | func inputAccessoryView(content: InputViewContent) -> Self
355 | ```
356 |
357 | ```swift
358 | VStack(alignment: .leading) {
359 | UIKitTextField(
360 | config: .init {
361 | PaddedTextField()
362 | }
363 | .placeholder("Enter your expression")
364 | .value(text: $expression)
365 | .focused($isFocused)
366 | .inputView(content: .view { uiTextField in
367 | KeyPad(uiTextField: uiTextField, onEvaluate: onEvaluate)
368 | })
369 | .shouldReturn { _ in
370 | onEvaluate()
371 | return false
372 | }
373 | )
374 | .padding(4)
375 | .border(Color.black)
376 |
377 | Text("Result: \(result)")
378 |
379 | Divider()
380 |
381 | Button {
382 | isFocused = false
383 | } label: {
384 | Text("Dismiss")
385 | }
386 | }
387 | .padding()
388 | ```
389 |
390 | Implementation of `KeyPad` can be found in `InputViewPage` from the example code. But the idea is to accept a `UITextField`
391 | parameter and render some buttons that do `uiTextField.insertText("...")` or `uiTextField.deleteBackward()`, like the
392 | following:
393 |
394 | ```swift
395 | struct CustomKeyboard: View {
396 | let uiTextField: UITextField
397 | var body: some View {
398 | VStack {
399 | HStack {
400 | Button {
401 | uiTextField.insertText("1")
402 | } label: {
403 | Text("1")
404 | }
405 | Button {
406 | uiTextField.insertText("2")
407 | } label: {
408 | Text("2")
409 | }
410 | Button {
411 | uiTextField.insertText("3")
412 | } label: {
413 | Text("3")
414 | }
415 | }
416 | HStack { /* ... */ }
417 | // ...
418 | }
419 | }
420 | }
421 | ```
422 |
423 |
424 |
425 | ### Custom Text Field Class
426 |
427 | ```swift
428 | init(_ makeUITextField: @escaping () -> UITextFieldType)
429 | ```
430 |
431 | A common use case of a `UITextField` subclass is to provide some internal padding which is also tappable. The following
432 | example demonstrates some extra leading padding to accomodate even an icon image
433 |
434 | ```swift
435 | class CustomTextField: BaseUITextField {
436 | let padding = UIEdgeInsets(top: 4, left: 8 + 32 + 8, bottom: 4, right: 8)
437 | public override func textRect(forBounds bounds: CGRect) -> CGRect {
438 | super.textRect(forBounds: bounds).inset(by: padding)
439 | }
440 | public override func editingRect(forBounds bounds: CGRect) -> CGRect {
441 | super.editingRect(forBounds: bounds).inset(by: padding)
442 | }
443 | }
444 |
445 | UIKitTextField(
446 | config: .init {
447 | CustomTextField()
448 | }
449 | .focused($isFocused)
450 | .textContentType(.emailAddress)
451 | .keyboardType(.emailAddress)
452 | .autocapitalizationType(UITextAutocapitalizationType.none)
453 | .autocorrectionType(.no)
454 | )
455 | .background(alignment: .leading) {
456 | HStack(spacing: 0) {
457 | Color.clear.frame(width: 8)
458 | ZStack {
459 | Image(systemName: "mail")
460 | }
461 | .frame(width: 32)
462 | }
463 | }
464 | .border(Color.black)
465 | ```
466 |
467 |
468 |
469 | `UITextFieldType` needs to conform to `UITextFieldProtocol` which is shown below:
470 |
471 | ```swift
472 | public protocol UITextFieldProtocol: UITextField {
473 | var inputViewController: UIInputViewController? { get set }
474 | var inputAccessoryViewController: UIInputViewController? { get set }
475 | }
476 | ```
477 |
478 | Basically, it needs have `inputViewController` and `inputAccessoryViewController` writable so the support
479 | for custom input view and custom input accessory view will work
480 |
481 | For most use cases, `BaseUITextField`, which provides baseline implementation of `UITextFieldProtocol`,
482 | can be subclassed to add more user defined behavior
483 |
484 | ### Extra Configuration
485 |
486 | ```swift
487 | func configure(handler: @escaping (_ uiTextField: UITextFieldType) -> Void) -> Self
488 | ```
489 |
490 | If there are configurations that `UIKitTextField` doesn't support out of the box, this is the place where we could add them.
491 | The extra configuration will be executed at the end of `updateUIView()` after applying all supported configuration (like data binding, etc)
492 |
493 | ```swift
494 | class PaddedTextField: BaseUITextField {
495 | var padding = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8) {
496 | didSet {
497 | setNeedsLayout()
498 | }
499 | }
500 |
501 | public override func textRect(forBounds bounds: CGRect) -> CGRect {
502 | super.textRect(forBounds: bounds).inset(by: padding)
503 | }
504 |
505 | public override func editingRect(forBounds bounds: CGRect) -> CGRect {
506 | super.editingRect(forBounds: bounds).inset(by: padding)
507 | }
508 | }
509 |
510 | @State var text = "some text..."
511 | @State var pads = true
512 |
513 | var body: some View {
514 | VStack {
515 | Toggle("Padding", isOn: $pads)
516 | UIKitTextField(
517 | config: .init {
518 | PaddedTextField()
519 | }
520 | .value(text: $text)
521 | .configure { uiTextField in
522 | uiTextField.padding = pads ? .init(top: 4, left: 8, bottom: 4, right: 8) : .zero
523 | }
524 | )
525 | .border(Color.black)
526 | }
527 | .padding()
528 | }
529 | ```
530 |
531 | The above example provides a button to toggle internal padding
532 |
533 |
534 |
535 |
536 | ### UITextFieldDelegate
537 |
538 | `UITextFieldDelegate` is fully supported
539 |
540 | ```swift
541 | func shouldBeginEditing(handler: @escaping (_ uiTextField: UITextFieldType) -> Bool) -> Self
542 |
543 | func onBeganEditing(handler: @escaping (_ uiTextField: UITextFieldType) -> Void) -> Self
544 |
545 | func shouldEndEditing(handler: @escaping (_ uiTextField: UITextFieldType) -> Bool) -> Self
546 |
547 | func onEndedEditing(handler: @escaping (_ uiTextField: UITextFieldType, _ reason: UITextField.DidEndEditingReason) -> Void) -> Self
548 |
549 | func shouldChangeCharacters(handler: @escaping (_ uiTextField: UITextFieldType, _ range: NSRange, _ replacementString: String) -> Bool) -> Self
550 |
551 | func onChangedSelection(handler: @escaping (_ uiTextField: UITextFieldType) -> Void) -> Self
552 |
553 | func shouldClear(handler: @escaping (_ uiTextField: UITextFieldType) -> Bool) -> Self
554 |
555 | func shouldReturn(handler: @escaping (_ uiTextField: UITextFieldType) -> Bool) -> Self
556 | ```
557 |
558 | ### UITextInputTraits
559 |
560 | Most of the commonly used parts of `UITextInputTraits` are supported
561 |
562 | ```swift
563 | func keyboardType(_ keyboardType: UIKeyboardType?) -> Self
564 |
565 | func keyboardAppearance(_ keyboardAppearance: UIKeyboardAppearance?) -> Self
566 |
567 | func returnKeyType(_ returnKeyType: UIReturnKeyType?) -> Self
568 |
569 | func textContentType(_ textContentType: UITextContentType?) -> Self
570 |
571 | func isSecureTextEntry(_ isSecureTextEntry: Bool?) -> Self
572 |
573 | func enablesReturnKeyAutomatically(_ enablesReturnKeyAutomatically: Bool?) -> Self
574 |
575 | func autocapitalizationType(_ autocapitalizationType: UITextAutocapitalizationType?) -> Self
576 |
577 | func autocorrectionType(_ autocorrectionType: UITextAutocorrectionType?) -> Self
578 |
579 | func spellCheckingType(_ spellCheckingType: UITextSpellCheckingType?) -> Self
580 |
581 | func smartQuotesType(_ smartQuotesType: UITextSmartQuotesType?) -> Self
582 |
583 | func smartDashesType(_ smartDashesType: UITextSmartDashesType?) -> Self
584 |
585 | func smartInsertDeleteType(_ smartInsertDeleteType: UITextSmartInsertDeleteType?) -> Self
586 | ```
587 |
588 | ## Examples
589 |
590 | `Examples/Example` is an example app that demonstrate how to use `UIKitTextField`
591 |
592 | ## Additional Notes
593 |
594 | `UITextField.isEnabled` is actually supported by the vanilla `.disabled(/* ... */)` which might not be very obvious
595 |
--------------------------------------------------------------------------------
/Tests/UIKitTextFieldTests/UIKitTextFieldTests.swift:
--------------------------------------------------------------------------------
1 | #if canImport(UIKit)
2 |
3 | import XCTest
4 | import SwiftUI
5 | @testable import UIKitTextField
6 | import ViewInspector
7 | import SnapshotTesting
8 |
9 | extension UIKitTextField: Inspectable {}
10 |
11 | final class UIKitTextFieldTests: XCTestCase {
12 | func testTextBinding() throws {
13 | class ViewModel: ObservableObject {
14 | @Published var text: String = "1234"
15 | }
16 | struct ContentView: View, Inspectable {
17 | @ObservedObject var viewModel: ViewModel
18 | var body: some View {
19 | UIKitTextField(
20 | config: .init()
21 | .value(text: $viewModel.text)
22 | )
23 | }
24 | }
25 |
26 | let viewModel = ViewModel()
27 | let view = ContentView(viewModel: viewModel)
28 | ViewHosting.host(view: view)
29 | defer {
30 | ViewHosting.expel()
31 | }
32 |
33 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
34 | XCTAssertEqual(textField.text, "1234")
35 |
36 | viewModel.text = "12345"
37 | wait(for: 0.1)
38 | XCTAssertEqual(textField.text, "12345")
39 |
40 | textField.becomeFirstResponder()
41 | textField.insertText("6")
42 | wait(for: 0.1)
43 | XCTAssertEqual(viewModel.text, "123456")
44 |
45 | textField.deleteBackward()
46 | wait(for: 0.1)
47 | XCTAssertEqual(viewModel.text, "12345")
48 | }
49 |
50 | @available(iOS 15.0, *)
51 | func testFormatBinding() throws {
52 | class ViewModel: ObservableObject {
53 | @Published var value: Double = 123
54 | }
55 | struct ContentView: View, Inspectable {
56 | @ObservedObject var viewModel: ViewModel
57 | var body: some View {
58 | UIKitTextField(
59 | config: .init()
60 | .value(value: $viewModel.value, format: .number)
61 | )
62 | }
63 | }
64 |
65 | let viewModel = ViewModel()
66 | let view = ContentView(viewModel: viewModel)
67 | ViewHosting.host(view: view)
68 | defer {
69 | ViewHosting.expel()
70 | }
71 |
72 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
73 |
74 | XCTAssertEqual(textField.text, "123")
75 |
76 | viewModel.value = 1234
77 | wait(for: 0.1)
78 | XCTAssertEqual(textField.text, "1,234")
79 |
80 | textField.becomeFirstResponder()
81 | textField.insertText("5")
82 | wait(for: 0.1)
83 | XCTAssertEqual(textField.text, "1,2345")
84 | XCTAssertEqual(viewModel.value, 12345)
85 |
86 | textField.resignFirstResponder()
87 | wait(for: 0.1)
88 | XCTAssertEqual(textField.text, "12,345")
89 | XCTAssertEqual(viewModel.value, 12345)
90 | }
91 |
92 | func testFormatterBinding() throws {
93 | class ViewModel: ObservableObject {
94 | @Published var value: Double = 123
95 | }
96 | struct ContentView: View, Inspectable {
97 | @ObservedObject var viewModel: ViewModel
98 | var body: some View {
99 | UIKitTextField(
100 | config: .init()
101 | .value(value: $viewModel.value, formatter: formatter)
102 | )
103 | }
104 | var formatter: Formatter {
105 | let formatter = NumberFormatter()
106 | formatter.numberStyle = .decimal
107 | return formatter
108 | }
109 | }
110 |
111 | let viewModel = ViewModel()
112 | let view = ContentView(viewModel: viewModel)
113 | ViewHosting.host(view: view)
114 | defer {
115 | ViewHosting.expel()
116 | }
117 |
118 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
119 |
120 | XCTAssertEqual(textField.text, "123")
121 |
122 | viewModel.value = 1234
123 | wait(for: 0.1)
124 | XCTAssertEqual(textField.text, "1,234")
125 |
126 | textField.becomeFirstResponder()
127 | textField.insertText("5")
128 | wait(for: 0.1)
129 | XCTAssertEqual(textField.text, "1,2345")
130 | // NOTE: `Formatter` has a slightly different behavior than `ParseableFormatStyle`
131 | XCTAssertEqual(viewModel.value, 1234)
132 |
133 | textField.resignFirstResponder()
134 | wait(for: 0.1)
135 | XCTAssertEqual(textField.text, "1,234")
136 | XCTAssertEqual(viewModel.value, 1234)
137 | }
138 |
139 | @available(iOS 15.0, *)
140 | func testOptionalFormatBinding() throws {
141 | class ViewModel: ObservableObject {
142 | @Published var value: Double? = 123
143 | }
144 | struct ContentView: View, Inspectable {
145 | @ObservedObject var viewModel: ViewModel
146 | var body: some View {
147 | UIKitTextField(
148 | config: .init()
149 | .value(value: $viewModel.value, format: .number)
150 | )
151 | }
152 | }
153 |
154 | let viewModel = ViewModel()
155 | let view = ContentView(viewModel: viewModel)
156 | ViewHosting.host(view: view)
157 | defer {
158 | ViewHosting.expel()
159 | }
160 |
161 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
162 |
163 | XCTAssertEqual(textField.text, "123")
164 |
165 | viewModel.value = 1234
166 | wait(for: 0.1)
167 | XCTAssertEqual(textField.text, "1,234")
168 |
169 | textField.becomeFirstResponder()
170 | textField.deleteBackward()
171 | textField.deleteBackward()
172 | textField.deleteBackward()
173 | textField.deleteBackward()
174 | textField.deleteBackward()
175 | textField.insertText("abc")
176 | wait(for: 0.1)
177 | XCTAssertEqual(textField.text, "abc")
178 | XCTAssertEqual(viewModel.value, nil)
179 |
180 | textField.resignFirstResponder()
181 | wait(for: 0.1)
182 | XCTAssertEqual(textField.text, "")
183 | XCTAssertEqual(viewModel.value, nil)
184 | }
185 |
186 | func testOptionalFormatterBinding() throws {
187 | class ViewModel: ObservableObject {
188 | @Published var value: Double? = 123
189 | }
190 | struct ContentView: View, Inspectable {
191 | @ObservedObject var viewModel: ViewModel
192 | var body: some View {
193 | UIKitTextField(
194 | config: .init()
195 | .value(value: $viewModel.value, formatter: formatter)
196 | )
197 | }
198 | var formatter: Formatter {
199 | let formatter = NumberFormatter()
200 | formatter.numberStyle = .decimal
201 | return formatter
202 | }
203 | }
204 |
205 | let viewModel = ViewModel()
206 | let view = ContentView(viewModel: viewModel)
207 | ViewHosting.host(view: view)
208 | defer {
209 | ViewHosting.expel()
210 | }
211 |
212 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
213 |
214 | XCTAssertEqual(textField.text, "123")
215 |
216 | viewModel.value = 1234
217 | wait(for: 0.1)
218 | XCTAssertEqual(textField.text, "1,234")
219 |
220 | textField.becomeFirstResponder()
221 | textField.deleteBackward()
222 | textField.deleteBackward()
223 | textField.deleteBackward()
224 | textField.deleteBackward()
225 | textField.deleteBackward()
226 | textField.insertText("abc")
227 | wait(for: 0.1)
228 | XCTAssertEqual(textField.text, "abc")
229 | XCTAssertEqual(viewModel.value, nil)
230 |
231 | textField.resignFirstResponder()
232 | wait(for: 0.1)
233 | XCTAssertEqual(textField.text, "")
234 | XCTAssertEqual(viewModel.value, nil)
235 | }
236 |
237 | func testPlaceholder() throws {
238 | let placeholder = "Enter something ..."
239 | let view = UIKitTextField(
240 | config: .init()
241 | .placeholder(placeholder)
242 | )
243 | ViewHosting.host(view: view)
244 | defer {
245 | ViewHosting.expel()
246 | }
247 |
248 | let textField = try view.inspect().actualView().uiView()
249 | XCTAssertEqual(textField.placeholder, placeholder)
250 | }
251 |
252 | func testFont() throws {
253 | let font = UIFont.systemFont(ofSize: 16)
254 | let view = UIKitTextField(
255 | config: .init()
256 | .font(font)
257 | )
258 | ViewHosting.host(view: view)
259 | defer {
260 | ViewHosting.expel()
261 | }
262 |
263 | let textField = try view.inspect().actualView().uiView()
264 | XCTAssertEqual(textField.font, font)
265 | }
266 |
267 | func testTextColor() throws {
268 | let textColor = Color.red
269 | let view = UIKitTextField(
270 | config: .init()
271 | .textColor(textColor)
272 | )
273 | ViewHosting.host(view: view)
274 | defer {
275 | ViewHosting.expel()
276 | }
277 |
278 | let textField = try view.inspect().actualView().uiView()
279 | XCTAssertEqual(textField.textColor?.isEqual(UIColor(textColor)), true)
280 | }
281 |
282 | func testTextAlignment() throws {
283 | let view = UIKitTextField(
284 | config: .init()
285 | .textAlignment(.center)
286 | )
287 | ViewHosting.host(view: view)
288 | defer {
289 | ViewHosting.expel()
290 | }
291 |
292 | let textField = try view.inspect().actualView().uiView()
293 | XCTAssertEqual(textField.textAlignment, .center)
294 | }
295 |
296 | func testClearsOnBeginEditing() throws {
297 | let view = UIKitTextField(
298 | config: .init()
299 | .clearsOnBeginEditing(true)
300 | )
301 | ViewHosting.host(view: view)
302 | defer {
303 | ViewHosting.expel()
304 | }
305 |
306 | let textField = try view.inspect().actualView().uiView()
307 | XCTAssertEqual(textField.clearsOnBeginEditing, true)
308 | }
309 |
310 | func testClearsOnInsertion() throws {
311 | let view = UIKitTextField(
312 | config: .init()
313 | .clearsOnInsertion(true)
314 | )
315 | ViewHosting.host(view: view)
316 | defer {
317 | ViewHosting.expel()
318 | }
319 |
320 | let textField = try view.inspect().actualView().uiView()
321 | XCTAssertEqual(textField.clearsOnInsertion, true)
322 | }
323 |
324 | func testClearButtonMode() throws {
325 | let view = UIKitTextField(
326 | config: .init()
327 | .clearButtonMode(.always)
328 | )
329 | ViewHosting.host(view: view)
330 | defer {
331 | ViewHosting.expel()
332 | }
333 |
334 | let textField = try view.inspect().actualView().uiView()
335 | XCTAssertEqual(textField.clearButtonMode, .always)
336 | }
337 |
338 | func testStretching() throws {
339 | assertSnapshot(
340 | matching: ZStack {
341 | UIKitTextField(
342 | config: .init()
343 | .value(text: .constant("Abcdef"))
344 | .stretches(horizontal: false, vertical: false)
345 | )
346 | .border(Color.green)
347 | }
348 | .frame(width: 200, height: 200)
349 | ,
350 | as: .image
351 | )
352 |
353 | assertSnapshot(
354 | matching: ZStack {
355 | UIKitTextField(
356 | config: .init()
357 | .value(text: .constant("Abcdef"))
358 | .stretches(horizontal: true, vertical: false)
359 | )
360 | .border(Color.green)
361 | }
362 | .frame(width: 200, height: 200)
363 | ,
364 | as: .image
365 | )
366 |
367 | assertSnapshot(
368 | matching: ZStack {
369 | UIKitTextField(
370 | config: .init()
371 | .value(text: .constant("Abcdef"))
372 | .stretches(horizontal: false, vertical: true)
373 | )
374 | .border(Color.green)
375 | }
376 | .frame(width: 200, height: 200)
377 | ,
378 | as: .image
379 | )
380 |
381 | assertSnapshot(
382 | matching: ZStack {
383 | UIKitTextField(
384 | config: .init()
385 | .value(text: .constant("Abcdef"))
386 | .stretches(horizontal: true, vertical: true)
387 | )
388 | .border(Color.green)
389 | }
390 | .frame(width: 200, height: 200)
391 | ,
392 | as: .image
393 | )
394 | }
395 |
396 | func testBoolFocusState() throws {
397 | class ViewModel: ObservableObject {
398 | @Published var isFocused: Bool = false
399 | }
400 | struct ContentView: View, Inspectable {
401 | @ObservedObject var viewModel: ViewModel
402 | var body: some View {
403 | UIKitTextField(
404 | config: .init()
405 | .focused($viewModel.isFocused)
406 | )
407 | }
408 | }
409 |
410 | let viewModel = ViewModel()
411 | let view = ContentView(viewModel: viewModel)
412 | ViewHosting.host(view: view)
413 | defer {
414 | ViewHosting.expel()
415 | }
416 |
417 | wait(for: 0.1)
418 |
419 | let textField = try view.inspect().find(UIKitTextField.self).actualView().uiView()
420 |
421 | XCTAssertEqual(textField.isFirstResponder, false)
422 |
423 | viewModel.isFocused = true
424 | wait(for: 0.1)
425 | XCTAssertEqual(textField.isFirstResponder, true)
426 |
427 | viewModel.isFocused = false
428 | wait(for: 0.1)
429 | XCTAssertEqual(textField.isFirstResponder, false)
430 |
431 | textField.becomeFirstResponder()
432 | wait(for: 0.1)
433 | XCTAssertEqual(viewModel.isFocused, true)
434 |
435 | textField.resignFirstResponder()
436 | wait(for: 0.1)
437 | XCTAssertEqual(viewModel.isFocused, false)
438 | }
439 |
440 | func testValueFocusState() throws {
441 | // NOTE: ViewInspector seems to have trouble locating the second text field, instead,
442 | // it returns the first one as the second one
443 | let textField0 = BaseUITextField()
444 | let textField1 = BaseUITextField()
445 |
446 | enum Field {
447 | case field0
448 | case field1
449 | }
450 | class ViewModel: ObservableObject {
451 | @Published var focusedField: Field?
452 | }
453 | struct ContentView: View, Inspectable {
454 | let textField0: BaseUITextField
455 | let textField1: BaseUITextField
456 | @ObservedObject var viewModel: ViewModel
457 | var body: some View {
458 | return VStack {
459 | UIKitTextField(
460 | config: .init {
461 | textField0
462 | }
463 | .value(text: .constant("abcdef"))
464 | .focused($viewModel.focusedField, equals: .field0)
465 | )
466 | UIKitTextField(
467 | config: .init {
468 | textField1
469 | }
470 | .value(text: .constant("123456"))
471 | .focused($viewModel.focusedField, equals: .field1)
472 | )
473 | }
474 | .frame(width: 200, height: 200)
475 | }
476 | }
477 |
478 | let viewModel = ViewModel()
479 | let view = ContentView(
480 | textField0: textField0,
481 | textField1: textField1,
482 | viewModel: viewModel
483 | )
484 | ViewHosting.host(view: view)
485 | defer {
486 | ViewHosting.expel()
487 | }
488 |
489 | wait(for: 0.1)
490 |
491 | XCTAssertEqual(textField0.isFirstResponder, false)
492 | XCTAssertEqual(textField1.isFirstResponder, false)
493 |
494 | viewModel.focusedField = .field0
495 | wait(for: 0.1)
496 | XCTAssertEqual(textField0.isFirstResponder, true)
497 | XCTAssertEqual(textField1.isFirstResponder, false)
498 |
499 | viewModel.focusedField = .field1
500 | wait(for: 0.1)
501 | XCTAssertEqual(textField0.isFirstResponder, false)
502 | XCTAssertEqual(textField1.isFirstResponder, true)
503 |
504 | viewModel.focusedField = nil
505 | wait(for: 0.1)
506 | XCTAssertEqual(textField0.isFirstResponder, false)
507 | XCTAssertEqual(textField1.isFirstResponder, false)
508 |
509 | textField0.becomeFirstResponder()
510 | wait(for: 0.1)
511 | XCTAssertEqual(viewModel.focusedField, .field0)
512 |
513 | textField1.becomeFirstResponder()
514 | wait(for: 0.1)
515 | XCTAssertEqual(viewModel.focusedField, .field1)
516 |
517 | textField1.resignFirstResponder()
518 | wait(for: 0.1)
519 | XCTAssertEqual(viewModel.focusedField, nil)
520 | }
521 |
522 | func testInputViews() throws {
523 | struct KeyButton: View {
524 | let uiTextField: UITextField
525 | let text: String
526 |
527 | var body: some View {
528 | Button {} label: {
529 | Text(text)
530 | .frame(maxWidth: .infinity)
531 | .frame(height: 100)
532 | .background(Color.white)
533 | }
534 | }
535 | }
536 | let textField = BaseUITextField()
537 | let view = UIKitTextField(
538 | config: .init {
539 | textField
540 | }
541 | .value(text: .constant("abc"))
542 | .inputView(content: .view { uiTextField in
543 | VStack(spacing: 1) {
544 | HStack(spacing: 1) {
545 | KeyButton(uiTextField: uiTextField, text: "1")
546 | KeyButton(uiTextField: uiTextField, text: "2")
547 | KeyButton(uiTextField: uiTextField, text: "3")
548 | }
549 | HStack(spacing: 1) {
550 | KeyButton(uiTextField: uiTextField, text: "4")
551 | KeyButton(uiTextField: uiTextField, text: "5")
552 | KeyButton(uiTextField: uiTextField, text: "6")
553 | }
554 | HStack(spacing: 1) {
555 | KeyButton(uiTextField: uiTextField, text: "7")
556 | KeyButton(uiTextField: uiTextField, text: "8")
557 | KeyButton(uiTextField: uiTextField, text: "9")
558 | }
559 | }
560 | .background(Color.gray)
561 | .border(Color.gray)
562 | })
563 | .inputAccessoryView(content: .view { uiTextField in
564 | HStack(spacing: 1) {
565 | KeyButton(uiTextField: uiTextField, text: "🐵")
566 | KeyButton(uiTextField: uiTextField, text: "🐶")
567 | KeyButton(uiTextField: uiTextField, text: "🦊")
568 | }
569 | .background(Color.gray)
570 | .border(Color.gray)
571 | .clipped()
572 | })
573 | )
574 | .frame(width: 200, height: 100)
575 |
576 | ViewHosting.host(view: view)
577 | defer {
578 | ViewHosting.expel()
579 | }
580 |
581 | wait(for: 0.1)
582 |
583 | textField.becomeFirstResponder()
584 |
585 | wait(for: 1)
586 |
587 | assertSnapshot(matching: textField.inputViewController!.view.layer, as: .image)
588 | assertSnapshot(matching: textField.inputAccessoryViewController!.view.layer, as: .image)
589 | }
590 |
591 | func testCustomTextField() throws {
592 | class CustomTextField: BaseUITextField {}
593 |
594 | let customTextField = CustomTextField()
595 |
596 | let view = UIKitTextField(
597 | config: .init {
598 | customTextField
599 | }
600 | )
601 | ViewHosting.host(view: view)
602 | defer {
603 | ViewHosting.expel()
604 | }
605 |
606 | let textField = try view.inspect().actualView().uiView()
607 | XCTAssertEqual(textField, customTextField)
608 | XCTAssert(type(of: textField) === CustomTextField.self)
609 | }
610 |
611 | func testConfigure() throws {
612 | var capture = (UITextField, Void)(.init(), ())
613 |
614 | let view = UIKitTextField(
615 | config: .init()
616 | .configure { uiTextField in
617 | capture = (uiTextField, ())
618 | }
619 | )
620 | ViewHosting.host(view: view)
621 | defer {
622 | ViewHosting.expel()
623 | }
624 |
625 | wait(for: 0.1)
626 |
627 | let textField = try view.inspect().actualView().uiView()
628 | XCTAssertEqual(capture.0, textField)
629 | }
630 | }
631 |
632 | #endif
633 |
--------------------------------------------------------------------------------
/AllTests/AllTests.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 55139ABB28128C7000A20C2E /* UITestingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55139ABA28128C7000A20C2E /* UITestingApp.swift */; };
11 | 55139ABD28128C7000A20C2E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55139ABC28128C7000A20C2E /* ContentView.swift */; };
12 | 55139ABF28128C7100A20C2E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 55139ABE28128C7100A20C2E /* Assets.xcassets */; };
13 | 55139AC228128C7100A20C2E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 55139AC128128C7100A20C2E /* Preview Assets.xcassets */; };
14 | 55139AE928128CAB00A20C2E /* UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55139AE828128CAB00A20C2E /* UITests.swift */; };
15 | 55139AF82812904F00A20C2E /* UIKitTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 55139AF72812904F00A20C2E /* UIKitTextField */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXContainerItemProxy section */
19 | 55139AEC28128CAB00A20C2E /* PBXContainerItemProxy */ = {
20 | isa = PBXContainerItemProxy;
21 | containerPortal = 55139AAC28128B9500A20C2E /* Project object */;
22 | proxyType = 1;
23 | remoteGlobalIDString = 55139AB628128C7000A20C2E;
24 | remoteInfo = UITestingApp;
25 | };
26 | /* End PBXContainerItemProxy section */
27 |
28 | /* Begin PBXFileReference section */
29 | 55139AB728128C7000A20C2E /* UITestingApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UITestingApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
30 | 55139ABA28128C7000A20C2E /* UITestingApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestingApp.swift; sourceTree = ""; };
31 | 55139ABC28128C7000A20C2E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
32 | 55139ABE28128C7100A20C2E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
33 | 55139AC128128C7100A20C2E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
34 | 55139AE628128CAB00A20C2E /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 55139AE828128CAB00A20C2E /* UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITests.swift; sourceTree = ""; };
36 | 55139AF628128E7200A20C2E /* uikit-textfield */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "uikit-textfield"; path = ..; sourceTree = ""; };
37 | /* End PBXFileReference section */
38 |
39 | /* Begin PBXFrameworksBuildPhase section */
40 | 55139AB428128C7000A20C2E /* Frameworks */ = {
41 | isa = PBXFrameworksBuildPhase;
42 | buildActionMask = 2147483647;
43 | files = (
44 | 55139AF82812904F00A20C2E /* UIKitTextField in Frameworks */,
45 | );
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | 55139AE328128CAB00A20C2E /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 55139AAB28128B9500A20C2E = {
59 | isa = PBXGroup;
60 | children = (
61 | 55139AF628128E7200A20C2E /* uikit-textfield */,
62 | 55139AB928128C7000A20C2E /* UITestingApp */,
63 | 55139AE728128CAB00A20C2E /* UITests */,
64 | 55139AB828128C7000A20C2E /* Products */,
65 | 55139AF128128D0700A20C2E /* Frameworks */,
66 | );
67 | sourceTree = "";
68 | };
69 | 55139AB828128C7000A20C2E /* Products */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 55139AB728128C7000A20C2E /* UITestingApp.app */,
73 | 55139AE628128CAB00A20C2E /* UITests.xctest */,
74 | );
75 | name = Products;
76 | sourceTree = "";
77 | };
78 | 55139AB928128C7000A20C2E /* UITestingApp */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 55139ABA28128C7000A20C2E /* UITestingApp.swift */,
82 | 55139ABC28128C7000A20C2E /* ContentView.swift */,
83 | 55139ABE28128C7100A20C2E /* Assets.xcassets */,
84 | 55139AC028128C7100A20C2E /* Preview Content */,
85 | );
86 | path = UITestingApp;
87 | sourceTree = "";
88 | };
89 | 55139AC028128C7100A20C2E /* Preview Content */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 55139AC128128C7100A20C2E /* Preview Assets.xcassets */,
93 | );
94 | path = "Preview Content";
95 | sourceTree = "";
96 | };
97 | 55139AE728128CAB00A20C2E /* UITests */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 55139AE828128CAB00A20C2E /* UITests.swift */,
101 | );
102 | path = UITests;
103 | sourceTree = "";
104 | };
105 | 55139AF128128D0700A20C2E /* Frameworks */ = {
106 | isa = PBXGroup;
107 | children = (
108 | );
109 | name = Frameworks;
110 | sourceTree = "";
111 | };
112 | /* End PBXGroup section */
113 |
114 | /* Begin PBXNativeTarget section */
115 | 55139AB628128C7000A20C2E /* UITestingApp */ = {
116 | isa = PBXNativeTarget;
117 | buildConfigurationList = 55139AD928128C7100A20C2E /* Build configuration list for PBXNativeTarget "UITestingApp" */;
118 | buildPhases = (
119 | 55139AB328128C7000A20C2E /* Sources */,
120 | 55139AB428128C7000A20C2E /* Frameworks */,
121 | 55139AB528128C7000A20C2E /* Resources */,
122 | );
123 | buildRules = (
124 | );
125 | dependencies = (
126 | );
127 | name = UITestingApp;
128 | packageProductDependencies = (
129 | 55139AF72812904F00A20C2E /* UIKitTextField */,
130 | );
131 | productName = UITestingApp;
132 | productReference = 55139AB728128C7000A20C2E /* UITestingApp.app */;
133 | productType = "com.apple.product-type.application";
134 | };
135 | 55139AE528128CAB00A20C2E /* UITests */ = {
136 | isa = PBXNativeTarget;
137 | buildConfigurationList = 55139AEE28128CAB00A20C2E /* Build configuration list for PBXNativeTarget "UITests" */;
138 | buildPhases = (
139 | 55139AE228128CAB00A20C2E /* Sources */,
140 | 55139AE328128CAB00A20C2E /* Frameworks */,
141 | 55139AE428128CAB00A20C2E /* Resources */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | 55139AED28128CAB00A20C2E /* PBXTargetDependency */,
147 | );
148 | name = UITests;
149 | productName = UITests;
150 | productReference = 55139AE628128CAB00A20C2E /* UITests.xctest */;
151 | productType = "com.apple.product-type.bundle.ui-testing";
152 | };
153 | /* End PBXNativeTarget section */
154 |
155 | /* Begin PBXProject section */
156 | 55139AAC28128B9500A20C2E /* Project object */ = {
157 | isa = PBXProject;
158 | attributes = {
159 | BuildIndependentTargetsInParallel = 1;
160 | LastSwiftUpdateCheck = 1330;
161 | LastUpgradeCheck = 1330;
162 | TargetAttributes = {
163 | 55139AB628128C7000A20C2E = {
164 | CreatedOnToolsVersion = 13.3;
165 | };
166 | 55139AE528128CAB00A20C2E = {
167 | CreatedOnToolsVersion = 13.3;
168 | TestTargetID = 55139AB628128C7000A20C2E;
169 | };
170 | };
171 | };
172 | buildConfigurationList = 55139AAF28128B9500A20C2E /* Build configuration list for PBXProject "AllTests" */;
173 | compatibilityVersion = "Xcode 13.0";
174 | developmentRegion = en;
175 | hasScannedForEncodings = 0;
176 | knownRegions = (
177 | en,
178 | Base,
179 | );
180 | mainGroup = 55139AAB28128B9500A20C2E;
181 | productRefGroup = 55139AB828128C7000A20C2E /* Products */;
182 | projectDirPath = "";
183 | projectRoot = "";
184 | targets = (
185 | 55139AB628128C7000A20C2E /* UITestingApp */,
186 | 55139AE528128CAB00A20C2E /* UITests */,
187 | );
188 | };
189 | /* End PBXProject section */
190 |
191 | /* Begin PBXResourcesBuildPhase section */
192 | 55139AB528128C7000A20C2E /* Resources */ = {
193 | isa = PBXResourcesBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | 55139AC228128C7100A20C2E /* Preview Assets.xcassets in Resources */,
197 | 55139ABF28128C7100A20C2E /* Assets.xcassets in Resources */,
198 | );
199 | runOnlyForDeploymentPostprocessing = 0;
200 | };
201 | 55139AE428128CAB00A20C2E /* Resources */ = {
202 | isa = PBXResourcesBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | };
208 | /* End PBXResourcesBuildPhase section */
209 |
210 | /* Begin PBXSourcesBuildPhase section */
211 | 55139AB328128C7000A20C2E /* Sources */ = {
212 | isa = PBXSourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 55139ABD28128C7000A20C2E /* ContentView.swift in Sources */,
216 | 55139ABB28128C7000A20C2E /* UITestingApp.swift in Sources */,
217 | );
218 | runOnlyForDeploymentPostprocessing = 0;
219 | };
220 | 55139AE228128CAB00A20C2E /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | 55139AE928128CAB00A20C2E /* UITests.swift in Sources */,
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | };
228 | /* End PBXSourcesBuildPhase section */
229 |
230 | /* Begin PBXTargetDependency section */
231 | 55139AED28128CAB00A20C2E /* PBXTargetDependency */ = {
232 | isa = PBXTargetDependency;
233 | target = 55139AB628128C7000A20C2E /* UITestingApp */;
234 | targetProxy = 55139AEC28128CAB00A20C2E /* PBXContainerItemProxy */;
235 | };
236 | /* End PBXTargetDependency section */
237 |
238 | /* Begin XCBuildConfiguration section */
239 | 55139AB028128B9500A20C2E /* Debug */ = {
240 | isa = XCBuildConfiguration;
241 | buildSettings = {
242 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
243 | };
244 | name = Debug;
245 | };
246 | 55139AB128128B9500A20C2E /* Release */ = {
247 | isa = XCBuildConfiguration;
248 | buildSettings = {
249 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
250 | };
251 | name = Release;
252 | };
253 | 55139ADA28128C7100A20C2E /* Debug */ = {
254 | isa = XCBuildConfiguration;
255 | buildSettings = {
256 | ALWAYS_SEARCH_USER_PATHS = NO;
257 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
258 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
259 | CLANG_ANALYZER_NONNULL = YES;
260 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_ENABLE_OBJC_WEAK = YES;
265 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
266 | CLANG_WARN_BOOL_CONVERSION = YES;
267 | CLANG_WARN_COMMA = YES;
268 | CLANG_WARN_CONSTANT_CONVERSION = YES;
269 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
271 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
272 | CLANG_WARN_EMPTY_BODY = YES;
273 | CLANG_WARN_ENUM_CONVERSION = YES;
274 | CLANG_WARN_INFINITE_RECURSION = YES;
275 | CLANG_WARN_INT_CONVERSION = YES;
276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
280 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
281 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
282 | CLANG_WARN_STRICT_PROTOTYPES = YES;
283 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
284 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
285 | CLANG_WARN_UNREACHABLE_CODE = YES;
286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
287 | CODE_SIGN_STYLE = Automatic;
288 | COPY_PHASE_STRIP = NO;
289 | CURRENT_PROJECT_VERSION = 1;
290 | DEBUG_INFORMATION_FORMAT = dwarf;
291 | DEVELOPMENT_ASSET_PATHS = "\"UITestingApp/Preview Content\"";
292 | ENABLE_PREVIEWS = YES;
293 | ENABLE_STRICT_OBJC_MSGSEND = YES;
294 | ENABLE_TESTABILITY = YES;
295 | GCC_C_LANGUAGE_STANDARD = gnu11;
296 | GCC_DYNAMIC_NO_PIC = NO;
297 | GCC_NO_COMMON_BLOCKS = YES;
298 | GCC_OPTIMIZATION_LEVEL = 0;
299 | GCC_PREPROCESSOR_DEFINITIONS = (
300 | "DEBUG=1",
301 | "$(inherited)",
302 | );
303 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
304 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
305 | GCC_WARN_UNDECLARED_SELECTOR = YES;
306 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
307 | GCC_WARN_UNUSED_FUNCTION = YES;
308 | GCC_WARN_UNUSED_VARIABLE = YES;
309 | GENERATE_INFOPLIST_FILE = YES;
310 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
311 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
312 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
313 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
314 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
315 | LD_RUNPATH_SEARCH_PATHS = (
316 | "$(inherited)",
317 | "@executable_path/Frameworks",
318 | );
319 | MARKETING_VERSION = 1.0;
320 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
321 | MTL_FAST_MATH = YES;
322 | ONLY_ACTIVE_ARCH = YES;
323 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.UITestingApp";
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | SDKROOT = iphoneos;
326 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
327 | SWIFT_EMIT_LOC_STRINGS = YES;
328 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
329 | SWIFT_VERSION = 5.0;
330 | TARGETED_DEVICE_FAMILY = "1,2";
331 | };
332 | name = Debug;
333 | };
334 | 55139ADB28128C7100A20C2E /* Release */ = {
335 | isa = XCBuildConfiguration;
336 | buildSettings = {
337 | ALWAYS_SEARCH_USER_PATHS = NO;
338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
339 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
340 | CLANG_ANALYZER_NONNULL = YES;
341 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
343 | CLANG_ENABLE_MODULES = YES;
344 | CLANG_ENABLE_OBJC_ARC = YES;
345 | CLANG_ENABLE_OBJC_WEAK = YES;
346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
347 | CLANG_WARN_BOOL_CONVERSION = YES;
348 | CLANG_WARN_COMMA = YES;
349 | CLANG_WARN_CONSTANT_CONVERSION = YES;
350 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
352 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
353 | CLANG_WARN_EMPTY_BODY = YES;
354 | CLANG_WARN_ENUM_CONVERSION = YES;
355 | CLANG_WARN_INFINITE_RECURSION = YES;
356 | CLANG_WARN_INT_CONVERSION = YES;
357 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
358 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
359 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
360 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
361 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
363 | CLANG_WARN_STRICT_PROTOTYPES = YES;
364 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
365 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
366 | CLANG_WARN_UNREACHABLE_CODE = YES;
367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
368 | CODE_SIGN_STYLE = Automatic;
369 | COPY_PHASE_STRIP = NO;
370 | CURRENT_PROJECT_VERSION = 1;
371 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
372 | DEVELOPMENT_ASSET_PATHS = "\"UITestingApp/Preview Content\"";
373 | ENABLE_NS_ASSERTIONS = NO;
374 | ENABLE_PREVIEWS = YES;
375 | ENABLE_STRICT_OBJC_MSGSEND = YES;
376 | GCC_C_LANGUAGE_STANDARD = gnu11;
377 | GCC_NO_COMMON_BLOCKS = YES;
378 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
379 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
380 | GCC_WARN_UNDECLARED_SELECTOR = YES;
381 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
382 | GCC_WARN_UNUSED_FUNCTION = YES;
383 | GCC_WARN_UNUSED_VARIABLE = YES;
384 | GENERATE_INFOPLIST_FILE = YES;
385 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
386 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
387 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
388 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
389 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
390 | LD_RUNPATH_SEARCH_PATHS = (
391 | "$(inherited)",
392 | "@executable_path/Frameworks",
393 | );
394 | MARKETING_VERSION = 1.0;
395 | MTL_ENABLE_DEBUG_INFO = NO;
396 | MTL_FAST_MATH = YES;
397 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.UITestingApp";
398 | PRODUCT_NAME = "$(TARGET_NAME)";
399 | SDKROOT = iphoneos;
400 | SWIFT_COMPILATION_MODE = wholemodule;
401 | SWIFT_EMIT_LOC_STRINGS = YES;
402 | SWIFT_OPTIMIZATION_LEVEL = "-O";
403 | SWIFT_VERSION = 5.0;
404 | TARGETED_DEVICE_FAMILY = "1,2";
405 | VALIDATE_PRODUCT = YES;
406 | };
407 | name = Release;
408 | };
409 | 55139AEF28128CAB00A20C2E /* Debug */ = {
410 | isa = XCBuildConfiguration;
411 | buildSettings = {
412 | ALWAYS_SEARCH_USER_PATHS = NO;
413 | CLANG_ANALYZER_NONNULL = YES;
414 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
416 | CLANG_ENABLE_MODULES = YES;
417 | CLANG_ENABLE_OBJC_ARC = YES;
418 | CLANG_ENABLE_OBJC_WEAK = YES;
419 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
420 | CLANG_WARN_BOOL_CONVERSION = YES;
421 | CLANG_WARN_COMMA = YES;
422 | CLANG_WARN_CONSTANT_CONVERSION = YES;
423 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
425 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
426 | CLANG_WARN_EMPTY_BODY = YES;
427 | CLANG_WARN_ENUM_CONVERSION = YES;
428 | CLANG_WARN_INFINITE_RECURSION = YES;
429 | CLANG_WARN_INT_CONVERSION = YES;
430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
431 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
432 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
433 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
434 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
436 | CLANG_WARN_STRICT_PROTOTYPES = YES;
437 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
438 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
439 | CLANG_WARN_UNREACHABLE_CODE = YES;
440 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
441 | CODE_SIGN_STYLE = Automatic;
442 | COPY_PHASE_STRIP = NO;
443 | CURRENT_PROJECT_VERSION = 1;
444 | DEBUG_INFORMATION_FORMAT = dwarf;
445 | ENABLE_STRICT_OBJC_MSGSEND = YES;
446 | ENABLE_TESTABILITY = YES;
447 | GCC_C_LANGUAGE_STANDARD = gnu11;
448 | GCC_DYNAMIC_NO_PIC = NO;
449 | GCC_NO_COMMON_BLOCKS = YES;
450 | GCC_OPTIMIZATION_LEVEL = 0;
451 | GCC_PREPROCESSOR_DEFINITIONS = (
452 | "DEBUG=1",
453 | "$(inherited)",
454 | );
455 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
456 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
457 | GCC_WARN_UNDECLARED_SELECTOR = YES;
458 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
459 | GCC_WARN_UNUSED_FUNCTION = YES;
460 | GCC_WARN_UNUSED_VARIABLE = YES;
461 | GENERATE_INFOPLIST_FILE = YES;
462 | MARKETING_VERSION = 1.0;
463 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
464 | MTL_FAST_MATH = YES;
465 | ONLY_ACTIVE_ARCH = YES;
466 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.UITests";
467 | PRODUCT_NAME = "$(TARGET_NAME)";
468 | SDKROOT = iphoneos;
469 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
470 | SWIFT_EMIT_LOC_STRINGS = NO;
471 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
472 | SWIFT_VERSION = 5.0;
473 | TARGETED_DEVICE_FAMILY = "1,2";
474 | TEST_TARGET_NAME = UITestingApp;
475 | };
476 | name = Debug;
477 | };
478 | 55139AF028128CAB00A20C2E /* Release */ = {
479 | isa = XCBuildConfiguration;
480 | buildSettings = {
481 | ALWAYS_SEARCH_USER_PATHS = NO;
482 | CLANG_ANALYZER_NONNULL = YES;
483 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
484 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
485 | CLANG_ENABLE_MODULES = YES;
486 | CLANG_ENABLE_OBJC_ARC = YES;
487 | CLANG_ENABLE_OBJC_WEAK = YES;
488 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
489 | CLANG_WARN_BOOL_CONVERSION = YES;
490 | CLANG_WARN_COMMA = YES;
491 | CLANG_WARN_CONSTANT_CONVERSION = YES;
492 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
493 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
494 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
495 | CLANG_WARN_EMPTY_BODY = YES;
496 | CLANG_WARN_ENUM_CONVERSION = YES;
497 | CLANG_WARN_INFINITE_RECURSION = YES;
498 | CLANG_WARN_INT_CONVERSION = YES;
499 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
500 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
501 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
502 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
503 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
504 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
505 | CLANG_WARN_STRICT_PROTOTYPES = YES;
506 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
507 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
508 | CLANG_WARN_UNREACHABLE_CODE = YES;
509 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
510 | CODE_SIGN_STYLE = Automatic;
511 | COPY_PHASE_STRIP = NO;
512 | CURRENT_PROJECT_VERSION = 1;
513 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
514 | ENABLE_NS_ASSERTIONS = NO;
515 | ENABLE_STRICT_OBJC_MSGSEND = YES;
516 | GCC_C_LANGUAGE_STANDARD = gnu11;
517 | GCC_NO_COMMON_BLOCKS = YES;
518 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
519 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
520 | GCC_WARN_UNDECLARED_SELECTOR = YES;
521 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
522 | GCC_WARN_UNUSED_FUNCTION = YES;
523 | GCC_WARN_UNUSED_VARIABLE = YES;
524 | GENERATE_INFOPLIST_FILE = YES;
525 | MARKETING_VERSION = 1.0;
526 | MTL_ENABLE_DEBUG_INFO = NO;
527 | MTL_FAST_MATH = YES;
528 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.UITests";
529 | PRODUCT_NAME = "$(TARGET_NAME)";
530 | SDKROOT = iphoneos;
531 | SWIFT_COMPILATION_MODE = wholemodule;
532 | SWIFT_EMIT_LOC_STRINGS = NO;
533 | SWIFT_OPTIMIZATION_LEVEL = "-O";
534 | SWIFT_VERSION = 5.0;
535 | TARGETED_DEVICE_FAMILY = "1,2";
536 | TEST_TARGET_NAME = UITestingApp;
537 | VALIDATE_PRODUCT = YES;
538 | };
539 | name = Release;
540 | };
541 | /* End XCBuildConfiguration section */
542 |
543 | /* Begin XCConfigurationList section */
544 | 55139AAF28128B9500A20C2E /* Build configuration list for PBXProject "AllTests" */ = {
545 | isa = XCConfigurationList;
546 | buildConfigurations = (
547 | 55139AB028128B9500A20C2E /* Debug */,
548 | 55139AB128128B9500A20C2E /* Release */,
549 | );
550 | defaultConfigurationIsVisible = 0;
551 | defaultConfigurationName = Release;
552 | };
553 | 55139AD928128C7100A20C2E /* Build configuration list for PBXNativeTarget "UITestingApp" */ = {
554 | isa = XCConfigurationList;
555 | buildConfigurations = (
556 | 55139ADA28128C7100A20C2E /* Debug */,
557 | 55139ADB28128C7100A20C2E /* Release */,
558 | );
559 | defaultConfigurationIsVisible = 0;
560 | defaultConfigurationName = Release;
561 | };
562 | 55139AEE28128CAB00A20C2E /* Build configuration list for PBXNativeTarget "UITests" */ = {
563 | isa = XCConfigurationList;
564 | buildConfigurations = (
565 | 55139AEF28128CAB00A20C2E /* Debug */,
566 | 55139AF028128CAB00A20C2E /* Release */,
567 | );
568 | defaultConfigurationIsVisible = 0;
569 | defaultConfigurationName = Release;
570 | };
571 | /* End XCConfigurationList section */
572 |
573 | /* Begin XCSwiftPackageProductDependency section */
574 | 55139AF72812904F00A20C2E /* UIKitTextField */ = {
575 | isa = XCSwiftPackageProductDependency;
576 | productName = UIKitTextField;
577 | };
578 | /* End XCSwiftPackageProductDependency section */
579 | };
580 | rootObject = 55139AAC28128B9500A20C2E /* Project object */;
581 | }
582 |
--------------------------------------------------------------------------------
/Examples/Example/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 559E11EA2816532E007CCB2F /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E11E92816532E007CCB2F /* ExampleApp.swift */; };
11 | 559E11EC2816532E007CCB2F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E11EB2816532E007CCB2F /* ContentView.swift */; };
12 | 559E11EE2816532F007CCB2F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 559E11ED2816532F007CCB2F /* Assets.xcassets */; };
13 | 559E11F12816532F007CCB2F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 559E11F02816532F007CCB2F /* Preview Assets.xcassets */; };
14 | 559E11FA281654D4007CCB2F /* UIKitTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 559E11F9281654D4007CCB2F /* UIKitTextField */; };
15 | 559E11FD28167A69007CCB2F /* MeasurementReader in Frameworks */ = {isa = PBXBuildFile; productRef = 559E11FC28167A69007CCB2F /* MeasurementReader */; };
16 | 559E12002817873C007CCB2F /* Expression in Frameworks */ = {isa = PBXBuildFile; productRef = 559E11FF2817873C007CCB2F /* Expression */; };
17 | 559E120228178E69007CCB2F /* TextBindingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120128178E69007CCB2F /* TextBindingPage.swift */; };
18 | 559E120528178E9F007CCB2F /* ValueBindingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120428178E9F007CCB2F /* ValueBindingPage.swift */; };
19 | 559E120728178EB9007CCB2F /* FocusBindingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120628178EB9007CCB2F /* FocusBindingPage.swift */; };
20 | 559E120928178EEA007CCB2F /* CustomTextFieldPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120828178EEA007CCB2F /* CustomTextFieldPage.swift */; };
21 | 559E120B28178F09007CCB2F /* StretchingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120A28178F09007CCB2F /* StretchingPage.swift */; };
22 | 559E120D28178F3A007CCB2F /* InputViewPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120C28178F3A007CCB2F /* InputViewPage.swift */; };
23 | 559E120F28178FFB007CCB2F /* PaddedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E120E28178FFB007CCB2F /* PaddedTextField.swift */; };
24 | 559E121128179449007CCB2F /* ConfigurePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E121028179449007CCB2F /* ConfigurePage.swift */; };
25 | 559E121A2818B297007CCB2F /* ExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559E12192818B297007CCB2F /* ExampleUITests.swift */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | 559E121D2818B297007CCB2F /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = 559E11DE2816532E007CCB2F /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 559E11E52816532E007CCB2F;
34 | remoteInfo = Example;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXFileReference section */
39 | 559E11E62816532E007CCB2F /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 559E11E92816532E007CCB2F /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = ""; };
41 | 559E11EB2816532E007CCB2F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
42 | 559E11ED2816532F007CCB2F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 559E11F02816532F007CCB2F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
44 | 559E11F728165453007CCB2F /* uikit-textfield */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "uikit-textfield"; path = ../..; sourceTree = ""; };
45 | 559E120128178E69007CCB2F /* TextBindingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBindingPage.swift; sourceTree = ""; };
46 | 559E120428178E9F007CCB2F /* ValueBindingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueBindingPage.swift; sourceTree = ""; };
47 | 559E120628178EB9007CCB2F /* FocusBindingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusBindingPage.swift; sourceTree = ""; };
48 | 559E120828178EEA007CCB2F /* CustomTextFieldPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextFieldPage.swift; sourceTree = ""; };
49 | 559E120A28178F09007CCB2F /* StretchingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StretchingPage.swift; sourceTree = ""; };
50 | 559E120C28178F3A007CCB2F /* InputViewPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputViewPage.swift; sourceTree = ""; };
51 | 559E120E28178FFB007CCB2F /* PaddedTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaddedTextField.swift; sourceTree = ""; };
52 | 559E121028179449007CCB2F /* ConfigurePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurePage.swift; sourceTree = ""; };
53 | 559E12172818B297007CCB2F /* ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 559E12192818B297007CCB2F /* ExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleUITests.swift; sourceTree = ""; };
55 | /* End PBXFileReference section */
56 |
57 | /* Begin PBXFrameworksBuildPhase section */
58 | 559E11E32816532E007CCB2F /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 559E11FD28167A69007CCB2F /* MeasurementReader in Frameworks */,
63 | 559E12002817873C007CCB2F /* Expression in Frameworks */,
64 | 559E11FA281654D4007CCB2F /* UIKitTextField in Frameworks */,
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | 559E12142818B297007CCB2F /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 559E11DD2816532E007CCB2F = {
79 | isa = PBXGroup;
80 | children = (
81 | 559E11F728165453007CCB2F /* uikit-textfield */,
82 | 559E11E82816532E007CCB2F /* Example */,
83 | 559E12182818B297007CCB2F /* ExampleUITests */,
84 | 559E11E72816532E007CCB2F /* Products */,
85 | 559E11F8281654D4007CCB2F /* Frameworks */,
86 | );
87 | sourceTree = "";
88 | };
89 | 559E11E72816532E007CCB2F /* Products */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 559E11E62816532E007CCB2F /* Example.app */,
93 | 559E12172818B297007CCB2F /* ExampleUITests.xctest */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 559E11E82816532E007CCB2F /* Example */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 559E120328178E90007CCB2F /* Pages */,
102 | 559E11E92816532E007CCB2F /* ExampleApp.swift */,
103 | 559E11EB2816532E007CCB2F /* ContentView.swift */,
104 | 559E11ED2816532F007CCB2F /* Assets.xcassets */,
105 | 559E11EF2816532F007CCB2F /* Preview Content */,
106 | );
107 | path = Example;
108 | sourceTree = "";
109 | };
110 | 559E11EF2816532F007CCB2F /* Preview Content */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 559E11F02816532F007CCB2F /* Preview Assets.xcassets */,
114 | );
115 | path = "Preview Content";
116 | sourceTree = "";
117 | };
118 | 559E11F8281654D4007CCB2F /* Frameworks */ = {
119 | isa = PBXGroup;
120 | children = (
121 | );
122 | name = Frameworks;
123 | sourceTree = "";
124 | };
125 | 559E120328178E90007CCB2F /* Pages */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 559E1212281795D7007CCB2F /* Views */,
129 | 559E120128178E69007CCB2F /* TextBindingPage.swift */,
130 | 559E120428178E9F007CCB2F /* ValueBindingPage.swift */,
131 | 559E120628178EB9007CCB2F /* FocusBindingPage.swift */,
132 | 559E120828178EEA007CCB2F /* CustomTextFieldPage.swift */,
133 | 559E120A28178F09007CCB2F /* StretchingPage.swift */,
134 | 559E120C28178F3A007CCB2F /* InputViewPage.swift */,
135 | 559E121028179449007CCB2F /* ConfigurePage.swift */,
136 | );
137 | path = Pages;
138 | sourceTree = "";
139 | };
140 | 559E1212281795D7007CCB2F /* Views */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 559E120E28178FFB007CCB2F /* PaddedTextField.swift */,
144 | );
145 | path = Views;
146 | sourceTree = "";
147 | };
148 | 559E12182818B297007CCB2F /* ExampleUITests */ = {
149 | isa = PBXGroup;
150 | children = (
151 | 559E12192818B297007CCB2F /* ExampleUITests.swift */,
152 | );
153 | path = ExampleUITests;
154 | sourceTree = "";
155 | };
156 | /* End PBXGroup section */
157 |
158 | /* Begin PBXNativeTarget section */
159 | 559E11E52816532E007CCB2F /* Example */ = {
160 | isa = PBXNativeTarget;
161 | buildConfigurationList = 559E11F42816532F007CCB2F /* Build configuration list for PBXNativeTarget "Example" */;
162 | buildPhases = (
163 | 559E11E22816532E007CCB2F /* Sources */,
164 | 559E11E32816532E007CCB2F /* Frameworks */,
165 | 559E11E42816532E007CCB2F /* Resources */,
166 | );
167 | buildRules = (
168 | );
169 | dependencies = (
170 | );
171 | name = Example;
172 | packageProductDependencies = (
173 | 559E11F9281654D4007CCB2F /* UIKitTextField */,
174 | 559E11FC28167A69007CCB2F /* MeasurementReader */,
175 | 559E11FF2817873C007CCB2F /* Expression */,
176 | );
177 | productName = Example;
178 | productReference = 559E11E62816532E007CCB2F /* Example.app */;
179 | productType = "com.apple.product-type.application";
180 | };
181 | 559E12162818B297007CCB2F /* ExampleUITests */ = {
182 | isa = PBXNativeTarget;
183 | buildConfigurationList = 559E12212818B297007CCB2F /* Build configuration list for PBXNativeTarget "ExampleUITests" */;
184 | buildPhases = (
185 | 559E12132818B297007CCB2F /* Sources */,
186 | 559E12142818B297007CCB2F /* Frameworks */,
187 | 559E12152818B297007CCB2F /* Resources */,
188 | );
189 | buildRules = (
190 | );
191 | dependencies = (
192 | 559E121E2818B297007CCB2F /* PBXTargetDependency */,
193 | );
194 | name = ExampleUITests;
195 | productName = ExampleUITests;
196 | productReference = 559E12172818B297007CCB2F /* ExampleUITests.xctest */;
197 | productType = "com.apple.product-type.bundle.ui-testing";
198 | };
199 | /* End PBXNativeTarget section */
200 |
201 | /* Begin PBXProject section */
202 | 559E11DE2816532E007CCB2F /* Project object */ = {
203 | isa = PBXProject;
204 | attributes = {
205 | BuildIndependentTargetsInParallel = 1;
206 | LastSwiftUpdateCheck = 1330;
207 | LastUpgradeCheck = 1330;
208 | TargetAttributes = {
209 | 559E11E52816532E007CCB2F = {
210 | CreatedOnToolsVersion = 13.3.1;
211 | };
212 | 559E12162818B297007CCB2F = {
213 | CreatedOnToolsVersion = 13.3.1;
214 | TestTargetID = 559E11E52816532E007CCB2F;
215 | };
216 | };
217 | };
218 | buildConfigurationList = 559E11E12816532E007CCB2F /* Build configuration list for PBXProject "Example" */;
219 | compatibilityVersion = "Xcode 13.0";
220 | developmentRegion = en;
221 | hasScannedForEncodings = 0;
222 | knownRegions = (
223 | en,
224 | Base,
225 | );
226 | mainGroup = 559E11DD2816532E007CCB2F;
227 | packageReferences = (
228 | 559E11FB28167A69007CCB2F /* XCRemoteSwiftPackageReference "measurement-reader" */,
229 | 559E11FE2817873C007CCB2F /* XCRemoteSwiftPackageReference "Expression" */,
230 | );
231 | productRefGroup = 559E11E72816532E007CCB2F /* Products */;
232 | projectDirPath = "";
233 | projectRoot = "";
234 | targets = (
235 | 559E11E52816532E007CCB2F /* Example */,
236 | 559E12162818B297007CCB2F /* ExampleUITests */,
237 | );
238 | };
239 | /* End PBXProject section */
240 |
241 | /* Begin PBXResourcesBuildPhase section */
242 | 559E11E42816532E007CCB2F /* Resources */ = {
243 | isa = PBXResourcesBuildPhase;
244 | buildActionMask = 2147483647;
245 | files = (
246 | 559E11F12816532F007CCB2F /* Preview Assets.xcassets in Resources */,
247 | 559E11EE2816532F007CCB2F /* Assets.xcassets in Resources */,
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | };
251 | 559E12152818B297007CCB2F /* Resources */ = {
252 | isa = PBXResourcesBuildPhase;
253 | buildActionMask = 2147483647;
254 | files = (
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | /* End PBXResourcesBuildPhase section */
259 |
260 | /* Begin PBXSourcesBuildPhase section */
261 | 559E11E22816532E007CCB2F /* Sources */ = {
262 | isa = PBXSourcesBuildPhase;
263 | buildActionMask = 2147483647;
264 | files = (
265 | 559E120228178E69007CCB2F /* TextBindingPage.swift in Sources */,
266 | 559E120F28178FFB007CCB2F /* PaddedTextField.swift in Sources */,
267 | 559E120928178EEA007CCB2F /* CustomTextFieldPage.swift in Sources */,
268 | 559E121128179449007CCB2F /* ConfigurePage.swift in Sources */,
269 | 559E120D28178F3A007CCB2F /* InputViewPage.swift in Sources */,
270 | 559E11EC2816532E007CCB2F /* ContentView.swift in Sources */,
271 | 559E120528178E9F007CCB2F /* ValueBindingPage.swift in Sources */,
272 | 559E11EA2816532E007CCB2F /* ExampleApp.swift in Sources */,
273 | 559E120B28178F09007CCB2F /* StretchingPage.swift in Sources */,
274 | 559E120728178EB9007CCB2F /* FocusBindingPage.swift in Sources */,
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | 559E12132818B297007CCB2F /* Sources */ = {
279 | isa = PBXSourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 559E121A2818B297007CCB2F /* ExampleUITests.swift in Sources */,
283 | );
284 | runOnlyForDeploymentPostprocessing = 0;
285 | };
286 | /* End PBXSourcesBuildPhase section */
287 |
288 | /* Begin PBXTargetDependency section */
289 | 559E121E2818B297007CCB2F /* PBXTargetDependency */ = {
290 | isa = PBXTargetDependency;
291 | target = 559E11E52816532E007CCB2F /* Example */;
292 | targetProxy = 559E121D2818B297007CCB2F /* PBXContainerItemProxy */;
293 | };
294 | /* End PBXTargetDependency section */
295 |
296 | /* Begin XCBuildConfiguration section */
297 | 559E11F22816532F007CCB2F /* Debug */ = {
298 | isa = XCBuildConfiguration;
299 | buildSettings = {
300 | ALWAYS_SEARCH_USER_PATHS = NO;
301 | CLANG_ANALYZER_NONNULL = YES;
302 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
303 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
304 | CLANG_ENABLE_MODULES = YES;
305 | CLANG_ENABLE_OBJC_ARC = YES;
306 | CLANG_ENABLE_OBJC_WEAK = YES;
307 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
308 | CLANG_WARN_BOOL_CONVERSION = YES;
309 | CLANG_WARN_COMMA = YES;
310 | CLANG_WARN_CONSTANT_CONVERSION = YES;
311 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
312 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
313 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
314 | CLANG_WARN_EMPTY_BODY = YES;
315 | CLANG_WARN_ENUM_CONVERSION = YES;
316 | CLANG_WARN_INFINITE_RECURSION = YES;
317 | CLANG_WARN_INT_CONVERSION = YES;
318 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
319 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
320 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
322 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
323 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
324 | CLANG_WARN_STRICT_PROTOTYPES = YES;
325 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
326 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
327 | CLANG_WARN_UNREACHABLE_CODE = YES;
328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
329 | COPY_PHASE_STRIP = NO;
330 | DEBUG_INFORMATION_FORMAT = dwarf;
331 | ENABLE_STRICT_OBJC_MSGSEND = YES;
332 | ENABLE_TESTABILITY = YES;
333 | GCC_C_LANGUAGE_STANDARD = gnu11;
334 | GCC_DYNAMIC_NO_PIC = NO;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_OPTIMIZATION_LEVEL = 0;
337 | GCC_PREPROCESSOR_DEFINITIONS = (
338 | "DEBUG=1",
339 | "$(inherited)",
340 | );
341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
342 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
343 | GCC_WARN_UNDECLARED_SELECTOR = YES;
344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
345 | GCC_WARN_UNUSED_FUNCTION = YES;
346 | GCC_WARN_UNUSED_VARIABLE = YES;
347 | IPHONEOS_DEPLOYMENT_TARGET = 15.4;
348 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
349 | MTL_FAST_MATH = YES;
350 | ONLY_ACTIVE_ARCH = YES;
351 | SDKROOT = iphoneos;
352 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
353 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
354 | };
355 | name = Debug;
356 | };
357 | 559E11F32816532F007CCB2F /* Release */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | ALWAYS_SEARCH_USER_PATHS = NO;
361 | CLANG_ANALYZER_NONNULL = YES;
362 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
363 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
364 | CLANG_ENABLE_MODULES = YES;
365 | CLANG_ENABLE_OBJC_ARC = YES;
366 | CLANG_ENABLE_OBJC_WEAK = YES;
367 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
368 | CLANG_WARN_BOOL_CONVERSION = YES;
369 | CLANG_WARN_COMMA = YES;
370 | CLANG_WARN_CONSTANT_CONVERSION = YES;
371 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
372 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
373 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
374 | CLANG_WARN_EMPTY_BODY = YES;
375 | CLANG_WARN_ENUM_CONVERSION = YES;
376 | CLANG_WARN_INFINITE_RECURSION = YES;
377 | CLANG_WARN_INT_CONVERSION = YES;
378 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
379 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
380 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
381 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
382 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
384 | CLANG_WARN_STRICT_PROTOTYPES = YES;
385 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
386 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
387 | CLANG_WARN_UNREACHABLE_CODE = YES;
388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
389 | COPY_PHASE_STRIP = NO;
390 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
391 | ENABLE_NS_ASSERTIONS = NO;
392 | ENABLE_STRICT_OBJC_MSGSEND = YES;
393 | GCC_C_LANGUAGE_STANDARD = gnu11;
394 | GCC_NO_COMMON_BLOCKS = YES;
395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
397 | GCC_WARN_UNDECLARED_SELECTOR = YES;
398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
399 | GCC_WARN_UNUSED_FUNCTION = YES;
400 | GCC_WARN_UNUSED_VARIABLE = YES;
401 | IPHONEOS_DEPLOYMENT_TARGET = 15.4;
402 | MTL_ENABLE_DEBUG_INFO = NO;
403 | MTL_FAST_MATH = YES;
404 | SDKROOT = iphoneos;
405 | SWIFT_COMPILATION_MODE = wholemodule;
406 | SWIFT_OPTIMIZATION_LEVEL = "-O";
407 | VALIDATE_PRODUCT = YES;
408 | };
409 | name = Release;
410 | };
411 | 559E11F52816532F007CCB2F /* Debug */ = {
412 | isa = XCBuildConfiguration;
413 | buildSettings = {
414 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
415 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
416 | CODE_SIGN_STYLE = Automatic;
417 | CURRENT_PROJECT_VERSION = 1;
418 | DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
419 | ENABLE_PREVIEWS = YES;
420 | GENERATE_INFOPLIST_FILE = YES;
421 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
422 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
423 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
424 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
425 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
426 | LD_RUNPATH_SEARCH_PATHS = (
427 | "$(inherited)",
428 | "@executable_path/Frameworks",
429 | );
430 | MARKETING_VERSION = 1.0;
431 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.Example";
432 | PRODUCT_NAME = "$(TARGET_NAME)";
433 | SWIFT_EMIT_LOC_STRINGS = YES;
434 | SWIFT_VERSION = 5.0;
435 | TARGETED_DEVICE_FAMILY = "1,2";
436 | };
437 | name = Debug;
438 | };
439 | 559E11F62816532F007CCB2F /* Release */ = {
440 | isa = XCBuildConfiguration;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
444 | CODE_SIGN_STYLE = Automatic;
445 | CURRENT_PROJECT_VERSION = 1;
446 | DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
447 | ENABLE_PREVIEWS = YES;
448 | GENERATE_INFOPLIST_FILE = YES;
449 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
450 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
451 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
452 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
453 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
454 | LD_RUNPATH_SEARCH_PATHS = (
455 | "$(inherited)",
456 | "@executable_path/Frameworks",
457 | );
458 | MARKETING_VERSION = 1.0;
459 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.Example";
460 | PRODUCT_NAME = "$(TARGET_NAME)";
461 | SWIFT_EMIT_LOC_STRINGS = YES;
462 | SWIFT_VERSION = 5.0;
463 | TARGETED_DEVICE_FAMILY = "1,2";
464 | };
465 | name = Release;
466 | };
467 | 559E121F2818B297007CCB2F /* Debug */ = {
468 | isa = XCBuildConfiguration;
469 | buildSettings = {
470 | CODE_SIGN_STYLE = Automatic;
471 | CURRENT_PROJECT_VERSION = 1;
472 | GENERATE_INFOPLIST_FILE = YES;
473 | MARKETING_VERSION = 1.0;
474 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.ExampleUITests";
475 | PRODUCT_NAME = "$(TARGET_NAME)";
476 | SWIFT_EMIT_LOC_STRINGS = NO;
477 | SWIFT_VERSION = 5.0;
478 | TARGETED_DEVICE_FAMILY = "1,2";
479 | TEST_TARGET_NAME = Example;
480 | };
481 | name = Debug;
482 | };
483 | 559E12202818B297007CCB2F /* Release */ = {
484 | isa = XCBuildConfiguration;
485 | buildSettings = {
486 | CODE_SIGN_STYLE = Automatic;
487 | CURRENT_PROJECT_VERSION = 1;
488 | GENERATE_INFOPLIST_FILE = YES;
489 | MARKETING_VERSION = 1.0;
490 | PRODUCT_BUNDLE_IDENTIFIER = "com.uikit-textfield.ExampleUITests";
491 | PRODUCT_NAME = "$(TARGET_NAME)";
492 | SWIFT_EMIT_LOC_STRINGS = NO;
493 | SWIFT_VERSION = 5.0;
494 | TARGETED_DEVICE_FAMILY = "1,2";
495 | TEST_TARGET_NAME = Example;
496 | };
497 | name = Release;
498 | };
499 | /* End XCBuildConfiguration section */
500 |
501 | /* Begin XCConfigurationList section */
502 | 559E11E12816532E007CCB2F /* Build configuration list for PBXProject "Example" */ = {
503 | isa = XCConfigurationList;
504 | buildConfigurations = (
505 | 559E11F22816532F007CCB2F /* Debug */,
506 | 559E11F32816532F007CCB2F /* Release */,
507 | );
508 | defaultConfigurationIsVisible = 0;
509 | defaultConfigurationName = Release;
510 | };
511 | 559E11F42816532F007CCB2F /* Build configuration list for PBXNativeTarget "Example" */ = {
512 | isa = XCConfigurationList;
513 | buildConfigurations = (
514 | 559E11F52816532F007CCB2F /* Debug */,
515 | 559E11F62816532F007CCB2F /* Release */,
516 | );
517 | defaultConfigurationIsVisible = 0;
518 | defaultConfigurationName = Release;
519 | };
520 | 559E12212818B297007CCB2F /* Build configuration list for PBXNativeTarget "ExampleUITests" */ = {
521 | isa = XCConfigurationList;
522 | buildConfigurations = (
523 | 559E121F2818B297007CCB2F /* Debug */,
524 | 559E12202818B297007CCB2F /* Release */,
525 | );
526 | defaultConfigurationIsVisible = 0;
527 | defaultConfigurationName = Release;
528 | };
529 | /* End XCConfigurationList section */
530 |
531 | /* Begin XCRemoteSwiftPackageReference section */
532 | 559E11FB28167A69007CCB2F /* XCRemoteSwiftPackageReference "measurement-reader" */ = {
533 | isa = XCRemoteSwiftPackageReference;
534 | repositoryURL = "https://github.com/vinceplusplus/measurement-reader.git";
535 | requirement = {
536 | kind = upToNextMajorVersion;
537 | minimumVersion = 2.1.1;
538 | };
539 | };
540 | 559E11FE2817873C007CCB2F /* XCRemoteSwiftPackageReference "Expression" */ = {
541 | isa = XCRemoteSwiftPackageReference;
542 | repositoryURL = "https://github.com/nicklockwood/Expression.git";
543 | requirement = {
544 | kind = upToNextMajorVersion;
545 | minimumVersion = 0.13.6;
546 | };
547 | };
548 | /* End XCRemoteSwiftPackageReference section */
549 |
550 | /* Begin XCSwiftPackageProductDependency section */
551 | 559E11F9281654D4007CCB2F /* UIKitTextField */ = {
552 | isa = XCSwiftPackageProductDependency;
553 | productName = UIKitTextField;
554 | };
555 | 559E11FC28167A69007CCB2F /* MeasurementReader */ = {
556 | isa = XCSwiftPackageProductDependency;
557 | package = 559E11FB28167A69007CCB2F /* XCRemoteSwiftPackageReference "measurement-reader" */;
558 | productName = MeasurementReader;
559 | };
560 | 559E11FF2817873C007CCB2F /* Expression */ = {
561 | isa = XCSwiftPackageProductDependency;
562 | package = 559E11FE2817873C007CCB2F /* XCRemoteSwiftPackageReference "Expression" */;
563 | productName = Expression;
564 | };
565 | /* End XCSwiftPackageProductDependency section */
566 | };
567 | rootObject = 559E11DE2816532E007CCB2F /* Project object */;
568 | }
569 |
--------------------------------------------------------------------------------