Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@samtstern
Copy link
Contributor

@samtstern samtstern commented Jan 24, 2018

WIP for #1123 πŸ’€

Change-Id: Id8ff386e4e2f3b567d351b644cd0fa8a7fb1c5be
Change-Id: Idd5aa9d75041a665273531ae76a369b27bc35e6e
Change-Id: Iae2b2cd5232dce19c2436145448cd1effd972659
Change-Id: I814b28ec989b86904c5914fbbe57345eaea7e412
Change-Id: I6d25fb985a35a8d3e090fa85e9f2d835c5e8b404
Change-Id: Iffc99fe57edd600cb1488ae562d410dace399564
@samtstern
Copy link
Contributor Author

@SUPERCILEX ok I just got into exactly the situation you said would happen: I've got identical code in two ViewModels.

How would you unify SmartLockViewModel and WelcomeBackPasswordHandler in your proposed design?

@SUPERCILEX
Copy link
Collaborator

I basically had a God class that took in an IdpResponse and handled everything from there. The main issue was that it needed to stay alive even if activities on top of the stack forced lower ones to die. I think a solution to that (which would remove my gross static fields) would be to just store the IdpResponse in the saved state and then restore the God class to its correct state. To fix the God class, I think we could create bunch of repository classes that are in charge of individual stuff like idp, email, and phone auth and saving the credential. Then we would just need a view model to coordinate all that.

Then again, do you have any better ideas? 😊

Change-Id: Ibe01e7a4341e8a9c0544981a92dcebec69151b94
Change-Id: Id25fc69430ad830dfd71dcdcf0c48bfd5055b982
Change-Id: I2191225ea9db5a1efd5c68816781259c24ce1f20
Change-Id: I18817b538c556516070f1be0c956a11c93e712d2
@samtstern
Copy link
Contributor Author

@SUPERCILEX I got rid of the duplicated logic. There aren't really any new abstractions here, the view just talks to multiple view models and calls one when the other is finished.

I'd like to remove all the logic from the view, but I couldn't think of a good way to do that right now. At least this continues the refactor without yet having any duplicated logic. Imo that's the minimum we can do at the moment.

Change-Id: I447b6838e0e9f61af80d868ba252d19e1788fdc8
@samtstern samtstern changed the title [WIP] Kill smartlock fragments Kill smartlock fragments Feb 6, 2018
@samtstern
Copy link
Contributor Author

@SUPERCILEX any thoughts on the recent changes?

@SUPERCILEX
Copy link
Collaborator

Will take a look at this tomorrow. πŸ‘

Copy link
Collaborator

@SUPERCILEX SUPERCILEX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like where this is going! My implementation failed in that it tried to have one God class do everything, so having a bunch of small, reusable ViewModels is refreshing.

Just a few comments, but I think this is good to go! πŸ˜„

private final Exception mException;

/**
* Creates a successful Resource<Void>.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creates a successful, empty Resource. would be clearer to read in the source code.

* @param exception error in computing the result
*/
public Resource(@NonNull Exception exception) {
Resource(@NonNull Exception exception) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those static factory methods look great! Is there any reason to keep these constructors at all?

mException = Preconditions.checkNotNull(exception, "Failure state cannot have null error.");
}

Resource(State state, T value, Exception exception) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be private?

null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "STATUS: Failed to send resolution.", e);
finish(RESULT_OK, mPendingIdpResponse.toIntent());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this implementation is specific to Smart Lock being failure tolerant, I feel like we should just inline it or add a comment specifying that it will finish the activity should an error occur. What do you think?

break;
case SUCCESS:
case FAILURE:
finish(RESULT_OK, mPendingIdpResponse.toIntent());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this seems too specific to Smart Lock to be in HelperActivityBase πŸ€”.


if (savedInstanceState != null) {
mPendingPassword = savedInstanceState.getString(ExtraConstants.EXTRA_PASSWORD, null);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm not fully understanding the idea behind these pending data, but wouldn't it make more sense to keep those around in the ViewModel? That seems to be what you're trying to do... πŸ€·β€β™‚οΈ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh. Thank you. I still have some bad old instincts from the pre-ViewModel dark ages.

case SUCCESS:
getDialogHolder().dismissDialog();

// TODO: Should this logic be in the View? If not how do we link the view models?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to have this in the View since it's acting as the glue binding all the different UI components together: we're moving from sign-in to credential input which are two different "screens".

import com.google.firebase.auth.FirebaseUser;

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class SaveSmartLock extends SmartLockBase<Void> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YAAAASSSSSSS! Thank you! πŸ‘πŸ™ŒπŸŽ‰πŸ₯‚πŸ˜

*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class SignInDelegate extends SmartLockBase<CredentialRequestResponse> {
public class SignInDelegate extends FragmentBase
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tick, tok, tick, tok, tick, tok... 😏

mResultLiveData.setValue(Resource.forVoidSuccess());
} else {
Log.e(TAG, "SAVE: Canceled by user.");
mResultLiveData.setValue(Resource.<Void>forFailure(new Exception("Save canceled by user.")));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably use FirebaseUiException.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump.

Change-Id: I1637e6670d6d4b7b3eab43f6d7fe4ad256a35fdf
Change-Id: I482e5a3d837bd88d85c9eb0e4299d23660c96185
Change-Id: I14a839e8acf99499de69a5d5d628adfccabe0f86
@samtstern samtstern changed the base branch from master to version-3.2.2-dev February 15, 2018 18:15
@firebase firebase deleted a comment from googlebot Feb 15, 2018
@samtstern
Copy link
Contributor Author

@SUPERCILEX thanks for taking a look. Still trying to untangle all this.

You just made me think: should smartlock just actually be another view? It could be a transparent Activity that we start for result whenever the flow needs to end in a save.

It seems like that would clean up everything, but want to get your thoughts before I do anything that crazy.

@samtstern
Copy link
Contributor Author

@SUPERCILEX I prototyped something here:
#1151

@SUPERCILEX
Copy link
Collaborator

@samtstern Actually, yeah, #1151 makes a lot of sense: if we're going to have everything be cleanly separated by component, then Smart Lock should be in its own activity. #1151 certainly makes HelperActivityBase nicer! πŸ˜‰

@samtstern
Copy link
Contributor Author

@SUPERCILEX ok I am going to go forward with that approach then, thanks for the sanity check. And sorry this PR is getting so big πŸ€·β€β™‚οΈ

@SUPERCILEX
Copy link
Collaborator

Haha, no prob!

Change-Id: Ibc686e40c998717eadc12c868e81857d5c71d097
Change-Id: I2fccf30aca42391d9317c33f2a65aab7ee092f7b
@samtstern samtstern added this to the 3.2.2 milestone Feb 16, 2018
@samtstern
Copy link
Contributor Author

samtstern commented Feb 16, 2018

@SUPERCILEX ok this one is almost done except for some rotational issues with the CredentialSaveActivity. The save dialog currently stacks if you rotate it, which is not what we want.

Edit: now I can't get that to happen. Maybe I was running an old app version?

Change-Id: I7026b3326a2125e69d64bbc4736f2b6524e0faf6
Copy link
Collaborator

@SUPERCILEX SUPERCILEX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost ready to go!

android:authorities="${applicationId}.authuiinitprovider"
android:exported="false"
android:initOrder="90" />

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add these blank lines back?

private Resource(State state, T value, Exception exception) {
mState = state;
mValue = value;
mException = exception;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the constructor should be above the static methods.

android:label=""
android:exported="false"
android:theme="@style/FirebaseUI.Transparent">
</activity>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this should just be />.

IdpResponse response) {

String accountType = ProviderUtils.idpResponseToAccountType(response);
Credential credential = CredentialsUtil.buildCredential(firebaseUser, password, accountType);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to pass in a credential indead of doing all that logic in here.

startSaveCredentials(user, mHandler.getPendingPassword(), resource.getValue());
break;
case FAILURE:
// TODO: Is this message what we want?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have an "incorrect password" string? We could see if the exception is an instance of the FirebaseAuthInvalidCredentialsException and use that string or else show the localized message. That's better than what we have. 😁

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually don't ... I added a TODO to make one since I don't want to add one here and get a red build for a non-translated string.


// TODO:
// FirebaseUser firebaseUser = task.getResult().getUser();
// mActivity.saveCredentialsOrFinish(firebaseUser, null, mResponse);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed, right?

mResultLiveData.setValue(Resource.forVoidSuccess());
} else {
Log.e(TAG, "SAVE: Canceled by user.");
mResultLiveData.setValue(Resource.<Void>forFailure(new Exception("Save canceled by user.")));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump.

Change-Id: I757fc2b42ba72d1820750e046f62912ef888f877
@samtstern
Copy link
Contributor Author

@SUPERCILEX I think I got it all, minus one TODO about getting a new translated error message.

Copy link
Collaborator

@SUPERCILEX SUPERCILEX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! LGTM as long as the build is green. πŸ‘

@samtstern samtstern merged commit 2bc242a into version-3.2.2-dev Feb 21, 2018
@samtstern samtstern deleted the kill-smartlock-fragments branch February 27, 2018 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants