Skip to content

Commit 1709a41

Browse files
author
Aurélien Grifasi
committed
🐛 Fix list controller
1 parent f9b1bdd commit 1709a41

12 files changed

+209
-168
lines changed

ExampleCocoapods/Example/ScrollViewController.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ class ScrollViewController: UIViewController {
2222
contentView.backgroundColor = UIColor.groupTableViewBackground
2323
scrollView.delaysContentTouches = false
2424

25-
phoneNumberTextField.countryListDisplayMode = .picker
25+
phoneNumberTextField.displayMode = .picker
2626
phoneNumberTextField.delegate = self
2727
}
2828
}
2929

3030
extension ScrollViewController: FPNTextFieldDelegate {
3131

32+
func fpnDisplayCountryList() {}
33+
3234
func fpnDidValidatePhoneNumber(textField: FPNTextField, isValid: Bool) {
3335
textField.rightViewMode = .always
3436
textField.rightView = UIImageView(image: isValid ? #imageLiteral(resourceName: "success") : #imageLiteral(resourceName: "error"))

ExampleCocoapods/Example/SimpleViewController.swift

+33-12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class SimpleViewController: UIViewController {
1313

1414
@IBOutlet weak var phoneNumberTextField: FPNTextField!
1515

16+
var listController: FPNCountryListViewController = FPNCountryListViewController(style: .grouped)
17+
1618
override func viewDidLoad() {
1719
super.viewDidLoad()
1820

@@ -21,34 +23,39 @@ class SimpleViewController: UIViewController {
2123
view.backgroundColor = UIColor.groupTableViewBackground
2224

2325
// To use your own flag icons, uncommment the line :
24-
// Bundle.FlagIcons = Bundle(for: ViewController.self)
26+
// Bundle.FlagIcons = Bundle(for: SimpleViewController.self)
2527

2628
phoneNumberTextField.borderStyle = .roundedRect
29+
// phoneNumberTextField.pickerView.showPhoneNumbers = false
30+
phoneNumberTextField.displayMode = .list // .picker by default
2731

28-
// Comment this line to not have access to the country list
29-
phoneNumberTextField.countryListDisplayMode = .presented(on: self)
30-
phoneNumberTextField.delegate = self
32+
listController.setup(repository: phoneNumberTextField.countryRepository)
33+
34+
listController.didSelect = { [weak self] country in
35+
self?.phoneNumberTextField.setFlag(countryCode: country.code)
36+
}
3137

38+
phoneNumberTextField.delegate = self
3239
phoneNumberTextField.font = UIFont.systemFont(ofSize: 14)
3340

3441
// Custom the size/edgeInsets of the flag button
3542
phoneNumberTextField.flagButtonSize = CGSize(width: 35, height: 35)
3643
phoneNumberTextField.flagButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
3744

3845
// Example of customizing the textField input accessory view
39-
// let items = [
40-
// UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.save, target: self, action: nil),
41-
// UIBarButtonItem(title: "Item 1", style: .plain, target: self, action: nil),
42-
// UIBarButtonItem(title: "Item 2", style: .plain, target: self, action: nil)
43-
// ]
44-
// phoneNumberTextField.textFieldInputAccessoryView = getCustomTextFieldInputAccessoryView(with: items)
46+
let items = [
47+
UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.save, target: self, action: nil),
48+
UIBarButtonItem(title: "Item 1", style: .plain, target: self, action: nil),
49+
UIBarButtonItem(title: "Item 2", style: .plain, target: self, action: nil)
50+
]
51+
phoneNumberTextField.textFieldInputAccessoryView = getCustomTextFieldInputAccessoryView(with: items)
4552

4653
// The placeholder is an example phone number of the selected country by default. You can add your own placeholder :
4754
phoneNumberTextField.hasPhoneNumberExample = true
48-
// phoneNumberTextField.placeholder = "Phone Number"
55+
phoneNumberTextField.placeholder = "Phone Number"
4956

5057
// Set the country list
51-
phoneNumberTextField.setCountries(including: [.ES, .IT, .BE, .LU, .DE])
58+
// phoneNumberTextField.setCountries(including: [.ES, .IT, .BE, .LU, .DE])
5259

5360
// Exclude countries from the list
5461
// phoneNumberTextField.setCountries(excluding: [.AM, .BW, .BA])
@@ -73,6 +80,10 @@ class SimpleViewController: UIViewController {
7380

7481
return toolbar
7582
}
83+
84+
@objc func dismissCountries() {
85+
listController.dismiss(animated: true, completion: nil)
86+
}
7687
}
7788

7889
extension SimpleViewController: FPNTextFieldDelegate {
@@ -94,4 +105,14 @@ extension SimpleViewController: FPNTextFieldDelegate {
94105
func fpnDidSelectCountry(name: String, dialCode: String, code: String) {
95106
print(name, dialCode, code)
96107
}
108+
109+
110+
func fpnDisplayCountryList() {
111+
let navigationViewController = UINavigationController(rootViewController: listController)
112+
113+
listController.title = "Countries"
114+
listController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(dismissCountries))
115+
116+
self.present(navigationViewController, animated: true, completion: nil)
117+
}
97118
}

ExampleCocoapods/Example/StackViewController.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ class StackViewController: UIViewController {
1919
title = "In Stack View"
2020
view.backgroundColor = UIColor.groupTableViewBackground
2121

22-
phoneNumberTextField.countryListDisplayMode = .picker
22+
phoneNumberTextField.displayMode = .picker
2323
phoneNumberTextField.delegate = self
2424
}
2525

2626
}
2727

2828
extension StackViewController: FPNTextFieldDelegate {
2929

30+
func fpnDisplayCountryList() {}
31+
3032
func fpnDidValidatePhoneNumber(textField: FPNTextField, isValid: Bool) {
3133
textField.rightViewMode = .always
3234
textField.rightView = UIImageView(image: isValid ? #imageLiteral(resourceName: "success") : #imageLiteral(resourceName: "error"))

ExampleCocoapods/Example/TableViewController.swift

+23-2
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,43 @@ class TableViewController: UITableViewController {
1414
@IBOutlet weak var firstPhoneNumberTextField: FPNTextField!
1515
@IBOutlet weak var secondPhoneNumberTextField: FPNTextField!
1616

17+
var listController: FPNCountryListViewController = FPNCountryListViewController(style: .grouped)
18+
var repository: FPNCountryRepository = FPNCountryRepository()
19+
1720
override func viewDidLoad() {
1821
super.viewDidLoad()
1922

2023
title = "In Table View"
2124
tableView.delaysContentTouches = false
2225

23-
firstPhoneNumberTextField.countryListDisplayMode = .picker
26+
firstPhoneNumberTextField.displayMode = .picker
2427
firstPhoneNumberTextField.delegate = self
2528

26-
secondPhoneNumberTextField.countryListDisplayMode = .presented(on: self)
29+
secondPhoneNumberTextField.displayMode = .list
2730
secondPhoneNumberTextField.delegate = self
31+
32+
listController.setup(repository: secondPhoneNumberTextField.countryRepository)
33+
34+
listController.didSelect = { [weak self] country in
35+
self?.secondPhoneNumberTextField.setFlag(countryCode: country.code)
36+
}
37+
}
38+
39+
@objc func dismissCountries() {
40+
listController.dismiss(animated: true, completion: nil)
2841
}
2942
}
3043

3144
extension TableViewController: FPNTextFieldDelegate {
3245

46+
func fpnDisplayCountryList() {
47+
let navigationViewController = UINavigationController(rootViewController: listController)
48+
49+
listController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(dismissCountries))
50+
51+
self.present(navigationViewController, animated: true, completion: nil)
52+
}
53+
3354
func fpnDidValidatePhoneNumber(textField: FPNTextField, isValid: Bool) {
3455
textField.rightViewMode = .always
3556
textField.rightView = UIImageView(image: isValid ? #imageLiteral(resourceName: "success") : #imageLiteral(resourceName: "error"))

README.md

+38-9
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,24 @@ FPNTextFieldDelegate inherites from UITextFieldDelegate so nothing change:
7070
phoneNumberTextField.delegate = self
7171
```
7272

73-
It provides two methods that lets you know when a country is selected and when the phone number is valid or not. Once a phone number is valid, you can get it in severals formats (E164, International, National, RFC3966):
73+
It provides you three methods:
7474

7575
```swift
7676
extension YourViewController: FPNTextFieldDelegate {
7777

78+
/// The place to present/push the listController if you choosen displayMode = .list
79+
func fpnDisplayCountryList() {
80+
let navigationViewController = UINavigationController(rootViewController: listController)
81+
82+
present(navigationViewController, animated: true, completion: nil)
83+
}
84+
85+
/// Lets you know when a country is selected
7886
func fpnDidSelectCountry(name: String, dialCode: String, code: String) {
7987
print(name, dialCode, code) // Output "France", "+33", "FR"
8088
}
8189

90+
/// Lets you know when the phone number is valid or not. Once a phone number is valid, you can get it in severals formats (E164, International, National, RFC3966)
8291
func fpnDidValidatePhoneNumber(textField: FPNTextField, isValid: Bool) {
8392
if isValid {
8493
// Do something...
@@ -96,6 +105,31 @@ extension YourViewController: FPNTextFieldDelegate {
96105

97106
## 🎨 Customization
98107

108+
By default, the picker view is showed but you can display the countries with a list view controller:
109+
110+
```swift
111+
var listController: FPNCountryListViewController = FPNCountryListViewController(style: .grouped)
112+
113+
phoneNumberTextField.displayMode = .list // .picker by default
114+
115+
listController.setup(repository: textField.countryRepository)
116+
listController.didSelect = { [weak self] country in
117+
self?.textField.setFlag(countryCode: country.code)
118+
}
119+
```
120+
121+
Don't forget to implement the `fpnDisplayCountryList`:
122+
123+
```swift
124+
func fpnDisplayCountryList() {
125+
let navigationViewController = UINavigationController(rootViewController: listController)
126+
127+
listController.title = "Countries"
128+
129+
self.present(navigationViewController, animated: true, completion: nil)
130+
}
131+
```
132+
99133
FlagKit is used by default but you can customize the list with your own flag icons assets:
100134
```swift
101135
// Be sure to set it before initializing a FlagPhoneNumber instance.
@@ -136,15 +170,10 @@ Or exclude countries from the list:
136170
phoneNumberTextField.setCountries(excluding: [.AM, .BW, .BA])
137171
```
138172

139-
You can choose to display the country list by picker or by a presented view controller:
140-
```swift
141-
phoneNumberTextField.countryListDisplayMode = .picker // by default
142-
phoneNumberTextField.countryListDisplayMode = .presented(on: self)
143-
```
144-
145-
You can choose to display the country phone code in the picker or in the presented view controller:
173+
You can choose to display the country phone code in the picker or in the list view controller:
146174
```swift
147-
phoneNumberTextField.showCountryPhoneCode = false // true by default
175+
phoneNumberTextField.pickerView.showCountryPhoneCode = false // true by default
176+
listController.showCountryPhoneCode = false // true by default
148177
```
149178

150179
You can reuses `FPN` classes as you see fit !

Sources/FPNCountryListViewController.swift

+26-42
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,31 @@ import UIKit
1010

1111
open class FPNCountryListViewController: UITableViewController, UISearchResultsUpdating, UISearchControllerDelegate {
1212

13-
var countries: [FPNCountry]
14-
var showCountryPhoneCode: Bool
13+
open var repository: FPNCountryRepository?
14+
open var showCountryPhoneCode: Bool = true
15+
open var searchController: UISearchController = UISearchController(searchResultsController: nil)
16+
open var didSelect: ((FPNCountry) -> Void)?
1517

16-
var searchController: UISearchController?
1718
var results: [FPNCountry]?
1819

19-
public var didSelect: ((FPNCountry) -> Void)?
20-
21-
public init(countries: [FPNCountry], showCountryPhoneCode: Bool = true) {
22-
self.countries = countries
23-
self.showCountryPhoneCode = showCountryPhoneCode
24-
25-
super.init(nibName: nil, bundle: nil)
26-
}
27-
28-
required public init?(coder aDecoder: NSCoder) {
29-
fatalError("init(coder:) has not been implemented")
30-
}
31-
3220
override open func viewDidLoad() {
3321
super.viewDidLoad()
3422

3523
tableView.tableFooterView = UIView()
36-
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(dismissController))
3724

3825
initSearchBarController()
3926
}
4027

41-
@objc private func dismissController() {
42-
dismiss(animated: true, completion: nil)
28+
open func setup(repository: FPNCountryRepository) {
29+
self.repository = repository
4330
}
4431

4532
private func initSearchBarController() {
46-
searchController = UISearchController(searchResultsController: nil)
47-
searchController?.searchResultsUpdater = self
48-
searchController?.delegate = self
33+
searchController.searchResultsUpdater = self
34+
searchController.delegate = self
4935

5036
if #available(iOS 9.1, *) {
51-
searchController?.obscuresBackgroundDuringPresentation = false
37+
searchController.obscuresBackgroundDuringPresentation = false
5238
} else {
5339
// Fallback on earlier versions
5440
}
@@ -57,39 +43,35 @@ open class FPNCountryListViewController: UITableViewController, UISearchResultsU
5743
navigationItem.searchController = searchController
5844
navigationItem.hidesSearchBarWhenScrolling = false
5945
} else {
60-
searchController?.dimsBackgroundDuringPresentation = false
61-
searchController?.hidesNavigationBarDuringPresentation = true
62-
searchController?.definesPresentationContext = true
46+
searchController.dimsBackgroundDuringPresentation = false
47+
searchController.hidesNavigationBarDuringPresentation = true
48+
searchController.definesPresentationContext = true
6349

64-
// searchController?.searchBar.sizeToFit()
65-
tableView.tableHeaderView = searchController?.searchBar
50+
// searchController.searchBar.sizeToFit()
51+
tableView.tableHeaderView = searchController.searchBar
6652
}
6753
definesPresentationContext = true
6854
}
6955

7056
private func getItem(at indexPath: IndexPath) -> FPNCountry {
71-
var array: [FPNCountry]!
72-
73-
if let searchController = searchController, searchController.isActive && results != nil && results!.count > 0 {
74-
array = results
57+
if searchController.isActive && results != nil && results!.count > 0 {
58+
return results![indexPath.row]
7559
} else {
76-
array = countries
60+
return repository!.countries[indexPath.row]
7761
}
78-
79-
return array[indexPath.row]
8062
}
8163

8264
override open func numberOfSections(in tableView: UITableView) -> Int {
8365
return 1
8466
}
8567

8668
override open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
87-
if let searchController = searchController, searchController.isActive {
69+
if searchController.isActive {
8870
if let count = searchController.searchBar.text?.count, count > 0 {
8971
return results?.count ?? 0
9072
}
9173
}
92-
return countries.count
74+
return repository?.countries.count ?? 0
9375
}
9476

9577
override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -113,14 +95,16 @@ open class FPNCountryListViewController: UITableViewController, UISearchResultsU
11395

11496
didSelect?(country)
11597

116-
searchController?.isActive = false
117-
searchController?.searchBar.resignFirstResponder()
118-
dismissController()
98+
searchController.isActive = false
99+
searchController.searchBar.resignFirstResponder()
100+
dismiss(animated: true, completion: nil)
119101
}
120102

121103
// UISearchResultsUpdating
122104

123-
public func updateSearchResults(for searchController: UISearchController) {
105+
open func updateSearchResults(for searchController: UISearchController) {
106+
guard let countries = repository?.countries else { return }
107+
124108
if countries.isEmpty {
125109
results?.removeAll()
126110
return
@@ -147,7 +131,7 @@ open class FPNCountryListViewController: UITableViewController, UISearchResultsU
147131

148132
// UISearchControllerDelegate
149133

150-
public func willDismissSearchController(_ searchController: UISearchController) {
134+
open func willDismissSearchController(_ searchController: UISearchController) {
151135
results?.removeAll()
152136
}
153137
}

0 commit comments

Comments
 (0)