Widgets app refactor (#22269)
* Refactor of cupertino/material/widgets app * update docs * Update tests for const
This commit is contained in:
parent
582f35dfb1
commit
ea5435c2ef
@ -15,7 +15,7 @@ void main() {
|
|||||||
await WidgetsBinding.instance.reassembleApplication();
|
await WidgetsBinding.instance.reassembleApplication();
|
||||||
return log;
|
return log;
|
||||||
});
|
});
|
||||||
runApp(MaterialApp(home: const Test()));
|
runApp(const MaterialApp(home: Test()));
|
||||||
}
|
}
|
||||||
|
|
||||||
class Test extends SingleChildRenderObjectWidget {
|
class Test extends SingleChildRenderObjectWidget {
|
||||||
|
@ -7,9 +7,9 @@ import 'package:flutter/material.dart';
|
|||||||
class AnimatedIconsTestApp extends StatelessWidget {
|
class AnimatedIconsTestApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return const MaterialApp(
|
||||||
title: 'Animated Icons Test',
|
title: 'Animated Icons Test',
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
body: IconsList(),
|
body: IconsList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -474,7 +474,7 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(MaterialApp(
|
runApp(const MaterialApp(
|
||||||
home: const AnimationDemo(),
|
home: AnimationDemo(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('grid_list_demo', (WidgetTester tester) async {
|
testWidgets('grid_list_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const GridListDemo()));
|
await tester.pumpWidget(const MaterialApp(home: GridListDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -105,21 +105,21 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('leave_behind_demo', (WidgetTester tester) async {
|
testWidgets('leave_behind_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const LeaveBehindDemo()));
|
await tester.pumpWidget(const MaterialApp(home: LeaveBehindDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('list_demo', (WidgetTester tester) async {
|
testWidgets('list_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const ListDemo()));
|
await tester.pumpWidget(const MaterialApp(home: ListDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('menu_demo', (WidgetTester tester) async {
|
testWidgets('menu_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const MenuDemo()));
|
await tester.pumpWidget(const MaterialApp(home: MenuDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -133,7 +133,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('overscroll_demo', (WidgetTester tester) async {
|
testWidgets('overscroll_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const OverscrollDemo()));
|
await tester.pumpWidget(const MaterialApp(home: OverscrollDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -161,7 +161,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('reorderable_list_demo', (WidgetTester tester) async {
|
testWidgets('reorderable_list_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const ReorderableListDemo()));
|
await tester.pumpWidget(const MaterialApp(home: ReorderableListDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -196,7 +196,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('snack_bar_demo', (WidgetTester tester) async {
|
testWidgets('snack_bar_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const SnackBarDemo()));
|
await tester.pumpWidget(const MaterialApp(home: SnackBarDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -217,7 +217,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('text_form_field_demo', (WidgetTester tester) async {
|
testWidgets('text_form_field_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(home: const TextFormFieldDemo()));
|
await tester.pumpWidget(const MaterialApp(home: TextFormFieldDemo()));
|
||||||
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
expect(tester, meetsGuideline(androidTapTargetGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
@ -380,12 +380,12 @@ void main() {
|
|||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('overscroll_demo $themeName', (WidgetTester tester) async {
|
testWidgets('overscroll_demo', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
await tester.pumpWidget(MaterialApp(theme: theme, home: const OverscrollDemo()));
|
await tester.pumpWidget(const MaterialApp(home: OverscrollDemo()));
|
||||||
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('page_selector_demo $themeName', (WidgetTester tester) async {
|
testWidgets('page_selector_demo $themeName', (WidgetTester tester) async {
|
||||||
final SemanticsHandle handle = tester.ensureSemantics();
|
final SemanticsHandle handle = tester.ensureSemantics();
|
||||||
|
@ -14,7 +14,7 @@ void main() {
|
|||||||
// We press the "1" and the "2" buttons and check that the display
|
// We press the "1" and the "2" buttons and check that the display
|
||||||
// reads "12".
|
// reads "12".
|
||||||
testWidgets('Flutter calculator app smoke test', (WidgetTester tester) async {
|
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');
|
final Finder oneButton = find.widgetWithText(InkResponse, '1');
|
||||||
expect(oneButton, findsOneWidget);
|
expect(oneButton, findsOneWidget);
|
||||||
|
@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('validates name field correctly', (WidgetTester tester) async {
|
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');
|
final Finder submitButton = find.widgetWithText(RaisedButton, 'SUBMIT');
|
||||||
expect(submitButton, findsOneWidget);
|
expect(submitButton, findsOneWidget);
|
||||||
|
@ -8,7 +8,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'button.dart';
|
import 'button.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'icons.dart';
|
import 'icons.dart';
|
||||||
import 'tab_view.dart';
|
import 'route.dart';
|
||||||
|
|
||||||
// Based on specs from https://developer.apple.com/design/resources/ for
|
// Based on specs from https://developer.apple.com/design/resources/ for
|
||||||
// iOS 12.
|
// iOS 12.
|
||||||
@ -74,8 +74,9 @@ class CupertinoApp extends StatefulWidget {
|
|||||||
/// This class creates an instance of [WidgetsApp].
|
/// This class creates an instance of [WidgetsApp].
|
||||||
///
|
///
|
||||||
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
|
/// 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,
|
Key key,
|
||||||
|
this.navigatorKey,
|
||||||
this.home,
|
this.home,
|
||||||
this.routes = const <String, WidgetBuilder>{},
|
this.routes = const <String, WidgetBuilder>{},
|
||||||
this.initialRoute,
|
this.initialRoute,
|
||||||
@ -97,43 +98,6 @@ class CupertinoApp extends StatefulWidget {
|
|||||||
this.debugShowCheckedModeBanner = true,
|
this.debugShowCheckedModeBanner = true,
|
||||||
}) : assert(routes != null),
|
}) : assert(routes != null),
|
||||||
assert(navigatorObservers != 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(title != null),
|
||||||
assert(showPerformanceOverlay != null),
|
assert(showPerformanceOverlay != null),
|
||||||
assert(checkerboardRasterCacheImages != null),
|
assert(checkerboardRasterCacheImages != null),
|
||||||
@ -142,31 +106,10 @@ class CupertinoApp extends StatefulWidget {
|
|||||||
assert(debugShowCheckedModeBanner != null),
|
assert(debugShowCheckedModeBanner != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// The widget for the default route of the app ([Navigator.defaultRouteName],
|
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
||||||
/// which is `/`).
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
///
|
|
||||||
/// This is the route that is displayed first when the application is started
|
/// {@macro flutter.widgets.widgetsApp.home}
|
||||||
/// 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;
|
final Widget home;
|
||||||
|
|
||||||
/// The application's top-level routing table.
|
/// The application's top-level routing table.
|
||||||
@ -176,81 +119,22 @@ class CupertinoApp extends StatefulWidget {
|
|||||||
/// [WidgetBuilder] is used to construct a [CupertinoPageRoute] that performs
|
/// [WidgetBuilder] is used to construct a [CupertinoPageRoute] that performs
|
||||||
/// an appropriate transition, including [Hero] animations, to the new route.
|
/// 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.
|
/// {@macro flutter.widgets.widgetsApp.routes}
|
||||||
///
|
|
||||||
/// 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;
|
final Map<String, WidgetBuilder> routes;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.initialRoute}
|
/// {@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;
|
final String initialRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
|
/// {@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;
|
final RouteFactory onGenerateRoute;
|
||||||
|
|
||||||
/// Called when [onGenerateRoute] fails to generate a route, except for the
|
|
||||||
/// [initialRoute].
|
|
||||||
///
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
|
/// {@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;
|
final RouteFactory onUnknownRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
|
/// {@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;
|
final List<NavigatorObserver> navigatorObservers;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.builder}
|
/// {@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;
|
final TransitionBuilder builder;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.title}
|
/// {@macro flutter.widgets.widgetsApp.title}
|
||||||
@ -304,6 +188,12 @@ class CupertinoApp extends StatefulWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
_CupertinoAppState createState() => _CupertinoAppState();
|
_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 {
|
class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
|
||||||
@ -320,51 +210,39 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _CupertinoAppState extends State<CupertinoApp> {
|
class _CupertinoAppState extends State<CupertinoApp> {
|
||||||
|
HeroController _heroController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_heroController = CupertinoApp.createCupertinoHeroController();
|
||||||
_updateNavigator();
|
_updateNavigator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(CupertinoApp oldWidget) {
|
void didUpdateWidget(CupertinoApp oldWidget) {
|
||||||
super.didUpdateWidget(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();
|
_updateNavigator();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _haveNavigator;
|
List<NavigatorObserver> _navigatorObservers;
|
||||||
void _updateNavigator() {
|
|
||||||
_haveNavigator = widget.home != null ||
|
|
||||||
widget.routes.isNotEmpty ||
|
|
||||||
widget.onGenerateRoute != null ||
|
|
||||||
widget.onUnknownRoute != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget defaultBuilder(BuildContext context, Widget child) {
|
void _updateNavigator() {
|
||||||
// The `child` coming back out from WidgetsApp will always be null since
|
if (widget.home != null ||
|
||||||
// we never passed in anything for it to create a Navigator inside
|
widget.routes.isNotEmpty ||
|
||||||
// WidgetsApp.
|
widget.onGenerateRoute != null ||
|
||||||
assert(child == null);
|
widget.onUnknownRoute != null) {
|
||||||
if (_haveNavigator) {
|
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
||||||
// Reuse CupertinoTabView which creates a routing Navigator for us.
|
..add(_heroController);
|
||||||
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 {
|
} else {
|
||||||
// We asserted that child is null above.
|
_navigatorObservers = null;
|
||||||
return widget.builder(context, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,10 +252,18 @@ class _CupertinoAppState extends State<CupertinoApp> {
|
|||||||
behavior: _AlwaysCupertinoScrollBehavior(),
|
behavior: _AlwaysCupertinoScrollBehavior(),
|
||||||
child: WidgetsApp(
|
child: WidgetsApp(
|
||||||
key: GlobalObjectKey(this),
|
key: GlobalObjectKey(this),
|
||||||
// We're passing in a builder and nothing else that the WidgetsApp uses
|
navigatorKey: widget.navigatorKey,
|
||||||
// to build its own Navigator because we're building a Navigator with
|
navigatorObservers: _navigatorObservers,
|
||||||
// routes in this class.
|
// TODO(dnfield): when https://github.com/dart-lang/sdk/issues/34572 is resolved
|
||||||
builder: defaultBuilder,
|
// this can use type arguments again
|
||||||
|
pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) =>
|
||||||
|
CupertinoPageRoute<dynamic>(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,
|
title: widget.title,
|
||||||
onGenerateTitle: widget.onGenerateTitle,
|
onGenerateTitle: widget.onGenerateTitle,
|
||||||
textStyle: _kDefaultTextStyle,
|
textStyle: _kDefaultTextStyle,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'app.dart' show CupertinoApp;
|
||||||
import 'route.dart';
|
import 'route.dart';
|
||||||
|
|
||||||
/// A single tab view with its own [Navigator] state and history.
|
/// A single tab view with its own [Navigator] state and history.
|
||||||
@ -114,7 +115,7 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_heroController = HeroController(); // Linear tweening.
|
_heroController = CupertinoApp.createCupertinoHeroController();
|
||||||
_updateObservers();
|
_updateObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class MaterialApp extends StatefulWidget {
|
|||||||
/// This class creates an instance of [WidgetsApp].
|
/// This class creates an instance of [WidgetsApp].
|
||||||
///
|
///
|
||||||
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
|
/// 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,
|
Key key,
|
||||||
this.navigatorKey,
|
this.navigatorKey,
|
||||||
this.home,
|
this.home,
|
||||||
@ -105,44 +105,6 @@ class MaterialApp extends StatefulWidget {
|
|||||||
this.debugShowCheckedModeBanner = true,
|
this.debugShowCheckedModeBanner = true,
|
||||||
}) : assert(routes != null),
|
}) : assert(routes != null),
|
||||||
assert(navigatorObservers != 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(title != null),
|
||||||
assert(debugShowMaterialGrid != null),
|
assert(debugShowMaterialGrid != null),
|
||||||
assert(showPerformanceOverlay != null),
|
assert(showPerformanceOverlay != null),
|
||||||
@ -152,48 +114,10 @@ class MaterialApp extends StatefulWidget {
|
|||||||
assert(debugShowCheckedModeBanner != null),
|
assert(debugShowCheckedModeBanner != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// A key to use when building the [Navigator].
|
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
||||||
///
|
|
||||||
/// 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;
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
|
|
||||||
/// The widget for the default route of the app ([Navigator.defaultRouteName],
|
/// {@macro flutter.widgets.widgetsApp.home}
|
||||||
/// 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;
|
final Widget home;
|
||||||
|
|
||||||
/// The application's top-level routing table.
|
/// The application's top-level routing table.
|
||||||
@ -203,82 +127,25 @@ class MaterialApp extends StatefulWidget {
|
|||||||
/// [WidgetBuilder] is used to construct a [MaterialPageRoute] that performs
|
/// [WidgetBuilder] is used to construct a [MaterialPageRoute] that performs
|
||||||
/// an appropriate transition, including [Hero] animations, to the new route.
|
/// 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.
|
/// {@macro flutter.widgets.widgetsApp.routes}
|
||||||
///
|
|
||||||
/// 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;
|
final Map<String, WidgetBuilder> routes;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.initialRoute}
|
/// {@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;
|
final String initialRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
|
/// {@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;
|
final RouteFactory onGenerateRoute;
|
||||||
|
|
||||||
/// Called when [onGenerateRoute] fails to generate a route, except for the
|
|
||||||
/// [initialRoute].
|
|
||||||
///
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
|
/// {@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;
|
final RouteFactory onUnknownRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
|
/// {@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;
|
final List<NavigatorObserver> navigatorObservers;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.builder}
|
/// {@macro flutter.widgets.widgetsApp.builder}
|
||||||
///
|
///
|
||||||
/// If no routes are provided using [home], [routes], [onGenerateRoute], or
|
/// Material specific features such as [showDialog] and [showMenu], and widgets
|
||||||
/// [onUnknownRoute], the `child` will be null, and it is the responsibility
|
/// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
|
||||||
/// 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.
|
/// function.
|
||||||
final TransitionBuilder builder;
|
final TransitionBuilder builder;
|
||||||
|
|
||||||
@ -472,73 +339,24 @@ class _MaterialAppState extends State<MaterialApp> {
|
|||||||
_updateNavigator();
|
_updateNavigator();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _haveNavigator;
|
|
||||||
List<NavigatorObserver> _navigatorObservers;
|
List<NavigatorObserver> _navigatorObservers;
|
||||||
|
|
||||||
void _updateNavigator() {
|
void _updateNavigator() {
|
||||||
_haveNavigator = widget.home != null ||
|
if (widget.home != null ||
|
||||||
widget.routes.isNotEmpty ||
|
widget.routes.isNotEmpty ||
|
||||||
widget.onGenerateRoute != null ||
|
widget.onGenerateRoute != null ||
|
||||||
widget.onUnknownRoute != null;
|
widget.onUnknownRoute != null) {
|
||||||
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
_navigatorObservers = List<NavigatorObserver>.from(widget.navigatorObservers)
|
||||||
..add(_heroController);
|
..add(_heroController);
|
||||||
|
} else {
|
||||||
|
_navigatorObservers = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RectTween _createRectTween(Rect begin, Rect end) {
|
RectTween _createRectTween(Rect begin, Rect end) {
|
||||||
return MaterialRectArcTween(begin: begin, end: 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
|
// Combine the Localizations for Material with the ones contributed
|
||||||
// by the localizationsDelegates parameter, if any. Only the first delegate
|
// by the localizationsDelegates parameter, if any. Only the first delegate
|
||||||
// of a particular LocalizationsDelegate.type is loaded so the
|
// of a particular LocalizationsDelegate.type is loaded so the
|
||||||
@ -559,10 +377,16 @@ class _MaterialAppState extends State<MaterialApp> {
|
|||||||
child: WidgetsApp(
|
child: WidgetsApp(
|
||||||
key: GlobalObjectKey(this),
|
key: GlobalObjectKey(this),
|
||||||
navigatorKey: widget.navigatorKey,
|
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<dynamic>(settings: settings, builder: builder),
|
||||||
|
home: widget.home,
|
||||||
|
routes: widget.routes,
|
||||||
initialRoute: widget.initialRoute,
|
initialRoute: widget.initialRoute,
|
||||||
onGenerateRoute: _haveNavigator ? _onGenerateRoute : null,
|
onGenerateRoute: widget.onGenerateRoute,
|
||||||
onUnknownRoute: _haveNavigator ? _onUnknownRoute : null,
|
onUnknownRoute: widget.onUnknownRoute,
|
||||||
builder: widget.builder,
|
builder: widget.builder,
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
onGenerateTitle: widget.onGenerateTitle,
|
onGenerateTitle: widget.onGenerateTitle,
|
||||||
|
@ -14,6 +14,7 @@ import 'framework.dart';
|
|||||||
import 'localizations.dart';
|
import 'localizations.dart';
|
||||||
import 'media_query.dart';
|
import 'media_query.dart';
|
||||||
import 'navigator.dart';
|
import 'navigator.dart';
|
||||||
|
import 'pages.dart';
|
||||||
import 'performance_overlay.dart';
|
import 'performance_overlay.dart';
|
||||||
import 'semantics_debugger.dart';
|
import 'semantics_debugger.dart';
|
||||||
import 'text.dart';
|
import 'text.dart';
|
||||||
@ -43,6 +44,13 @@ typedef LocaleResolutionCallback = Locale Function(Locale locale, Iterable<Local
|
|||||||
/// This function must not return null.
|
/// This function must not return null.
|
||||||
typedef GenerateAppTitle = String Function(BuildContext context);
|
typedef GenerateAppTitle = String Function(BuildContext context);
|
||||||
|
|
||||||
|
/// The signature of [WidgetsApp.pageRouteBuilder].
|
||||||
|
///
|
||||||
|
/// Creates a [PageRoute] using the given [RouteSettings] and [WidgetBuilder].
|
||||||
|
// TODO(dnfield): when https://github.com/dart-lang/sdk/issues/34572 is resolved
|
||||||
|
// this can use type arguments again
|
||||||
|
typedef PageRouteFactory = PageRoute<dynamic> Function(RouteSettings settings, WidgetBuilder builder);
|
||||||
|
|
||||||
/// A convenience class that wraps a number of widgets that are commonly
|
/// A convenience class that wraps a number of widgets that are commonly
|
||||||
/// required for an application.
|
/// required for an application.
|
||||||
///
|
///
|
||||||
@ -58,8 +66,10 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// The boolean arguments, [color], and [navigatorObservers] must not be null.
|
/// The boolean arguments, [color], and [navigatorObservers] must not be null.
|
||||||
///
|
///
|
||||||
/// If the [builder] is null, the [onGenerateRoute] argument is required, and
|
/// If the [builder] is null, the [onGenerateRoute] and [pageRouteBuilder]
|
||||||
/// corresponds to [Navigator.onGenerateRoute]. If the [builder] is non-null
|
/// 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
|
/// and the [onGenerateRoute] argument is null, then the [builder] will not be
|
||||||
/// provided with a [Navigator]. If [onGenerateRoute] is not provided,
|
/// provided with a [Navigator]. If [onGenerateRoute] is not provided,
|
||||||
/// [navigatorKey], [onUnknownRoute], [navigatorObservers], and [initialRoute]
|
/// [navigatorKey], [onUnknownRoute], [navigatorObservers], and [initialRoute]
|
||||||
@ -74,6 +84,9 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
this.onUnknownRoute,
|
this.onUnknownRoute,
|
||||||
this.navigatorObservers = const <NavigatorObserver>[],
|
this.navigatorObservers = const <NavigatorObserver>[],
|
||||||
this.initialRoute,
|
this.initialRoute,
|
||||||
|
this.pageRouteBuilder,
|
||||||
|
this.home,
|
||||||
|
this.routes = const <String, WidgetBuilder>{},
|
||||||
this.builder,
|
this.builder,
|
||||||
this.title = '',
|
this.title = '',
|
||||||
this.onGenerateTitle,
|
this.onGenerateTitle,
|
||||||
@ -91,11 +104,49 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
this.debugShowCheckedModeBanner = true,
|
this.debugShowCheckedModeBanner = true,
|
||||||
this.inspectorSelectButtonBuilder,
|
this.inspectorSelectButtonBuilder,
|
||||||
}) : assert(navigatorObservers != null),
|
}) : assert(navigatorObservers != null),
|
||||||
assert(onGenerateRoute != null || navigatorKey == null),
|
assert(routes != null),
|
||||||
assert(onGenerateRoute != null || onUnknownRoute == null),
|
assert(
|
||||||
assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),
|
home == null ||
|
||||||
assert(onGenerateRoute != null || initialRoute == null),
|
!routes.containsKey(Navigator.defaultRouteName),
|
||||||
assert(onGenerateRoute != null || builder != null),
|
'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(title != null),
|
||||||
assert(color != null),
|
assert(color != null),
|
||||||
assert(supportedLocales != null && supportedLocales.isNotEmpty),
|
assert(supportedLocales != null && supportedLocales.isNotEmpty),
|
||||||
@ -107,6 +158,7 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
assert(debugShowWidgetInspector != null),
|
assert(debugShowWidgetInspector != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
|
/// {@template flutter.widgets.widgetsApp.navigatorKey}
|
||||||
/// A key to use when building the [Navigator].
|
/// A key to use when building the [Navigator].
|
||||||
///
|
///
|
||||||
/// If a [navigatorKey] is specified, the [Navigator] can be directly
|
/// 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
|
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
|
||||||
/// null, [navigatorKey] must also be null.
|
/// null, [navigatorKey] must also be null.
|
||||||
|
/// {@endTemplate}
|
||||||
final GlobalKey<NavigatorState> navigatorKey;
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.onGenerateRoute}
|
/// {@template flutter.widgets.widgetsApp.onGenerateRoute}
|
||||||
@ -134,25 +187,103 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
/// During normal app operation, the [onGenerateRoute] callback will only be
|
/// During normal app operation, the [onGenerateRoute] callback will only be
|
||||||
/// applied to route names pushed by the application, and so should never
|
/// applied to route names pushed by the application, and so should never
|
||||||
/// return null.
|
/// 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}
|
/// {@endtemplate}
|
||||||
///
|
///
|
||||||
/// The [Navigator] is only built if [onGenerateRoute] is not null. If
|
/// If this property is not set, either the [routes] or [home] properties must
|
||||||
/// [onGenerateRoute] is null, the [builder] must be non-null.
|
/// 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;
|
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<String, WidgetBuilder> routes;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.onUnknownRoute}
|
/// {@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
|
/// This callback is typically used for error handling. For example, this
|
||||||
/// callback might always generate a "not found" page that describes the route
|
/// callback might always generate a "not found" page that describes the route
|
||||||
/// that wasn't found.
|
/// that wasn't found.
|
||||||
///
|
///
|
||||||
/// Unknown routes can arise either from errors in the app or from external
|
/// Unknown routes can arise either from errors in the app or from external
|
||||||
/// requests to push routes, such as from Android intents.
|
/// requests to push routes, such as from Android intents.
|
||||||
/// {@endtemplate}
|
|
||||||
///
|
///
|
||||||
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
|
/// The [Navigator] is only built if routes are provided (either via [home],
|
||||||
/// null, [onUnknownRoute] must also be null.
|
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
|
||||||
|
/// [builder] must not be null.
|
||||||
|
/// {@endtemplate}
|
||||||
final RouteFactory onUnknownRoute;
|
final RouteFactory onUnknownRoute;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.initialRoute}
|
/// {@template flutter.widgets.widgetsApp.initialRoute}
|
||||||
@ -170,16 +301,16 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
/// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead
|
/// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead
|
||||||
/// (`/`). This can happen if the app is started with an intent that specifies
|
/// (`/`). This can happen if the app is started with an intent that specifies
|
||||||
/// a non-existent route.
|
/// a non-existent route.
|
||||||
/// {@endtemplate}
|
/// The [Navigator] is only built if routes are provided (either via [home],
|
||||||
///
|
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
|
||||||
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
|
/// [initialRoute] must be null and [builder] must not be null.
|
||||||
/// null, [initialRoute] must also be null.
|
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [Navigator.initialRoute], which is used to implement this property.
|
/// * [Navigator.initialRoute], which is used to implement this property.
|
||||||
/// * [Navigator.push], for pushing additional routes.
|
/// * [Navigator.push], for pushing additional routes.
|
||||||
/// * [Navigator.pop], for removing a route from the stack.
|
/// * [Navigator.pop], for removing a route from the stack.
|
||||||
|
/// {@endtemplate}
|
||||||
final String initialRoute;
|
final String initialRoute;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.navigatorObservers}
|
/// {@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
|
/// This list must be replaced by a list of newly-created observers if the
|
||||||
/// [navigatorKey] is changed.
|
/// [navigatorKey] is changed.
|
||||||
/// {@endtemplate}
|
|
||||||
///
|
///
|
||||||
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
|
/// The [Navigator] is only built if routes are provided (either via [home],
|
||||||
/// null, [navigatorObservers] must be left to its default value, the empty
|
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
|
||||||
/// list.
|
/// [navigatorObservers] must be the empty list and [builder] must not be null.
|
||||||
|
/// {@endtemplate}
|
||||||
final List<NavigatorObserver> navigatorObservers;
|
final List<NavigatorObserver> navigatorObservers;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.builder}
|
/// {@template flutter.widgets.widgetsApp.builder}
|
||||||
@ -214,21 +345,27 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// The [builder] callback is passed two arguments, the [BuildContext] (as
|
/// The [builder] callback is passed two arguments, the [BuildContext] (as
|
||||||
/// `context`) and a [Navigator] widget (as `child`).
|
/// `context`) and a [Navigator] widget (as `child`).
|
||||||
/// {@endtemplate}
|
|
||||||
///
|
///
|
||||||
/// If [onGenerateRoute] is null, the `child` will be null, and it is the
|
/// If no routes are provided using [home], [routes], [onGenerateRoute], or
|
||||||
/// responsibility of the [builder] to provide the application's routing
|
/// [onUnknownRoute], the `child` will be null, and it is the responsibility
|
||||||
/// machinery.
|
/// of the [builder] to provide the application's routing machinery.
|
||||||
///
|
///
|
||||||
/// If [onGenerateRoute] is not null, then `child` is not null, and the
|
/// If routes _are_ provided using one or more of those properties, then
|
||||||
/// returned value should include the `child` in the widget subtree; if it
|
/// `child` is not null, and the returned value should include the `child` in
|
||||||
/// does not, then the application will have no navigator and the
|
/// the widget subtree; if it does not, then the application will have no
|
||||||
/// [navigatorKey], [onGenerateRoute], [onUnknownRoute], [initialRoute], and
|
/// navigator and the [navigatorKey], [home], [routes], [onGenerateRoute],
|
||||||
/// [navigatorObservers] properties will have no effect.
|
/// [onUnknownRoute], [initialRoute], and [navigatorObservers] properties will
|
||||||
|
/// have no effect.
|
||||||
///
|
///
|
||||||
/// If [builder] is null, it is as if a builder was specified that returned
|
/// If [builder] is null, it is as if a builder was specified that returned
|
||||||
/// the `child` directly. At least one of either [onGenerateRoute] or
|
/// the `child` directly. If it is null, routes must be provided using one of
|
||||||
/// [builder] must be non-null.
|
/// 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;
|
final TransitionBuilder builder;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.title}
|
/// {@template flutter.widgets.widgetsApp.title}
|
||||||
@ -455,11 +592,64 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
GlobalKey<NavigatorState> _navigator;
|
GlobalKey<NavigatorState> _navigator;
|
||||||
|
|
||||||
void _updateNavigator() {
|
void _updateNavigator() {
|
||||||
if (widget.onGenerateRoute == null) {
|
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
|
||||||
_navigator = null;
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(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<dynamic> 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<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.
|
// On Android: the user has pressed the back button.
|
||||||
@ -566,9 +756,14 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
if (_navigator != null) {
|
if (_navigator != null) {
|
||||||
navigator = Navigator(
|
navigator = Navigator(
|
||||||
key: _navigator,
|
key: _navigator,
|
||||||
initialRoute: widget.initialRoute ?? ui.window.defaultRouteName,
|
// If ui.window.defaultRouteName isn't '/', we should assume it was set
|
||||||
onGenerateRoute: widget.onGenerateRoute,
|
// intentionally via `setInitialRoute`, and should override whatever
|
||||||
onUnknownRoute: widget.onUnknownRoute,
|
// 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,
|
observers: widget.navigatorObservers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Has semantic annotations', (WidgetTester tester) async {
|
testWidgets('Has semantic annotations', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
await tester.pumpWidget(MaterialApp(home: const Material(
|
await tester.pumpWidget(const MaterialApp(home: Material(
|
||||||
child: CupertinoAlertDialog(
|
child: CupertinoAlertDialog(
|
||||||
title: Text('The Title'),
|
title: Text('The Title'),
|
||||||
content: Text('Content'),
|
content: Text('Content'),
|
||||||
|
@ -16,8 +16,8 @@ int count = 0;
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
|
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
leading: CupertinoButton(child: Text('Something'), onPressed: null,),
|
leading: CupertinoButton(child: Text('Something'), onPressed: null,),
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
),
|
),
|
||||||
@ -30,8 +30,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Middle still in center with back button', (WidgetTester tester) async {
|
testWidgets('Middle still in center with back button', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -54,8 +54,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
|
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
backgroundColor: Color(0xFFE5E5E5),
|
backgroundColor: Color(0xFFE5E5E5),
|
||||||
),
|
),
|
||||||
@ -66,8 +66,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async {
|
testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -120,8 +120,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Padding works in RTL', (WidgetTester tester) async {
|
testWidgets('Padding works in RTL', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Directionality(
|
home: Directionality(
|
||||||
textDirection: TextDirection.rtl,
|
textDirection: TextDirection.rtl,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
@ -151,8 +151,8 @@ void main() {
|
|||||||
testWidgets('Verify styles of each slot', (WidgetTester tester) async {
|
testWidgets('Verify styles of each slot', (WidgetTester tester) async {
|
||||||
count = 0x000000;
|
count = 0x000000;
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
leading: _ExpectStyles(color: Color(0xFF001122), index: 0x000001),
|
leading: _ExpectStyles(color: Color(0xFF001122), index: 0x000001),
|
||||||
middle: _ExpectStyles(color: Color(0xFF000000), letterSpacing: -0.08, index: 0x000100),
|
middle: _ExpectStyles(color: Color(0xFF000000), letterSpacing: -0.08, index: 0x000100),
|
||||||
trailing: _ExpectStyles(color: Color(0xFF001122), index: 0x010000),
|
trailing: _ExpectStyles(color: Color(0xFF001122), index: 0x010000),
|
||||||
@ -165,8 +165,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('No slivers with no large titles', (WidgetTester tester) async {
|
testWidgets('No slivers with no large titles', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoPageScaffold(
|
home: CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
),
|
),
|
||||||
@ -431,8 +431,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Auto back/close button', (WidgetTester tester) async {
|
testWidgets('Auto back/close button', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Home page'),
|
middle: Text('Home page'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -486,8 +486,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Long back label turns into "back"', (WidgetTester tester) async {
|
testWidgets('Long back label turns into "back"', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -529,8 +529,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
|
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -551,8 +551,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Overrides border color', (WidgetTester tester) async {
|
testWidgets('Overrides border color', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
@ -580,8 +580,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Border should not be displayed when null', (WidgetTester tester) async {
|
testWidgets('Border should not be displayed when null', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoNavigationBar(
|
home: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
border: null,
|
border: null,
|
||||||
),
|
),
|
||||||
@ -746,8 +746,8 @@ void main() {
|
|||||||
'Standard title golden',
|
'Standard title golden',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const RepaintBoundary(
|
home: RepaintBoundary(
|
||||||
child: CupertinoPageScaffold(
|
child: CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text('Bling bling'),
|
middle: Text('Bling bling'),
|
||||||
|
@ -14,8 +14,8 @@ Future<void> startTransitionBetween(
|
|||||||
String toTitle,
|
String toTitle,
|
||||||
}) async {
|
}) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -195,8 +195,8 @@ void main() {
|
|||||||
testWidgets('Fullscreen dialogs do not create heroes',
|
testWidgets('Fullscreen dialogs do not create heroes',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -146,8 +146,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
|
testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Center(child: Text('Page 1')),
|
home: Center(child: Text('Page 1')),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Middle auto-populates with title', (WidgetTester tester) async {
|
testWidgets('Middle auto-populates with title', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -39,8 +39,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Large title auto-populates with title', (WidgetTester tester) async {
|
testWidgets('Large title auto-populates with title', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -104,8 +104,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Leading auto-populates with back button with previous title', (WidgetTester tester) async {
|
testWidgets('Leading auto-populates with back button with previous title', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -150,8 +150,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async {
|
testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -193,8 +193,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Previous title stays up to date with changing routes', (WidgetTester tester) async {
|
testWidgets('Previous title stays up to date with changing routes', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ import '../painting/mocks_for_image_cache.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Contents are behind translucent bar', (WidgetTester tester) async {
|
testWidgets('Contents are behind translucent bar', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoPageScaffold(
|
home: CupertinoPageScaffold(
|
||||||
// Default nav bar is translucent.
|
// Default nav bar is translucent.
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text('Title'),
|
middle: Text('Title'),
|
||||||
@ -276,8 +276,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Decorated with white background by default', (WidgetTester tester) async {
|
testWidgets('Decorated with white background by default', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoPageScaffold(
|
home: CupertinoPageScaffold(
|
||||||
child: Center(),
|
child: Center(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -292,8 +292,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Overrides background color', (WidgetTester tester) async {
|
testWidgets('Overrides background color', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
const CupertinoApp(
|
||||||
home: const CupertinoPageScaffold(
|
home: CupertinoPageScaffold(
|
||||||
child: Center(),
|
child: Center(),
|
||||||
backgroundColor: Color(0xFF010203),
|
backgroundColor: Color(0xFF010203),
|
||||||
),
|
),
|
||||||
|
@ -67,9 +67,9 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('About box logic defaults to executable name for app name', (WidgetTester tester) async {
|
testWidgets('About box logic defaults to executable name for app name', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
title: 'flutter_tester',
|
title: 'flutter_tester',
|
||||||
home: const Material(child: AboutListTile()),
|
home: Material(child: AboutListTile()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(find.text('About flutter_tester'), findsOneWidget);
|
expect(find.text('About flutter_tester'), findsOneWidget);
|
||||||
@ -89,8 +89,8 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Center(
|
home: Center(
|
||||||
child: LicensePage(),
|
child: LicensePage(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -28,9 +28,9 @@ class StateMarkerState extends State<StateMarker> {
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Can nest apps', (WidgetTester tester) async {
|
testWidgets('Can nest apps', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: MaterialApp(
|
home: MaterialApp(
|
||||||
home: const Text('Home sweet home'),
|
home: Text('Home sweet home'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -57,8 +57,8 @@ void main() {
|
|||||||
await tester.pumpWidget(FocusScope(
|
await tester.pumpWidget(FocusScope(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
node: focusScopeNode,
|
node: focusScopeNode,
|
||||||
child: MaterialApp(
|
child: const MaterialApp(
|
||||||
home: const Text('Home'),
|
home: Text('Home'),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -67,8 +67,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Can show grid without losing sync', (WidgetTester tester) async {
|
testWidgets('Can show grid without losing sync', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const StateMarker(),
|
home: StateMarker(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -76,9 +76,9 @@ void main() {
|
|||||||
state1.marker = 'original';
|
state1.marker = 'original';
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
debugShowMaterialGrid: true,
|
debugShowMaterialGrid: true,
|
||||||
home: const StateMarker(),
|
home: StateMarker(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Cannot pop the initial route', (WidgetTester tester) async {
|
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);
|
expect(find.text('Home'), findsOneWidget);
|
||||||
|
|
||||||
@ -400,9 +400,9 @@ void main() {
|
|||||||
home: const Placeholder(),
|
home: const Placeholder(),
|
||||||
));
|
));
|
||||||
expect(key.currentState, isInstanceOf<NavigatorState>());
|
expect(key.currentState, isInstanceOf<NavigatorState>());
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(const MaterialApp(
|
||||||
color: const Color(0xFF112233),
|
color: Color(0xFF112233),
|
||||||
home: const Placeholder(),
|
home: Placeholder(),
|
||||||
));
|
));
|
||||||
expect(key.currentState, isNull);
|
expect(key.currentState, isNull);
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
@ -9,8 +9,8 @@ import 'package:flutter/rendering.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('no overlap with floating action button', (WidgetTester tester) async {
|
testWidgets('no overlap with floating action button', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
),
|
),
|
||||||
@ -95,8 +95,8 @@ void main() {
|
|||||||
// _BottomAppBarClipper will try an illegal downcast.
|
// _BottomAppBarClipper will try an illegal downcast.
|
||||||
testWidgets('toggle shape to null', (WidgetTester tester) async {
|
testWidgets('toggle shape to null', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: BottomAppBar(
|
bottomNavigationBar: BottomAppBar(
|
||||||
shape: RectangularNotch(),
|
shape: RectangularNotch(),
|
||||||
),
|
),
|
||||||
@ -105,8 +105,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: BottomAppBar(
|
bottomNavigationBar: BottomAppBar(
|
||||||
shape: null,
|
shape: null,
|
||||||
),
|
),
|
||||||
@ -115,8 +115,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: BottomAppBar(
|
bottomNavigationBar: BottomAppBar(
|
||||||
shape: RectangularNotch(),
|
shape: RectangularNotch(),
|
||||||
),
|
),
|
||||||
@ -127,8 +127,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('no notch when notch param is null', (WidgetTester tester) async {
|
testWidgets('no notch when notch param is null', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: ShapeListener(BottomAppBar(
|
bottomNavigationBar: ShapeListener(BottomAppBar(
|
||||||
shape: null,
|
shape: null,
|
||||||
)),
|
)),
|
||||||
@ -159,8 +159,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('notch no margin', (WidgetTester tester) async {
|
testWidgets('notch no margin', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: ShapeListener(
|
bottomNavigationBar: ShapeListener(
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
child: SizedBox(height: 100.0),
|
child: SizedBox(height: 100.0),
|
||||||
@ -211,8 +211,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('notch with margin', (WidgetTester tester) async {
|
testWidgets('notch with margin', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: ShapeListener(
|
bottomNavigationBar: ShapeListener(
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
child: SizedBox(height: 100.0),
|
child: SizedBox(height: 100.0),
|
||||||
@ -263,8 +263,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('observes safe area', (WidgetTester tester) async {
|
testWidgets('observes safe area', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const MediaQuery(
|
home: MediaQuery(
|
||||||
data: MediaQueryData(
|
data: MediaQueryData(
|
||||||
padding: EdgeInsets.all(50.0),
|
padding: EdgeInsets.all(50.0),
|
||||||
),
|
),
|
||||||
@ -287,8 +287,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('clipBehavior is propagated', (WidgetTester tester) async {
|
testWidgets('clipBehavior is propagated', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar:
|
bottomNavigationBar:
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
child: SizedBox(height: 100.0),
|
child: SizedBox(height: 100.0),
|
||||||
@ -303,8 +303,8 @@ void main() {
|
|||||||
expect(physicalShape.clipBehavior, Clip.none);
|
expect(physicalShape.clipBehavior, Clip.none);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar:
|
bottomNavigationBar:
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
child: SizedBox(height: 100.0),
|
child: SizedBox(height: 100.0),
|
||||||
|
@ -1181,8 +1181,8 @@ void main() {
|
|||||||
testWidgets('label only', (WidgetTester tester) async {
|
testWidgets('label only', (WidgetTester tester) async {
|
||||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: RawChip(
|
child: RawChip(
|
||||||
label: Text('test'),
|
label: Text('test'),
|
||||||
),
|
),
|
||||||
|
@ -106,8 +106,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Simple dialog control test', (WidgetTester tester) async {
|
testWidgets('Simple dialog control test', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: RaisedButton(
|
child: RaisedButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
@ -149,8 +149,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Barrier dismissible', (WidgetTester tester) async {
|
testWidgets('Barrier dismissible', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: RaisedButton(
|
child: RaisedButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
@ -212,8 +212,8 @@ void main() {
|
|||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
const String buttonText = 'A button covered by dialog overlay';
|
const String buttonText = 'A button covered by dialog overlay';
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: RaisedButton(
|
child: RaisedButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
|
@ -61,8 +61,8 @@ void main() {
|
|||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
drawer: Drawer()
|
drawer: Drawer()
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -86,8 +86,8 @@ void main() {
|
|||||||
testWidgets('Drawer dismiss barrier has no label on Android', (WidgetTester tester) async {
|
testWidgets('Drawer dismiss barrier has no label on Android', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
drawer: Drawer()
|
drawer: Drawer()
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -36,8 +36,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Floating Action Button tooltip', (WidgetTester tester) async {
|
testWidgets('Floating Action Button tooltip', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
tooltip: 'Add',
|
tooltip: 'Add',
|
||||||
@ -54,8 +54,8 @@ void main() {
|
|||||||
// Regression test for: https://github.com/flutter/flutter/pull/21084
|
// Regression test for: https://github.com/flutter/flutter/pull/21084
|
||||||
testWidgets('Floating Action Button tooltip (long press button edge)', (WidgetTester tester) async {
|
testWidgets('Floating Action Button tooltip (long press button edge)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
tooltip: 'Add',
|
tooltip: 'Add',
|
||||||
@ -75,8 +75,8 @@ void main() {
|
|||||||
// Regression test for: https://github.com/flutter/flutter/pull/21084
|
// Regression test for: https://github.com/flutter/flutter/pull/21084
|
||||||
testWidgets('Floating Action Button tooltip (long press button edge - no child)', (WidgetTester tester) async {
|
testWidgets('Floating Action Button tooltip (long press button edge - no child)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
tooltip: 'Add',
|
tooltip: 'Add',
|
||||||
@ -94,8 +94,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Floating Action Button tooltip (no child)', (WidgetTester tester) async {
|
testWidgets('Floating Action Button tooltip (no child)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
tooltip: 'Add',
|
tooltip: 'Add',
|
||||||
@ -150,8 +150,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async {
|
testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(onPressed: null),
|
floatingActionButton: FloatingActionButton(onPressed: null),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -180,8 +180,8 @@ void main() {
|
|||||||
|
|
||||||
// Remove the persistent bottomSheet
|
// Remove the persistent bottomSheet
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
bottomSheet: null,
|
bottomSheet: null,
|
||||||
body: Placeholder(),
|
body: Placeholder(),
|
||||||
),
|
),
|
||||||
|
@ -124,7 +124,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Floating action entrance/exit animation', (WidgetTester tester) async {
|
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(
|
floatingActionButton: FloatingActionButton(
|
||||||
key: Key('one'),
|
key: Key('one'),
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
@ -134,7 +134,7 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.binding.transientCallbackCount, 0);
|
expect(tester.binding.transientCallbackCount, 0);
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
key: Key('two'),
|
key: Key('two'),
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
@ -146,11 +146,11 @@ void main() {
|
|||||||
await tester.pumpWidget(Container());
|
await tester.pumpWidget(Container());
|
||||||
expect(tester.binding.transientCallbackCount, 0);
|
expect(tester.binding.transientCallbackCount, 0);
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(home: const Scaffold()));
|
await tester.pumpWidget(const MaterialApp(home: Scaffold()));
|
||||||
|
|
||||||
expect(tester.binding.transientCallbackCount, 0);
|
expect(tester.binding.transientCallbackCount, 0);
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
key: Key('one'),
|
key: Key('one'),
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
@ -569,7 +569,7 @@ void main() {
|
|||||||
const String drawerLabel = 'I am the reason for this test';
|
const String drawerLabel = 'I am the reason for this test';
|
||||||
|
|
||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||||
body: Text(bodyLabel),
|
body: Text(bodyLabel),
|
||||||
persistentFooterButtons: <Widget>[Text(persistentFooterButtonLabel)],
|
persistentFooterButtons: <Widget>[Text(persistentFooterButtonLabel)],
|
||||||
bottomNavigationBar: Text(bottomNavigationBarLabel),
|
bottomNavigationBar: Text(bottomNavigationBarLabel),
|
||||||
@ -970,7 +970,7 @@ void main() {
|
|||||||
const String endDrawerLabel = 'I am the label on end side';
|
const String endDrawerLabel = 'I am the label on end side';
|
||||||
|
|
||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
await tester.pumpWidget(MaterialApp(home: const Scaffold(
|
await tester.pumpWidget(const MaterialApp(home: Scaffold(
|
||||||
body: Text(bodyLabel),
|
body: Text(bodyLabel),
|
||||||
drawer: Drawer(child: Text(drawerLabel)),
|
drawer: Drawer(child: Text(drawerLabel)),
|
||||||
endDrawer: Drawer(child: Text(endDrawerLabel)),
|
endDrawer: Drawer(child: Text(endDrawerLabel)),
|
||||||
|
@ -37,8 +37,8 @@ void main() {
|
|||||||
expect(tester.testTextInput.isVisible, isFalse);
|
expect(tester.testTextInput.isVisible, isFalse);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
@ -59,8 +59,8 @@ void main() {
|
|||||||
expect(tester.testTextInput.isVisible, isFalse);
|
expect(tester.testTextInput.isVisible, isFalse);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextField(),
|
child: TextField(),
|
||||||
),
|
),
|
||||||
@ -93,8 +93,8 @@ void main() {
|
|||||||
expect(tester.testTextInput.isVisible, isFalse);
|
expect(tester.testTextInput.isVisible, isFalse);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
@ -211,8 +211,8 @@ void main() {
|
|||||||
// Regression test for https://github.com/flutter/flutter/issues/16880
|
// Regression test for https://github.com/flutter/flutter/issues/16880
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
decoration: null
|
decoration: null
|
||||||
|
@ -7,11 +7,11 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async {
|
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));
|
expect(find.text('Awesome'), findsNWidgets(1));
|
||||||
await tester.pump(const Duration(milliseconds: 100));
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
expect(find.text('Awesome'), findsNWidgets(1));
|
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));
|
expect(find.text('Awesome'), findsNWidgets(2));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1721,8 +1721,8 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('setting maxLength shows counter', (WidgetTester tester) async {
|
testWidgets('setting maxLength shows counter', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -1746,8 +1746,8 @@ void main() {
|
|||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
|
@ -610,8 +610,8 @@ void main() {
|
|||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Center(
|
home: Center(
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: 'Foo',
|
message: 'Foo',
|
||||||
child: Text('Bar'),
|
child: Text('Bar'),
|
||||||
@ -645,8 +645,8 @@ void main() {
|
|||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Center(
|
home: Center(
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: 'Foo',
|
message: 'Foo',
|
||||||
child: Text('Bar'),
|
child: Text('Bar'),
|
||||||
|
@ -269,7 +269,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async {
|
testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async {
|
||||||
debugDisableShadows = false;
|
debugDisableShadows = false;
|
||||||
await tester.pumpWidget(MaterialApp(home: const Placeholder()));
|
await tester.pumpWidget(const MaterialApp(home: Placeholder()));
|
||||||
expect(find.byType(CheckedModeBanner), paints
|
expect(find.byType(CheckedModeBanner), paints
|
||||||
..save()
|
..save()
|
||||||
..translate(x: 800.0, y: 0.0)
|
..translate(x: 800.0, y: 0.0)
|
||||||
|
@ -7,8 +7,8 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('reassemble does not crash', (WidgetTester tester) async {
|
testWidgets('reassemble does not crash', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(const MaterialApp(
|
||||||
home: const Text('Hello World')
|
home: Text('Hello World')
|
||||||
));
|
));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
tester.binding.reassembleApplication();
|
tester.binding.reassembleApplication();
|
||||||
|
@ -10,8 +10,8 @@ void main() {
|
|||||||
testWidgets('receiveAction() forwards exception when exception occurs during action processing',
|
testWidgets('receiveAction() forwards exception when exception occurs during action processing',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
// Setup a widget that can receive focus so that we can open the keyboard.
|
// Setup a widget that can receive focus so that we can open the keyboard.
|
||||||
final Widget widget = MaterialApp(
|
const Widget widget = MaterialApp(
|
||||||
home: const Material(
|
home: Material(
|
||||||
child: TextField(),
|
child: TextField(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -533,8 +533,8 @@ void main() {
|
|||||||
group('getSemanticsData', () {
|
group('getSemanticsData', () {
|
||||||
testWidgets('throws when there are no semantics', (WidgetTester tester) async {
|
testWidgets('throws when there are no semantics', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
const MaterialApp(
|
||||||
home: const Scaffold(
|
home: Scaffold(
|
||||||
body: Text('hello'),
|
body: Text('hello'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user