@@ -19,7 +19,7 @@ import UIKit
19
19
import FirebaseDev // FirebaseAuth
20
20
import GoogleSignIn // GoogleSignIn
21
21
22
- final class ViewController : UIViewController {
22
+ final class ViewController : UIViewController , UITextFieldDelegate {
23
23
/// The profile image for the currently signed-in user.
24
24
@IBOutlet weak var profileImage : UIImageView !
25
25
@@ -56,6 +56,15 @@ final class ViewController: UIViewController {
56
56
/// The "password" text field.
57
57
@IBOutlet weak var passwordField : UITextField !
58
58
59
+ /// The "phone" text field.
60
+ @IBOutlet weak var phoneField : UITextField !
61
+
62
+ /// The scroll view holding all content.
63
+ @IBOutlet weak var scrollView : UIScrollView !
64
+
65
+ // The active keyboard input field.
66
+ var activeField : UITextField ?
67
+
59
68
/// The currently selected action type.
60
69
fileprivate var actionType = ActionType ( rawValue: 0 ) ! {
61
70
didSet {
@@ -86,6 +95,67 @@ final class ViewController: UIViewController {
86
95
}
87
96
}
88
97
98
+ func registerForKeyboardNotifications( ) {
99
+ NotificationCenter . default. addObserver ( self ,
100
+ selector:
101
+ #selector( keyboardWillBeShown ( notification: ) ) ,
102
+ name: NSNotification . Name. UIKeyboardWillShow,
103
+ object: nil )
104
+ NotificationCenter . default. addObserver ( self ,
105
+ selector: #selector( keyboardWillBeHidden ( notification: ) ) ,
106
+ name: NSNotification . Name. UIKeyboardWillHide,
107
+ object: nil )
108
+ }
109
+
110
+ func deregisterFromKeyboardNotifications( ) {
111
+ NotificationCenter . default. removeObserver ( self ,
112
+ name: NSNotification . Name. UIKeyboardWillShow,
113
+ object: nil )
114
+ NotificationCenter . default. removeObserver ( self ,
115
+ name: NSNotification . Name. UIKeyboardWillHide,
116
+ object: nil )
117
+ }
118
+
119
+ func keyboardWillBeShown( notification: NSNotification ) {
120
+ scrollView. isScrollEnabled = true
121
+ let info = notification. userInfo!
122
+ let keyboardSize = ( info [ UIKeyboardFrameBeginUserInfoKey] as? NSValue ) ? . cgRectValue. size
123
+ let contentInsets : UIEdgeInsets = UIEdgeInsetsMake ( 0.0 , 0.0 , keyboardSize!. height, 0.0 )
124
+
125
+ scrollView. contentInset = contentInsets
126
+ scrollView. scrollIndicatorInsets = contentInsets
127
+
128
+ var aRect = self . view. frame
129
+ aRect. size. height -= keyboardSize!. height
130
+ if let activeField = activeField {
131
+ if ( !aRect. contains ( activeField. frame. origin) ) {
132
+ scrollView. scrollRectToVisible ( activeField. frame, animated: true )
133
+ }
134
+ }
135
+ }
136
+
137
+ func keyboardWillBeHidden( notification: NSNotification ) {
138
+ let info = notification. userInfo!
139
+ let keyboardSize = ( info [ UIKeyboardFrameBeginUserInfoKey] as? NSValue ) ? . cgRectValue. size
140
+ let contentInsets : UIEdgeInsets = UIEdgeInsetsMake ( 0.0 , 0.0 , - keyboardSize!. height, 0.0 )
141
+ scrollView. contentInset = contentInsets
142
+ scrollView. scrollIndicatorInsets = contentInsets
143
+ self . view. endEditing ( true )
144
+ scrollView. isScrollEnabled = false
145
+ }
146
+
147
+ func textFieldDidBeginEditing( _ textField: UITextField ) {
148
+ activeField = textField
149
+ }
150
+
151
+ func textFieldDidEndEditing( _ textField: UITextField ) {
152
+ activeField = nil
153
+ }
154
+
155
+ func dismissKeyboard( ) {
156
+ view. endEditing ( true )
157
+ }
158
+
89
159
/// The user's photo URL used by the last network request for its contents.
90
160
fileprivate var lastPhotoURL : URL ? = nil
91
161
@@ -96,6 +166,15 @@ final class ViewController: UIViewController {
96
166
object: Auth . auth ( ) , queue: nil ) { notification in
97
167
self . updateUserInfo ( notification. object as? Auth )
98
168
}
169
+ phoneField. delegate = self
170
+ registerForKeyboardNotifications ( )
171
+
172
+ let tap = UITapGestureRecognizer ( target: self , action: #selector( dismissKeyboard) )
173
+ scrollView. addGestureRecognizer ( tap)
174
+ }
175
+
176
+ override func viewWillDisappear( _ animated: Bool ) {
177
+ deregisterFromKeyboardNotifications ( )
99
178
}
100
179
101
180
/// Executes the action designated by the operator on the UI.
@@ -200,7 +279,34 @@ final class ViewController: UIViewController {
200
279
GIDSignIn . sharedInstance ( ) . signIn ( )
201
280
case . password:
202
281
completion ( EmailAuthProvider . credential ( withEmail: emailField. text!,
203
- password: passwordField. text!) )
282
+ password: passwordField. text!) )
283
+ case . phone:
284
+ if #available( iOS 8 . 0 , * ) {
285
+ let phoneNumber = phoneField. text
286
+ PhoneAuthProvider . provider ( ) . verifyPhoneNumber ( phoneNumber!) { verificationID, error in
287
+ guard error == nil else {
288
+ self . showAlert ( title: " Error " , message: error!. localizedDescription)
289
+ return
290
+ }
291
+
292
+ let codeAlertController =
293
+ UIAlertController ( title: " Enter Code " , message: nil , preferredStyle: . alert)
294
+ codeAlertController. addTextField { ( textfield) in
295
+ textfield. placeholder = " SMS Codde "
296
+ textfield. keyboardType = UIKeyboardType . numberPad
297
+ }
298
+ codeAlertController. addAction ( UIAlertAction ( title: " OK " ,
299
+ style: . default,
300
+ handler: { ( UIAlertAction) in
301
+ let code = codeAlertController. textFields!. first!. text!
302
+ let phoneCredential =
303
+ PhoneAuthProvider . provider ( ) . credential ( withVerificationID: verificationID ?? " " ,
304
+ verificationCode: code)
305
+ completion ( phoneCredential)
306
+ } ) )
307
+ self . present ( codeAlertController, animated: true , completion: nil )
308
+ }
309
+ }
204
310
}
205
311
}
206
312
@@ -250,6 +356,7 @@ final class ViewController: UIViewController {
250
356
action. requiresPassword
251
357
passwordInputLabel. alpha = isPasswordEnabled ? 1.0 : 0.6
252
358
passwordField. isEnabled = isPasswordEnabled
359
+ phoneField. isEnabled = credentialType. requiresPhone
253
360
}
254
361
255
362
fileprivate func showAlert( title: String , message: String ? = " " ) {
@@ -486,11 +593,11 @@ fileprivate enum UserAction: Int, Action {
486
593
/// The list of all possible credential types the operator can use to sign in or link.
487
594
fileprivate enum CredentialType : Int {
488
595
489
- case google, password
596
+ case google, password, phone
490
597
491
598
/// Total number of enum values.
492
599
static var count : Int {
493
- return CredentialType . password . rawValue + 1
600
+ return CredentialType . phone . rawValue + 1
494
601
}
495
602
496
603
/// The text description for a particular enum value.
@@ -500,6 +607,12 @@ fileprivate enum CredentialType: Int {
500
607
return " Google "
501
608
case . password:
502
609
return " Password ➡️️ "
610
+ case . phone:
611
+ if #available( iOS 8 . 0 , * ) {
612
+ return " Phone ➡️️ "
613
+ } else {
614
+ return " - "
615
+ }
503
616
}
504
617
}
505
618
@@ -512,6 +625,11 @@ fileprivate enum CredentialType: Int {
512
625
var requiresPassword : Bool {
513
626
return self == . password
514
627
}
628
+
629
+ /// Whether or not the credential requires phone.
630
+ var requiresPhone : Bool {
631
+ return self == . phone
632
+ }
515
633
}
516
634
517
635
fileprivate extension User {
0 commit comments