Commit f64101ab authored by Ian Hickson's avatar Ian Hickson

Merge pull request #2451 from Hixie/widgetapp

Factor out non-Material parts of MaterialApp into WidgetsApp
parents 36694ac0 6a239012
......@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui' as ui show WindowPadding, window;
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
import 'page.dart';
import 'theme.dart';
......@@ -21,204 +18,75 @@ const TextStyle _errorTextStyle = const TextStyle(
fontWeight: FontWeight.w900,
textAlign: TextAlign.right,
decoration: TextDecoration.underline,
decorationColor: const Color(0xFFFF00),
decorationColor: const Color(0xFFFFFF00),
decorationStyle: TextDecorationStyle.double
);
AssetBundle _initDefaultBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _defaultBundle = _initDefaultBundle();
class RouteArguments {
const RouteArguments({ this.context });
final BuildContext context;
}
typedef Widget RouteBuilder(RouteArguments args);
typedef Future<LocaleQueryData> LocaleChangedCallback(Locale locale);
class MaterialApp extends StatefulComponent {
class MaterialApp extends WidgetsApp {
MaterialApp({
Key key,
this.title,
this.theme,
this.routes: const <String, RouteBuilder>{},
this.onGenerateRoute,
this.onLocaleChanged,
String title,
ThemeData theme,
Map<String, RouteBuilder> routes: const <String, RouteBuilder>{},
RouteFactory onGenerateRoute,
LocaleChangedCallback onLocaleChanged,
this.debugShowMaterialGrid: false,
this.showPerformanceOverlay: false,
this.showSemanticsDebugger: false,
this.debugShowCheckedModeBanner: true
}) : super(key: key) {
assert(routes != null);
assert(routes.containsKey(Navigator.defaultRouteName) || onGenerateRoute != null);
bool showPerformanceOverlay: false,
bool showSemanticsDebugger: false,
bool debugShowCheckedModeBanner: true
}) : theme = theme,
super(
key: key,
title: title,
textStyle: _errorTextStyle,
color: theme?.primaryColor ?? Colors.blue[500], // blue[500] is the primary color of the default theme
routes: routes,
onGenerateRoute: (RouteSettings settings) {
RouteBuilder builder = routes[settings.name];
if (builder != null) {
return new MaterialPageRoute(
builder: (BuildContext context) {
return builder(new RouteArguments(context: context));
},
settings: settings
);
}
if (onGenerateRoute != null)
return onGenerateRoute(settings);
return null;
},
onLocaleChanged: onLocaleChanged,
showPerformanceOverlay: showPerformanceOverlay,
showSemanticsDebugger: showSemanticsDebugger,
debugShowCheckedModeBanner: debugShowCheckedModeBanner
) {
assert(debugShowMaterialGrid != null);
assert(showPerformanceOverlay != null);
assert(showSemanticsDebugger != null);
}
/// A one-line description of this app for use in the window manager.
final String title;
/// The colors to use for the application's widgets.
final ThemeData theme;
/// The default table of routes for the application. When the
/// [Navigator] is given a named route, the name will be looked up
/// in this table first. If the name is not available, then
/// [onGenerateRoute] will be called instead.
final Map<String, RouteBuilder> routes;
/// The route generator callback used when the app is navigated to a
/// named route but the name is not in the [routes] table.
final RouteFactory onGenerateRoute;
/// Callback that is invoked when the operating system changes the
/// current locale.
final LocaleChangedCallback onLocaleChanged;
/// Turns on a [GridPaper] overlay that paints a baseline grid
/// Material apps:
/// https://www.google.com/design/spec/layout/metrics-keylines.html
/// Only available in checked mode.
final bool debugShowMaterialGrid;
/// Turns on a performance overlay.
/// https://flutter.io/debugging/#performanceoverlay
final bool showPerformanceOverlay;
/// Turns on an overlay that shows the accessibility information
/// reported by the framework.
final bool showSemanticsDebugger;
/// Turns on a "SLOW MODE" little 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
/// MaterialApp, include a [CheckedModeBanner] widget in your app.
///
/// This banner is intended to avoid people 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.
final bool debugShowCheckedModeBanner;
_MaterialAppState createState() => new _MaterialAppState();
}
EdgeDims _getPadding(ui.WindowPadding padding) {
return new EdgeDims.TRBL(padding.top, padding.right, padding.bottom, padding.left);
}
class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
GlobalObjectKey _navigator;
LocaleQueryData _localeData;
void initState() {
super.initState();
_navigator = new GlobalObjectKey(this);
didChangeLocale(ui.window.locale);
WidgetFlutterBinding.instance.addObserver(this);
}
void dispose() {
WidgetFlutterBinding.instance.removeObserver(this);
super.dispose();
}
bool didPopRoute() {
assert(mounted);
NavigatorState navigator = _navigator.currentState;
assert(navigator != null);
bool result = false;
navigator.openTransaction((NavigatorTransaction transaction) {
result = transaction.pop();
});
return result;
}
void didChangeMetrics() {
setState(() {
// The properties of ui.window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}
void didChangeLocale(Locale locale) {
if (config.onLocaleChanged != null) {
config.onLocaleChanged(locale).then((LocaleQueryData data) {
if (mounted)
setState(() { _localeData = data; });
});
}
}
void didChangeAppLifecycleState(AppLifecycleState state) { }
class _MaterialAppState extends WidgetsAppState<MaterialApp> {
final HeroController _heroController = new HeroController();
Route _generateRoute(RouteSettings settings) {
RouteBuilder builder = config.routes[settings.name];
if (builder != null) {
return new MaterialPageRoute(
builder: (BuildContext context) {
return builder(new RouteArguments(context: context));
},
settings: settings
);
}
if (config.onGenerateRoute != null)
return config.onGenerateRoute(settings);
return null;
}
NavigatorObserver get navigatorObserver => _heroController;
Widget build(BuildContext context) {
if (config.onLocaleChanged != null && _localeData == null) {
// If the app expects a locale but we don't yet know the locale, then
// don't build the widgets now.
return new Container();
}
ThemeData theme = config.theme ?? new ThemeData.fallback();
Widget result = new MediaQuery(
data: new MediaQueryData(
size: ui.window.size,
devicePixelRatio: ui.window.devicePixelRatio,
padding: _getPadding(ui.window.padding)
),
child: new LocaleQuery(
data: _localeData,
child: new AnimatedTheme(
data: theme,
duration: kThemeAnimationDuration,
child: new DefaultTextStyle(
style: _errorTextStyle,
child: new AssetVendor(
bundle: _defaultBundle,
devicePixelRatio: ui.window.devicePixelRatio,
child: new Title(
title: config.title,
color: theme.primaryColor,
child: new Navigator(
key: _navigator,
initialRoute: ui.window.defaultRouteName,
onGenerateRoute: _generateRoute,
observer: _heroController
)
)
)
)
)
)
Widget result = new AnimatedTheme(
data: theme,
duration: kThemeAnimationDuration,
child: super.build(context)
);
assert(() {
if (config.debugShowMaterialGrid) {
......@@ -232,27 +100,6 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
}
return true;
});
if (config.showPerformanceOverlay) {
result = new Stack(
children: <Widget>[
result,
new Positioned(bottom: 0.0, left: 0.0, right: 0.0, child: new PerformanceOverlay.allEnabled()),
]
);
}
if (config.showSemanticsDebugger) {
result = new SemanticsDebugger(
child: result
);
}
assert(() {
if (config.debugShowCheckedModeBanner) {
result = new CheckedModeBanner(
child: result
);
}
return true;
});
return result;
}
......
// Copyright 2015 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 'dart:async';
import 'dart:ui' as ui show Locale, WindowPadding, window;
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'asset_vendor.dart';
import 'basic.dart';
import 'binding.dart';
import 'checked_mode_banner.dart';
import 'framework.dart';
import 'locale_query.dart';
import 'media_query.dart';
import 'navigator.dart';
import 'performance_overlay.dart';
import 'semantics_debugger.dart';
import 'title.dart';
AssetBundle _initDefaultBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _defaultBundle = _initDefaultBundle();
class RouteArguments {
const RouteArguments({ this.context });
final BuildContext context;
}
typedef Widget RouteBuilder(RouteArguments args);
typedef Future<LocaleQueryData> LocaleChangedCallback(Locale locale);
class WidgetsApp extends StatefulComponent {
WidgetsApp({
Key key,
this.title,
this.textStyle,
this.color,
this.routes: const <String, RouteBuilder>{},
this.onGenerateRoute,
this.onLocaleChanged,
this.showPerformanceOverlay: false,
this.showSemanticsDebugger: false,
this.debugShowCheckedModeBanner: true
}) : super(key: key) {
assert(routes != null);
assert(routes.containsKey(Navigator.defaultRouteName) || onGenerateRoute != null);
assert(showPerformanceOverlay != null);
assert(showSemanticsDebugger != null);
}
/// A one-line description of this app for use in the window manager.
final String title;
/// The default text style for [Text] in the application.
final TextStyle textStyle;
/// 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.
final Color color;
/// The default table of routes for the application. When the
/// [Navigator] is given a named route, the name will be looked up
/// in this table first. If the name is not available, then
/// [onGenerateRoute] will be called instead.
final Map<String, RouteBuilder> routes;
/// The route generator callback used when the app is navigated to a
/// named route but the name is not in the [routes] table.
final RouteFactory onGenerateRoute;
/// Callback that is invoked when the operating system changes the
/// current locale.
final LocaleChangedCallback onLocaleChanged;
/// Turns on a performance overlay.
/// https://flutter.io/debugging/#performanceoverlay
final bool showPerformanceOverlay;
/// Turns on an overlay that shows the accessibility information
/// reported by the framework.
final bool showSemanticsDebugger;
/// Turns on a "SLOW MODE" little 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 avoid people 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.
final bool debugShowCheckedModeBanner;
WidgetsAppState<WidgetsApp> createState() => new WidgetsAppState<WidgetsApp>();
}
EdgeDims _getPadding(ui.WindowPadding padding) {
return new EdgeDims.TRBL(padding.top, padding.right, padding.bottom, padding.left);
}
class WidgetsAppState<T extends WidgetsApp> extends State<T> implements BindingObserver {
GlobalObjectKey _navigator;
LocaleQueryData _localeData;
void initState() {
super.initState();
_navigator = new GlobalObjectKey(this);
didChangeLocale(ui.window.locale);
WidgetFlutterBinding.instance.addObserver(this);
}
void dispose() {
WidgetFlutterBinding.instance.removeObserver(this);
super.dispose();
}
bool didPopRoute() {
assert(mounted);
NavigatorState navigator = _navigator.currentState;
assert(navigator != null);
bool result = false;
navigator.openTransaction((NavigatorTransaction transaction) {
result = transaction.pop();
});
return result;
}
void didChangeMetrics() {
setState(() {
// The properties of ui.window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}
void didChangeLocale(Locale locale) {
if (config.onLocaleChanged != null) {
config.onLocaleChanged(locale).then((LocaleQueryData data) {
if (mounted)
setState(() { _localeData = data; });
});
}
}
void didChangeAppLifecycleState(AppLifecycleState state) { }
NavigatorObserver get navigatorObserver => null;
Widget build(BuildContext context) {
if (config.onLocaleChanged != null && _localeData == null) {
// If the app expects a locale but we don't yet know the locale, then
// don't build the widgets now.
// TODO(ianh): Make this unnecessary. See https://github.com/flutter/flutter/issues/1865
return new Container();
}
Widget result = new MediaQuery(
data: new MediaQueryData(
size: ui.window.size,
devicePixelRatio: ui.window.devicePixelRatio,
padding: _getPadding(ui.window.padding)
),
child: new LocaleQuery(
data: _localeData,
child: new DefaultTextStyle(
style: config.textStyle,
child: new AssetVendor(
bundle: _defaultBundle,
devicePixelRatio: ui.window.devicePixelRatio,
child: new Title(
title: config.title,
color: config.color,
child: new Navigator(
key: _navigator,
initialRoute: ui.window.defaultRouteName,
onGenerateRoute: config.onGenerateRoute,
observer: navigatorObserver
)
)
)
)
)
);
if (config.showPerformanceOverlay) {
result = new Stack(
children: <Widget>[
result,
new Positioned(bottom: 0.0, left: 0.0, right: 0.0, child: new PerformanceOverlay.allEnabled()),
]
);
}
if (config.showSemanticsDebugger) {
result = new SemanticsDebugger(
child: result
);
}
assert(() {
if (config.debugShowCheckedModeBanner) {
result = new CheckedModeBanner(
child: result
);
}
return true;
});
return result;
}
}
......@@ -5,6 +5,7 @@
/// The Flutter widget framework.
library widgets;
export 'src/widgets/app.dart';
export 'src/widgets/asset_vendor.dart';
export 'src/widgets/auto_layout.dart';
export 'src/widgets/basic.dart';
......
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