Skip to content
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

New license page. #57588

Merged
merged 42 commits into from Jun 23, 2020
Merged

New license page. #57588

merged 42 commits into from Jun 23, 2020

Conversation

TonicArtos
Copy link
Contributor

@TonicArtos TonicArtos commented May 19, 2020

Description

This is a PR addressing #57226 - Proposal: New UI for Licenses Page.

This PR replaces the previous single panel license page with one that uses a master/detail flow (MDFlow) to display packages and their respective licenses.

Existing behaviour

The existing license page is a single list of all licenses collected from the packages linked in the application. Also, at the top of the list is an entry which displays some information about the application.

Issues with existing behaviour
  1. It is hard to navigate.
    Because all versions of a license must be displayed, some packages have many tens of similar entries in this list, often with little more than a date change. Should a user wish to see licenses for a particular package, they must hunt through the list to find the package and its licenses.
  2. It is not polished.
    The existing license page does not adjust for the size of the screen and can present extremely long strings of legalese running across the screen.
How this PR addresses the above (Changes)

The License Page API remains unchanged. The logic for processing the license data is kept largely the same. This PR changes how the licenses are displayed, by introducing a responsive UI using the master/detail UI pattern. For now I am calling it Master Detail Flow, or MDFlow.

MDFlow manifests as two layouts depending on the screen size. On small and medium displays, as determined by the breakpoints given by the Material Design Spec, MDFlow utilises a nested layout. On large displays, MDFlow uses a two panel (lateral) layout. MDFlow is implemented in this PR using a Navigator for the nested layout, and a Stack for the lateral layout. The master and detail views are built using builders. For the interactive component, detail pages are requested from the master view using a proxy obtained by a widget lookup on the build context; MasterDetailFlow.of(context).

Demo of new license page

New License Page showing packages (small and medium displays)
Screenshot from 2020-05-20 01-03-13

New License Page showing licenses for a package (small and medium displays)
Screenshot from 2020-05-20 01-03-20

New License Page (large displays)
Screenshot from 2020-05-20 01-02-57

Existing License Page (all displays)
Screenshot from 2020-05-20 01-07-34

Related Issues

Resolves #57226
Resolves #18281

Tests

Widget tests for the new UI remain to be updated.

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

  • Yes, this is a breaking change. If not, delete the remainder of this section.
    • Design doc waved. See @Hixie New license page. #57588 (comment)
    • I got input from the developer relations team, specifically from: Replace with the names of who gave advice
    • I wrote a migration guide: Migration should not be required

@fluttergithubbot fluttergithubbot added f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. work in progress; do not review labels May 19, 2020
@TonicArtos
Copy link
Contributor Author

@Hixie The new UI require changes to the tests in about_test.dart. The changes involve adding navigation of packages to show the license content, something the tests current assume is unneeded.

Anyway, is it okay to update these tests without writing a design doc?

@fluttergithubbot fluttergithubbot added the a: internationalization Supporting other languages or locales. (aka i18n) label May 20, 2020
@TonicArtos TonicArtos changed the title Draft of new license UI. New license page. May 20, 2020
@Hixie
Copy link
Contributor

Hixie commented May 20, 2020

@Hixie The new UI require changes to the tests in about_test.dart. The changes involve adding navigation of packages to show the license content, something the tests current assume is unneeded.

Anyway, is it okay to update these tests without writing a design doc?

Yeah that should be fine. Thanks for checking.

@TonicArtos
Copy link
Contributor Author

Okay, so I am looking for feedback now. I think these are the right people to tag. @HansMuller, @timsneath, @Hixie.

MaterialLocalizations.of(context);
final double gutterSize = _getGutterSize(context);

if (widget.scrollController == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

there's a lot of duplicated content here, might be worth seeing if there's a way to factor it out so the branches are only the pieces that differ

typedef _ActionBuilder = List<Widget> Function(
BuildContext context,
_ActionLevel actionLevel,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

these can all just be on one line

);
}

Widget _buildPackagesView(final BuildContext _, final bool isLateral) {
Copy link
Contributor

Choose a reason for hiding this comment

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

here and in other places where you have build methods, might be better to factor those out into their own widgets

@Hixie
Copy link
Contributor

Hixie commented May 21, 2020

Overall this looks great. I'll defer to @HansMuller or @goderbauer for more detailed review.

@TonicArtos
Copy link
Contributor Author

TonicArtos commented May 22, 2020

Overall this looks great. I'll defer to @HansMuller or @goderbauer for more detailed review.

Okay. I'll follow your guidance once I get their feedback. I don't want to be making changes over the top of what they may be reviewing.

expand: false,
builder: (BuildContext context, ScrollController controller) {
return MouseRegion(
// Workaround bug where things behind sheet still get mouse hover events.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you turn this into a TODO saying to remove the workaround, and reference the issue that describes the bug (and if there isn't one, please file one)?

@@ -72,6 +72,14 @@
"description": "The title for the Flutter licenses page."
},

"licensesPackageDetailTextZero": "No licenses",
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we just skip (and not display) any packages that have no licenses at all? That way we don't need to do translation for the zero case. You could update the description to say that it isn't allowed to have a value of zero.

@TonicArtos
Copy link
Contributor Author

Sorry, I got caught up this week. I'll make the changes this weekend.

@gspencergoog
Copy link
Contributor

@TonicArtos have you had a chance to take a look at the changes?

@TonicArtos TonicArtos marked this pull request as ready for review June 18, 2020 07:01
@TonicArtos
Copy link
Contributor Author

TonicArtos commented Jun 18, 2020

@gspencergoog Sorry for the delay. It is a pretty messed up time. I've gone through the comments and implemented each request. They are referred on the specific commit addressing them. It all looks fine to me on my devices and with the local tests.

However, I don't understand why customer_testing-windows failed on the CI system. The issue looks like an image pixel comparison check. Is there some way to get more detail on this so I can fix it?

Copy link
Contributor

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

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

Thanks for the update! It's looking pretty good, I just saw some small things to address.

);
}

Widget _packageLicensePage(BuildContext _, Object args, ScrollController sc) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use a more descriptive name for sc. (e.g. scrollController).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.

),
),
],
final MaterialLocalizations localisations = MaterialLocalizations.of(context);
Copy link
Contributor

Choose a reason for hiding this comment

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

localisations => localizations. We try to use American English spellings, for consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, the z. It kills me. Yeah, okay, I should have stuck to the US spelling no matter how it does the head in.

@@ -623,3 +982,651 @@ Widget _defaultApplicationIcon(BuildContext context) {
// TODO(ianh): Get this from the embedder somehow.
return null;
}

double _getGutterSize(BuildContext context) => MediaQuery.of(context).size.width >= 720 ? 24 : 12;
Copy link
Contributor

Choose a reason for hiding this comment

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

We try not to have "magic" numbers. It's best to have a constant for each of the numbers like this, so that they're self-documenting.

For instance:

  static const int _narrowGutterWidthLimit = 720;
  static const int _wideGutterSize = 24;
  static const int _narrowGutterSize = 12;

https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-mysterious-and-magical-numbers-that-lack-a-clear-derivation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. I remember thinking I would fix this when I wrote it. I clearly didn't.


Widget _packageLicensePage(BuildContext _, Object args, ScrollController sc) {
assert(args is _DetailArguments);
final _DetailArguments a = args as _DetailArguments;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use a more descriptive name for a. e.g. detailArguments.

https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-abbreviations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry. It looks like I was trying to avoid the stuttering caused by the cast. The style guide should have been followed.

style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
Container(height: 18.0),
Copy link
Contributor

Choose a reason for hiding this comment

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

Here, and the next Container, please define this constant as a separate static const variable to make it self documenting.

Also, consider using a SizedBox instead of a Container: SizedBox can be a const object, and so it's more performant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.

return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final double availableWidth = constraints.maxWidth;
if (availableWidth >= (widget.breakpoint ?? 840)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Make 840 into a constant with a name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.

@override
String licensesPackageDetailText(int licenseCount) {
switch (licenseCount) {
case 0:
Copy link
Contributor

Choose a reason for hiding this comment

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

If you skip packages with zero licenses, this case should assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added assertion licenseCount >= 1, removed case 0.

String firstPackage;

void addLicense(LicenseEntry entry) {
for (final String package in entry.packages) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps skip packages with zero licenses?

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 said below in #57588 (comment) that I would do this. However, going over the code again it really is already the case that each package always has one or more licenses. This is because we only know about a package should it be recorded as a package to which a given license applies.

Obviously the code must not be clear enough as is, so I'll go through this part and added comments to try and clarify it.

packages/flutter/lib/src/material/about.dart Outdated Show resolved Hide resolved
String get licensesPackageDetailTextOther => '\$licenseCount licenses';

@override
String get licensesPackageDetailTextZero => 'No licenses';
Copy link
Contributor

Choose a reason for hiding this comment

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

All of these "Zero" cases would be eliminated if you skip packages with zero licenses.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The license page is an inversion of the data hierarchy. LicenseRegistry collects licenses and includes the packages from which those licenses came from as a property on each license. As such, there is a many-to-many relationship between licenses and packages with the constraint that each package has at least one license, and each license has at least one package.

So the zero case is not checked for, since by implementation, it should come up. However, it is undeniably more robust to add checking for, and the exclusion of, packages that have zero licenses. So I will do this.

However. I would like to highlight, should you include special dispensation for zero license packages, it may be arguable that it is better to highlight packages with zero licenses by using a special unlicensed, or commons, page. But, I also suggest that it is unneeded and zealous work to add this. We should never normally encounter packages with zero licenses. Unless, of course, there is a design change down the line.

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 just realised why this zero case keeps getting regenerated. It is coming from the default text generated for the different locales from when I ran gen_missing_localizations.dart as instructed to do when adding to material_localizations.

@gspencergoog
Copy link
Contributor

As for the customer_testing failures, I don't think those were related to your code. If you rebase the the HEAD of the master branch, I think it will pass.

@TonicArtos
Copy link
Contributor Author

So I did the rebase. See if this will work. I can redo it with a squash if you like.

Copy link
Contributor

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

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

This looks pretty good! And it looks like the customer_testing is passing now too.

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

Unless you have any more updates, I can merge this as soon as the tree is green. I'll wait until you say it's ready, though.

// the safe area is sufficiently respected.
expect(
tester.getTopLeft(find.text('Licenses')),
const Offset(16.0 + safeareaPadding, 18 + safeareaPadding),
Copy link
Contributor

Choose a reason for hiding this comment

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

Be consistent about doubles: either use 16, or 18.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I'll go through the change list and conform to 18.0 everywhere. On closer inspection it seems to be the convention.

@TonicArtos
Copy link
Contributor Author

This looks pretty good! And it looks like the customer_testing is passing now too.

Okay I addressed your last comment. I also went through the CL one last time and noticed the documentation still mentioned the localised zero case was required, so I fixed that too.

Unless you have any more updates, I can merge this as soon as the tree is green. I'll wait until you say it's ready, though.

I see no reason to hold back, once these last two commits complete the CI process and the tree goes green again.

Oh, if you want to talk about the MDFlow thing and seeing if that can go somewhere, I'd be happy to. I think with work it could become something quite good.

Otherwise, or in addition, I'll move on and see about getting all this done again for the Cupertino side of things too. Over at #57638.

@gspencergoog
Copy link
Contributor

Thanks Tonic! Great work, we really appreciate it!

I'll commit this as soon as the tree is green and it passes the CI tests.

@TonicArtos
Copy link
Contributor Author

@gspencergoog Do you want me to squash the PR or are you going to do that?

@gspencergoog
Copy link
Contributor

No, no need to squash: it'll do that automatically when I merge. The tree's been extra red: we had an issue in our device lab.

@gspencergoog gspencergoog merged commit 65550d0 into flutter:master Jun 23, 2020
gspencergoog added a commit to gspencergoog/flutter that referenced this pull request Jun 29, 2020
gspencergoog added a commit to gspencergoog/flutter that referenced this pull request Jun 29, 2020
… that have zero licenses."

This reverts commit f1b9fdf.
gspencergoog added a commit to gspencergoog/flutter that referenced this pull request Jun 29, 2020
gspencergoog added a commit that referenced this pull request Jun 30, 2020
This amends #57588 by adding code that also handles the zero license case, and adds translation strings for that.
Comment on lines +1633 to +1635
onTap: () {
print('draggable');
},
Copy link
Member

Choose a reason for hiding this comment

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

This print (and probably the entire gesture detector?) should probably be removed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ooh, yes, good point. @TonicArtos can you take care of that?

Copy link
Contributor Author

@TonicArtos TonicArtos Jul 1, 2020

Choose a reason for hiding this comment

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

Yes. It is late here. I'll get caught up and get the fix sorted tomorrow.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, no huge rush: most of us will be on holiday until Monday (it's Independence Day in the U.S.).

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 went through my journal. It turns out the GestureDetector is left from when I was looking at #59741. I forgot to remove it once I figured what was happening.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PR #60730 Remove superfluous GestureDetector.

@gspencergoog
Copy link
Contributor

Sure, that would be great.

@TonicArtos TonicArtos deleted the md_license branch July 8, 2020 02:11
if (widget.scrollController == null) {
page = Scaffold(
appBar: AppBar(
title: _PackageLicensePageTitle(title, subtitle, theme.primaryTextTheme),
Copy link
Contributor

Choose a reason for hiding this comment

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

@TonicArtos

Why did you specify theme.primaryTextTheme?

It may break color system when AppBarTheme is used for example.

Choose a reason for hiding this comment

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

Indeed, it broke my background color.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would have preferred for this to (private) widget to have been factored a little differently - to not have used primaryTextTheme.

If you can file an issue with a simple test case that demonstrates a regression, we'll try and fix it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@HansMuller

If you can file an issue with a simple test case that demonstrates a regression, we'll try and fix it.

Okay, I've created an issue: #63239.

Copy link
Contributor

@mono0926 mono0926 Aug 8, 2020

Choose a reason for hiding this comment

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

@HansMuller

I tried to fix at #63249, but I’m welcome to be closed and refactored by your pull request.

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 would have preferred for this to (private) widget to have been factored a little differently - to not have used primaryTextTheme.

If you can file an issue with a simple test case that demonstrates a regression, we'll try and fix it.

Sorry about the issue. What do you think the original solution should have been?

Copy link
Contributor

@mono0926 mono0926 Aug 9, 2020

Choose a reason for hiding this comment

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

@TonicArtos

What do you think the original solution should have been?

I think #63249 is the simplest fix for existing implementation.

mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
This is a PR addressing flutter#57226 - Proposal: New UI for Licenses Page.

This PR replaces the previous single panel license page with one that uses a master/detail flow (MDFlow) to display packages and their respective licenses.

The License Page API remains unchanged. The logic for processing the license data is kept largely the same. This PR changes how the licenses are displayed, by introducing a responsive UI using the master/detail UI pattern. For now I am calling it Master Detail Flow, or MDFlow.

MDFlow manifests as two layouts depending on the screen size. On small and medium displays, as determined by the breakpoints given by the Material Design Spec, MDFlow utilises a nested layout. On large displays, MDFlow uses a two panel (lateral) layout. MDFlow is implemented in this PR using a Navigator for the nested layout, and a Stack for the lateral layout. The master and detail views are built using builders. For the interactive component, detail pages are requested from the master view using a proxy obtained by a widget lookup on the build context; MasterDetailFlow.of(context).
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
This amends flutter#57588 by adding code that also handles the zero license case, and adds translation strings for that.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: internationalization Supporting other languages or locales. (aka i18n) f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: New UI for Licenses Page. Licenses display has multiple copies of the "boringssl" licence
9 participants