Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

For #10173: login duplicates and save #11208

Merged

Conversation

eliserichards
Copy link
Contributor

@eliserichards eliserichards commented Jun 3, 2020

For #10173
Related to mozilla/application-services#3330 - fix in mozilla/application-services#3331
Requires mozilla-mobile/android-components#7694

Requirements for this PR

  • Save button enabled/disabled based on errors
  • Pull list of duplicates and don't allow dupes to be saved
  • UX cleanup for login detail and edit screens
  • Move AC components.core.passwordsStorage calls into their own store: LoginsDataStore
    • to be tested

Pull Request checklist

  • Tests: This PR includes thorough tests or an explanation of why it does not
  • Screenshots: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not
  • Accessibility: The code in this PR follows accessibility best practices or does not include any user facing features. In addition, it includes a screenshot of a successful accessibility scan to ensure no new defects are added to the product.

After merge

  • Milestone: Make sure issues finished by this pull request are added to the milestone of the version currently in development.

To download an APK when reviewing a PR:

  1. click on Show All Checks,
  2. click Details next to "Taskcluster (pull_request)" after it appears and then finishes with a green checkmark,
  3. click on the "Fenix - assemble" task, then click "Run Artifacts".
  4. the APK links should be on the left side of the screen, named for each CPU architecture

@eliserichards eliserichards marked this pull request as ready for review June 9, 2020 15:15
@eliserichards eliserichards force-pushed the 10173-login-duplicates branch 2 times, most recently from 843a584 to 60cca68 Compare June 10, 2020 22:25
@codecov-commenter

This comment has been minimized.

@ekager
Copy link
Contributor

ekager commented Jun 11, 2020

Can you comment the filed out data review form here so we can get that review rolling too? see example: #11446 (comment)

@eliserichards
Copy link
Contributor Author

Request for data collection review form

All questions are mandatory. You must receive review from a data steward peer on your responses to these questions before shipping new data collection.

  1. What questions will you answer with this data?
  • What % of our users use CRUD actions (create, read, update, delete) on their saved logins?
  • How frequently do users manipulate their saved logins?
  1. Why does Mozilla need to answer these questions? Are there benefits for users? Do we need this information to address product or business requirements?
  • It is crucial we know what types of user segments we have so we can prioritize future logins features. This data will help us better slice our user population & figure out retention metrics. It will also help us to understand the relationship between the Lockwise userbase (standalone password manager) and the Fenix browser users who use saved logins.
  1. What alternative methods did you consider to answer these questions? Why were they not sufficient?
  • There are currently no alternatives.
  1. Can current instrumentation answer these questions?
  • No, there are no currently metrics around these actions.
  1. List all proposed measurements and indicate the category of data collection for each measurement, using the Firefox data collection categories on the found on the Mozilla wiki.
  • All data is Category 2.
  1. How long will this data be collected?
  • Until 09/01/2020
  1. What populations will you measure?
  • All release, beta, and nightly users with telemetry enabled.
  1. Please provide a general description of how you will analyze this data.
  • Glean / Amplitude
  1. Where do you intend to share the results of your analysis?
  • Only on Glean, Amplitude and with mobile teams.

@eliserichards eliserichards added the needs:data-review PR is awaiting a data review label Jun 11, 2020
app/metrics.yaml Outdated Show resolved Hide resolved
ekager
ekager previously requested changes Jun 11, 2020
Copy link
Contributor

@ekager ekager left a comment

Choose a reason for hiding this comment

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

Okay, all the pieces look there but we need to refactor some of the architecture. Let's not create a new paradigm here if possible! The interactor -> controller model that is used elsewhere should really replace the LoginsDataStore. Look at bookmarks, history, or the other logins fragments for examples of how this should look. You should start with a View for the EditLoginFragment following the pattern of the other fragments, then we can update that view in consumeFrom. The view can call the interactor, and the interactor calls the controller.

Let's pull out the string to land separately so we can definitely make string freeze by tomorrow.

Copy link
Contributor

@liuche liuche left a comment

Choose a reason for hiding this comment

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

Data-review+ only

A few nits and renaming, inline

Data Review Form (to be filled by Data Stewards)

  1. Is there or will there be documentation that describes the schema for the ultimate data set in a public, complete, and accurate way?

Yes, documented the 3 view/edit/delete password probes added

  1. Is there a control mechanism that allows the user to turn the data collection on and off?

Yes, controlled by Fenix data controls

  1. If the request is for permanent data collection, is there someone who will monitor the data over time?

Probes have expiry

  1. Using the category system of data types on the Mozilla wiki, what collection type of data do the requested measurements fall under?

Type 2, interaction with settings

  1. Is the data collection request for default-on or default-off?

default on

  1. Does the instrumentation include the addition of any new identifiers (whether anonymous or otherwise; e.g., username, random IDs, etc. See the appendix for more details)?

No, user interaction with UI

  1. Is the data collection covered by the existing Firefox privacy notice?

Yes

  1. Does there need to be a check-in in the future to determine whether to renew the data? (Yes/No) (If yes, set a todo reminder or file a bug if appropriate)**

No

  1. Does the data collection use a third-party collection tool?

no

app/metrics.yaml Outdated Show resolved Hide resolved
app/metrics.yaml Outdated Show resolved Hide resolved
@eliserichards
Copy link
Contributor Author

Pulled out the string into #11516 and tagged you for approval @ekager 🔥

@liuche liuche removed the needs:data-review PR is awaiting a data review label Jun 16, 2020
@eliserichards
Copy link
Contributor Author

eliserichards commented Jul 9, 2020

Waiting on mozilla/application-services#3331 to land

@eliserichards eliserichards added the 🙅 waiting Issues that are blocked or has dependencies that are not ready label Jul 9, 2020
ekager
ekager previously requested changes Jul 13, 2020
Copy link
Contributor

@ekager ekager left a comment

Choose a reason for hiding this comment

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

Looking much better! Wondering if we can do some of the cleanup I suggested and if you could also cherry-pick @Mugurell 's commits from #12507 into this PR? (Since they conflict with some of your changes)
cc @Mugurell if you also wanted to take a look at these logins changes and leave some feedback since you've been touching it more recently

app/metrics.yaml Outdated Show resolved Hide resolved
app/metrics.yaml Outdated Show resolved Hide resolved
getString(
R.string.history_delete_single_item_snackbar,
historyItems.first().url.toShortUrl(requireComponents.publicSuffixList)
String.format(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

lint/detekt error

private val navController: NavController,
private val loginsFragmentStore: LoginsFragmentStore
) {
private val activity: HomeActivity = context as HomeActivity
Copy link
Contributor

Choose a reason for hiding this comment

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

nit - if we're only using the context to grab the activity can we just pass in the activity?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also looking at the rest of the class it's unclear to me why we need to cast this context to an activity? Can we just use the passed in context?

Copy link
Contributor

Choose a reason for hiding this comment

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

About the Context..
I'm normally against passing it around and then expect all receivers to know how to build/extract their end dependencies from it. (Demeter's law).
To keep the code clean, have a better separation of responsibilities, loose coupling and ease testing I would propose to have end dependencies sent as parameters to the controller.
Here I see that anyway the context, cast to a specific activity!? is only used for obtaining a reference to components.core.passwordsStorage. That can easily be injected in the constructor without even worrying about it become bloated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a flow taken from a number of other places in the app. I would not like to change it without cleaning up every other place as well. Maybe we can file an eng health ticket.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@ekager ekager Jul 14, 2020

Choose a reason for hiding this comment

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

It is a common pattern in the rest of the app (that we can file a followup ticket about), but in this case we really are only using the context to get the passwordsStorage, so instead of passing in the context, we can just pass in the passwordsStorage directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed this to use context instead of HomeActivity, and filed a followup: #12565

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can still improve this further by changing it pass passwordsStorage directly since AFAICT that's all we use it for

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is it cool to pass a component around like that?

Copy link
Contributor

Choose a reason for hiding this comment

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

containerView.passwordText?.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
containerView.revealPasswordButton?.setImageDrawable(
ResourcesCompat.getDrawable(context.resources,
Copy link
Contributor

Choose a reason for hiding this comment

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

elsewhere we use AppCompatResources.getDrawable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was a lint or detekt error telling me to use ResourcesCompat. I can use AppCompatResources instead :)

Copy link
Contributor

@Mugurell Mugurell left a comment

Choose a reason for hiding this comment

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

Left some drop-by comments mainly about the architecture.
If we are to refactor this I think we should also focus on improving the architecture and code quality.

@@ -54,11 +54,11 @@ sealed class LoginsAction : Action {
data class UpdateLoginsList(val list: List<SavedLogin>) : LoginsAction()
data class UpdateCurrentLogin(val item: SavedLogin) : LoginsAction()
data class SortLogins(val sortingStrategy: SortingStrategy) : LoginsAction()
data class ListOfDupes(val dupeList: List<SavedLogin>) : LoginsAction()
Copy link
Contributor

Choose a reason for hiding this comment

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

https://github.com/mozilla-mobile/fenix/blob/master/docs/architecture-overview.md#action
"An Action describes something that happened, and carries any data relevant to that change"
Maybe this Action can be changed to something like "DuplicatesListChanged"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer this name. If possible duplicates exist, this list is non-empty. The action does not depend on the list changing; it will be changing with every edit.

private val navController: NavController,
private val loginsFragmentStore: LoginsFragmentStore
) {
private val activity: HomeActivity = context as HomeActivity
Copy link
Contributor

Choose a reason for hiding this comment

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

About the Context..
I'm normally against passing it around and then expect all receivers to know how to build/extract their end dependencies from it. (Demeter's law).
To keep the code clean, have a better separation of responsibilities, loose coupling and ease testing I would propose to have end dependencies sent as parameters to the controller.
Here I see that anyway the context, cast to a specific activity!? is only used for obtaining a reference to components.core.passwordsStorage. That can easily be injected in the constructor without even worrying about it become bloated.


interactor = LoginDetailInteractor(
SavedLoginsStorageController(
context = requireContext(),
Copy link
Contributor

Choose a reason for hiding this comment

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

We should look into passing end dependencies to clients and so remove the responsability of them knowing how to and creating such dependencies.
In this case the context seems to only be used for getting components.core.passwordsStorage. We can pass that instead of the Context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wondering if this might warrant a larger cleanup in the codebase...

@Mugurell
Copy link
Contributor

One other important improvement to be made:
Since there are 38 files here it is pretty hard to properly review this, there is a high risk un bugs, and afterwards it will be pretty hard to follow why something changed.
I see 21 commits, there will possibly be more followed by a merge of them all at the end, with.. 38 files.
Would be great to have the code split into smaller commits, each addressing a specific need, each having a clear commit message detailing why the change. And then for every fixup needed, like something being raised in review do a rebase-fixup.
I for one very much trust in this guidelines - https://github.com/google/eng-practices/blob/master/review/developer/index.md

@eliserichards eliserichards dismissed ekager’s stale review July 14, 2020 22:50

Addressed comments. Will rebase with Mugurell's PR once it's merged. Once the app services version (62.0.0) is updated in AC and we get that version into Fenix, I would like this to land and then do followups. I don't want to keep this open for any longer than it already has been.

@ekager
Copy link
Contributor

ekager commented Jul 16, 2020

test-debug failing on WHEN finding login dupes, THEN update duplicates in the store

@eliserichards eliserichards changed the title [WIP] For #10173: login duplicates and save For #10173: login duplicates and save Jul 16, 2020
…er based on username.

Create edit login controller. Add text watchers and check for duplicates.

Edit controller test
Save enabled in datastore.

Move login data to datastore

Rebase with password error states

Update metrics to be more specific for edit
…parate out some layout manipulation.

Inflate view in edit fragment. Double layout showing up.

Edit view

Controller tests

Controller tests passing

Interactor tests

Lint and detekt cleanup
@eliserichards eliserichards force-pushed the 10173-login-duplicates branch 2 times, most recently from a35683a to 68895cb Compare July 16, 2020 20:29
Copy link
Contributor

@ekager ekager left a comment

Choose a reason for hiding this comment

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

r+ with ktlint fix up :)

…assword storage.

Addressed comments

Lint
:

Rebase - 1
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants