This reverts commit 61cf946ba8c55c73c9119a203d07b8c025b6aa92.
This commit is contained in:
parent
61cf946ba8
commit
a52bd81560
@ -15,7 +15,7 @@ void main() {
|
||||
await WidgetsBinding.instance.reassembleApplication();
|
||||
return log;
|
||||
});
|
||||
runApp(const MaterialApp(home: Test()));
|
||||
runApp(MaterialApp(home: const Test()));
|
||||
}
|
||||
|
||||
class Test extends SingleChildRenderObjectWidget {
|
||||
|
@ -7,9 +7,9 @@ import 'package:flutter/material.dart';
|
||||
class AnimatedIconsTestApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
return MaterialApp(
|
||||
title: 'Animated Icons Test',
|
||||
home: Scaffold(
|
||||
home: const Scaffold(
|
||||
body: IconsList(),
|
||||
),
|
||||
);
|
||||
|
@ -474,7 +474,7 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
|
||||
}
|
||||
|
||||
void main() {
|
||||
runApp(const MaterialApp(
|
||||
home: AnimationDemo(),
|
||||
runApp(MaterialApp(
|
||||
home: const AnimationDemo(),
|
||||
));
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ void main() {
|
||||
|
||||
testWidgets('grid_list_demo', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(const MaterialApp(home: GridListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: LeaveBehindDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const LeaveBehindDemo()));
|
||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('list_demo', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(const MaterialApp(home: ListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const ListDemo()));
|
||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('menu_demo', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(const MaterialApp(home: MenuDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: OverscrollDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: ReorderableListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: SnackBarDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: TextFormFieldDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const TextFormFieldDemo()));
|
||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
@ -380,12 +380,12 @@ void main() {
|
||||
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('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('page_selector_demo $themeName', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
|
@ -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(const MaterialApp(home: CalculatorDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const CalculatorDemo()));
|
||||
|
||||
final Finder oneButton = find.widgetWithText(InkResponse, '1');
|
||||
expect(oneButton, findsOneWidget);
|
||||
|
@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('validates name field correctly', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(home: TextFormFieldDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: const TextFormFieldDemo()));
|
||||
|
||||
final Finder submitButton = find.widgetWithText(RaisedButton, 'SUBMIT');
|
||||
expect(submitButton, findsOneWidget);
|
||||
|
@ -8,7 +8,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'button.dart';
|
||||
import 'colors.dart';
|
||||
import 'icons.dart';
|
||||
import 'route.dart';
|
||||
import 'tab_view.dart';
|
||||
|
||||
// Based on specs from https://developer.apple.com/design/resources/ for
|
||||
// iOS 12.
|
||||
@ -74,9 +74,8 @@ class CupertinoApp extends StatefulWidget {
|
||||
/// This class creates an instance of [WidgetsApp].
|
||||
///
|
||||
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
|
||||
const CupertinoApp({
|
||||
CupertinoApp({ // can't be const because the asserts use methods on Map :-(
|
||||
Key key,
|
||||
this.navigatorKey,
|
||||
this.home,
|
||||
this.routes = const <String, WidgetBuilder>{},
|
||||
this.initialRoute,
|
||||
@ -98,6 +97,43 @@ 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),
|
||||
@ -106,10 +142,31 @@ class CupertinoApp extends StatefulWidget {
|
||||
assert(debugShowCheckedModeBanner != null),
|
||||
super(key: key);
|
||||
|
||||
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
|
||||
/// {@macro 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 [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).
|
||||
final Widget home;
|
||||
|
||||
/// The application's top-level routing table.
|
||||
@ -119,22 +176,81 @@ class CupertinoApp extends StatefulWidget {
|
||||
/// [WidgetBuilder] is used to construct a [CupertinoPageRoute] that performs
|
||||
/// an appropriate transition, including [Hero] animations, to the new route.
|
||||
///
|
||||
/// {@macro 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.
|
||||
final Map<String, WidgetBuilder> 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<NavigatorObserver> 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}
|
||||
@ -188,12 +304,6 @@ 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 {
|
||||
@ -210,39 +320,51 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
|
||||
}
|
||||
|
||||
class _CupertinoAppState extends State<CupertinoApp> {
|
||||
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();
|
||||
}
|
||||
|
||||
List<NavigatorObserver> _navigatorObservers;
|
||||
|
||||
bool _haveNavigator;
|
||||
void _updateNavigator() {
|
||||
if (widget.home != null ||
|
||||
widget.routes.isNotEmpty ||
|
||||
widget.onGenerateRoute != null ||
|
||||
widget.onUnknownRoute != null) {
|
||||
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
||||
..add(_heroController);
|
||||
_haveNavigator = widget.home != null ||
|
||||
widget.routes.isNotEmpty ||
|
||||
widget.onGenerateRoute != null ||
|
||||
widget.onUnknownRoute != null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
_navigatorObservers = null;
|
||||
// We asserted that child is null above.
|
||||
return widget.builder(context, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,16 +374,10 @@ class _CupertinoAppState extends State<CupertinoApp> {
|
||||
behavior: _AlwaysCupertinoScrollBehavior(),
|
||||
child: WidgetsApp(
|
||||
key: GlobalObjectKey(this),
|
||||
navigatorKey: widget.navigatorKey,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
|
||||
CupertinoPageRoute<T>(settings: settings, builder: builder),
|
||||
home: widget.home,
|
||||
routes: widget.routes,
|
||||
initialRoute: widget.initialRoute,
|
||||
onGenerateRoute: widget.onGenerateRoute,
|
||||
onUnknownRoute: widget.onUnknownRoute,
|
||||
builder: widget.builder,
|
||||
// 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,
|
||||
title: widget.title,
|
||||
onGenerateTitle: widget.onGenerateTitle,
|
||||
textStyle: _kDefaultTextStyle,
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'app.dart' show CupertinoApp;
|
||||
import 'route.dart';
|
||||
|
||||
/// A single tab view with its own [Navigator] state and history.
|
||||
@ -115,7 +114,7 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_heroController = CupertinoApp.createCupertinoHeroController();
|
||||
_heroController = HeroController(); // Linear tweening.
|
||||
_updateObservers();
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
const MaterialApp({
|
||||
MaterialApp({ // can't be const because the asserts use methods on Map :-(
|
||||
Key key,
|
||||
this.navigatorKey,
|
||||
this.home,
|
||||
@ -105,6 +105,44 @@ 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),
|
||||
@ -114,10 +152,48 @@ class MaterialApp extends StatefulWidget {
|
||||
assert(debugShowCheckedModeBanner != null),
|
||||
super(key: key);
|
||||
|
||||
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
||||
/// 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.
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
|
||||
/// {@macro 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, [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).
|
||||
final Widget home;
|
||||
|
||||
/// The application's top-level routing table.
|
||||
@ -127,25 +203,82 @@ class MaterialApp extends StatefulWidget {
|
||||
/// [WidgetBuilder] is used to construct a [MaterialPageRoute] that performs
|
||||
/// an appropriate transition, including [Hero] animations, to the new route.
|
||||
///
|
||||
/// {@macro 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.
|
||||
final Map<String, WidgetBuilder> 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<NavigatorObserver> navigatorObservers;
|
||||
|
||||
/// {@macro flutter.widgets.widgetsApp.builder}
|
||||
///
|
||||
/// Material specific features such as [showDialog] and [showMenu], and widgets
|
||||
/// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
|
||||
/// 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
|
||||
/// function.
|
||||
final TransitionBuilder builder;
|
||||
|
||||
@ -339,24 +472,73 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
_updateNavigator();
|
||||
}
|
||||
|
||||
bool _haveNavigator;
|
||||
List<NavigatorObserver> _navigatorObservers;
|
||||
|
||||
void _updateNavigator() {
|
||||
if (widget.home != null ||
|
||||
widget.routes.isNotEmpty ||
|
||||
widget.onGenerateRoute != null ||
|
||||
widget.onUnknownRoute != null) {
|
||||
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
||||
..add(_heroController);
|
||||
} else {
|
||||
_navigatorObservers = null;
|
||||
}
|
||||
_haveNavigator = widget.home != null ||
|
||||
widget.routes.isNotEmpty ||
|
||||
widget.onGenerateRoute != null ||
|
||||
widget.onUnknownRoute != null;
|
||||
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
||||
..add(_heroController);
|
||||
}
|
||||
|
||||
RectTween _createRectTween(Rect begin, Rect end) {
|
||||
return MaterialRectArcTween(begin: begin, end: end);
|
||||
}
|
||||
|
||||
Route<dynamic> _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<dynamic>(
|
||||
builder: builder,
|
||||
settings: settings,
|
||||
);
|
||||
}
|
||||
if (widget.onGenerateRoute != null)
|
||||
return widget.onGenerateRoute(settings);
|
||||
return null;
|
||||
}
|
||||
|
||||
Route<dynamic> _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<dynamic> 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
|
||||
@ -377,14 +559,10 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
child: WidgetsApp(
|
||||
key: GlobalObjectKey(this),
|
||||
navigatorKey: widget.navigatorKey,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
|
||||
MaterialPageRoute<T>(settings: settings, builder: builder),
|
||||
home: widget.home,
|
||||
routes: widget.routes,
|
||||
navigatorObservers: _haveNavigator ? _navigatorObservers : null,
|
||||
initialRoute: widget.initialRoute,
|
||||
onGenerateRoute: widget.onGenerateRoute,
|
||||
onUnknownRoute: widget.onUnknownRoute,
|
||||
onGenerateRoute: _haveNavigator ? _onGenerateRoute : null,
|
||||
onUnknownRoute: _haveNavigator ? _onUnknownRoute : null,
|
||||
builder: widget.builder,
|
||||
title: widget.title,
|
||||
onGenerateTitle: widget.onGenerateTitle,
|
||||
|
@ -14,7 +14,6 @@ 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';
|
||||
@ -44,11 +43,6 @@ typedef LocaleResolutionCallback = Locale Function(Locale locale, Iterable<Local
|
||||
/// This function must not return null.
|
||||
typedef GenerateAppTitle = String Function(BuildContext context);
|
||||
|
||||
/// The signature of [WidgetsApp.pageRouteBuilder].
|
||||
///
|
||||
/// Creates a [PageRoute] using the given [RouteSettings] and [WidgetBuilder].
|
||||
typedef PageRouteFactory = PageRoute<T> Function<T>(RouteSettings settings, WidgetBuilder builder);
|
||||
|
||||
/// A convenience class that wraps a number of widgets that are commonly
|
||||
/// required for an application.
|
||||
///
|
||||
@ -64,10 +58,8 @@ class WidgetsApp extends StatefulWidget {
|
||||
///
|
||||
/// The boolean arguments, [color], and [navigatorObservers] must not be 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
|
||||
/// If the [builder] is null, the [onGenerateRoute] argument is required, and
|
||||
/// corresponds to [Navigator.onGenerateRoute]. 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]
|
||||
@ -82,9 +74,6 @@ class WidgetsApp extends StatefulWidget {
|
||||
this.onUnknownRoute,
|
||||
this.navigatorObservers = const <NavigatorObserver>[],
|
||||
this.initialRoute,
|
||||
this.pageRouteBuilder,
|
||||
this.home,
|
||||
this.routes = const <String, WidgetBuilder>{},
|
||||
this.builder,
|
||||
this.title = '',
|
||||
this.onGenerateTitle,
|
||||
@ -102,49 +91,11 @@ class WidgetsApp extends StatefulWidget {
|
||||
this.debugShowCheckedModeBanner = true,
|
||||
this.inspectorSelectButtonBuilder,
|
||||
}) : assert(navigatorObservers != 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(onGenerateRoute != null || navigatorKey == null),
|
||||
assert(onGenerateRoute != null || onUnknownRoute == null),
|
||||
assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),
|
||||
assert(onGenerateRoute != null || initialRoute == null),
|
||||
assert(onGenerateRoute != null || builder != null),
|
||||
assert(title != null),
|
||||
assert(color != null),
|
||||
assert(supportedLocales != null && supportedLocales.isNotEmpty),
|
||||
@ -156,7 +107,6 @@ 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
|
||||
@ -171,7 +121,6 @@ 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<NavigatorState> navigatorKey;
|
||||
|
||||
/// {@template flutter.widgets.widgetsApp.onGenerateRoute}
|
||||
@ -185,103 +134,25 @@ 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}
|
||||
///
|
||||
/// 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.
|
||||
/// The [Navigator] is only built if [onGenerateRoute] is not null. If
|
||||
/// [onGenerateRoute] is null, the [builder] must be non-null.
|
||||
final RouteFactory onGenerateRoute;
|
||||
|
||||
/// The [PageRoute] generator callback used when the app is navigated to a
|
||||
/// named route.
|
||||
/// Called when [onGenerateRoute] fails to generate a 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<String, WidgetBuilder> 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.
|
||||
///
|
||||
/// 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 it is
|
||||
/// null, [onUnknownRoute] must also be null.
|
||||
final RouteFactory onUnknownRoute;
|
||||
|
||||
/// {@template flutter.widgets.widgetsApp.initialRoute}
|
||||
@ -299,16 +170,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.
|
||||
/// 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.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
|
||||
/// null, [initialRoute] must also 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}
|
||||
@ -316,11 +187,11 @@ class WidgetsApp extends StatefulWidget {
|
||||
///
|
||||
/// This list must be replaced by a list of newly-created observers if the
|
||||
/// [navigatorKey] is changed.
|
||||
///
|
||||
/// 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}
|
||||
///
|
||||
/// 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.
|
||||
final List<NavigatorObserver> navigatorObservers;
|
||||
|
||||
/// {@template flutter.widgets.widgetsApp.builder}
|
||||
@ -343,27 +214,21 @@ class WidgetsApp extends StatefulWidget {
|
||||
///
|
||||
/// The [builder] callback is passed two arguments, the [BuildContext] (as
|
||||
/// `context`) and a [Navigator] widget (as `child`).
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// 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 null, 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 [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 [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.
|
||||
/// {@endtemplate}
|
||||
/// the `child` directly. At least one of either [onGenerateRoute] or
|
||||
/// [builder] must be non-null.
|
||||
final TransitionBuilder builder;
|
||||
|
||||
/// {@template flutter.widgets.widgetsApp.title}
|
||||
@ -590,64 +455,11 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
||||
GlobalKey<NavigatorState> _navigator;
|
||||
|
||||
void _updateNavigator() {
|
||||
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
|
||||
}
|
||||
|
||||
Route<dynamic> _onGenerateRoute(RouteSettings settings) {
|
||||
final String name = settings.name;
|
||||
WidgetBuilder builder;
|
||||
if (name == Navigator.defaultRouteName && widget.home != null) {
|
||||
builder = (BuildContext context) => widget.home;
|
||||
if (widget.onGenerateRoute == null) {
|
||||
_navigator = null;
|
||||
} else {
|
||||
builder = widget.routes[name];
|
||||
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
|
||||
}
|
||||
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<dynamic> route = widget.pageRouteBuilder<dynamic>(
|
||||
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<dynamic> _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<dynamic> 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.
|
||||
@ -754,14 +566,9 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
||||
if (_navigator != null) {
|
||||
navigator = Navigator(
|
||||
key: _navigator,
|
||||
// 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,
|
||||
initialRoute: widget.initialRoute ?? ui.window.defaultRouteName,
|
||||
onGenerateRoute: widget.onGenerateRoute,
|
||||
onUnknownRoute: widget.onUnknownRoute,
|
||||
observers: widget.navigatorObservers,
|
||||
);
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ void main() {
|
||||
|
||||
testWidgets('Has semantic annotations', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material(
|
||||
await tester.pumpWidget(MaterialApp(home: const Material(
|
||||
child: CupertinoAlertDialog(
|
||||
title: Text('The Title'),
|
||||
content: Text('Content'),
|
||||
|
@ -16,8 +16,8 @@ int count = 0;
|
||||
void main() {
|
||||
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const CupertinoNavigationBar(
|
||||
middle: Text('Title'),
|
||||
),
|
||||
),
|
||||
@ -54,8 +54,8 @@ void main() {
|
||||
|
||||
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const CupertinoNavigationBar(
|
||||
middle: Text('Title'),
|
||||
),
|
||||
),
|
||||
@ -120,8 +120,8 @@ void main() {
|
||||
|
||||
testWidgets('Padding works in RTL', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Directionality(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoPageScaffold(
|
||||
CupertinoApp(
|
||||
home: const CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Title'),
|
||||
),
|
||||
@ -431,8 +431,8 @@ void main() {
|
||||
|
||||
testWidgets('Auto back/close button', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const CupertinoNavigationBar(
|
||||
middle: Text('Home page'),
|
||||
),
|
||||
),
|
||||
@ -486,8 +486,8 @@ void main() {
|
||||
|
||||
testWidgets('Long back label turns into "back"', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -529,8 +529,8 @@ void main() {
|
||||
|
||||
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const CupertinoNavigationBar(
|
||||
middle: Text('Title'),
|
||||
),
|
||||
),
|
||||
@ -551,8 +551,8 @@ void main() {
|
||||
|
||||
testWidgets('Overrides border color', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar(
|
||||
CupertinoApp(
|
||||
home: const CupertinoNavigationBar(
|
||||
middle: Text('Title'),
|
||||
border: null,
|
||||
),
|
||||
@ -746,8 +746,8 @@ void main() {
|
||||
'Standard title golden',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
CupertinoApp(
|
||||
home: const RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Bling bling'),
|
||||
|
@ -14,8 +14,8 @@ Future<void> startTransitionBetween(
|
||||
String toTitle,
|
||||
}) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -195,8 +195,8 @@ void main() {
|
||||
testWidgets('Fullscreen dialogs do not create heroes',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -146,8 +146,8 @@ void main() {
|
||||
|
||||
testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Center(child: Text('Page 1')),
|
||||
CupertinoApp(
|
||||
home: const Center(child: Text('Page 1')),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -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(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -39,8 +39,8 @@ void main() {
|
||||
|
||||
testWidgets('Large title auto-populates with title', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -104,8 +104,8 @@ void main() {
|
||||
|
||||
testWidgets('Leading auto-populates with back button with previous title', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -150,8 +150,8 @@ void main() {
|
||||
|
||||
testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -193,8 +193,8 @@ void main() {
|
||||
|
||||
testWidgets('Previous title stays up to date with changing routes', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: Placeholder(),
|
||||
CupertinoApp(
|
||||
home: const Placeholder(),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoPageScaffold(
|
||||
CupertinoApp(
|
||||
home: const 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(
|
||||
const CupertinoApp(
|
||||
home: CupertinoPageScaffold(
|
||||
CupertinoApp(
|
||||
home: const CupertinoPageScaffold(
|
||||
child: Center(),
|
||||
),
|
||||
),
|
||||
@ -292,8 +292,8 @@ void main() {
|
||||
|
||||
testWidgets('Overrides background color', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoPageScaffold(
|
||||
CupertinoApp(
|
||||
home: const CupertinoPageScaffold(
|
||||
child: Center(),
|
||||
backgroundColor: Color(0xFF010203),
|
||||
),
|
||||
|
@ -67,9 +67,9 @@ void main() {
|
||||
|
||||
testWidgets('About box logic defaults to executable name for app name', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
MaterialApp(
|
||||
title: 'flutter_tester',
|
||||
home: Material(child: AboutListTile()),
|
||||
home: const Material(child: AboutListTile()),
|
||||
),
|
||||
);
|
||||
expect(find.text('About flutter_tester'), findsOneWidget);
|
||||
@ -89,8 +89,8 @@ void main() {
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Center(
|
||||
MaterialApp(
|
||||
home: const Center(
|
||||
child: LicensePage(),
|
||||
),
|
||||
),
|
||||
|
@ -28,9 +28,9 @@ class StateMarkerState extends State<StateMarker> {
|
||||
void main() {
|
||||
testWidgets('Can nest apps', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
MaterialApp(
|
||||
home: MaterialApp(
|
||||
home: Text('Home sweet home'),
|
||||
home: const Text('Home sweet home'),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -57,8 +57,8 @@ void main() {
|
||||
await tester.pumpWidget(FocusScope(
|
||||
autofocus: true,
|
||||
node: focusScopeNode,
|
||||
child: const MaterialApp(
|
||||
home: Text('Home'),
|
||||
child: MaterialApp(
|
||||
home: const Text('Home'),
|
||||
),
|
||||
));
|
||||
|
||||
@ -67,8 +67,8 @@ void main() {
|
||||
|
||||
testWidgets('Can show grid without losing sync', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: StateMarker(),
|
||||
MaterialApp(
|
||||
home: const StateMarker(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -76,9 +76,9 @@ void main() {
|
||||
state1.marker = 'original';
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
MaterialApp(
|
||||
debugShowMaterialGrid: true,
|
||||
home: StateMarker(),
|
||||
home: const StateMarker(),
|
||||
),
|
||||
);
|
||||
|
||||
@ -205,7 +205,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Cannot pop the initial route', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(home: Text('Home')));
|
||||
await tester.pumpWidget(MaterialApp(home: const Text('Home')));
|
||||
|
||||
expect(find.text('Home'), findsOneWidget);
|
||||
|
||||
@ -400,9 +400,9 @@ void main() {
|
||||
home: const Placeholder(),
|
||||
));
|
||||
expect(key.currentState, isInstanceOf<NavigatorState>());
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
color: Color(0xFF112233),
|
||||
home: Placeholder(),
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
color: const Color(0xFF112233),
|
||||
home: const Placeholder(),
|
||||
));
|
||||
expect(key.currentState, isNull);
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
|
@ -9,8 +9,8 @@ import 'package:flutter/rendering.dart';
|
||||
void main() {
|
||||
testWidgets('no overlap with floating action button', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
shape: RectangularNotch(),
|
||||
),
|
||||
@ -105,8 +105,8 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
shape: null,
|
||||
),
|
||||
@ -115,8 +115,8 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomNavigationBar: ShapeListener(BottomAppBar(
|
||||
shape: null,
|
||||
)),
|
||||
@ -159,8 +159,8 @@ void main() {
|
||||
|
||||
testWidgets('notch no margin', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: MediaQuery(
|
||||
MaterialApp(
|
||||
home: const MediaQuery(
|
||||
data: MediaQueryData(
|
||||
padding: EdgeInsets.all(50.0),
|
||||
),
|
||||
@ -287,8 +287,8 @@ void main() {
|
||||
|
||||
testWidgets('clipBehavior is propagated', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomNavigationBar:
|
||||
BottomAppBar(
|
||||
child: SizedBox(height: 100.0),
|
||||
@ -303,8 +303,8 @@ void main() {
|
||||
expect(physicalShape.clipBehavior, Clip.none);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomNavigationBar:
|
||||
BottomAppBar(
|
||||
child: SizedBox(height: 100.0),
|
||||
|
@ -1181,8 +1181,8 @@ void main() {
|
||||
testWidgets('label only', (WidgetTester tester) async {
|
||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Material(
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: const Material(
|
||||
child: RawChip(
|
||||
label: Text('test'),
|
||||
),
|
||||
|
@ -106,8 +106,8 @@ void main() {
|
||||
|
||||
testWidgets('Simple dialog control test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: Center(
|
||||
child: RaisedButton(
|
||||
onPressed: null,
|
||||
@ -149,8 +149,8 @@ void main() {
|
||||
|
||||
testWidgets('Barrier dismissible', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: Center(
|
||||
child: RaisedButton(
|
||||
onPressed: null,
|
||||
|
@ -61,8 +61,8 @@ void main() {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
drawer: Drawer()
|
||||
),
|
||||
),
|
||||
|
@ -36,8 +36,8 @@ void main() {
|
||||
|
||||
testWidgets('Floating Action Button tooltip', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: null,
|
||||
tooltip: 'Add',
|
||||
@ -150,8 +150,8 @@ void main() {
|
||||
|
||||
testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
floatingActionButton: FloatingActionButton(onPressed: null),
|
||||
),
|
||||
),
|
||||
|
@ -180,8 +180,8 @@ void main() {
|
||||
|
||||
// Remove the persistent bottomSheet
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
bottomSheet: null,
|
||||
body: Placeholder(),
|
||||
),
|
||||
|
@ -124,7 +124,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Floating action entrance/exit animation', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
key: Key('one'),
|
||||
onPressed: null,
|
||||
@ -134,7 +134,7 @@ void main() {
|
||||
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
|
||||
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: Scaffold()));
|
||||
await tester.pumpWidget(MaterialApp(home: const Scaffold()));
|
||||
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
|
||||
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: Scaffold(
|
||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
||||
body: Text(bodyLabel),
|
||||
persistentFooterButtons: <Widget>[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(const MaterialApp(home: Scaffold(
|
||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
||||
body: Text(bodyLabel),
|
||||
drawer: Drawer(child: Text(drawerLabel)),
|
||||
endDrawer: Drawer(child: Text(endDrawerLabel)),
|
||||
|
@ -37,8 +37,8 @@ void main() {
|
||||
expect(tester.testTextInput.isVisible, isFalse);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
autofocus: true,
|
||||
@ -59,8 +59,8 @@ void main() {
|
||||
expect(tester.testTextInput.isVisible, isFalse);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: Center(
|
||||
child: TextField(),
|
||||
),
|
||||
@ -93,8 +93,8 @@ void main() {
|
||||
expect(tester.testTextInput.isVisible, isFalse);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
decoration: null
|
||||
|
@ -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(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome')))));
|
||||
await tester.pumpWidget(MaterialApp(home: const 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(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(errorText: 'Awesome')))));
|
||||
await tester.pumpWidget(MaterialApp(home: const Material(child: TextField(decoration: InputDecoration(errorText: 'Awesome')))));
|
||||
expect(find.text('Awesome'), findsNWidgets(2));
|
||||
});
|
||||
}
|
||||
|
@ -1721,8 +1721,8 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('setting maxLength shows counter', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Material(
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: const 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(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
MaterialApp(
|
||||
home: const Material(
|
||||
child: DefaultTextStyle(
|
||||
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
||||
child: Center(
|
||||
|
@ -610,8 +610,8 @@ void main() {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Center(
|
||||
MaterialApp(
|
||||
home: const Center(
|
||||
child: Tooltip(
|
||||
message: 'Foo',
|
||||
child: Text('Bar'),
|
||||
@ -645,8 +645,8 @@ void main() {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Center(
|
||||
MaterialApp(
|
||||
home: const Center(
|
||||
child: Tooltip(
|
||||
message: 'Foo',
|
||||
child: Text('Bar'),
|
||||
|
@ -269,7 +269,7 @@ void main() {
|
||||
|
||||
testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async {
|
||||
debugDisableShadows = false;
|
||||
await tester.pumpWidget(const MaterialApp(home: Placeholder()));
|
||||
await tester.pumpWidget(MaterialApp(home: const Placeholder()));
|
||||
expect(find.byType(CheckedModeBanner), paints
|
||||
..save()
|
||||
..translate(x: 800.0, y: 0.0)
|
||||
|
@ -7,8 +7,8 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('reassemble does not crash', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Text('Hello World')
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: const Text('Hello World')
|
||||
));
|
||||
await tester.pump();
|
||||
tester.binding.reassembleApplication();
|
||||
|
@ -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.
|
||||
const Widget widget = MaterialApp(
|
||||
home: Material(
|
||||
final Widget widget = MaterialApp(
|
||||
home: const Material(
|
||||
child: TextField(),
|
||||
),
|
||||
);
|
||||
|
@ -533,8 +533,8 @@ void main() {
|
||||
group('getSemanticsData', () {
|
||||
testWidgets('throws when there are no semantics', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
home: const Scaffold(
|
||||
body: Text('hello'),
|
||||
),
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user