-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite phone auth with new architecture and finalize progress revamp #1253
Rewrite phone auth with new architecture and finalize progress revamp #1253
Conversation
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Not gonna look at this yet but +604 -1406 !!!! |
…rewrite # Conflicts: # auth/src/main/java/com/firebase/ui/auth/data/remote/TwitterSignInHandler.java # auth/src/main/java/com/firebase/ui/auth/ui/phone/VerifyPhoneNumberFragment.java # auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneActivityTest.java
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
@samtstern Alrighty, this one is ready for review! Gonna take a look a your PR next. Some notes about this PR:
|
@SUPERCILEX excited to review this one! But I've come down with a really strong case of I/O fever, so if I get to this at all this week it will be on Friday. Sorry and appreciate the effort / patience! |
<string name="fui_error_too_many_attempts">Este número de teléfono se usó demasiadas veces</string> | ||
<string name="fui_error_quota_exceeded">Ocurrió un problema durante la verificación de tu número de teléfono</string> | ||
<string name="fui_error_session_expired">Este código ya no es válido</string> | ||
<string name="fui_sign_in_with_phone_number">Acceder con el número de teléfono</string> | ||
<string name="fui_done">Listo</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely a highly annoying request, but could we split out the string removals into another PR? That way this one doesn't have 177 files changed and thousands of lines. I don't want an important behavioral change to get lost among all of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at all, I thought you might ask so I removed all the strings in one easily rebasable commit. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some brief comments.
@@ -127,6 +129,16 @@ private void redirectSignIn(String provider, String email) { | |||
EmailActivity.createIntent(getApplication(), getArguments(), email), | |||
RequestCodes.EMAIL_FLOW))); | |||
break; | |||
case PhoneAuthProvider.PROVIDER_ID: | |||
Bundle args = new Bundle(); | |||
args.putString(ExtraConstants.PHONE, email); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename the email
arg to identifier
or something? Seems strange to see put(PHONE, email)
@@ -70,10 +67,6 @@ public FlowParameters getFlowParams() { | |||
return mParams; | |||
} | |||
|
|||
public AuthHelper getAuthHelper() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the helper activity doesn't even have a helper! Love seeing this class die haha.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, that was the first class to die when I started the refactor—it killed me when I had to add it back for the staged PRs. 😆
nationalNumber = params.getString(ExtraConstants.NATIONAL_NUMBER); | ||
} | ||
|
||
if (!TextUtils.isEmpty(countryIso) && !TextUtils.isEmpty(nationalNumber)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This block is pretty much the heart of the decision making here so I think a comment or two would be good, especially for the final elseif block.
mPhoneEditText.setSelection(number.getPhoneNumber().length()); | ||
} | ||
if (PhoneNumber.isCountryValid(number)) { | ||
setCountryCode(number); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If isCountryValid
is true
but isValid
is false
then it looks like we'll call onNext()
with a situation that will cause getPseudoValidPhoneNumber()
to return null and then put an error on screen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, you're right.
mPhoneNumber = savedInstanceState.getString(KEY_VERIFICATION_PHONE); | ||
final PhoneProviderResponseHandler handler = | ||
ViewModelProviders.of(this).get(PhoneProviderResponseHandler.class); | ||
handler.init(getFlowParams()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: name this something more specific than handler
? When it's used inside of verificationHandler
it gets a bit confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed verificationHandler
to phoneVerifier
.
protected void onSuccess(@NonNull PhoneAuthCredential credential) { | ||
handler.startSignIn(credential, new IdpResponse.Builder( | ||
new User.Builder(PhoneAuthProvider.PROVIDER_ID, null) | ||
.setPhoneNumber(getPhoneNumber()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok looking at the two methods where we do fragment detection, getErrorView()
and getPhoneNumber()
, that's where we both agree we could improve.
Here I see that we use getPhoneNumber()
in the verification handler to kick off the other handler.
What's the original reason why this flow benefits from being a multi-Fragment activity rather than a series of activities? Would that help cut down on the patterns we don't like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You actually just gave me a different idea here: I made the phone number pass through the verification view model—not sure why I didn't think of that before. 🤦♂️ It still doesn't address the error view thing though, but that's not as bad as the phone number bit IMO.
As for activities, I'm not sure how they would be solving our problem... they would make it harder to talk between them since we'd be relying on a bunch of bundles. Whad'ya think of bfb3b22? It's certainly an improvement over the current PhoneActivity
! 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks better to me!
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
} | ||
|
||
private void start(PhoneNumber number) { | ||
if (PhoneNumber.isValid(number)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: nornmally I think this pattern is clearer:
if (bad condition) {
// ...
return;
}
// Good condition....
Less indentation and survives future editing better.
|
||
import com.firebase.ui.auth.R; | ||
|
||
public final class CompletableProgressDialog extends DialogFragment { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am all for killing this dialog, but we should preserve the UX that it was meant to provide. This special "checkmark progress dialog" thing came from UX studies that the former Digits team did.
In the situation where the phone number is auto-verified or the SMS is auto-retrieved, it can be opaque to the user why they were signed in without any action.
So we need to handle each of those two cases in the UI specifically.
} | ||
|
||
private void onCodeSent() { | ||
completeLoadingDialog(getString(R.string.fui_code_sent)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is part of the same comment from above, making sure that even when things happen really quickly the user has a chance to notice each step of phone auth.
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { | ||
@Override | ||
public void onVerificationCompleted(@NonNull PhoneAuthCredential credential) { | ||
setResult(Resource.forSuccess(Pair.create(number, credential))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the case where retrieval happened without any user interaction. Any ideas for how we can send a special signal to the UI and what it should look like?
/** | ||
* Activity to control the entire phone verification flow. Plays host to {@link | ||
* VerifyPhoneNumberFragment} and {@link SubmitConfirmationCodeFragment} | ||
* CheckPhoneNumberFragment} and {@link SubmitConfirmationCodeFragment} | ||
*/ | ||
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) | ||
public class PhoneActivity extends AppCompatBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this text-free dialog that flickers into and out of existence at the start of the flow?
https://drive.google.com/file/d/1DifkJhYY8iPVGW2AWgTnc0muPyFPWsPf/view
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That one isn't my fault, it's the Smart Lock dialog. 🤷♂️ Not much we can do there.
mSubmitConfirmationButton = view.findViewById(R.id.submit_confirmation_code); | ||
|
||
getActivity().setTitle(getString(R.string.fui_verify_your_phone_title)); | ||
mCountdown.run(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be mHandler.postRunnable(mCountDown())
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
@SUPERCILEX do you think you can address the UX concerns and all other remaining issues in time for Also if there are any translations needed for this and you're shooting for |
@samtstern yeah, probably not going to get this done in time so 4.0.1 it is. (Unless I beat the tos translations and you have time to review—again, not likely. 😂) |
# Conflicts: # auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java # auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java # auth/src/main/java/com/firebase/ui/auth/ui/phone/CompletableProgressDialog.java # auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java # auth/src/main/java/com/firebase/ui/auth/ui/phone/SubmitConfirmationCodeFragment.java # auth/src/main/java/com/firebase/ui/auth/ui/phone/VerifyPhoneNumberFragment.java # auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java # auth/src/main/res/layout/fui_phone_progress_dialog.xml
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
protected void onSuccess(@NonNull PhoneVerification verification) { | ||
if (verification.isAutoVerified()) { | ||
Toast.makeText( | ||
PhoneActivity.this, R.string.fui_verified, Toast.LENGTH_LONG).show(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this address your auto verified concerns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a Snackbar? Or are we using Toast
since it will last across the UI transition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh also I just went through and tried this, I think we should extend the fui_verified
message to be something like "Phone number automatically verified"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm using a Toast since the UI will disappear too fast. And good point about the string, I'll rename it to fui_auto_verified
too to minimize translation confusion.
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good!
Btw not sure if you saw this but it's now pretty easy to test all the different branches of this flow:
https://firebase.google.com/docs/auth/android/phone-auth#integration-testing
@@ -97,15 +74,13 @@ public void startSaveCredentials( | |||
|
|||
@Override | |||
public void showProgress(@StringRes int message) { | |||
getDialogHolder().showLoadingDialog(message); | |||
throw new UnsupportedOperationException( | |||
"Either a fragment or activity must handle progress updates."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just make these two methods abstract
then if we want to force the subclass to implement them?
I think what you're trying to do is not allow events to bubble up from fragments but maybe then we should remove the default behavior from the fragment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, I thought we still had some fragments that forwarded progress updates to the activity, but I guess the was in the ProgressDialog
world. Everything is abstract now. 👍
countryIso, | ||
String.valueOf(PhoneNumberUtils.getCountryCode(countryIso)))); | ||
} else if (getFlowParams().enableHints) { | ||
FlowUtils.unhandled(this, new PendingIntentRequiredException( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a strange patter: we're faking a PendingIntentRequiredException
just to launch the hint picker. Should we instead bubble up some event that will allow this to be fired from the ViewModel
as normal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I'm even using mHandler.getApplication()
for the context so I must have forgotten this bit sometime while refactoring. 😊
protected void onSuccess(@NonNull PhoneVerification verification) { | ||
if (verification.isAutoVerified()) { | ||
Toast.makeText( | ||
PhoneActivity.this, R.string.fui_verified, Toast.LENGTH_LONG).show(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a Snackbar? Or are we using Toast
since it will last across the UI transition?
@Override | ||
protected void onFailure(@NonNull Exception e) { | ||
if (e instanceof PhoneNumberVerificationRequiredException) { | ||
// Ignore if resending verification code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add some more explanation for how this comment relates to the code below?
} | ||
@Override | ||
public void showProgress(int message) { | ||
FragmentBase fragment = (CheckPhoneNumberFragment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we DRY up the first few lines from showProgress
and hideProgress
into some getActiveFragment
method or something?
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
@SUPERCILEX nice! This looks good to me once the conflicts are gone. I think for |
…rewrite # Conflicts: # auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java
@samtstern SGTM, though I had already merged from 4.1 dev. Do you want me to try and rebase those changes out to target 4.0.1? |
Oh whoops. That's my bad. Don't worry about it this can be in 4.1
…On Wed, May 30, 2018, 5:29 PM Alex Saveau ***@***.***> wrote:
@samtstern <https://github.com/samtstern> SGTM, though I had already
merged from 4.1 dev. Do you want me to try and rebase those changes out to
target 4.0.1?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1253 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AIEw6u1MY8IKGtY17wKh3pgfGqjw21klks5t3zmCgaJpZM4TSo1m>
.
|
@SUPERCILEX boom! Your second big kahuna is now complete! |
This is it! Half a year later and we're almost done! 👏🍾🎉