Unverified Commit 06f63aaa authored by xster's avatar xster Committed by GitHub

Create a CupertinoApp (#18469)

parent aad1bb4b
bc99a4bdea0533994b34bc49f160af75f4904952
413041fd6bbedd1c8bc6ca0b6ea6ea948079b669
......@@ -8,6 +8,7 @@
library cupertino;
export 'src/cupertino/activity_indicator.dart';
export 'src/cupertino/app.dart';
export 'src/cupertino/bottom_tab_bar.dart';
export 'src/cupertino/button.dart';
export 'src/cupertino/colors.dart';
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'button.dart';
import 'colors.dart';
import 'icons.dart';
import 'tab_view.dart';
// Based on specs from https://developer.apple.com/design/resources/ for
// iOS 12.
const TextStyle _kDefaultTextStyle = const TextStyle(
fontFamily: '.SF Pro Text',
fontSize: 17.0,
letterSpacing: -0.38,
color: CupertinoColors.black,
decoration: TextDecoration.none,
);
/// An application that uses Cupertino design.
///
/// A convenience widget that wraps a number of widgets that are commonly
/// required for an iOS-design targeting application. It builds upon a
/// [WidgetsApp] by iOS specific defaulting such as fonts and scrolling
/// physics.
///
/// The [CupertinoApp] configures the top-level [Navigator] to search for routes
/// in the following order:
///
/// 1. For the `/` route, the [home] property, if non-null, is used.
///
/// 2. Otherwise, the [routes] table is used, if it has an entry for the route.
///
/// 3. Otherwise, [onGenerateRoute] is called, if provided. It should return a
/// non-null value for any _valid_ route not handled by [home] and [routes].
///
/// 4. Finally if all else fails [onUnknownRoute] is called.
///
/// If [home], [routes], [onGenerateRoute], and [onUnknownRoute] are all null,
/// and [builder] is not null, then no [Navigator] is created.
///
/// Using this widget with caution on Android since it may produce behaviors
/// Android users are not expecting such as:
///
/// * Pages will be dismissible via a back swipe.
/// * Scrolling past extremities will trigger iOS-style spring overscrolls.
/// * The San Francisco font family is unavailable on Android and can result
/// in undefined font behavior.
///
/// See also:
///
/// * [CupertinoPageScaffold], which provides a standard page layout default
/// with nav bars.
/// * [Navigator], which is used to manage the app's stack of pages.
/// * [CupertinoPageRoute], which defines an app page that transitions in an
/// iOS-specific way.
/// * [WidgetsApp], which defines the basic app elements but does not depend
/// on the Cupertino library.
class CupertinoApp extends StatefulWidget {
/// Creates a CupertinoApp.
///
/// At least one of [home], [routes], [onGenerateRoute], or [builder] must be
/// non-null. If only [routes] is given, it must include an entry for the
/// [Navigator.defaultRouteName] (`/`), since that is the route used when the
/// application is launched with an intent that specifies an otherwise
/// unsupported route.
///
/// This class creates an instance of [WidgetsApp].
///
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
CupertinoApp({ // can't be const because the asserts use methods on Map :-(
Key key,
this.home,
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
this.onGenerateRoute,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '',
this.onGenerateTitle,
this.color,
this.locale,
this.localizationsDelegates,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[const Locale('en', 'US')],
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true,
}) : assert(routes != null),
assert(navigatorObservers != null),
assert(
home == null ||
!routes.containsKey(Navigator.defaultRouteName),
'If the home property is specified, the routes table '
'cannot include an entry for "/", since it would be redundant.'
),
assert(
builder != null ||
home != null ||
routes.containsKey(Navigator.defaultRouteName) ||
onGenerateRoute != null ||
onUnknownRoute != null,
'Either the home property must be specified, '
'or the routes table must include an entry for "/", '
'or there must be on onGenerateRoute callback specified, '
'or there must be an onUnknownRoute callback specified, '
'or the builder property must be specified, '
'because otherwise there is nothing to fall back on if the '
'app is started with an intent that specifies an unknown route.'
),
assert(
(home != null ||
routes.isNotEmpty ||
onGenerateRoute != null ||
onUnknownRoute != null)
||
(builder != null &&
initialRoute == null &&
navigatorObservers.isEmpty),
'If no route is provided using '
'home, routes, onGenerateRoute, or onUnknownRoute, '
'a non-null callback for the builder property must be provided, '
'and the other navigator-related properties, '
'navigatorKey, initialRoute, and navigatorObservers, '
'must have their initial values '
'(null, null, and the empty list, respectively).'
),
assert(title != null),
assert(showPerformanceOverlay != null),
assert(checkerboardRasterCacheImages != null),
assert(checkerboardOffscreenLayers != null),
assert(showSemanticsDebugger != null),
assert(debugShowCheckedModeBanner != null),
super(key: key);
/// The widget for the default route of the app ([Navigator.defaultRouteName],
/// which is `/`).
///
/// This is the route that is displayed first when the application is started
/// normally, unless [initialRoute] is specified. It's also the route that's
/// displayed if the [initialRoute] can't be displayed.
///
/// To be able to directly call [MediaQuery.of], [Navigator.of], etc, in the
/// code that sets the [home] argument in the constructor, you can use a
/// [Builder] widget to get a [BuildContext].
///
/// If [home] is specified, then [routes] must not include an entry for `/`,
/// as [home] takes its place.
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [builder] must not be null.
///
/// The difference between using [home] and using [builder] is that the [home]
/// subtree is inserted into the application below a [Navigator] (and thus
/// below an [Overlay], which [Navigator] uses). With [home], therefore,
/// dialog boxes will work automatically, the [routes] table will be used, and
/// APIs such as [Navigator.push] and [Navigator.pop] will work as expected.
/// In contrast, the widget returned from [builder] is inserted _above_ the
/// [CupertinoApp]'s [Navigator] (if any).
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 [CupertinoPageRoute] that performs
/// an appropriate transition to the new route.
///
/// If the app only has one page, then you can specify it using [home] instead.
///
/// If [home] is specified, then it implies an entry in this table for the
/// [Navigator.defaultRouteName] route (`/`), and it is an error to
/// redundantly provide such a route in the [routes] table.
///
/// If a route is requested that is not specified in this table (or by
/// [home]), then the [onGenerateRoute] callback is called to build the page
/// instead.
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [builder] must not be null.
final Map<String, WidgetBuilder> routes;
/// {@macro flutter.widgets.widgetsApp.initialRoute}
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [initialRoute] must be null and [builder] must not be null.
///
/// See also:
///
/// * [Navigator.initialRoute], which is used to implement this property.
/// * [Navigator.push], for pushing additional routes.
/// * [Navigator.pop], for removing a route from the stack.
final String initialRoute;
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
///
/// This is used if [routes] does not contain the requested route.
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [builder] must not be null.
final RouteFactory onGenerateRoute;
/// Called when [onGenerateRoute] fails to generate a route, except for the
/// [initialRoute].
///
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [builder] must not be null.
final RouteFactory onUnknownRoute;
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [navigatorObservers] must be the empty list and [builder] must not be null.
final List<NavigatorObserver> navigatorObservers;
/// {@macro flutter.widgets.widgetsApp.builder}
///
/// If no routes are provided using [home], [routes], [onGenerateRoute], or
/// [onUnknownRoute], the `child` will be null, and it is the responsibility
/// of the [builder] to provide the application's routing machinery.
///
/// If routes _are_ provided using one or more of those properties, then
/// `child` is not null, and the returned value should include the `child` in
/// the widget subtree; if it does not, then the application will have no
/// navigator and the [navigatorKey], [home], [routes], [onGenerateRoute],
/// [onUnknownRoute], [initialRoute], and [navigatorObservers] properties will
/// have no effect.
///
/// If [builder] is null, it is as if a builder was specified that returned
/// the `child` directly. If it is null, routes must be provided using one of
/// the other properties listed above.
///
/// Unless a [Navigator] is provided, either implicitly from [builder] being
/// null, or by a [builder] including its `child` argument, or by a [builder]
/// explicitly providing a [Navigator] of its own, APIs such as
/// [Navigator.push] and [Navigator.pop], will not function.
final TransitionBuilder builder;
/// {@macro flutter.widgets.widgetsApp.title}
///
/// This value is passed unmodified to [WidgetsApp.title].
final String title;
/// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
///
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
final GenerateAppTitle onGenerateTitle;
/// {@macro flutter.widgets.widgetsApp.color}
final Color color;
/// {@macro flutter.widgets.widgetsApp.locale}
final Locale locale;
/// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
/// {@macro flutter.widgets.widgetsApp.localeResolutionCallback}
///
/// This callback is passed along to the [WidgetsApp] built by this widget.
final LocaleResolutionCallback localeResolutionCallback;
/// {@macro flutter.widgets.widgetsApp.supportedLocales}
///
/// It is passed along unmodified to the [WidgetsApp] built by this widget.
final Iterable<Locale> supportedLocales;
/// Turns on a performance overlay.
///
/// See also:
///
/// * <https://flutter.io/debugging/#performanceoverlay>
final bool showPerformanceOverlay;
/// Turns on checkerboarding of raster cache images.
final bool checkerboardRasterCacheImages;
/// Turns on checkerboarding of layers rendered to offscreen bitmaps.
final bool checkerboardOffscreenLayers;
/// Turns on an overlay that shows the accessibility information
/// reported by the framework.
final bool showSemanticsDebugger;
/// {@macro flutter.widgets.widgetsApp.debugShowCheckedModeBanner}
final bool debugShowCheckedModeBanner;
@override
_CupertinoAppState createState() => new _CupertinoAppState();
}
class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
@override
Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) {
// Never build any overscroll glow indicators.
return child;
}
@override
ScrollPhysics getScrollPhysics(BuildContext context) {
return const BouncingScrollPhysics();
}
}
class _CupertinoAppState extends State<CupertinoApp> {
@override
void initState() {
super.initState();
_updateNavigator();
}
@override
void didUpdateWidget(CupertinoApp oldWidget) {
super.didUpdateWidget(oldWidget);
_updateNavigator();
}
bool _haveNavigator;
void _updateNavigator() {
_haveNavigator = widget.home != null ||
widget.routes.isNotEmpty ||
widget.onGenerateRoute != null ||
widget.onUnknownRoute != null;
}
Widget defaultBuilder(BuildContext context, Widget child) {
// The `child` coming back out from WidgetsApp will always be null since
// we never passed in anything for it to create a Navigator inside
// WidgetsApp.
assert(child == null);
if (_haveNavigator) {
// Reuse CupertinoTabView which creates a routing Navigator for us.
final Widget navigator = new 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 {
// We asserted that child is null above.
return widget.builder(context, null);
}
}
@override
Widget build(BuildContext context) {
return new ScrollConfiguration(
behavior: new _AlwaysCupertinoScrollBehavior(),
child: new WidgetsApp(
key: new GlobalObjectKey(this),
// We're passing in a builder and nothing else that the WidgetsApp uses
// to build its own Navigator because we're building a Navigator with
// routes in this class.
builder: defaultBuilder,
title: widget.title,
onGenerateTitle: widget.onGenerateTitle,
textStyle: _kDefaultTextStyle,
color: widget.color ?? CupertinoColors.activeBlue,
locale: widget.locale,
localizationsDelegates: widget.localizationsDelegates,
localeResolutionCallback: widget.localeResolutionCallback,
supportedLocales: widget.supportedLocales,
showPerformanceOverlay: widget.showPerformanceOverlay,
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
showSemanticsDebugger: widget.showSemanticsDebugger,
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
inspectorSelectButtonBuilder: (BuildContext context, VoidCallback onPressed) {
return new CupertinoButton(
child: const Icon(
CupertinoIcons.search,
size: 28.0,
color: CupertinoColors.white,
),
color: CupertinoColors.activeBlue,
padding: EdgeInsets.zero,
onPressed: onPressed,
);
},
),
);
}
}
......@@ -218,20 +218,7 @@ class MaterialApp extends StatefulWidget {
/// [builder] must not be null.
final Map<String, WidgetBuilder> routes;
/// The name of the first route to show, if a [Navigator] is built.
///
/// Defaults to [Window.defaultRouteName], which may be overridden by the code
/// that launched the application.
///
/// If the route contains slashes, then it is treated as a "deep link", and
/// before this route is pushed, the routes leading to this one are pushed
/// also. For example, if the route was `/a/b/c`, then the app would start
/// with the three routes `/a`, `/a/b`, and `/a/b/c` loaded, in that order.
///
/// If any part of this process fails to generate routes, then the
/// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead
/// (`/`). This can happen if the app is started with an intent that specifies
/// a non-existent route.
/// {@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,
......@@ -244,19 +231,10 @@ class MaterialApp extends StatefulWidget {
/// * [Navigator.pop], for removing a route from the stack.
final String initialRoute;
/// The route generator callback used when the app is navigated to a
/// named route.
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
///
/// This is used if [routes] does not contain the requested route.
///
/// If this returns null when building the routes to handle the specified
/// [initialRoute], then all the routes are discarded and
/// [Navigator.defaultRouteName] is used instead (`/`). See [initialRoute].
///
/// During normal app operation, the [onGenerateRoute] callback will only be
/// applied to route names pushed by the application, and so should never
/// return null.
///
/// The [Navigator] is only built if routes are provided (either via [home],
/// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
/// [builder] must not be null.
......@@ -265,44 +243,21 @@ class MaterialApp extends StatefulWidget {
/// Called when [onGenerateRoute] fails to generate a route, except for the
/// [initialRoute].
///
/// This callback is typically used for error handling. For example, this
/// callback might always generate a "not found" page that describes the route
/// that wasn't found.
///
/// The default implementation pushes a route that displays an ugly error
/// message.
/// {@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;
/// The list of observers for the [Navigator] created for this app.
///
/// This list must be replaced by a list of newly-created observers if the
/// [navigatorKey] is changed.
/// {@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;
/// A builder for inserting widgets above the [Navigator] but below the other
/// widgets created by the [MaterialApp] widget, or for replacing the
/// [Navigator] entirely.
///
/// For example, from the [BuildContext] passed to this method, the
/// [Directionality], [Localizations], [DefaultTextStyle], [MediaQuery], etc,
/// are all available. They can also be overridden in a way that impacts all
/// the routes in the [Navigator].
///
/// This is rarely useful, but can be used in applications that wish to
/// override those defaults, e.g. to force the application into right-to-left
/// mode despite being in English, or to override the [MediaQuery] metrics
/// (e.g. to leave a gap for advertisements shown by a plugin from OEM code).
///
/// The [builder] callback is passed two arguments, the [BuildContext] (as
/// `context`) and a [Navigator] widget (as `child`).
/// {@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
......@@ -325,34 +280,14 @@ class MaterialApp extends StatefulWidget {
/// [showDialog] and [showMenu], widgets such as [Tooltip], [PopupMenuButton],
/// or [Hero], and APIs such as [Navigator.push] and [Navigator.pop], will not
/// function.
///
/// For specifically overriding the [title] with a value based on the
/// [Localizations], consider [onGenerateTitle] instead.
final TransitionBuilder builder;
/// A one-line description used by the device to identify the app for the user.
///
/// On Android the titles appear above the task manager's app snapshots which are
/// displayed when the user presses the "recent apps" button. Similarly, on
/// iOS the titles appear in the App Switcher when the user double presses the
/// home button.
///
/// To provide a localized title instead, use [onGenerateTitle].
/// {@macro flutter.widgets.widgetsApp.title}
///
/// This value is passed unmodified to [WidgetsApp.title].
final String title;
/// If non-null this callback is called to produce the app's
/// title string, otherwise [title] is used.
///
/// The [onGenerateTitle] `context` parameter includes the [WidgetsApp]'s
/// [Localizations] widget so that this callback can be used to produce a
/// localized title.
///
/// This callback function must not return null.
///
/// The [onGenerateTitle] callback is called each time the [MaterialApp]
/// rebuilds.
/// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
///
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
final GenerateAppTitle onGenerateTitle;
......@@ -360,22 +295,13 @@ class MaterialApp extends StatefulWidget {
/// The colors to use for the application's widgets.
final ThemeData theme;
/// The primary color to use for the application in the operating system
/// interface.
///
/// For example, on Android this is the color used for the application in the
/// application switcher.
/// {@macro flutter.widgets.widgetsApp.color}
final Color color;
/// The initial locale for this app's [Localizations] widget.
///
/// If the `locale` is null the system's locale value is used.
/// {@macro flutter.widgets.widgetsApp.locale}
final Locale locale;
/// The delegates for this app's [Localizations] widget.
///
/// The delegates collectively define all of the localized resources
/// for this application's [Localizations] widget.
/// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
///
/// Delegates that produce [WidgetsLocalizations] and [MaterialLocalizations]
/// are included automatically. Apps can provide their own versions of these
......@@ -433,43 +359,14 @@ class MaterialApp extends StatefulWidget {
/// ```
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
/// This callback is responsible for choosing the app's locale
/// when the app is started, and when the user changes the
/// device's locale.
///
/// The returned value becomes the locale of this app's [Localizations]
/// widget. The callback's `locale` parameter is the device's locale when
/// the app started, or the device locale the user selected after the app was
/// started. The callback's `supportedLocales` parameter is just the value
/// [supportedLocales].
///
/// An app could use this callback to substitute locales based on the app's
/// intended audience. If the device's OS provides a prioritized
/// list of locales, this callback could be used to defer to it.
///
/// If the callback is null then the resolved locale is:
/// - The callback's `locale` parameter if it's equal to a supported locale.
/// - The first supported locale with the same [Locale.languageCode] as the
/// callback's `locale` parameter.
/// - The first supported locale.
/// {@macro flutter.widgets.widgetsApp.localeResolutionCallback}
///
/// This callback is passed along to the [WidgetsApp] built by this widget.
final LocaleResolutionCallback localeResolutionCallback;
/// The list of locales that this app has been localized for.
///
/// By default only the American English locale is supported. Apps should
/// configure this list to match the locales they support.
/// {@macro flutter.widgets.widgetsApp.supportedLocales}
///
/// This list must not null. It's default value is just
/// `[const Locale('en', 'US')]`. It is passed along unmodified to the
/// [WidgetsApp] built by this widget.
///
/// The order of the list matters. By default, if the device's locale doesn't
/// exactly match a locale in [supportedLocales] then the first locale in
/// [supportedLocales] with a matching [Locale.languageCode] is used. If that
/// fails then the first locale in [supportedLocales] is used. The default
/// locale resolution algorithm can be overridden with [localeResolutionCallback].
/// It is passed along unmodified to the [WidgetsApp] built by this widget.
///
/// The material widgets include translations for locales with the following
/// language codes:
......@@ -510,19 +407,7 @@ class MaterialApp extends StatefulWidget {
/// reported by the framework.
final bool showSemanticsDebugger;
/// Turns on a little "DEBUG" banner in checked mode to indicate
/// that the app is in checked mode. This is on by default (in
/// checked mode), to turn it off, set the constructor argument to
/// false. In release mode this has no effect.
///
/// To get this banner in your application if you're not using
/// WidgetsApp, include a [CheckedModeBanner] widget in your app.
///
/// This banner is intended to deter people from complaining that your
/// app is slow when it's in checked mode. In checked mode, Flutter
/// enables a large number of expensive diagnostics to aid in
/// development, and so performance in checked mode is not
/// representative of what will happen in release mode.
/// {@macro flutter.widgets.widgetsApp.debugShowCheckedModeBanner}
final bool debugShowCheckedModeBanner;
/// Turns on a [GridPaper] overlay that paints a baseline grid
......
......@@ -123,6 +123,7 @@ class WidgetsApp extends StatefulWidget {
/// null, [navigatorKey] must also be null.
final GlobalKey<NavigatorState> navigatorKey;
/// {@template flutter.widgets.widgetsApp.onGenerateRoute}
/// The route generator callback used when the app is navigated to a
/// named route.
///
......@@ -133,6 +134,7 @@ class WidgetsApp extends StatefulWidget {
/// During normal app operation, the [onGenerateRoute] callback will only be
/// applied to route names pushed by the application, and so should never
/// return null.
/// {@endtemplate}
///
/// The [Navigator] is only built if [onGenerateRoute] is not null. If
/// [onGenerateRoute] is null, the [builder] must be non-null.
......@@ -140,18 +142,21 @@ class WidgetsApp extends StatefulWidget {
/// Called when [onGenerateRoute] fails to generate a route.
///
/// {@template flutter.widgets.widgetsApp.onUnknownRoute}
/// This callback is typically used for error handling. For example, this
/// callback might always generate a "not found" page that describes the route
/// that wasn't found.
///
/// Unknown routes can arise either from errors in the app or from external
/// requests to push routes, such as from Android intents.
/// {@endtemplate}
///
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
/// null, [onUnknownRoute] must also be null.
final RouteFactory onUnknownRoute;
/// The name of the first route to show.
/// {@template flutter.widgets.widgetsApp.initialRoute}
/// The name of the first route to show, if a [Navigator] is built.
///
/// Defaults to [Window.defaultRouteName], which may be overridden by the code
/// that launched the application.
......@@ -165,6 +170,7 @@ class WidgetsApp extends StatefulWidget {
/// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead
/// (`/`). This can happen if the app is started with an intent that specifies
/// a non-existent route.
/// {@endtemplate}
///
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
/// null, [initialRoute] must also be null.
......@@ -176,16 +182,19 @@ class WidgetsApp extends StatefulWidget {
/// * [Navigator.pop], for removing a route from the stack.
final String initialRoute;
/// {@template flutter.widgets.widgetsApp.navigatorObservers}
/// The list of observers for the [Navigator] created for this app.
///
/// This list must be replaced by a list of newly-created observers if the
/// [navigatorKey] is changed.
/// {@endtemplate}
///
/// The [Navigator] is only built if [onGenerateRoute] is not null; if it is
/// null, [navigatorObservers] must be left to its default value, the empty
/// list.
final List<NavigatorObserver> navigatorObservers;
/// {@template flutter.widgets.widgetsApp.builder}
/// A builder for inserting widgets above the [Navigator] but below the other
/// widgets created by the [WidgetsApp] widget, or for replacing the
/// [Navigator] entirely.
......@@ -200,8 +209,12 @@ class WidgetsApp extends StatefulWidget {
/// mode despite being in English, or to override the [MediaQuery] metrics
/// (e.g. to leave a gap for advertisements shown by a plugin from OEM code).
///
/// For specifically overriding the [title] with a value based on the
/// [Localizations], consider [onGenerateTitle] instead.
///
/// The [builder] callback is passed two arguments, the [BuildContext] (as
/// `context`) and a [Navigator] widget (as `child`).
/// {@endtemplate}
///
/// If [onGenerateRoute] is null, the `child` will be null, and it is the
/// responsibility of the [builder] to provide the application's routing
......@@ -216,11 +229,9 @@ class WidgetsApp extends StatefulWidget {
/// If [builder] is null, it is as if a builder was specified that returned
/// the `child` directly. At least one of either [onGenerateRoute] or
/// [builder] must be non-null.
///
/// For specifically overriding the [title] with a value based on the
/// [Localizations], consider [onGenerateTitle] instead.
final TransitionBuilder builder;
/// {@template flutter.widgets.widgetsApp.title}
/// A one-line description used by the device to identify the app for the user.
///
/// On Android the titles appear above the task manager's app snapshots which are
......@@ -229,8 +240,10 @@ class WidgetsApp extends StatefulWidget {
/// home button.
///
/// To provide a localized title instead, use [onGenerateTitle].
/// {@endtemplate}
final String title;
/// {@template flutter.widgets.widgetsApp.onGenerateTitle}
/// If non-null this callback function is called to produce the app's
/// title string, otherwise [title] is used.
///
......@@ -242,29 +255,37 @@ class WidgetsApp extends StatefulWidget {
///
/// The [onGenerateTitle] callback is called each time the [WidgetsApp]
/// rebuilds.
/// {@endtemplate}
final GenerateAppTitle onGenerateTitle;
/// The default text style for [Text] in the application.
final TextStyle textStyle;
/// {@template flutter.widgets.widgetsApp.color}
/// The primary color to use for the application in the operating system
/// interface.
///
/// For example, on Android this is the color used for the application in the
/// application switcher.
/// {@endtemplate}
final Color color;
/// {@template flutter.widgets.widgetsApp.locale}
/// The initial locale for this app's [Localizations] widget.
///
/// If the 'locale' is null the system's locale value is used.
/// {@endtemplate}
final Locale locale;
/// {@template flutter.widgets.widgetsApp.localizationsDelegates}
/// The delegates for this app's [Localizations] widget.
///
/// The delegates collectively define all of the localized resources
/// for this application's [Localizations] widget.
/// {@endtemplate}
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
/// {@template flutter.widgets.widgetsApp.localeResolutionCallback}
/// This callback is responsible for choosing the app's locale
/// when the app is started, and when the user changes the
/// device's locale.
......@@ -281,6 +302,7 @@ class WidgetsApp extends StatefulWidget {
/// - The first supported locale with the same [Locale.languageCode] as the
/// callback's `locale` parameter.
/// - The first locale in [supportedLocales].
/// {@endtemplate}
///
/// See also:
///
......@@ -288,6 +310,7 @@ class WidgetsApp extends StatefulWidget {
/// [WidgetsApp] it creates.
final LocaleResolutionCallback localeResolutionCallback;
/// {@template flutter.widgets.widgetsApp.supportedLocales}
/// The list of locales that this app has been localized for.
///
/// By default only the American English locale is supported. Apps should
......@@ -301,6 +324,7 @@ class WidgetsApp extends StatefulWidget {
/// [supportedLocales] with a matching [Locale.languageCode] is used. If that
/// fails then the first locale in [supportedLocales] is used. The default
/// locale resolution algorithm can be overridden with [localeResolutionCallback].
/// {@endtemplate}
///
/// See also:
///
......@@ -315,7 +339,10 @@ class WidgetsApp extends StatefulWidget {
final Iterable<Locale> supportedLocales;
/// Turns on a performance overlay.
/// https://flutter.io/debugging/#performanceoverlay
///
/// See also:
///
/// * <https://flutter.io/debugging/#performanceoverlay>
final bool showPerformanceOverlay;
/// Checkerboards raster cache images.
......@@ -347,7 +374,8 @@ class WidgetsApp extends StatefulWidget {
/// material package.
final InspectorSelectButtonBuilder inspectorSelectButtonBuilder;
/// Turns on a "DEBUG" little banner in checked mode to indicate
/// {@template flutter.widgets.widgetsApp.debugShowCheckedModeBanner}
/// Turns on a little "DEBUG" banner in checked mode to indicate
/// that the app is in checked mode. This is on by default (in
/// checked mode), to turn it off, set the constructor argument to
/// false. In release mode this has no effect.
......@@ -355,11 +383,12 @@ class WidgetsApp extends StatefulWidget {
/// To get this banner in your application if you're not using
/// WidgetsApp, include a [CheckedModeBanner] widget in your app.
///
/// This banner is intended to avoid people complaining that your
/// This banner is intended to deter people from complaining that your
/// app is slow when it's in checked mode. In checked mode, Flutter
/// enables a large number of expensive diagnostics to aid in
/// development, and so performance in checked mode is not
/// representative of what will happen in release mode.
/// {@endtemplate}
final bool debugShowCheckedModeBanner;
/// If true, forces the performance overlay to be visible in all instances.
......
......@@ -16,19 +16,11 @@ int count = 0;
void main() {
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
leading: const CupertinoButton(child: const Text('Something'), onPressed: null,),
middle: const Text('Title'),
);
},
);
},
),
),
);
......@@ -38,19 +30,11 @@ void main() {
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Title'),
backgroundColor: const Color(0xFFE5E5E5),
);
},
);
},
),
),
);
expect(find.byType(BackdropFilter), findsNothing);
......@@ -58,18 +42,10 @@ void main() {
testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Title'),
);
},
);
},
),
),
);
expect(find.byType(BackdropFilter), findsOneWidget);
......@@ -78,21 +54,13 @@ void main() {
testWidgets('Verify styles of each slot', (WidgetTester tester) async {
count = 0x000000;
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
leading: const _ExpectStyles(color: const Color(0xFF001122), index: 0x000001),
middle: const _ExpectStyles(color: const Color(0xFF000000), letterSpacing: -0.08, index: 0x000100),
trailing: const _ExpectStyles(color: const Color(0xFF001122), index: 0x010000),
actionsForegroundColor: const Color(0xFF001122),
);
},
);
},
),
),
);
expect(count, 0x010101);
......@@ -100,21 +68,13 @@ void main() {
testWidgets('No slivers with no large titles', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoPageScaffold(
new CupertinoApp(
home: const CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: const Text('Title'),
),
child: const Center(),
);
},
);
},
),
),
);
......@@ -128,13 +88,8 @@ void main() {
final Key trailingKey = new GlobalKey();
final Key titleKey = new GlobalKey();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new MediaQuery(
new CupertinoApp(
home: new MediaQuery(
data: const MediaQueryData(
padding: const EdgeInsets.only(
top: 10.0,
......@@ -161,10 +116,7 @@ void main() {
],
),
),
);
},
);
},
),
),
);
......@@ -180,13 +132,8 @@ void main() {
testWidgets('Large title nav bar scrolls', (WidgetTester tester) async {
final ScrollController scrollController = new ScrollController();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
controller: scrollController,
slivers: <Widget>[
......@@ -200,10 +147,7 @@ void main() {
),
],
),
);
},
);
},
),
),
);
......@@ -268,13 +212,8 @@ void main() {
testWidgets('Small title can be overridden', (WidgetTester tester) async {
final ScrollController scrollController = new ScrollController();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
controller: scrollController,
slivers: <Widget>[
......@@ -289,10 +228,7 @@ void main() {
),
],
),
);
},
);
},
),
),
);
......@@ -339,18 +275,10 @@ void main() {
testWidgets('Auto back/close button', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Home page'),
);
},
);
},
),
),
);
......@@ -403,18 +331,10 @@ void main() {
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Title'),
);
},
);
},
),
),
);
......@@ -433,13 +353,8 @@ void main() {
testWidgets('Overrides border color', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Title'),
border: const Border(
bottom: const BorderSide(
......@@ -447,10 +362,7 @@ void main() {
width: 0.0,
),
),
);
},
);
},
),
),
);
......@@ -470,19 +382,11 @@ void main() {
testWidgets('Border should not be displayed when null', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
new CupertinoApp(
home: const CupertinoNavigationBar(
middle: const Text('Title'),
border: null,
);
},
);
},
),
),
);
......@@ -500,13 +404,8 @@ void main() {
'Border is displayed by default in sliver nav bar',
(WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: const <Widget>[
const CupertinoSliverNavigationBar(
......@@ -514,10 +413,7 @@ void main() {
),
],
),
);
},
);
},
),
),
);
......@@ -538,13 +434,8 @@ void main() {
'Border is not displayed when null in sliver nav bar',
(WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: const <Widget>[
const CupertinoSliverNavigationBar(
......@@ -553,10 +444,7 @@ void main() {
),
],
),
);
},
);
},
),
),
);
......@@ -573,13 +461,8 @@ void main() {
testWidgets('CupertinoSliverNavigationBar has semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
await tester.pumpWidget(new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: const <Widget>[
const CupertinoSliverNavigationBar(
......@@ -588,10 +471,7 @@ void main() {
),
],
),
);
},
);
}
),
));
expect(semantics.nodesWith(
......@@ -606,21 +486,13 @@ void main() {
testWidgets('CupertinoNavigationBar has semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
await tester.pumpWidget(new CupertinoApp(
home: new CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: const Text('Fixed Title'),
),
child: new Container(),
);
},
);
}
),
));
expect(semantics.nodesWith(
......@@ -636,13 +508,8 @@ void main() {
'Border can be overridden in sliver nav bar',
(WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: const <Widget>[
const CupertinoSliverNavigationBar(
......@@ -656,10 +523,7 @@ void main() {
),
],
),
);
},
);
},
),
),
);
......@@ -684,23 +548,15 @@ void main() {
'Standard title golden',
(WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const RepaintBoundary(
new CupertinoApp(
home: const RepaintBoundary(
child: const CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: const Text('Bling bling'),
),
child: const Center(),
),
);
},
);
},
),
),
);
......@@ -718,13 +574,9 @@ void main() {
'Large title golden',
(WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
new CupertinoApp(
home: new RepaintBoundary(
child: new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: <Widget>[
const CupertinoSliverNavigationBar(
......@@ -737,10 +589,8 @@ void main() {
),
],
),
);
},
);
},
),
),
),
);
......
......@@ -8,8 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('test iOS page transition (LTR)', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
new CupertinoApp(
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
......@@ -76,11 +75,10 @@ void main() {
testWidgets('test iOS page transition (RTL)', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
new CupertinoApp(
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
const RtlOverrideWidgetsDelegate(),
],
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
......@@ -148,16 +146,8 @@ void main() {
testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const Center(child: const Text('Page 1'));
}
);
},
new CupertinoApp(
home: const Center(child: const Text('Page 1')),
),
);
......@@ -216,8 +206,7 @@ void main() {
testWidgets('test only edge swipes work (LTR)', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
new CupertinoApp(
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
......@@ -278,11 +267,10 @@ void main() {
testWidgets('test only edge swipes work (RTL)', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
new CupertinoApp(
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
const RtlOverrideWidgetsDelegate(),
],
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
......
......@@ -11,22 +11,14 @@ import '../painting/mocks_for_image_cache.dart';
void main() {
testWidgets('Contents are behind translucent bar', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoPageScaffold(
new CupertinoApp(
home: const CupertinoPageScaffold(
// Default nav bar is translucent.
navigationBar: const CupertinoNavigationBar(
middle: const Text('Title'),
),
child: const Center(),
);
},
);
},
),
),
);
......@@ -37,13 +29,8 @@ void main() {
const Center page1Center = const Center();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: new CupertinoTabBar(
backgroundColor: CupertinoColors.white,
items: const <BottomNavigationBarItem>[
......@@ -67,12 +54,9 @@ void main() {
child: page1Center,
)
: new Stack();
}
);
},
);
},
),
),
);
expect(tester.getSize(find.byWidget(page1Center)).height, 600.0 - 44.0 - 50.0);
......@@ -82,13 +66,8 @@ void main() {
final Container content = new Container(height: 600.0, width: 600.0);
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new MediaQuery(
new CupertinoApp(
home: new MediaQuery(
data: const MediaQueryData(
padding: const EdgeInsets.symmetric(vertical: 20.0),
),
......@@ -120,10 +99,7 @@ void main() {
: new Stack();
}
),
);
},
);
},
),
),
);
......@@ -132,6 +108,8 @@ void main() {
// Overscroll to the bottom.
await tester.drag(find.byWidget(content), const Offset(0.0, -400.0));
// Let it bounce back.
await tester.pump();
await tester.pump(const Duration(seconds: 1));
// List content automatically padded by tab bar and bottom media query padding.
......@@ -142,13 +120,8 @@ void main() {
// A full on iOS information architecture app with 2 tabs, and 2 pages
// in each with independent navigation states.
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: new CupertinoTabBar(
items: const <BottomNavigationBarItem>[
const BottomNavigationBarItem(
......@@ -200,10 +173,7 @@ void main() {
},
);
},
);
},
);
},
),
),
);
......@@ -257,18 +227,10 @@ void main() {
testWidgets('Decorated with white background by default', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoPageScaffold(
new CupertinoApp(
home: const CupertinoPageScaffold(
child: const Center(),
);
},
);
},
),
),
);
......@@ -281,19 +243,11 @@ void main() {
testWidgets('Overrides background color', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoPageScaffold(
new CupertinoApp(
home: const CupertinoPageScaffold(
child: const Center(),
backgroundColor: const Color(0xFF010203),
);
},
);
},
),
),
);
......
......@@ -20,13 +20,8 @@ void main() {
final List<int> tabsPainted = <int>[];
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: _buildTabBar(),
tabBuilder: (BuildContext context, int index) {
return new CustomPaint(
......@@ -36,10 +31,7 @@ void main() {
)
);
},
);
},
);
},
),
),
);
......@@ -82,22 +74,14 @@ void main() {
final List<int> tabsBuilt = <int>[];
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: _buildTabBar(),
tabBuilder: (BuildContext context, int index) {
tabsBuilt.add(index);
return new Text('Page ${index + 1}');
},
);
},
);
},
),
),
);
......@@ -126,13 +110,8 @@ void main() {
final List<FocusNode> focusNodes = <FocusNode>[new FocusNode(), new FocusNode()];
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new Material(
new CupertinoApp(
home: new Material(
child: new CupertinoTabScaffold(
tabBar: _buildTabBar(),
tabBuilder: (BuildContext context, int index) {
......@@ -142,10 +121,7 @@ void main() {
);
},
),
);
},
);
},
),
),
);
......@@ -170,13 +146,8 @@ void main() {
];
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new Material(
new CupertinoApp(
home: new Material(
child: new CupertinoTabScaffold(
tabBar: _buildTabBar(),
tabBuilder: (BuildContext context, int index) {
......@@ -198,10 +169,7 @@ void main() {
);
},
),
);
},
);
},
),
),
);
......@@ -242,10 +210,8 @@ void main() {
final List<int> tabsPainted = <int>[];
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
builder: (BuildContext context, Widget child) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: _buildTabBar(),
tabBuilder: (BuildContext context, int index) {
return new CustomPaint(
......@@ -255,18 +221,15 @@ void main() {
)
);
},
);
},
),
),
);
expect(tabsPainted, <int>[0]);
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
builder: (BuildContext context, Widget child) {
return new CupertinoTabScaffold(
new CupertinoApp(
home: new CupertinoTabScaffold(
tabBar: _buildTabBar(selectedTab: 1), // Programmatically change the tab now.
tabBuilder: (BuildContext context, int index) {
return new CustomPaint(
......@@ -276,8 +239,7 @@ void main() {
)
);
},
);
},
),
),
);
......
......@@ -8,18 +8,10 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Use home', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabView(
new CupertinoApp(
home: new CupertinoTabView(
builder: (BuildContext context) => const Text('home'),
);
},
);
},
),
),
);
......@@ -28,20 +20,12 @@ void main() {
testWidgets('Use routes', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabView(
new CupertinoApp(
home: new CupertinoTabView(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => const Text('first route'),
},
);
},
);
},
),
),
);
......@@ -50,13 +34,8 @@ void main() {
testWidgets('Use home and named routes', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabView(
new CupertinoApp(
home: new CupertinoTabView(
builder: (BuildContext context) {
return new CupertinoButton(
child: const Text('go to second page'),
......@@ -68,10 +47,7 @@ void main() {
routes: <String, WidgetBuilder>{
'/2': (BuildContext context) => const Text('second named route'),
},
);
},
);
},
),
),
);
......@@ -84,13 +60,8 @@ void main() {
testWidgets('Use onGenerateRoute', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabView(
new CupertinoApp(
home: new CupertinoTabView(
onGenerateRoute: (RouteSettings settings) {
if (settings.name == Navigator.defaultRouteName) {
return new CupertinoPageRoute<void>(
......@@ -101,10 +72,7 @@ void main() {
);
}
},
);
},
);
},
),
),
);
......@@ -114,20 +82,12 @@ void main() {
testWidgets('Use onUnknownRoute', (WidgetTester tester) async {
String unknownForRouteCalled;
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoTabView(
new CupertinoApp(
home: new CupertinoTabView(
onUnknownRoute: (RouteSettings settings) {
unknownForRouteCalled = settings.name;
},
);
},
);
},
),
),
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment