Skip to content

Commit 9e3a9ee

Browse files
authored
Merge pull request firebase#175 from firebase/custom-recovery
implement custom password recovery controller
2 parents e2c30de + a0b50b5 commit 9e3a9ee

25 files changed

+430
-89
lines changed

FirebaseAuthUI/FIRAuthUI.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
@class FIREmailEntryViewController;
2626
@class FIRPasswordSignInViewController;
2727
@class FIRPasswordSignUpViewController;
28+
@class FIRPasswordRecoveryViewController;
2829

2930
NS_ASSUME_NONNULL_BEGIN
3031

@@ -68,25 +69,34 @@ typedef void (^FIRAuthUIResultCallback)(FIRUser *_Nullable user, NSError *_Nulla
6869
- (FIREmailEntryViewController *)emailEntryViewControllerForAuthUI:(FIRAuthUI *)authUI;
6970

7071
/** @fn passwordSignInViewControllerForAuthUI:email:
71-
@brief Sent to the receiver to ask for an instance of @c FIRPasswordSignInViewController subclass
72-
to allow sign-in UI customizations.
73-
@param authUI The @c FIRAuthUI instance sending the message.
74-
@param email The email user is using for sin-in.
75-
@return an instance of @c FIRPasswordSignInViewController subclass.
72+
@brief Sent to the receiver to ask for an instance of @c FIRPasswordSignInViewController subclass
73+
to allow sign-in UI customizations.
74+
@param authUI The @c FIRAuthUI instance sending the message.
75+
@param email The email user is using for sin-in.
76+
@return an instance of @c FIRPasswordSignInViewController subclass.
7677
*/
7778
- (FIRPasswordSignInViewController *)passwordSignInViewControllerForAuthUI:(FIRAuthUI *)authUI
7879
email:(NSString *)email;
7980

8081
/** @fn passwordSignInViewControllerForAuthUI:email:
81-
@brief Sent to the receiver to ask for an instance of @c FIRPasswordSignUpViewController subclass
82-
to allow sign-up UI customizations.
83-
@param authUI The @c FIRAuthUI instance sending the message.
84-
@param email The email user is using for sin-in.
85-
@return an instance of @c FIRPasswordSignUpViewController subclass.
82+
@brief Sent to the receiver to ask for an instance of @c FIRPasswordSignUpViewController subclass
83+
to allow sign-up UI customizations.
84+
@param authUI The @c FIRAuthUI instance sending the message.
85+
@param email The email user is using for sin-in.
86+
@return an instance of @c FIRPasswordSignUpViewController subclass.
8687
*/
8788
- (FIRPasswordSignUpViewController *)passwordSignUpViewControllerForAuthUI:(FIRAuthUI *)authUI
8889
email:(NSString *)email;
8990

91+
/** @fn passwordRecoveryViewControllerForAuthUI:email:
92+
@brief Sent to the receiver to ask for an instance of @c FIRPasswordRecoveryViewController subclass
93+
to allow sign-up UI customizations.
94+
@param authUI The @c FIRAuthUI instance sending the message.
95+
@param email The email user is using for password recovery.
96+
@return an instance of @c FIRPasswordRecoveryViewController subclass.
97+
*/
98+
- (FIRPasswordRecoveryViewController *)passwordRecoveryViewControllerForAuthUI:(FIRAuthUI *)authUI
99+
email:(NSString *)email;
90100
@end
91101

92102
/** @class FIRAuthUI

FirebaseAuthUI/FIRAuthUIStrings.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
*/
4646
+ (NSString *)invalidEmailError;
4747

48+
/** @fn invalidPasswordError
49+
@brief Error message displayed when user enters an empty password.
50+
@return Localized string.
51+
*/
52+
+ (NSString *)invalidPasswordError;
53+
4854
/** @fn cannotAuthenticateError
4955
@brief Error message displayed when the app cannot authenticate user's account.
5056
@return Localized string.

FirebaseAuthUI/FIRAuthUIStrings.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
static NSString *const kSignInWithEmail = @"SignInWithEmail";
2525
static NSString *const kEnterYourEmail = @"EnterYourEmail";
2626
static NSString *const kInvalidEmailError = @"InvalidEmailError";
27+
static NSString *const kInvalidPasswordError = @"InvalidPasswordError";
2728
static NSString *const kCannotAuthenticateError = @"CannotAuthenticateError";
2829
static NSString *const kExistingAccountTitle = @"ExistingAccountTitle";
2930
static NSString *const kProviderUsedPreviouslyMessage = @"ProviderUsedPreviouslyMessage";
@@ -104,6 +105,10 @@ + (NSString *)invalidEmailError {
104105
return [self localizedStringForKey:kInvalidEmailError];
105106
}
106107

108+
+ (NSString *)invalidPasswordError {
109+
return [self localizedStringForKey:kInvalidPasswordError];
110+
}
111+
107112
+ (NSString *)cannotAuthenticateError {
108113
return [self localizedStringForKey:kCannotAuthenticateError];
109114
}

FirebaseAuthUI/FIREmailEntryViewController.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ NS_ASSUME_NONNULL_BEGIN
3232
*/
3333
- (void)onNext:(NSString *)emailText;
3434

35-
/** @fn onEmailValueChanged:
35+
/** @fn didChangeEmail:
3636
@brief Should be called after any change of email value. Updates UI controls state
3737
(e g state of next button)
3838
@param emailText Email value entered by user.
3939
*/
40-
- (void)onEmailValueChanged:(NSString *)emailText;
40+
- (void)didChangeEmail:(NSString *)emailText;
4141

4242
@end
4343

FirebaseAuthUI/FIREmailEntryViewController.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ - (void)onNext:(NSString *)emailText {
165165
}
166166

167167
- (void)textFieldDidChange {
168-
[self onEmailValueChanged:_emailField.text];
168+
[self didChangeEmail:_emailField.text];
169169
}
170170

171-
- (void)onEmailValueChanged:(NSString *)emailText {
171+
- (void)didChangeEmail:(NSString *)emailText {
172172
self.navigationItem.rightBarButtonItem.enabled = (emailText.length > 0);
173173
}
174174

@@ -199,7 +199,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView
199199
[cell.textField addTarget:self
200200
action:@selector(textFieldDidChange)
201201
forControlEvents:UIControlEventEditingChanged];
202-
[self onEmailValueChanged:_emailField.text];
202+
[self didChangeEmail:_emailField.text];
203203
return cell;
204204
}
205205

FirebaseAuthUI/FIRPasswordRecoveryViewController.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ NS_ASSUME_NONNULL_BEGIN
2525
*/
2626
@interface FIRPasswordRecoveryViewController : FIRAuthUIBaseViewController
2727

28-
/** @property footerTextView
29-
@brief The text view in the footer of the table.
30-
*/
31-
@property(nonatomic, strong) IBOutlet UITextView *footerTextView;
32-
3328
/** @fn initWithNibName:bundle:authUI:
3429
@brief Please use @c initWithAuthUI:email:.
3530
*/
@@ -42,14 +37,33 @@ NS_ASSUME_NONNULL_BEGIN
4237
*/
4338
- (instancetype)initWithAuthUI:(FIRAuthUI *)authUI NS_UNAVAILABLE;
4439

45-
/** @fn initWithAuthUI:email:
40+
/** @fn initWithNibName:bundle:authUI:email:
4641
@brief Designated initializer.
42+
@param nibNameOrNil The name of the nib file to associate with the view controller.
43+
@param nibBundleOrNil The bundle in which to search for the nib file.
4744
@param authUI The @c FIRAuthUI instance that manages this view controller.
4845
@param email The email address of the user.
4946
*/
50-
- (instancetype)initWithAuthUI:(FIRAuthUI *)authUI
51-
email:(NSString *_Nullable)email NS_DESIGNATED_INITIALIZER;
47+
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil
48+
bundle:(nullable NSBundle *)nibBundleOrNil
49+
authUI:(FIRAuthUI *)authUI
50+
email:(NSString *_Nullable)email NS_DESIGNATED_INITIALIZER;
51+
5252

53+
/** @fn didChangeEmail:
54+
@brief Should be called after any change of email value. Updates UI controls state
55+
(e g state of send button)
56+
@param email The email address of the user.
57+
*/
58+
- (void)didChangeEmail:(NSString *)email;
59+
60+
61+
/** @fn recoverEmail:
62+
@brief Should be called when user want to recover password for specified email.
63+
Sends email recover request.
64+
@param email The email address of the user.
65+
*/
66+
- (void)recoverEmail:(NSString *)email;
5367
@end
5468

5569
NS_ASSUME_NONNULL_END

FirebaseAuthUI/FIRPasswordRecoveryViewController.m

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,16 @@
3333
static const CGFloat kFooterTextViewHorizontalInset = 8.0f;
3434

3535
@interface FIRPasswordRecoveryViewController () <UITableViewDataSource, UITextFieldDelegate>
36+
/** @property footerTextView
37+
@brief The text view in the footer of the table.
38+
*/
39+
@property(nonatomic, strong) IBOutlet UITextView *footerTextView;
40+
3641
@end
3742

3843
@implementation FIRPasswordRecoveryViewController {
3944
/** @var _email
40-
@brief The @c The email address of the user from the previous screen.
45+
@brief The @c email address of the user from the previous screen.
4146
*/
4247
NSString *_email;
4348

@@ -47,10 +52,12 @@ @implementation FIRPasswordRecoveryViewController {
4752
UITextField *_emailField;
4853
}
4954

50-
- (instancetype)initWithAuthUI:(FIRAuthUI *)authUI
51-
email:(NSString *_Nullable)email {
52-
self = [super initWithNibName:NSStringFromClass([self class])
53-
bundle:[FIRAuthUIUtils frameworkBundle]
55+
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil
56+
bundle:(nullable NSBundle *)nibBundleOrNil
57+
authUI:(FIRAuthUI *)authUI
58+
email:(NSString *_Nullable)email {
59+
self = [super initWithNibName:nibNameOrNil
60+
bundle:nibBundleOrNil
5461
authUI:authUI];
5562
if (self) {
5663
_email = [email copy];
@@ -86,7 +93,10 @@ - (void)viewDidLayoutSubviews {
8693
#pragma mark - Actions
8794

8895
- (void)send {
89-
NSString *email = _emailField.text;
96+
[self recoverEmail:_emailField.text];
97+
}
98+
99+
- (void)recoverEmail:(NSString *)email {
90100
if (![[self class] isValidEmail:email]) {
91101
[self showAlertWithMessage:[FIRAuthUIStrings invalidEmailError]];
92102
return;
@@ -96,36 +106,37 @@ - (void)send {
96106

97107
[self.auth sendPasswordResetWithEmail:email
98108
completion:^(NSError *_Nullable error) {
99-
// The dispatch is a workaround for a bug in FirebaseAuth 3.0.2, which doesn't call the
100-
// completion block on the main queue.
101-
dispatch_async(dispatch_get_main_queue(), ^{
102-
[self decrementActivity];
103-
104-
if (error) {
105-
if (error.code == FIRAuthErrorCodeUserNotFound) {
106-
[self showAlertWithMessage:[FIRAuthUIStrings userNotFoundError]];
107-
return;
108-
}
109-
110-
[self.navigationController dismissViewControllerAnimated:YES completion:^{
111-
[self.authUI invokeResultCallbackWithUser:nil error:error];
112-
}];
113-
return;
114-
}
115-
116-
NSString *message =
117-
[NSString stringWithFormat:[FIRAuthUIStrings passwordRecoveryEmailSentMessage], email];
118-
[self showAlertWithMessage:message];
119-
});
120-
}];
109+
// The dispatch is a workaround for a bug in FirebaseAuth 3.0.2, which doesn't call the
110+
// completion block on the main queue.
111+
dispatch_async(dispatch_get_main_queue(), ^{
112+
[self decrementActivity];
113+
114+
if (error) {
115+
if (error.code == FIRAuthErrorCodeUserNotFound) {
116+
[self showAlertWithMessage:[FIRAuthUIStrings userNotFoundError]];
117+
return;
118+
}
119+
120+
[self.navigationController dismissViewControllerAnimated:YES completion:^{
121+
[self.authUI invokeResultCallbackWithUser:nil error:error];
122+
}];
123+
return;
124+
}
125+
126+
NSString *message =
127+
[NSString stringWithFormat:[FIRAuthUIStrings passwordRecoveryEmailSentMessage], email];
128+
[self showAlertWithMessage:message];
129+
});
130+
}];
121131
}
122132

123133
- (void)textFieldDidChange {
124-
[self updateActionButton];
134+
[self didChangeEmail:_emailField.text];
125135
}
126136

127-
- (void)updateActionButton {
128-
self.navigationItem.rightBarButtonItem.enabled = (_emailField.text.length > 0);
137+
- (void)didChangeEmail:(NSString *)email {
138+
self.navigationItem.rightBarButtonItem.enabled = (email.length > 0);
139+
129140
}
130141

131142
#pragma mark - UITableViewDataSource
@@ -153,7 +164,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView
153164
[cell.textField addTarget:self
154165
action:@selector(textFieldDidChange)
155166
forControlEvents:UIControlEventEditingChanged];
156-
[self updateActionButton];
167+
[self didChangeEmail:_emailField.text];
157168
return cell;
158169
}
159170

FirebaseAuthUI/FIRPasswordSignInViewController.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@ NS_ASSUME_NONNULL_BEGIN
2424
@brief The view controller that asks for user's password.
2525
*/
2626
@interface FIRPasswordSignInViewController : FIRAuthUIBaseViewController
27-
{
28-
@protected
29-
/** @var _email
30-
@brief The @c email address of the user from the previous screen.
31-
*/
32-
NSString *_email;
33-
34-
}
3527

3628
/** @fn initWithNibName:bundle:authUI:
3729
@brief Please use @c initWithNibName:bundle:authUI:email:.

FirebaseAuthUI/FIRPasswordSignInViewController.m

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ @interface FIRPasswordSignInViewController () <UITableViewDataSource, UITextFiel
3232
@end
3333

3434
@implementation FIRPasswordSignInViewController {
35+
/** @var _email
36+
@brief The @c email address of the user from the previous screen.
37+
*/
38+
NSString *_email;
39+
3540
/** @var _emailField
3641
@brief The @c UITextField that user enters email address into.
3742
*/
@@ -77,6 +82,10 @@ - (void)signInWithEmail:(NSString *)email andPassword:(NSString *)password {
7782
[self showAlertWithMessage:[FIRAuthUIStrings invalidEmailError]];
7883
return;
7984
}
85+
if (password.length <= 0) {
86+
[self showAlertWithMessage:[FIRAuthUIStrings invalidPasswordError]];
87+
return;
88+
}
8089

8190
[self incrementActivity];
8291

@@ -113,9 +122,16 @@ - (void)signIn {
113122
}
114123

115124
- (void)forgotPasswordForEmail:(NSString *)email {
116-
UIViewController *viewController =
117-
[[FIRPasswordRecoveryViewController alloc] initWithAuthUI:self.authUI
118-
email:email];
125+
UIViewController *viewController;
126+
if ([self.authUI.delegate respondsToSelector:@selector(passwordRecoveryViewControllerForAuthUI:email:)]) {
127+
viewController = [self.authUI.delegate passwordRecoveryViewControllerForAuthUI:self.authUI
128+
email:email];
129+
} else {
130+
viewController = [[FIRPasswordRecoveryViewController alloc] initWithNibName:NSStringFromClass([FIRPasswordRecoveryViewController class])
131+
bundle:[FIRAuthUIUtils frameworkBundle]
132+
authUI:self.authUI
133+
email:email];
134+
}
119135
[self pushViewController:viewController];
120136

121137
}

FirebaseAuthUI/FIRPasswordSignUpViewController.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,6 @@ NS_ASSUME_NONNULL_BEGIN
2424
@brief The view controller where user signs up as a password account.
2525
*/
2626
@interface FIRPasswordSignUpViewController : FIRAuthUIBaseViewController
27-
{
28-
@protected
29-
/** @var _email
30-
@brief The @c email address of the user from the previous screen.
31-
*/
32-
NSString *_email;
33-
}
3427

3528
/** @property footerTextView
3629
@brief The text view in the footer of the table.

0 commit comments

Comments
 (0)