Skip to content

Conversation

@dnfield
Copy link
Contributor

@dnfield dnfield commented Sep 22, 2018

CupertinoApp does not properly process calls from setInitialRoute in the embedder. The root cause of this is that it tries to use CupertinoTabView (which probably was not originally intended to ever create a root navigator) to create a navigator instead of WidgetsApp.

This change fixes that, and refactors MaterialApp and WidgetsApp to place more of the common route/home logic and documentation into WidgetsApp.

This change is intended to be completely non-breaking. WidgetsApp can still be invoked with the same parameters that have been valid up until now, but it can also be used with the same home/routes style invocation that MaterialApp and CupertinoApp have, but with the additional need of a pageRouteBuilder to tell it which kind of page transition to build (e.g. CupertinoPageRoute or MaterialPageroute). However, it does make it possible for MaterialApp and CupertinoApp to be const (the asserts preventing this now all live on WidgetsApp, which already couldn't be const), so the tests had to be appropriately updated to make the analyzer happy.

Fixes part of #22054 (the part reporting that setInitialRoute doesn't work from iOS - which was happening because I was testing with a CupertinoApp which didn't bother to use the property on window before).

/cc @xster @HansMuller @Hixie @matthew-carroll

/// The [HeroController] used for Cupertino page transitions.
///
/// Used by [CupertinoTabView] and [CupertinoApp].
static HeroController createCupterinoTransitionController() =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@HansMuller I believe you're doing something related to this for Material right now - should this really be going in a theme somewhere?

Copy link
Member

Choose a reason for hiding this comment

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

Spelling

Copy link
Member

Choose a reason for hiding this comment

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

Also no need to make it abstract. Just call it createCupertinoHeroController.

Copy link
Contributor

Choose a reason for hiding this comment

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

#21715 makes the default transition for MaterialPageRoute a theme feature. MaterialPageRoutes use Cupertino-style horizontal page transitions on iOS by default. I don't think anyone has proposed using Cupertino-style heroics in Material apps.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 23, 2018

One other change to call out:

The existing logic today prevents setInitialRoute from working if the app specifies an initialRoute. This will give setInitialRoute precedence over the app's initialRoute parameter in the case where the setInitialRoute is not set to /.

/// If the [builder] is null, the [onGenerateRoute] argument is required, and
/// corresponds to [Navigator.onGenerateRoute]. If the [builder] is non-null
/// If the [builder] is null, the [onGenerateRoute] and [pageRouteBuilder]
/// arguments are required. The [onGenerateRoute] parameters corresponds to
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this read "parameter" in the singular?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Copy paste error, thanks for catching

@matthew-carroll
Copy link
Contributor

I'm not particular familiar with the internals of the App Widgets, but generally LGTM.

Copy link
Member

@xster xster left a comment

Choose a reason for hiding this comment

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

LGTM

/// The [HeroController] used for Cupertino page transitions.
///
/// Used by [CupertinoTabView] and [CupertinoApp].
static HeroController createCupterinoTransitionController() =>
Copy link
Member

Choose a reason for hiding this comment

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

Spelling

/// The [HeroController] used for Cupertino page transitions.
///
/// Used by [CupertinoTabView] and [CupertinoApp].
static HeroController createCupterinoTransitionController() =>
Copy link
Member

Choose a reason for hiding this comment

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

Also no need to make it abstract. Just call it createCupertinoHeroController.

'must have their initial values '
'(null, null, and the empty list, respectively).'
),
assert(onGenerateRoute != null || pageRouteBuilder != null),
Copy link
Member

Choose a reason for hiding this comment

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

We can't assume people have read the docs before / all docs and error messages should be clear independently.

This needs an error message since if people hit this check out of the blue, they won't get the relationship between onGenerateRoute and pageRouteBuilder.

/// If this property is set, the [pageRouteBuilder] property must also be set
/// so that the default route handler will know what kind of [PageRoute]s to
/// build.
final Map<String, WidgetBuilder> routes;
Copy link
Contributor

Choose a reason for hiding this comment

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

This property has a default value so its set by default. Is that what we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes - we want to make sure it's not null (if empty, just an empty map). that's from existing code in MaterialApp

Copy link
Contributor

Choose a reason for hiding this comment

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

I was trying to square the property with the doc If this property is set, the [pageRouteBuilder] property must also be set. The constructor doesn't require pageRouteBuilder to be set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the doc to "If the routes map is not empty..." in b82e038

@dnfield dnfield merged commit 61cf946 into flutter:master Sep 25, 2018
dnfield added a commit that referenced this pull request Sep 25, 2018
dnfield added a commit that referenced this pull request Sep 25, 2018
@Hixie
Copy link
Contributor

Hixie commented Sep 26, 2018

I'm not sure this is really the direction I would have liked us to go with this... it doesn't seem really in sync with either my Router work or Hans' route transition theme work. For this kind of low-level change in the future please make sure to get reviews from @HansMuller, @goderbauer, and/or myself.

@Hixie
Copy link
Contributor

Hixie commented Sep 26, 2018

(i don't think we need to revert this, it's fine to leave as is.)

@Hixie
Copy link
Contributor

Hixie commented Sep 27, 2018

Around the time of this PR, flutter_gallery_ios32__transition_perf got much more flaky.

@xster
Copy link
Member

xster commented Sep 29, 2018

@Hixie so we know what to watch for for the future, what did you have in mind? I get the impression from your branch that *App will compose a Router which composes a Navigator.

This PR just makes the 3 *App's APIs consistent. Or did you intent for the Router to only be configured by the MaterialApp but not WidgetsApp?

Hans' transition theme is further down the widget tree and should be orthogonal.

@Hixie
Copy link
Contributor

Hixie commented Sep 29, 2018

Right, but Navigator doesn't know about routes, and the idea is to move away from routes and more towards pages.

@matthew-carroll
Copy link
Contributor

@Hixie do you have an up to date doc that explains the high level logistics of the routing solution you're working on?

@xster
Copy link
Member

xster commented Sep 29, 2018

Ah I see, so master...Hixie:router#diff-c798125dc01f08ce6bd3a0931482078bR627 is just a parallel backward compatibility mechanism apart from pages?

The lines above said "it's most common to use the navigator created by the [Router] which itself is created and configured by a [WidgetsApp] or a [MaterialApp] widget". I thought the *App implicitly translated the routes map into pages before creating a Router internally.

Will watch out for navigation related PRs in the future.

@Hixie
Copy link
Contributor

Hixie commented Sep 30, 2018

@matthew-carroll no, only the API docs on my branch.

@dnfield dnfield deleted the set_initial_route branch October 12, 2018 20:30
@ice-cream-coder
Copy link

@dnfield I have a question regarding one of the asserts added to WidgetsApp in this commit. I'm trying to create a simple one page app that doesn't have any need of routes, but I want to use the WidgetsApp class so that I can get the safe area.

Before this commit I had a simple implementation like this:

  @override
  Widget build(BuildContext context) {
    return new WidgetsApp(
      builder: (BuildContext context, Widget child) {
        return MyStuff();
      },
      textStyle: const TextStyle(color: Colors.black),
      color: Color(0xFF0000FF),
    );
  }
}

Which was broken by this assertion:
assert(onGenerateRoute != null || pageRouteBuilder != null) in packages/flutter/lib/src/widgets/app.dart

Since I'm not using routes, I don't think should need to have either of those.
I was able to fix it like this:

class MyWidgetsApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new WidgetsApp(
      builder: (BuildContext context, Widget child) {
        return MyStuff();
      },
      pageRouteBuilder: pageRouteBuilder,
      textStyle: const TextStyle(color: Colors.black),
      color: Color(0xFF0000FF),
    );
  }

  PageRoute pageRouteBuilder(RouteSettings settings, WidgetBuilder builder) {
    return MaterialPageRoute(settings: settings, builder: builder);
  }
}

So I'm wondering if I'm doing this correctly and also if this was an intentional change. The flutter docs around this are not very clear.

@dnfield
Copy link
Contributor Author

dnfield commented Nov 6, 2018

Hmm. This was intended to be a non-breaking change.

The assert message on the one that is being violated was meant to explain what to do here - if you're not providing a way to do routing, you need apageRouteBuilder is needed to avoid making an incorrect assumption about what kind of routing transitions you would want if any do occur.

I suppose we could add a check to that assert for something like onGenerateRoute != null || (routes.length > 1 && pageRouteBuilder != null), which I think would unbreak you here and still work. Of course we'd be in a mess if someone added routes during runtime, but there are a few other places where the logic breaks down in that case anyway.

What do you think of that?

@dnfield
Copy link
Contributor Author

dnfield commented Nov 6, 2018

Actually, this should be the correct assert:

 assert(
         builder != null ||
         onGenerateRoute != null ||
         pageRouteBuilder != null,
         'If neither builder nor onGenerateRoute are provided, the '
         'pageRouteBuilder must be specified so that the default handler '
         'will know what kind of PageRoute transition to build.'
       ),

@dnfield
Copy link
Contributor Author

dnfield commented Nov 6, 2018

Let's continue discussion at the linked PR #23976

@HansMuller
Copy link
Contributor

@roydaw The MaterialApp and WidgetsApp builder parameter was really intended to enable adding widgets to the app's BuildContext, "above" the app's home. A simple app like the one you've described would typically be written like this:

  @override
  Widget build(BuildContext context) {
    return new WidgetsApp(
      home: MyStuff();
      textStyle: const TextStyle(color: Colors.black),
      color: Color(0xFF0000FF),
    );
  }

That said, we didn't intend to introduce a backwards-incompatible change here. In other words, just specifying a builder should still work.

@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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants