Skip to content

Commit cf6c7df

Browse files
SUPERCILEXsamtstern
authored andcommitted
Refactor reset password flow to use new architecture (#1048)
1 parent 7700502 commit cf6c7df

File tree

12 files changed

+308
-169
lines changed

12 files changed

+308
-169
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.firebase.ui.auth.data.model;
2+
3+
import android.support.annotation.NonNull;
4+
import android.support.annotation.Nullable;
5+
import android.support.annotation.RestrictTo;
6+
7+
import com.firebase.ui.auth.util.Preconditions;
8+
9+
/**
10+
* Base state model object.
11+
* <p>
12+
* This state can either be successful or not. In either case, it must be complete to represent
13+
* these states.
14+
*/
15+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
16+
public final class Resource<T> {
17+
private final State mState;
18+
private final T mValue;
19+
private final Exception mException;
20+
21+
/**
22+
* Creates a default, unfinished, state.
23+
*/
24+
public Resource() {
25+
mState = State.LOADING;
26+
mValue = null;
27+
mException = null;
28+
}
29+
30+
/**
31+
* Creates a finished success state.
32+
*
33+
* @param value result of the operation
34+
*/
35+
public Resource(@NonNull T value) {
36+
mState = State.SUCCESS;
37+
mValue = Preconditions.checkNotNull(value, "Success state cannot have null result.");
38+
mException = null;
39+
}
40+
41+
/**
42+
* Creates a finished failure state.
43+
*
44+
* @param exception error in computing the result
45+
*/
46+
public Resource(@NonNull Exception exception) {
47+
mState = State.FAILURE;
48+
mValue = null;
49+
mException = Preconditions.checkNotNull(exception, "Failure state cannot have null error.");
50+
}
51+
52+
@NonNull
53+
public State getState() {
54+
return mState;
55+
}
56+
57+
@Nullable
58+
public final Exception getException() {
59+
return mException;
60+
}
61+
62+
@Nullable
63+
public T getValue() {
64+
return mValue;
65+
}
66+
67+
@Override
68+
public boolean equals(Object o) {
69+
if (this == o) return true;
70+
if (o == null || getClass() != o.getClass()) return false;
71+
72+
Resource<?> resource = (Resource<?>) o;
73+
74+
return mState == resource.mState
75+
&& (mValue == null ? resource.mValue == null : mValue.equals(resource.mValue))
76+
&& (mException == null ? resource.mException == null : mException.equals(resource.mException));
77+
}
78+
79+
@Override
80+
public int hashCode() {
81+
int result = mState.hashCode();
82+
result = 31 * result + (mValue == null ? 0 : mValue.hashCode());
83+
result = 31 * result + (mException == null ? 0 : mException.hashCode());
84+
return result;
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return "Resource{" +
90+
"mState=" + mState +
91+
", mValue=" + mValue +
92+
", mException=" + mException +
93+
'}';
94+
}
95+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.firebase.ui.auth.data.model;
2+
3+
import android.support.annotation.RestrictTo;
4+
5+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
6+
public enum State {
7+
SUCCESS, FAILURE, LOADING
8+
}

auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,10 @@
2222
@SuppressWarnings("Registered")
2323
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
2424
public class AppCompatBase extends HelperActivityBase {
25-
2625
@Override
27-
protected void onCreate(Bundle savedInstance) {
28-
super.onCreate(savedInstance);
29-
configureTheme();
30-
}
31-
32-
private void configureTheme() {
26+
protected void onCreate(Bundle savedInstanceState) {
27+
super.onCreate(savedInstanceState);
3328
setTheme(R.style.FirebaseUI); // Provides default values
34-
setTheme(getFlowParams().themeId);
29+
setTheme(getFlowHolder().getArguments().themeId);
3530
}
36-
3731
}

auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.firebase.ui.auth.ui;
22

33
import android.app.Activity;
4+
import android.arch.lifecycle.ViewModelProviders;
45
import android.content.Context;
56
import android.content.Intent;
67
import android.os.Bundle;
@@ -14,6 +15,7 @@
1415
import com.firebase.ui.auth.util.AuthHelper;
1516
import com.firebase.ui.auth.util.ExtraConstants;
1617
import com.firebase.ui.auth.util.signincontainer.SaveSmartLock;
18+
import com.firebase.ui.auth.util.ui.FlowHolder;
1719
import com.google.firebase.auth.FirebaseUser;
1820

1921
import static com.firebase.ui.auth.util.Preconditions.checkNotNull;
@@ -22,6 +24,8 @@
2224
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
2325
public class HelperActivityBase extends AppCompatActivity {
2426

27+
private FlowHolder mFlowHolder;
28+
2529
private FlowParameters mFlowParameters;
2630
private AuthHelper mAuthHelper;
2731
private ProgressDialogHolder mProgressDialogHolder;
@@ -50,6 +54,15 @@ protected void onDestroy() {
5054
mProgressDialogHolder.dismissDialog();
5155
}
5256

57+
public FlowHolder getFlowHolder() {
58+
if (mFlowHolder == null) {
59+
mFlowHolder = ViewModelProviders.of(this).get(FlowHolder.class);
60+
mFlowHolder.init(FlowParameters.fromIntent(getIntent()));
61+
}
62+
63+
return mFlowHolder;
64+
}
65+
5366
public FlowParameters getFlowParams() {
5467
if (mFlowParameters == null) {
5568
mFlowParameters = FlowParameters.fromIntent(getIntent());

auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,45 @@
1414

1515
package com.firebase.ui.auth.ui.email;
1616

17+
import android.app.Activity;
18+
import android.arch.lifecycle.Observer;
19+
import android.arch.lifecycle.ViewModelProviders;
1720
import android.content.Context;
21+
import android.content.DialogInterface;
1822
import android.content.Intent;
1923
import android.os.Bundle;
20-
import android.support.annotation.NonNull;
2124
import android.support.annotation.RestrictTo;
2225
import android.support.design.widget.TextInputLayout;
26+
import android.support.v7.app.AlertDialog;
2327
import android.view.View;
2428
import android.widget.EditText;
2529

2630
import com.firebase.ui.auth.R;
2731
import com.firebase.ui.auth.data.model.FlowParameters;
32+
import com.firebase.ui.auth.data.model.Resource;
33+
import com.firebase.ui.auth.data.model.State;
2834
import com.firebase.ui.auth.ui.AppCompatBase;
2935
import com.firebase.ui.auth.ui.HelperActivityBase;
30-
import com.firebase.ui.auth.ui.TaskFailureLogger;
3136
import com.firebase.ui.auth.util.ExtraConstants;
37+
import com.firebase.ui.auth.util.ui.ImeHelper;
3238
import com.firebase.ui.auth.util.ui.fieldvalidators.EmailFieldValidator;
33-
import com.google.android.gms.tasks.OnFailureListener;
34-
import com.google.android.gms.tasks.OnSuccessListener;
39+
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
3540
import com.google.firebase.auth.FirebaseAuthInvalidUserException;
3641

3742
/**
3843
* Activity to initiate the "forgot password" flow by asking for the user's email.
3944
*/
4045
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
41-
public class RecoverPasswordActivity extends AppCompatBase implements View.OnClickListener {
42-
private static final String TAG = "RecoverPasswordActivity";
46+
public class RecoverPasswordActivity extends AppCompatBase implements View.OnClickListener,
47+
ImeHelper.DonePressedListener {
48+
private RecoverPasswordHandler mHandler;
4349

50+
private TextInputLayout mEmailInputLayout;
4451
private EditText mEmailEditText;
4552
private EmailFieldValidator mEmailFieldValidator;
4653

47-
public static Intent createIntent(Context context, FlowParameters flowParams, String email) {
48-
return HelperActivityBase.createBaseIntent(context, RecoverPasswordActivity.class, flowParams)
54+
public static Intent createIntent(Context context, FlowParameters params, String email) {
55+
return HelperActivityBase.createBaseIntent(context, RecoverPasswordActivity.class, params)
4956
.putExtra(ExtraConstants.EXTRA_EMAIL, email);
5057
}
5158

@@ -54,51 +61,67 @@ protected void onCreate(Bundle savedInstanceState) {
5461
super.onCreate(savedInstanceState);
5562
setContentView(R.layout.fui_forgot_password_layout);
5663

57-
mEmailFieldValidator =
58-
new EmailFieldValidator((TextInputLayout) findViewById(R.id.email_layout));
64+
mHandler = ViewModelProviders.of(this).get(RecoverPasswordHandler.class);
65+
mHandler.init(getFlowHolder().getArguments());
66+
mHandler.getProgressLiveData().observe(this, new Observer<Resource<String>>() {
67+
@Override
68+
public void onChanged(Resource<String> resource) {
69+
if (resource.getState() == State.LOADING) {
70+
getDialogHolder().showLoadingDialog(R.string.fui_progress_dialog_sending);
71+
return;
72+
}
73+
74+
getDialogHolder().dismissDialog();
75+
if (resource.getState() == State.SUCCESS) {
76+
mEmailInputLayout.setError(null);
77+
showEmailSentDialog(resource.getValue());
78+
} else if (resource.getException() instanceof FirebaseAuthInvalidUserException
79+
|| resource.getException() instanceof FirebaseAuthInvalidCredentialsException) {
80+
// No FirebaseUser exists with this email address, show error.
81+
mEmailInputLayout.setError(getString(R.string.fui_error_email_does_not_exist));
82+
} else {
83+
mEmailInputLayout.setError(resource.getException().getLocalizedMessage());
84+
}
85+
}
86+
});
87+
88+
mEmailInputLayout = findViewById(R.id.email_layout);
5989
mEmailEditText = findViewById(R.id.email);
90+
mEmailFieldValidator = new EmailFieldValidator(mEmailInputLayout);
6091

6192
String email = getIntent().getStringExtra(ExtraConstants.EXTRA_EMAIL);
6293
if (email != null) {
6394
mEmailEditText.setText(email);
6495
}
6596

97+
ImeHelper.setImeOnDoneListener(mEmailEditText, this);
6698
findViewById(R.id.button_done).setOnClickListener(this);
6799
}
68100

69-
private void next(final String email) {
70-
getAuthHelper().getFirebaseAuth()
71-
.sendPasswordResetEmail(email)
72-
.addOnFailureListener(
73-
new TaskFailureLogger(TAG, "Error sending password reset email"))
74-
.addOnSuccessListener(new OnSuccessListener<Void>() {
75-
@Override
76-
public void onSuccess(Void aVoid) {
77-
getDialogHolder().dismissDialog();
78-
RecoveryEmailSentDialog.show(
79-
email, getSupportFragmentManager());
80-
}
81-
})
82-
.addOnFailureListener(this, new OnFailureListener() {
83-
@Override
84-
public void onFailure(@NonNull Exception e) {
85-
getDialogHolder().dismissDialog();
86-
87-
if (e instanceof FirebaseAuthInvalidUserException) {
88-
// No FirebaseUser exists with this email address, show error.
89-
mEmailEditText.setError(getString(R.string.fui_error_email_does_not_exist));
90-
}
91-
}
92-
});
93-
}
94-
95101
@Override
96102
public void onClick(View view) {
97-
if (view.getId() == R.id.button_done) {
98-
if (mEmailFieldValidator.validate(mEmailEditText.getText())) {
99-
getDialogHolder().showLoadingDialog(R.string.fui_progress_dialog_sending);
100-
next(mEmailEditText.getText().toString());
101-
}
103+
if (view.getId() == R.id.button_done
104+
&& mEmailFieldValidator.validate(mEmailEditText.getText())) {
105+
onDonePressed();
102106
}
103107
}
108+
109+
@Override
110+
public void onDonePressed() {
111+
mHandler.startReset(mEmailEditText.getText().toString());
112+
}
113+
114+
private void showEmailSentDialog(String email) {
115+
new AlertDialog.Builder(this)
116+
.setTitle(R.string.fui_title_confirm_recover_password)
117+
.setMessage(getString(R.string.fui_confirm_recovery_body, email))
118+
.setOnDismissListener(new DialogInterface.OnDismissListener() {
119+
@Override
120+
public void onDismiss(DialogInterface dialog) {
121+
finish(Activity.RESULT_OK, new Intent());
122+
}
123+
})
124+
.setPositiveButton(android.R.string.ok, null)
125+
.show();
126+
}
104127
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.firebase.ui.auth.ui.email;
2+
3+
import android.app.Application;
4+
import android.arch.lifecycle.LiveData;
5+
import android.arch.lifecycle.MutableLiveData;
6+
import android.support.annotation.NonNull;
7+
import android.support.annotation.RestrictTo;
8+
9+
import com.firebase.ui.auth.data.model.Resource;
10+
import com.firebase.ui.auth.util.data.AuthViewModelBase;
11+
import com.google.android.gms.tasks.OnCompleteListener;
12+
import com.google.android.gms.tasks.Task;
13+
14+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
15+
public class RecoverPasswordHandler extends AuthViewModelBase {
16+
private final MutableLiveData<Resource<String>> mProgressLiveData =
17+
new MutableLiveData<>();
18+
19+
public RecoverPasswordHandler(Application application) {
20+
super(application);
21+
}
22+
23+
public LiveData<Resource<String>> getProgressLiveData() {
24+
return mProgressLiveData;
25+
}
26+
27+
public void startReset(final String email) {
28+
mProgressLiveData.setValue(new Resource<String>());
29+
getAuth().sendPasswordResetEmail(email)
30+
.addOnCompleteListener(new OnCompleteListener<Void>() {
31+
@Override
32+
public void onComplete(@NonNull Task<Void> task) {
33+
Resource<String> state = task.isSuccessful() ? new Resource<>(email)
34+
: new Resource<String>(task.getException());
35+
mProgressLiveData.setValue(state);
36+
}
37+
});
38+
}
39+
}

0 commit comments

Comments
 (0)