From ea5435c2ef2692ae4f5e403a894181ceeb809bcb Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 25 Sep 2018 13:57:12 -0400 Subject: [PATCH] Widgets app refactor (#22269) * Refactor of cupertino/material/widgets app * update docs * Update tests for const --- dev/integration_tests/ui/lib/commands.dart | 2 +- dev/manual_tests/lib/animated_icons.dart | 4 +- dev/manual_tests/lib/material_arc.dart | 4 +- .../test/accessibility_test.dart | 28 +- .../test/calculator/smoke_test.dart | 2 +- .../material/text_form_field_demo_test.dart | 2 +- packages/flutter/lib/src/cupertino/app.dart | 202 +++---------- .../flutter/lib/src/cupertino/tab_view.dart | 3 +- packages/flutter/lib/src/material/app.dart | 224 ++------------- packages/flutter/lib/src/widgets/app.dart | 271 +++++++++++++++--- .../flutter/test/cupertino/dialog_test.dart | 2 +- .../flutter/test/cupertino/nav_bar_test.dart | 52 ++-- .../cupertino/nav_bar_transition_test.dart | 8 +- .../flutter/test/cupertino/page_test.dart | 4 +- .../flutter/test/cupertino/route_test.dart | 20 +- .../flutter/test/cupertino/scaffold_test.dart | 12 +- .../flutter/test/material/about_test.dart | 8 +- packages/flutter/test/material/app_test.dart | 24 +- .../test/material/bottom_app_bar_test.dart | 40 +-- packages/flutter/test/material/chip_test.dart | 4 +- .../flutter/test/material/dialog_test.dart | 12 +- .../flutter/test/material/drawer_test.dart | 8 +- .../material/floating_action_button_test.dart | 20 +- .../persistent_bottom_sheet_test.dart | 4 +- .../flutter/test/material/scaffold_test.dart | 12 +- .../test/material/text_field_focus_test.dart | 16 +- .../material/text_field_helper_text_test.dart | 4 +- .../test/material/text_field_test.dart | 8 +- .../flutter/test/material/tooltip_test.dart | 8 +- .../flutter/test/widgets/banner_test.dart | 2 +- .../flutter/test/widgets/reassemble_test.dart | 4 +- .../test/test_text_input_test.dart | 4 +- .../flutter_test/test/widget_tester_test.dart | 4 +- 33 files changed, 464 insertions(+), 558 deletions(-) diff --git a/dev/integration_tests/ui/lib/commands.dart b/dev/integration_tests/ui/lib/commands.dart index e15bbad87de..f5d758f3697 100644 --- a/dev/integration_tests/ui/lib/commands.dart +++ b/dev/integration_tests/ui/lib/commands.dart @@ -15,7 +15,7 @@ void main() { await WidgetsBinding.instance.reassembleApplication(); return log; }); - runApp(MaterialApp(home: const Test())); + runApp(const MaterialApp(home: Test())); } class Test extends SingleChildRenderObjectWidget { diff --git a/dev/manual_tests/lib/animated_icons.dart b/dev/manual_tests/lib/animated_icons.dart index 718dba876d7..3cf6f10e1f1 100644 --- a/dev/manual_tests/lib/animated_icons.dart +++ b/dev/manual_tests/lib/animated_icons.dart @@ -7,9 +7,9 @@ import 'package:flutter/material.dart'; class AnimatedIconsTestApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( + return const MaterialApp( title: 'Animated Icons Test', - home: const Scaffold( + home: Scaffold( body: IconsList(), ), ); diff --git a/dev/manual_tests/lib/material_arc.dart b/dev/manual_tests/lib/material_arc.dart index 06cdf9f45ad..5b7fadaef35 100644 --- a/dev/manual_tests/lib/material_arc.dart +++ b/dev/manual_tests/lib/material_arc.dart @@ -474,7 +474,7 @@ class _AnimationDemoState extends State with TickerProviderStateM } void main() { - runApp(MaterialApp( - home: const AnimationDemo(), + runApp(const MaterialApp( + home: AnimationDemo(), )); } diff --git a/examples/flutter_gallery/test/accessibility_test.dart b/examples/flutter_gallery/test/accessibility_test.dart index 423469cc5f6..56681265540 100644 --- a/examples/flutter_gallery/test/accessibility_test.dart +++ b/examples/flutter_gallery/test/accessibility_test.dart @@ -91,7 +91,7 @@ void main() { testWidgets('grid_list_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const GridListDemo())); + await tester.pumpWidget(const MaterialApp(home: GridListDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -105,21 +105,21 @@ void main() { testWidgets('leave_behind_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const LeaveBehindDemo())); + await tester.pumpWidget(const MaterialApp(home: LeaveBehindDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); testWidgets('list_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const ListDemo())); + await tester.pumpWidget(const MaterialApp(home: ListDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); testWidgets('menu_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const MenuDemo())); + await tester.pumpWidget(const MaterialApp(home: MenuDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -133,7 +133,7 @@ void main() { testWidgets('overscroll_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const OverscrollDemo())); + await tester.pumpWidget(const MaterialApp(home: OverscrollDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -161,7 +161,7 @@ void main() { testWidgets('reorderable_list_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const ReorderableListDemo())); + await tester.pumpWidget(const MaterialApp(home: ReorderableListDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -196,7 +196,7 @@ void main() { testWidgets('snack_bar_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const SnackBarDemo())); + await tester.pumpWidget(const MaterialApp(home: SnackBarDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -217,7 +217,7 @@ void main() { testWidgets('text_form_field_demo', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(home: const TextFormFieldDemo())); + await tester.pumpWidget(const MaterialApp(home: TextFormFieldDemo())); expect(tester, meetsGuideline(androidTapTargetGuideline)); handle.dispose(); }); @@ -380,12 +380,12 @@ void main() { handle.dispose(); }); - testWidgets('overscroll_demo $themeName', (WidgetTester tester) async { - final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(MaterialApp(theme: theme, home: const OverscrollDemo())); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - handle.dispose(); - }); + testWidgets('overscroll_demo', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget(const MaterialApp(home: OverscrollDemo())); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + handle.dispose(); + }); testWidgets('page_selector_demo $themeName', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); diff --git a/examples/flutter_gallery/test/calculator/smoke_test.dart b/examples/flutter_gallery/test/calculator/smoke_test.dart index 177ac3d2e1c..8f4b2e56b81 100644 --- a/examples/flutter_gallery/test/calculator/smoke_test.dart +++ b/examples/flutter_gallery/test/calculator/smoke_test.dart @@ -14,7 +14,7 @@ void main() { // We press the "1" and the "2" buttons and check that the display // reads "12". testWidgets('Flutter calculator app smoke test', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: const CalculatorDemo())); + await tester.pumpWidget(const MaterialApp(home: CalculatorDemo())); final Finder oneButton = find.widgetWithText(InkResponse, '1'); expect(oneButton, findsOneWidget); diff --git a/examples/flutter_gallery/test/demo/material/text_form_field_demo_test.dart b/examples/flutter_gallery/test/demo/material/text_form_field_demo_test.dart index 8ca1a276f9b..7a79303c99f 100644 --- a/examples/flutter_gallery/test/demo/material/text_form_field_demo_test.dart +++ b/examples/flutter_gallery/test/demo/material/text_form_field_demo_test.dart @@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('validates name field correctly', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: const TextFormFieldDemo())); + await tester.pumpWidget(const MaterialApp(home: TextFormFieldDemo())); final Finder submitButton = find.widgetWithText(RaisedButton, 'SUBMIT'); expect(submitButton, findsOneWidget); diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 1bb7d6a2683..362c043151e 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -8,7 +8,7 @@ import 'package:flutter/widgets.dart'; import 'button.dart'; import 'colors.dart'; import 'icons.dart'; -import 'tab_view.dart'; +import 'route.dart'; // Based on specs from https://developer.apple.com/design/resources/ for // iOS 12. @@ -74,8 +74,9 @@ class CupertinoApp extends StatefulWidget { /// This class creates an instance of [WidgetsApp]. /// /// The boolean arguments, [routes], and [navigatorObservers], must not be null. - CupertinoApp({ // can't be const because the asserts use methods on Map :-( + const CupertinoApp({ Key key, + this.navigatorKey, this.home, this.routes = const {}, this.initialRoute, @@ -97,43 +98,6 @@ class CupertinoApp extends StatefulWidget { this.debugShowCheckedModeBanner = true, }) : assert(routes != null), assert(navigatorObservers != null), - assert( - home == null || - !routes.containsKey(Navigator.defaultRouteName), - 'If the home property is specified, the routes table ' - 'cannot include an entry for "/", since it would be redundant.' - ), - assert( - builder != null || - home != null || - routes.containsKey(Navigator.defaultRouteName) || - onGenerateRoute != null || - onUnknownRoute != null, - 'Either the home property must be specified, ' - 'or the routes table must include an entry for "/", ' - 'or there must be on onGenerateRoute callback specified, ' - 'or there must be an onUnknownRoute callback specified, ' - 'or the builder property must be specified, ' - 'because otherwise there is nothing to fall back on if the ' - 'app is started with an intent that specifies an unknown route.' - ), - assert( - (home != null || - routes.isNotEmpty || - onGenerateRoute != null || - onUnknownRoute != null) - || - (builder != null && - initialRoute == null && - navigatorObservers.isEmpty), - 'If no route is provided using ' - 'home, routes, onGenerateRoute, or onUnknownRoute, ' - 'a non-null callback for the builder property must be provided, ' - 'and the other navigator-related properties, ' - 'navigatorKey, initialRoute, and navigatorObservers, ' - 'must have their initial values ' - '(null, null, and the empty list, respectively).' - ), assert(title != null), assert(showPerformanceOverlay != null), assert(checkerboardRasterCacheImages != null), @@ -142,31 +106,10 @@ class CupertinoApp extends StatefulWidget { assert(debugShowCheckedModeBanner != null), super(key: key); - /// The widget for the default route of the app ([Navigator.defaultRouteName], - /// which is `/`). - /// - /// This is the route that is displayed first when the application is started - /// normally, unless [initialRoute] is specified. It's also the route that's - /// displayed if the [initialRoute] can't be displayed. - /// - /// To be able to directly call [MediaQuery.of], [Navigator.of], etc, in the - /// code that sets the [home] argument in the constructor, you can use a - /// [Builder] widget to get a [BuildContext]. - /// - /// If [home] is specified, then [routes] must not include an entry for `/`, - /// as [home] takes its place. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. - /// - /// The difference between using [home] and using [builder] is that the [home] - /// subtree is inserted into the application below a [Navigator] (and thus - /// below an [Overlay], which [Navigator] uses). With [home], therefore, - /// dialog boxes will work automatically, the [routes] table will be used, and - /// APIs such as [Navigator.push] and [Navigator.pop] will work as expected. - /// In contrast, the widget returned from [builder] is inserted _above_ the - /// [CupertinoApp]'s [Navigator] (if any). + /// {@macro flutter.widgets.widgetsApp.navigatorKey} + final GlobalKey navigatorKey; + + /// {@macro flutter.widgets.widgetsApp.home} final Widget home; /// The application's top-level routing table. @@ -176,81 +119,22 @@ class CupertinoApp extends StatefulWidget { /// [WidgetBuilder] is used to construct a [CupertinoPageRoute] that performs /// an appropriate transition, including [Hero] animations, to the new route. /// - /// If the app only has one page, then you can specify it using [home] instead. - /// - /// If [home] is specified, then it implies an entry in this table for the - /// [Navigator.defaultRouteName] route (`/`), and it is an error to - /// redundantly provide such a route in the [routes] table. - /// - /// If a route is requested that is not specified in this table (or by - /// [home]), then the [onGenerateRoute] callback is called to build the page - /// instead. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. + /// {@macro flutter.widgets.widgetsApp.routes} final Map routes; /// {@macro flutter.widgets.widgetsApp.initialRoute} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [initialRoute] must be null and [builder] must not be null. - /// - /// See also: - /// - /// * [Navigator.initialRoute], which is used to implement this property. - /// * [Navigator.push], for pushing additional routes. - /// * [Navigator.pop], for removing a route from the stack. final String initialRoute; /// {@macro flutter.widgets.widgetsApp.onGenerateRoute} - /// - /// This is used if [routes] does not contain the requested route. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. final RouteFactory onGenerateRoute; - /// Called when [onGenerateRoute] fails to generate a route, except for the - /// [initialRoute]. - /// /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. final RouteFactory onUnknownRoute; /// {@macro flutter.widgets.widgetsApp.navigatorObservers} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [navigatorObservers] must be the empty list and [builder] must not be null. final List navigatorObservers; /// {@macro flutter.widgets.widgetsApp.builder} - /// - /// If no routes are provided using [home], [routes], [onGenerateRoute], or - /// [onUnknownRoute], the `child` will be null, and it is the responsibility - /// of the [builder] to provide the application's routing machinery. - /// - /// If routes _are_ provided using one or more of those properties, then - /// `child` is not null, and the returned value should include the `child` in - /// the widget subtree; if it does not, then the application will have no - /// navigator and the [navigatorKey], [home], [routes], [onGenerateRoute], - /// [onUnknownRoute], [initialRoute], and [navigatorObservers] properties will - /// have no effect. - /// - /// If [builder] is null, it is as if a builder was specified that returned - /// the `child` directly. If it is null, routes must be provided using one of - /// the other properties listed above. - /// - /// Unless a [Navigator] is provided, either implicitly from [builder] being - /// null, or by a [builder] including its `child` argument, or by a [builder] - /// explicitly providing a [Navigator] of its own, widgets and APIs such as - /// [Hero], [Navigator.push] and [Navigator.pop], will not function. final TransitionBuilder builder; /// {@macro flutter.widgets.widgetsApp.title} @@ -304,6 +188,12 @@ class CupertinoApp extends StatefulWidget { @override _CupertinoAppState createState() => _CupertinoAppState(); + + /// The [HeroController] used for Cupertino page transitions. + /// + /// Used by [CupertinoTabView] and [CupertinoApp]. + static HeroController createCupertinoHeroController() => + HeroController(); // Linear tweening. } class _AlwaysCupertinoScrollBehavior extends ScrollBehavior { @@ -320,51 +210,39 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior { } class _CupertinoAppState extends State { + HeroController _heroController; @override void initState() { super.initState(); + _heroController = CupertinoApp.createCupertinoHeroController(); _updateNavigator(); } @override void didUpdateWidget(CupertinoApp oldWidget) { super.didUpdateWidget(oldWidget); + if (widget.navigatorKey != oldWidget.navigatorKey) { + // If the Navigator changes, we have to create a new observer, because the + // old Navigator won't be disposed (and thus won't unregister with its + // observers) until after the new one has been created (because the + // Navigator has a GlobalKey). + _heroController = CupertinoApp.createCupertinoHeroController(); + } _updateNavigator(); } - bool _haveNavigator; - void _updateNavigator() { - _haveNavigator = widget.home != null || - widget.routes.isNotEmpty || - widget.onGenerateRoute != null || - widget.onUnknownRoute != null; - } + List _navigatorObservers; - Widget defaultBuilder(BuildContext context, Widget child) { - // The `child` coming back out from WidgetsApp will always be null since - // we never passed in anything for it to create a Navigator inside - // WidgetsApp. - assert(child == null); - if (_haveNavigator) { - // Reuse CupertinoTabView which creates a routing Navigator for us. - final Widget navigator = CupertinoTabView( - builder: widget.home != null - ? (BuildContext context) => widget.home - : null, - routes: widget.routes, - onGenerateRoute: widget.onGenerateRoute, - onUnknownRoute: widget.onUnknownRoute, - navigatorObservers: widget.navigatorObservers, - ); - if (widget.builder != null) { - return widget.builder(context, navigator); - } else { - return navigator; - } + void _updateNavigator() { + if (widget.home != null || + widget.routes.isNotEmpty || + widget.onGenerateRoute != null || + widget.onUnknownRoute != null) { + _navigatorObservers = List.from(widget.navigatorObservers) + ..add(_heroController); } else { - // We asserted that child is null above. - return widget.builder(context, null); + _navigatorObservers = null; } } @@ -374,10 +252,18 @@ class _CupertinoAppState extends State { behavior: _AlwaysCupertinoScrollBehavior(), child: WidgetsApp( key: GlobalObjectKey(this), - // We're passing in a builder and nothing else that the WidgetsApp uses - // to build its own Navigator because we're building a Navigator with - // routes in this class. - builder: defaultBuilder, + navigatorKey: widget.navigatorKey, + navigatorObservers: _navigatorObservers, + // TODO(dnfield): when https://github.com/dart-lang/sdk/issues/34572 is resolved + // this can use type arguments again + pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) => + CupertinoPageRoute(settings: settings, builder: builder), + home: widget.home, + routes: widget.routes, + initialRoute: widget.initialRoute, + onGenerateRoute: widget.onGenerateRoute, + onUnknownRoute: widget.onUnknownRoute, + builder: widget.builder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, textStyle: _kDefaultTextStyle, diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart index d27a86cd9c0..08bb6151e8f 100644 --- a/packages/flutter/lib/src/cupertino/tab_view.dart +++ b/packages/flutter/lib/src/cupertino/tab_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; +import 'app.dart' show CupertinoApp; import 'route.dart'; /// A single tab view with its own [Navigator] state and history. @@ -114,7 +115,7 @@ class _CupertinoTabViewState extends State { @override void initState() { super.initState(); - _heroController = HeroController(); // Linear tweening. + _heroController = CupertinoApp.createCupertinoHeroController(); _updateObservers(); } diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index a47f803f82b..e1b6274e777 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -79,7 +79,7 @@ class MaterialApp extends StatefulWidget { /// This class creates an instance of [WidgetsApp]. /// /// The boolean arguments, [routes], and [navigatorObservers], must not be null. - MaterialApp({ // can't be const because the asserts use methods on Map :-( + const MaterialApp({ Key key, this.navigatorKey, this.home, @@ -105,44 +105,6 @@ class MaterialApp extends StatefulWidget { this.debugShowCheckedModeBanner = true, }) : assert(routes != null), assert(navigatorObservers != null), - assert( - home == null || - !routes.containsKey(Navigator.defaultRouteName), - 'If the home property is specified, the routes table ' - 'cannot include an entry for "/", since it would be redundant.' - ), - assert( - builder != null || - home != null || - routes.containsKey(Navigator.defaultRouteName) || - onGenerateRoute != null || - onUnknownRoute != null, - 'Either the home property must be specified, ' - 'or the routes table must include an entry for "/", ' - 'or there must be on onGenerateRoute callback specified, ' - 'or there must be an onUnknownRoute callback specified, ' - 'or the builder property must be specified, ' - 'because otherwise there is nothing to fall back on if the ' - 'app is started with an intent that specifies an unknown route.' - ), - assert( - (home != null || - routes.isNotEmpty || - onGenerateRoute != null || - onUnknownRoute != null) - || - (builder != null && - navigatorKey == null && - initialRoute == null && - navigatorObservers.isEmpty), - 'If no route is provided using ' - 'home, routes, onGenerateRoute, or onUnknownRoute, ' - 'a non-null callback for the builder property must be provided, ' - 'and the other navigator-related properties, ' - 'navigatorKey, initialRoute, and navigatorObservers, ' - 'must have their initial values ' - '(null, null, and the empty list, respectively).' - ), assert(title != null), assert(debugShowMaterialGrid != null), assert(showPerformanceOverlay != null), @@ -152,48 +114,10 @@ class MaterialApp extends StatefulWidget { assert(debugShowCheckedModeBanner != null), super(key: key); - /// A key to use when building the [Navigator]. - /// - /// If a [navigatorKey] is specified, the [Navigator] can be directly - /// manipulated without first obtaining it from a [BuildContext] via - /// [Navigator.of]: from the [navigatorKey], use the [GlobalKey.currentState] - /// getter. - /// - /// If this is changed, a new [Navigator] will be created, losing all the - /// application state in the process; in that case, the [navigatorObservers] - /// must also be changed, since the previous observers will be attached to the - /// previous navigator. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [navigatorKey] must be null and [builder] must not be null. + /// {@macro flutter.widgets.widgetsApp.navigatorKey} final GlobalKey navigatorKey; - /// The widget for the default route of the app ([Navigator.defaultRouteName], - /// which is `/`). - /// - /// This is the route that is displayed first when the application is started - /// normally, unless [initialRoute] is specified. It's also the route that's - /// displayed if the [initialRoute] can't be displayed. - /// - /// To be able to directly call [Theme.of], [MediaQuery.of], etc, in the code - /// that sets the [home] argument in the constructor, you can use a [Builder] - /// widget to get a [BuildContext]. - /// - /// If [home] is specified, then [routes] must not include an entry for `/`, - /// as [home] takes its place. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. - /// - /// The difference between using [home] and using [builder] is that the [home] - /// subtree is inserted into the application below a [Navigator] (and thus - /// below an [Overlay], which [Navigator] uses). With [home], therefore, - /// dialog boxes will work automatically, [Tooltip]s will work, the [routes] - /// table will be used, and APIs such as [Navigator.push] and [Navigator.pop] - /// will work as expected. In contrast, the widget returned from [builder] is - /// inserted _above_ the [MaterialApp]'s [Navigator] (if any). + /// {@macro flutter.widgets.widgetsApp.home} final Widget home; /// The application's top-level routing table. @@ -203,82 +127,25 @@ class MaterialApp extends StatefulWidget { /// [WidgetBuilder] is used to construct a [MaterialPageRoute] that performs /// an appropriate transition, including [Hero] animations, to the new route. /// - /// If the app only has one page, then you can specify it using [home] instead. - /// - /// If [home] is specified, then it implies an entry in this table for the - /// [Navigator.defaultRouteName] route (`/`), and it is an error to - /// redundantly provide such a route in the [routes] table. - /// - /// If a route is requested that is not specified in this table (or by - /// [home]), then the [onGenerateRoute] callback is called to build the page - /// instead. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. + /// {@macro flutter.widgets.widgetsApp.routes} final Map routes; /// {@macro flutter.widgets.widgetsApp.initialRoute} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [initialRoute] must be null and [builder] must not be null. - /// - /// See also: - /// - /// * [Navigator.initialRoute], which is used to implement this property. - /// * [Navigator.push], for pushing additional routes. - /// * [Navigator.pop], for removing a route from the stack. final String initialRoute; /// {@macro flutter.widgets.widgetsApp.onGenerateRoute} - /// - /// This is used if [routes] does not contain the requested route. - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. final RouteFactory onGenerateRoute; - /// Called when [onGenerateRoute] fails to generate a route, except for the - /// [initialRoute]. - /// /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [builder] must not be null. final RouteFactory onUnknownRoute; /// {@macro flutter.widgets.widgetsApp.navigatorObservers} - /// - /// The [Navigator] is only built if routes are provided (either via [home], - /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, - /// [navigatorObservers] must be the empty list and [builder] must not be null. final List navigatorObservers; /// {@macro flutter.widgets.widgetsApp.builder} /// - /// If no routes are provided using [home], [routes], [onGenerateRoute], or - /// [onUnknownRoute], the `child` will be null, and it is the responsibility - /// of the [builder] to provide the application's routing machinery. - /// - /// If routes _are_ provided using one or more of those properties, then - /// `child` is not null, and the returned value should include the `child` in - /// the widget subtree; if it does not, then the application will have no - /// navigator and the [navigatorKey], [home], [routes], [onGenerateRoute], - /// [onUnknownRoute], [initialRoute], and [navigatorObservers] properties will - /// have no effect. - /// - /// If [builder] is null, it is as if a builder was specified that returned - /// the `child` directly. If it is null, routes must be provided using one of - /// the other properties listed above. - /// - /// Unless a [Navigator] is provided, either implicitly from [builder] being - /// null, or by a [builder] including its `child` argument, or by a [builder] - /// explicitly providing a [Navigator] of its own, features such as - /// [showDialog] and [showMenu], widgets such as [Tooltip], [PopupMenuButton], - /// or [Hero], and APIs such as [Navigator.push] and [Navigator.pop], will not + /// Material specific features such as [showDialog] and [showMenu], and widgets + /// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly /// function. final TransitionBuilder builder; @@ -472,73 +339,24 @@ class _MaterialAppState extends State { _updateNavigator(); } - bool _haveNavigator; List _navigatorObservers; void _updateNavigator() { - _haveNavigator = widget.home != null || - widget.routes.isNotEmpty || - widget.onGenerateRoute != null || - widget.onUnknownRoute != null; - _navigatorObservers = List.from(widget.navigatorObservers) - ..add(_heroController); + if (widget.home != null || + widget.routes.isNotEmpty || + widget.onGenerateRoute != null || + widget.onUnknownRoute != null) { + _navigatorObservers = List.from(widget.navigatorObservers) + ..add(_heroController); + } else { + _navigatorObservers = null; + } } RectTween _createRectTween(Rect begin, Rect end) { return MaterialRectArcTween(begin: begin, end: end); } - Route _onGenerateRoute(RouteSettings settings) { - final String name = settings.name; - WidgetBuilder builder; - if (name == Navigator.defaultRouteName && widget.home != null) { - builder = (BuildContext context) => widget.home; - } else { - builder = widget.routes[name]; - } - if (builder != null) { - return MaterialPageRoute( - builder: builder, - settings: settings, - ); - } - if (widget.onGenerateRoute != null) - return widget.onGenerateRoute(settings); - return null; - } - - Route _onUnknownRoute(RouteSettings settings) { - assert(() { - if (widget.onUnknownRoute == null) { - throw FlutterError( - 'Could not find a generator for route $settings in the $runtimeType.\n' - 'Generators for routes are searched for in the following order:\n' - ' 1. For the "/" route, the "home" property, if non-null, is used.\n' - ' 2. Otherwise, the "routes" table is used, if it has an entry for ' - 'the route.\n' - ' 3. Otherwise, onGenerateRoute is called. It should return a ' - 'non-null value for any valid route not handled by "home" and "routes".\n' - ' 4. Finally if all else fails onUnknownRoute is called.\n' - 'Unfortunately, onUnknownRoute was not set.' - ); - } - return true; - }()); - final Route result = widget.onUnknownRoute(settings); - assert(() { - if (result == null) { - throw FlutterError( - 'The onUnknownRoute callback returned null.\n' - 'When the $runtimeType requested the route $settings from its ' - 'onUnknownRoute callback, the callback returned null. Such callbacks ' - 'must never return null.' - ); - } - return true; - }()); - return result; - } - // Combine the Localizations for Material with the ones contributed // by the localizationsDelegates parameter, if any. Only the first delegate // of a particular LocalizationsDelegate.type is loaded so the @@ -559,10 +377,16 @@ class _MaterialAppState extends State { child: WidgetsApp( key: GlobalObjectKey(this), navigatorKey: widget.navigatorKey, - navigatorObservers: _haveNavigator ? _navigatorObservers : null, + navigatorObservers: _navigatorObservers, + // TODO(dnfield): when https://github.com/dart-lang/sdk/issues/34572 is resolved + // this can use type arguments again + pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) => + MaterialPageRoute(settings: settings, builder: builder), + home: widget.home, + routes: widget.routes, initialRoute: widget.initialRoute, - onGenerateRoute: _haveNavigator ? _onGenerateRoute : null, - onUnknownRoute: _haveNavigator ? _onUnknownRoute : null, + onGenerateRoute: widget.onGenerateRoute, + onUnknownRoute: widget.onUnknownRoute, builder: widget.builder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index e8c95eaee44..a6db3e347d7 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -14,6 +14,7 @@ import 'framework.dart'; import 'localizations.dart'; import 'media_query.dart'; import 'navigator.dart'; +import 'pages.dart'; import 'performance_overlay.dart'; import 'semantics_debugger.dart'; import 'text.dart'; @@ -43,6 +44,13 @@ typedef LocaleResolutionCallback = Locale Function(Locale locale, Iterable Function(RouteSettings settings, WidgetBuilder builder); + /// A convenience class that wraps a number of widgets that are commonly /// required for an application. /// @@ -58,8 +66,10 @@ class WidgetsApp extends StatefulWidget { /// /// The boolean arguments, [color], and [navigatorObservers] must not be null. /// - /// 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] parameter corresponds to + /// [Navigator.onGenerateRoute], and [pageRouteBuilder] will create a [PageRoute] + /// that wraps newly built routes. If the [builder] is non-null /// and the [onGenerateRoute] argument is null, then the [builder] will not be /// provided with a [Navigator]. If [onGenerateRoute] is not provided, /// [navigatorKey], [onUnknownRoute], [navigatorObservers], and [initialRoute] @@ -74,6 +84,9 @@ class WidgetsApp extends StatefulWidget { this.onUnknownRoute, this.navigatorObservers = const [], this.initialRoute, + this.pageRouteBuilder, + this.home, + this.routes = const {}, this.builder, this.title = '', this.onGenerateTitle, @@ -91,11 +104,49 @@ class WidgetsApp extends StatefulWidget { this.debugShowCheckedModeBanner = true, this.inspectorSelectButtonBuilder, }) : assert(navigatorObservers != null), - assert(onGenerateRoute != null || navigatorKey == null), - assert(onGenerateRoute != null || onUnknownRoute == null), - assert(onGenerateRoute != null || navigatorObservers == const []), - assert(onGenerateRoute != null || initialRoute == null), - assert(onGenerateRoute != null || builder != null), + assert(routes != null), + assert( + home == null || + !routes.containsKey(Navigator.defaultRouteName), + 'If the home property is specified, the routes table ' + 'cannot include an entry for "/", since it would be redundant.' + ), + assert( + builder != null || + home != null || + routes.containsKey(Navigator.defaultRouteName) || + onGenerateRoute != null || + onUnknownRoute != null, + 'Either the home property must be specified, ' + 'or the routes table must include an entry for "/", ' + 'or there must be on onGenerateRoute callback specified, ' + 'or there must be an onUnknownRoute callback specified, ' + 'or the builder property must be specified, ' + 'because otherwise there is nothing to fall back on if the ' + 'app is started with an intent that specifies an unknown route.' + ), + assert( + (home != null || + routes.isNotEmpty || + onGenerateRoute != null || + onUnknownRoute != null) + || + (builder != null && + navigatorKey == null && + initialRoute == null && + navigatorObservers.isEmpty), + 'If no route is provided using ' + 'home, routes, onGenerateRoute, or onUnknownRoute, ' + 'a non-null callback for the builder property must be provided, ' + 'and the other navigator-related properties, ' + 'navigatorKey, initialRoute, and navigatorObservers, ' + 'must have their initial values ' + '(null, null, and the empty list, respectively).' + ), + assert(onGenerateRoute != null || pageRouteBuilder != null, + 'If onGenerateRoute is not provided, the pageRouteBuilder must be specified ' + 'so that the default handler will know what kind of PageRoute transition ' + 'bo build.'), assert(title != null), assert(color != null), assert(supportedLocales != null && supportedLocales.isNotEmpty), @@ -107,6 +158,7 @@ class WidgetsApp extends StatefulWidget { assert(debugShowWidgetInspector != null), super(key: key); + /// {@template flutter.widgets.widgetsApp.navigatorKey} /// A key to use when building the [Navigator]. /// /// If a [navigatorKey] is specified, the [Navigator] can be directly @@ -121,6 +173,7 @@ class WidgetsApp extends StatefulWidget { /// /// The [Navigator] is only built if [onGenerateRoute] is not null; if it is /// null, [navigatorKey] must also be null. + /// {@endTemplate} final GlobalKey navigatorKey; /// {@template flutter.widgets.widgetsApp.onGenerateRoute} @@ -134,25 +187,103 @@ class WidgetsApp extends StatefulWidget { /// During normal app operation, the [onGenerateRoute] callback will only be /// applied to route names pushed by the application, and so should never /// return null. + /// + /// This is used if [routes] does not contain the requested route. + /// + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [builder] must not be null. /// {@endtemplate} /// - /// The [Navigator] is only built if [onGenerateRoute] is not null. If - /// [onGenerateRoute] is null, the [builder] must be non-null. + /// If this property is not set, either the [routes] or [home] properties must + /// be set, and the [pageRouteBuilder] must also be set so that the + /// default handler will know what routes and [PageRoute]s to build. final RouteFactory onGenerateRoute; - /// Called when [onGenerateRoute] fails to generate a route. + /// The [PageRoute] generator callback used when the app is navigated to a + /// named route. /// + /// This callback can be used, for example, to specify that a [MaterialPageRoute] + /// or a [CupertinoPageRoute] should be used for building page transitions. + final PageRouteFactory pageRouteBuilder; + + /// {@template flutter.widgets.widgetsApp.home} + /// The widget for the default route of the app ([Navigator.defaultRouteName], + /// which is `/`). + /// + /// This is the route that is displayed first when the application is started + /// normally, unless [initialRoute] is specified. It's also the route that's + /// displayed if the [initialRoute] can't be displayed. + /// + /// To be able to directly call [Theme.of], [MediaQuery.of], etc, in the code + /// that sets the [home] argument in the constructor, you can use a [Builder] + /// widget to get a [BuildContext]. + /// + /// If [home] is specified, then [routes] must not include an entry for `/`, + /// as [home] takes its place. + /// + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [builder] must not be null. + /// + /// The difference between using [home] and using [builder] is that the [home] + /// subtree is inserted into the application below a [Navigator] (and thus + /// below an [Overlay], which [Navigator] uses). With [home], therefore, + /// dialog boxes will work automatically, the [routes] table will be used, and + /// APIs such as [Navigator.push] and [Navigator.pop] will work as expected. + /// In contrast, the widget returned from [builder] is inserted _above_ the + /// app's [Navigator] (if any). + /// {@endTemplate} + /// + /// 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 Widget home; + + /// The application's top-level routing table. + /// + /// When a named route is pushed with [Navigator.pushNamed], the route name is + /// looked up in this map. If the name is present, the associated + /// [WidgetBuilder] is used to construct a [PageRoute] specified by + /// [pageRouteBuilder] to perform an appropriate transition, including [Hero] + /// animations, to the new route. + /// + /// {@template flutter.widgets.widgetsApp.routes} + /// If the app only has one page, then you can specify it using [home] instead. + /// + /// If [home] is specified, then it implies an entry in this table for the + /// [Navigator.defaultRouteName] route (`/`), and it is an error to + /// redundantly provide such a route in the [routes] table. + /// + /// If a route is requested that is not specified in this table (or by + /// [home]), then the [onGenerateRoute] callback is called to build the page + /// instead. + /// + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [builder] must not be null. + /// {@endTemplate} + /// + /// If the routes map is not empty, the [pageRouteBuilder] property must be set + /// so that the default route handler will know what kind of [PageRoute]s to + /// build. + final Map routes; + /// {@template flutter.widgets.widgetsApp.onUnknownRoute} + /// Called when [onGenerateRoute] fails to generate a route, except for the + /// [initialRoute]. + /// /// This callback is typically used for error handling. For example, this /// callback might always generate a "not found" page that describes the route /// that wasn't found. /// /// Unknown routes can arise either from errors in the app or from external /// requests to push routes, such as from Android intents. - /// {@endtemplate} /// - /// The [Navigator] is only built if [onGenerateRoute] is not null; if it is - /// null, [onUnknownRoute] must also be null. + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [builder] must not be null. + /// {@endtemplate} final RouteFactory onUnknownRoute; /// {@template flutter.widgets.widgetsApp.initialRoute} @@ -170,16 +301,16 @@ class WidgetsApp extends StatefulWidget { /// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead /// (`/`). This can happen if the app is started with an intent that specifies /// a non-existent route. - /// {@endtemplate} - /// - /// The [Navigator] is only built if [onGenerateRoute] is not null; if it is - /// null, [initialRoute] must also be null. + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [initialRoute] must be null and [builder] must not be null. /// /// See also: /// /// * [Navigator.initialRoute], which is used to implement this property. /// * [Navigator.push], for pushing additional routes. /// * [Navigator.pop], for removing a route from the stack. + /// {@endtemplate} final String initialRoute; /// {@template flutter.widgets.widgetsApp.navigatorObservers} @@ -187,11 +318,11 @@ class WidgetsApp extends StatefulWidget { /// /// This list must be replaced by a list of newly-created observers if the /// [navigatorKey] is changed. - /// {@endtemplate} /// - /// The [Navigator] is only built if [onGenerateRoute] is not null; if it is - /// null, [navigatorObservers] must be left to its default value, the empty - /// list. + /// The [Navigator] is only built if routes are provided (either via [home], + /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, + /// [navigatorObservers] must be the empty list and [builder] must not be null. + /// {@endtemplate} final List navigatorObservers; /// {@template flutter.widgets.widgetsApp.builder} @@ -214,21 +345,27 @@ class WidgetsApp extends StatefulWidget { /// /// The [builder] callback is passed two arguments, the [BuildContext] (as /// `context`) and a [Navigator] widget (as `child`). - /// {@endtemplate} /// - /// If [onGenerateRoute] is null, the `child` will be null, and it is the - /// responsibility of the [builder] to provide the application's routing - /// machinery. + /// If no routes are provided using [home], [routes], [onGenerateRoute], or + /// [onUnknownRoute], the `child` will be null, and it is the responsibility + /// of the [builder] to provide the application's routing machinery. /// - /// If [onGenerateRoute] is not null, then `child` is not null, and the - /// returned value should include the `child` in the widget subtree; if it - /// does not, then the application will have no navigator and the - /// [navigatorKey], [onGenerateRoute], [onUnknownRoute], [initialRoute], and - /// [navigatorObservers] properties will have no effect. + /// If routes _are_ provided using one or more of those properties, then + /// `child` is not null, and the returned value should include the `child` in + /// the widget subtree; if it does not, then the application will have no + /// navigator and the [navigatorKey], [home], [routes], [onGenerateRoute], + /// [onUnknownRoute], [initialRoute], and [navigatorObservers] properties will + /// have no effect. /// /// If [builder] is null, it is as if a builder was specified that returned - /// the `child` directly. At least one of either [onGenerateRoute] or - /// [builder] must be non-null. + /// the `child` directly. If it is null, routes must be provided using one of + /// the other properties listed above. + /// + /// Unless a [Navigator] is provided, either implicitly from [builder] being + /// null, or by a [builder] including its `child` argument, or by a [builder] + /// explicitly providing a [Navigator] of its own, widgets and APIs such as + /// [Hero], [Navigator.push] and [Navigator.pop], will not function. + /// {@endtemplate} final TransitionBuilder builder; /// {@template flutter.widgets.widgetsApp.title} @@ -455,11 +592,64 @@ class _WidgetsAppState extends State implements WidgetsBindingObserv GlobalKey _navigator; void _updateNavigator() { - if (widget.onGenerateRoute == null) { - _navigator = null; + _navigator = widget.navigatorKey ?? GlobalObjectKey(this); + } + + Route _onGenerateRoute(RouteSettings settings) { + final String name = settings.name; + WidgetBuilder builder; + if (name == Navigator.defaultRouteName && widget.home != null) { + builder = (BuildContext context) => widget.home; } else { - _navigator = widget.navigatorKey ?? GlobalObjectKey(this); + builder = widget.routes[name]; } + if (builder != null) { + assert(widget.pageRouteBuilder != null, + 'The default onGenerateRoute handler for WidgetsApp must have a ' + 'pageRouteBuilder set if the home or routes properties are set.'); + final Route route = widget.pageRouteBuilder( + settings, + builder, + ); + assert(route != null, + 'The pageRouteBuilder for WidgetsApp must return a valid non-null Route.'); + return route; + } + if (widget.onGenerateRoute != null) + return widget.onGenerateRoute(settings); + return null; + } + + Route _onUnknownRoute(RouteSettings settings) { + assert(() { + if (widget.onUnknownRoute == null) { + throw FlutterError( + 'Could not find a generator for route $settings in the $runtimeType.\n' + 'Generators for routes are searched for in the following order:\n' + ' 1. For the "/" route, the "home" property, if non-null, is used.\n' + ' 2. Otherwise, the "routes" table is used, if it has an entry for ' + 'the route.\n' + ' 3. Otherwise, onGenerateRoute is called. It should return a ' + 'non-null value for any valid route not handled by "home" and "routes".\n' + ' 4. Finally if all else fails onUnknownRoute is called.\n' + 'Unfortunately, onUnknownRoute was not set.' + ); + } + return true; + }()); + final Route result = widget.onUnknownRoute(settings); + assert(() { + if (result == null) { + throw FlutterError( + 'The onUnknownRoute callback returned null.\n' + 'When the $runtimeType requested the route $settings from its ' + 'onUnknownRoute callback, the callback returned null. Such callbacks ' + 'must never return null.' + ); + } + return true; + }()); + return result; } // On Android: the user has pressed the back button. @@ -566,9 +756,14 @@ class _WidgetsAppState extends State implements WidgetsBindingObserv if (_navigator != null) { navigator = Navigator( key: _navigator, - initialRoute: widget.initialRoute ?? ui.window.defaultRouteName, - onGenerateRoute: widget.onGenerateRoute, - onUnknownRoute: widget.onUnknownRoute, + // If ui.window.defaultRouteName isn't '/', we should assume it was set + // intentionally via `setInitialRoute`, and should override whatever + // is in [widget.initialRoute]. + initialRoute: ui.window.defaultRouteName != Navigator.defaultRouteName + ? ui.window.defaultRouteName + : widget.initialRoute ?? ui.window.defaultRouteName, + onGenerateRoute: _onGenerateRoute, + onUnknownRoute: _onUnknownRoute, observers: widget.navigatorObservers, ); } diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 65133e9d6f4..29a3bccb9ec 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -66,7 +66,7 @@ void main() { testWidgets('Has semantic annotations', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp(home: const Material( + await tester.pumpWidget(const MaterialApp(home: Material( child: CupertinoAlertDialog( title: Text('The Title'), content: Text('Content'), diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index 8ca3f6c5df6..3ccadc00ed0 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -16,8 +16,8 @@ int count = 0; void main() { testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( leading: CupertinoButton(child: Text('Something'), onPressed: null,), middle: Text('Title'), ), @@ -30,8 +30,8 @@ void main() { testWidgets('Middle still in center with back button', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), ), ), @@ -54,8 +54,8 @@ void main() { testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), backgroundColor: Color(0xFFE5E5E5), ), @@ -66,8 +66,8 @@ void main() { testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), ), ), @@ -120,8 +120,8 @@ void main() { testWidgets('Padding works in RTL', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Directionality( + const CupertinoApp( + home: Directionality( textDirection: TextDirection.rtl, child: Align( alignment: Alignment.topCenter, @@ -151,8 +151,8 @@ void main() { testWidgets('Verify styles of each slot', (WidgetTester tester) async { count = 0x000000; await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( leading: _ExpectStyles(color: Color(0xFF001122), index: 0x000001), middle: _ExpectStyles(color: Color(0xFF000000), letterSpacing: -0.08, index: 0x000100), trailing: _ExpectStyles(color: Color(0xFF001122), index: 0x010000), @@ -165,8 +165,8 @@ void main() { testWidgets('No slivers with no large titles', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoPageScaffold( + const CupertinoApp( + home: CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text('Title'), ), @@ -431,8 +431,8 @@ void main() { testWidgets('Auto back/close button', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Home page'), ), ), @@ -486,8 +486,8 @@ void main() { testWidgets('Long back label turns into "back"', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -529,8 +529,8 @@ void main() { testWidgets('Border should be displayed by default', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), ), ), @@ -551,8 +551,8 @@ void main() { testWidgets('Overrides border color', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), border: Border( bottom: BorderSide( @@ -580,8 +580,8 @@ void main() { testWidgets('Border should not be displayed when null', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoNavigationBar( + const CupertinoApp( + home: CupertinoNavigationBar( middle: Text('Title'), border: null, ), @@ -746,8 +746,8 @@ void main() { 'Standard title golden', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const RepaintBoundary( + const CupertinoApp( + home: RepaintBoundary( child: CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text('Bling bling'), diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index d7715a4e569..a4b2e8a6882 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -14,8 +14,8 @@ Future startTransitionBetween( String toTitle, }) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -195,8 +195,8 @@ void main() { testWidgets('Fullscreen dialogs do not create heroes', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); diff --git a/packages/flutter/test/cupertino/page_test.dart b/packages/flutter/test/cupertino/page_test.dart index 5bf44ffc693..a6de3b22fcb 100644 --- a/packages/flutter/test/cupertino/page_test.dart +++ b/packages/flutter/test/cupertino/page_test.dart @@ -146,8 +146,8 @@ void main() { testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Center(child: Text('Page 1')), + const CupertinoApp( + home: Center(child: Text('Page 1')), ), ); diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 3f74462db46..de721c5ef18 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -9,8 +9,8 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('Middle auto-populates with title', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -39,8 +39,8 @@ void main() { testWidgets('Large title auto-populates with title', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -104,8 +104,8 @@ void main() { testWidgets('Leading auto-populates with back button with previous title', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -150,8 +150,8 @@ void main() { testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); @@ -193,8 +193,8 @@ void main() { testWidgets('Previous title stays up to date with changing routes', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const Placeholder(), + const CupertinoApp( + home: Placeholder(), ), ); diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index dbeca86934c..6620e0018f1 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -11,8 +11,8 @@ import '../painting/mocks_for_image_cache.dart'; void main() { testWidgets('Contents are behind translucent bar', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoPageScaffold( + const CupertinoApp( + home: CupertinoPageScaffold( // Default nav bar is translucent. navigationBar: CupertinoNavigationBar( middle: Text('Title'), @@ -276,8 +276,8 @@ void main() { testWidgets('Decorated with white background by default', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoPageScaffold( + const CupertinoApp( + home: CupertinoPageScaffold( child: Center(), ), ), @@ -292,8 +292,8 @@ void main() { testWidgets('Overrides background color', (WidgetTester tester) async { await tester.pumpWidget( - CupertinoApp( - home: const CupertinoPageScaffold( + const CupertinoApp( + home: CupertinoPageScaffold( child: Center(), backgroundColor: Color(0xFF010203), ), diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index a4134a53d5b..f71ba902a3f 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -67,9 +67,9 @@ void main() { testWidgets('About box logic defaults to executable name for app name', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( + const MaterialApp( title: 'flutter_tester', - home: const Material(child: AboutListTile()), + home: Material(child: AboutListTile()), ), ); expect(find.text('About flutter_tester'), findsOneWidget); @@ -89,8 +89,8 @@ void main() { }); await tester.pumpWidget( - MaterialApp( - home: const Center( + const MaterialApp( + home: Center( child: LicensePage(), ), ), diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index b42e86c847b..bbd05e77607 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -28,9 +28,9 @@ class StateMarkerState extends State { void main() { testWidgets('Can nest apps', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( + const MaterialApp( home: MaterialApp( - home: const Text('Home sweet home'), + home: Text('Home sweet home'), ), ), ); @@ -57,8 +57,8 @@ void main() { await tester.pumpWidget(FocusScope( autofocus: true, node: focusScopeNode, - child: MaterialApp( - home: const Text('Home'), + child: const MaterialApp( + home: Text('Home'), ), )); @@ -67,8 +67,8 @@ void main() { testWidgets('Can show grid without losing sync', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const StateMarker(), + const MaterialApp( + home: StateMarker(), ), ); @@ -76,9 +76,9 @@ void main() { state1.marker = 'original'; await tester.pumpWidget( - MaterialApp( + const MaterialApp( debugShowMaterialGrid: true, - home: const StateMarker(), + home: StateMarker(), ), ); @@ -205,7 +205,7 @@ void main() { }); testWidgets('Cannot pop the initial route', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: const Text('Home'))); + await tester.pumpWidget(const MaterialApp(home: Text('Home'))); expect(find.text('Home'), findsOneWidget); @@ -400,9 +400,9 @@ void main() { home: const Placeholder(), )); expect(key.currentState, isInstanceOf()); - await tester.pumpWidget(MaterialApp( - color: const Color(0xFF112233), - home: const Placeholder(), + await tester.pumpWidget(const MaterialApp( + color: Color(0xFF112233), + home: Placeholder(), )); expect(key.currentState, isNull); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index c783cc522b6..2d020163450 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -9,8 +9,8 @@ import 'package:flutter/rendering.dart'; void main() { testWidgets('no overlap with floating action button', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, ), @@ -95,8 +95,8 @@ void main() { // _BottomAppBarClipper will try an illegal downcast. testWidgets('toggle shape to null', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: BottomAppBar( shape: RectangularNotch(), ), @@ -105,8 +105,8 @@ void main() { ); await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: BottomAppBar( shape: null, ), @@ -115,8 +115,8 @@ void main() { ); await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: BottomAppBar( shape: RectangularNotch(), ), @@ -127,8 +127,8 @@ void main() { testWidgets('no notch when notch param is null', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: ShapeListener(BottomAppBar( shape: null, )), @@ -159,8 +159,8 @@ void main() { testWidgets('notch no margin', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: ShapeListener( BottomAppBar( child: SizedBox(height: 100.0), @@ -211,8 +211,8 @@ void main() { testWidgets('notch with margin', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: ShapeListener( BottomAppBar( child: SizedBox(height: 100.0), @@ -263,8 +263,8 @@ void main() { testWidgets('observes safe area', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const MediaQuery( + const MaterialApp( + home: MediaQuery( data: MediaQueryData( padding: EdgeInsets.all(50.0), ), @@ -287,8 +287,8 @@ void main() { testWidgets('clipBehavior is propagated', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: BottomAppBar( child: SizedBox(height: 100.0), @@ -303,8 +303,8 @@ void main() { expect(physicalShape.clipBehavior, Clip.none); await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomNavigationBar: BottomAppBar( child: SizedBox(height: 100.0), diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 082e8aed30b..43ff699f8d8 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -1181,8 +1181,8 @@ void main() { testWidgets('label only', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp( - home: const Material( + await tester.pumpWidget(const MaterialApp( + home: Material( child: RawChip( label: Text('test'), ), diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index a275c4ae77c..10ed47be7b6 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -106,8 +106,8 @@ void main() { testWidgets('Simple dialog control test', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: RaisedButton( onPressed: null, @@ -149,8 +149,8 @@ void main() { testWidgets('Barrier dismissible', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: RaisedButton( onPressed: null, @@ -212,8 +212,8 @@ void main() { final SemanticsTester semantics = SemanticsTester(tester); const String buttonText = 'A button covered by dialog overlay'; await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: RaisedButton( onPressed: null, diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart index ff29764e09a..9a542eb9712 100644 --- a/packages/flutter/test/material/drawer_test.dart +++ b/packages/flutter/test/material/drawer_test.dart @@ -61,8 +61,8 @@ void main() { final SemanticsTester semantics = SemanticsTester(tester); debugDefaultTargetPlatformOverride = TargetPlatform.iOS; await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( drawer: Drawer() ), ), @@ -86,8 +86,8 @@ void main() { testWidgets('Drawer dismiss barrier has no label on Android', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( drawer: Drawer() ), ), diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 63bf4ed6162..526419c632d 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -36,8 +36,8 @@ void main() { testWidgets('Floating Action Button tooltip', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, tooltip: 'Add', @@ -54,8 +54,8 @@ void main() { // Regression test for: https://github.com/flutter/flutter/pull/21084 testWidgets('Floating Action Button tooltip (long press button edge)', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, tooltip: 'Add', @@ -75,8 +75,8 @@ void main() { // Regression test for: https://github.com/flutter/flutter/pull/21084 testWidgets('Floating Action Button tooltip (long press button edge - no child)', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, tooltip: 'Add', @@ -94,8 +94,8 @@ void main() { testWidgets('Floating Action Button tooltip (no child)', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, tooltip: 'Add', @@ -150,8 +150,8 @@ void main() { testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton(onPressed: null), ), ), diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index 9b752168c36..c880aeeca19 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -180,8 +180,8 @@ void main() { // Remove the persistent bottomSheet await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( bottomSheet: null, body: Placeholder(), ), diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart index 2e807d707ec..4c23e53b8b5 100644 --- a/packages/flutter/test/material/scaffold_test.dart +++ b/packages/flutter/test/material/scaffold_test.dart @@ -124,7 +124,7 @@ void main() { }); testWidgets('Floating action entrance/exit animation', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: const Scaffold( + await tester.pumpWidget(const MaterialApp(home: Scaffold( floatingActionButton: FloatingActionButton( key: Key('one'), onPressed: null, @@ -134,7 +134,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); - await tester.pumpWidget(MaterialApp(home: const Scaffold( + await tester.pumpWidget(const MaterialApp(home: Scaffold( floatingActionButton: FloatingActionButton( key: Key('two'), onPressed: null, @@ -146,11 +146,11 @@ void main() { await tester.pumpWidget(Container()); expect(tester.binding.transientCallbackCount, 0); - await tester.pumpWidget(MaterialApp(home: const Scaffold())); + await tester.pumpWidget(const MaterialApp(home: Scaffold())); expect(tester.binding.transientCallbackCount, 0); - await tester.pumpWidget(MaterialApp(home: const Scaffold( + await tester.pumpWidget(const MaterialApp(home: Scaffold( floatingActionButton: FloatingActionButton( key: Key('one'), onPressed: null, @@ -569,7 +569,7 @@ void main() { const String drawerLabel = 'I am the reason for this test'; final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp(home: const Scaffold( + await tester.pumpWidget(const MaterialApp(home: Scaffold( body: Text(bodyLabel), persistentFooterButtons: [Text(persistentFooterButtonLabel)], bottomNavigationBar: Text(bottomNavigationBarLabel), @@ -970,7 +970,7 @@ void main() { const String endDrawerLabel = 'I am the label on end side'; final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(MaterialApp(home: const Scaffold( + await tester.pumpWidget(const MaterialApp(home: Scaffold( body: Text(bodyLabel), drawer: Drawer(child: Text(drawerLabel)), endDrawer: Drawer(child: Text(endDrawerLabel)), diff --git a/packages/flutter/test/material/text_field_focus_test.dart b/packages/flutter/test/material/text_field_focus_test.dart index 4bb79d6c4c0..a21594723c4 100644 --- a/packages/flutter/test/material/text_field_focus_test.dart +++ b/packages/flutter/test/material/text_field_focus_test.dart @@ -37,8 +37,8 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: TextField( autofocus: true, @@ -59,8 +59,8 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: TextField(), ), @@ -93,8 +93,8 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: TextField( autofocus: true, @@ -211,8 +211,8 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/16880 await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: Center( child: TextField( decoration: null diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index ff4d5cd33f9..f4d68b3e0bb 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -7,11 +7,11 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: const Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); + await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); expect(find.text('Awesome'), findsNWidgets(1)); - await tester.pumpWidget(MaterialApp(home: const Material(child: TextField(decoration: InputDecoration(errorText: 'Awesome'))))); + await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(errorText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(2)); }); } diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 5a1d8d6d3a2..46979c5fb48 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -1721,8 +1721,8 @@ void main() { }); testWidgets('setting maxLength shows counter', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp( - home: const Material( + await tester.pumpWidget(const MaterialApp( + home: Material( child: DefaultTextStyle( style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0), child: Center( @@ -1746,8 +1746,8 @@ void main() { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( - MaterialApp( - home: const Material( + const MaterialApp( + home: Material( child: DefaultTextStyle( style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0), child: Center( diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 8c117f81d79..b1bea3ad9e3 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -610,8 +610,8 @@ void main() { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( - MaterialApp( - home: const Center( + const MaterialApp( + home: Center( child: Tooltip( message: 'Foo', child: Text('Bar'), @@ -645,8 +645,8 @@ void main() { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( - MaterialApp( - home: const Center( + const MaterialApp( + home: Center( child: Tooltip( message: 'Foo', child: Text('Bar'), diff --git a/packages/flutter/test/widgets/banner_test.dart b/packages/flutter/test/widgets/banner_test.dart index c11a6e09b6b..58eb350b6e5 100644 --- a/packages/flutter/test/widgets/banner_test.dart +++ b/packages/flutter/test/widgets/banner_test.dart @@ -269,7 +269,7 @@ void main() { testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async { debugDisableShadows = false; - await tester.pumpWidget(MaterialApp(home: const Placeholder())); + await tester.pumpWidget(const MaterialApp(home: Placeholder())); expect(find.byType(CheckedModeBanner), paints ..save() ..translate(x: 800.0, y: 0.0) diff --git a/packages/flutter/test/widgets/reassemble_test.dart b/packages/flutter/test/widgets/reassemble_test.dart index c107812217a..adc74baf98d 100644 --- a/packages/flutter/test/widgets/reassemble_test.dart +++ b/packages/flutter/test/widgets/reassemble_test.dart @@ -7,8 +7,8 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('reassemble does not crash', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp( - home: const Text('Hello World') + await tester.pumpWidget(const MaterialApp( + home: Text('Hello World') )); await tester.pump(); tester.binding.reassembleApplication(); diff --git a/packages/flutter_test/test/test_text_input_test.dart b/packages/flutter_test/test/test_text_input_test.dart index 2c89f5669ce..2bed6132df1 100644 --- a/packages/flutter_test/test/test_text_input_test.dart +++ b/packages/flutter_test/test/test_text_input_test.dart @@ -10,8 +10,8 @@ void main() { testWidgets('receiveAction() forwards exception when exception occurs during action processing', (WidgetTester tester) async { // Setup a widget that can receive focus so that we can open the keyboard. - final Widget widget = MaterialApp( - home: const Material( + const Widget widget = MaterialApp( + home: Material( child: TextField(), ), ); diff --git a/packages/flutter_test/test/widget_tester_test.dart b/packages/flutter_test/test/widget_tester_test.dart index c26094f1212..ecb5ba05024 100644 --- a/packages/flutter_test/test/widget_tester_test.dart +++ b/packages/flutter_test/test/widget_tester_test.dart @@ -533,8 +533,8 @@ void main() { group('getSemanticsData', () { testWidgets('throws when there are no semantics', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - home: const Scaffold( + const MaterialApp( + home: Scaffold( body: Text('hello'), ), ),