Commit 9693cd55 authored by Jason Simmons's avatar Jason Simmons

Add a LocaleQuery widget that can be used to fetch locale-specific data

Users of MaterialApp can provide an onLocaleChanged handler that will be
called to asynchronously fetch locale-specific data.  MaterialApp will
then instantiate a LocaleQuery that supplies the locale data to its
descendants.
parent 1e1761d1
......@@ -94,6 +94,14 @@ class StocksAppState extends State<StocksApp> {
return null;
}
Future<LocaleQueryData> _onLocaleChanged(ui.Locale locale) {
String localeString = locale.toString();
return initializeMessages(localeString).then((_) {
Intl.defaultLocale = localeString;
return StockStrings.instance;
});
}
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Stocks',
......@@ -102,13 +110,12 @@ class StocksAppState extends State<StocksApp> {
'/': (RouteArguments args) => new StockHome(_stocks, _symbols, _optimismSetting, modeUpdater),
'/settings': (RouteArguments args) => new StockSettings(_optimismSetting, _backupSetting, settingsUpdater)
},
onGenerateRoute: _getRoute
onGenerateRoute: _getRoute,
onLocaleChanged: _onLocaleChanged
);
}
}
void main() {
initializeMessages(Intl.defaultLocale).then((_) {
runApp(new StocksApp());
});
}
......@@ -147,7 +147,7 @@ class StockHomeState extends State<StockHome> {
Widget buildToolBar() {
return new ToolBar(
elevation: 0,
center: new Text(StockStrings.title()),
center: new Text(StockStrings.of(context).title()),
right: <Widget>[
new IconButton(
icon: "action/search",
......@@ -161,8 +161,9 @@ class StockHomeState extends State<StockHome> {
tabBar: new TabBar(
selection: _tabBarSelection,
labels: <TabLabel>[
new TabLabel(text: StockStrings.market()),
new TabLabel(text: StockStrings.portfolio())]
new TabLabel(text: StockStrings.of(context).market()),
new TabLabel(text: StockStrings.of(context).portfolio())
]
)
);
}
......
......@@ -8,20 +8,26 @@ part of stocks;
// To generate the stock_messages_*.dart files from the ARB files, run:
// pub run intl:generate_from_arb --output-dir=lib/i18n --generated-file-prefix=stock_ --no-use-deferred-loading lib/stock_strings.dart lib/i18n/stocks_*.arb
class StockStrings {
static String title() => Intl.message(
class StockStrings extends LocaleQueryData {
static StockStrings of(BuildContext context) {
return LocaleQuery.of(context);
}
static final StockStrings instance = new StockStrings();
String title() => Intl.message(
'Stocks',
name: 'title',
desc: 'Title for the Stocks application'
);
static String market() => Intl.message(
String market() => Intl.message(
'MARKET',
name: 'market',
desc: 'Label for the Market tab'
);
static String portfolio() => Intl.message(
String portfolio() => Intl.message(
'PORTFOLIO',
name: 'portfolio',
desc: 'Label for the Portfolio tab'
......
......@@ -2,6 +2,7 @@
// 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;
import 'package:flutter/rendering.dart';
......@@ -37,13 +38,16 @@ class RouteArguments {
}
typedef Widget RouteBuilder(RouteArguments args);
typedef Future<LocaleQueryData> LocaleChangedCallback(ui.Locale locale);
class MaterialApp extends StatefulComponent {
MaterialApp({
Key key,
this.title,
this.theme,
this.routes: const <String, RouteBuilder>{},
this.onGenerateRoute
this.onGenerateRoute,
this.onLocaleChanged
}) : super(key: key) {
assert(routes != null);
assert(routes.containsKey(Navigator.defaultRouteName) || onGenerateRoute != null);
......@@ -53,6 +57,7 @@ class MaterialApp extends StatefulComponent {
final ThemeData theme;
final Map<String, RouteBuilder> routes;
final RouteFactory onGenerateRoute;
final LocaleChangedCallback onLocaleChanged;
_MaterialAppState createState() => new _MaterialAppState();
}
......@@ -62,11 +67,13 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
GlobalObjectKey _navigator;
Size _size;
LocaleQueryData _localeData;
void initState() {
super.initState();
_navigator = new GlobalObjectKey(this);
_size = ui.window.size;
didChangeLocale(ui.window.locale);
FlutterBinding.instance.addObserver(this);
}
......@@ -88,6 +95,15 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
void didChangeSize(Size size) => setState(() { _size = size; });
void didChangeLocale(ui.Locale locale) {
if (config.onLocaleChanged != null) {
config.onLocaleChanged(locale).then((LocaleQueryData data) {
if (mounted)
setState(() { _localeData = data; });
});
}
}
final HeroController _heroController = new HeroController();
Route _generateRoute(NamedRouteSettings settings) {
......@@ -106,9 +122,17 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
}
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();
return new MediaQuery(
data: new MediaQueryData(size: _size),
child: new LocaleQuery(
data: _localeData,
child: new Theme(
data: theme,
child: new DefaultTextStyle(
......@@ -128,6 +152,7 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
)
)
)
)
);
}
......
......@@ -197,6 +197,7 @@ class _PointerEventConverter {
class BindingObserver {
bool didPopRoute() => false;
void didChangeSize(Size size) { }
void didChangeLocale(ui.Locale locale) { }
}
/// The glue between the render tree and the Flutter engine
......@@ -208,6 +209,7 @@ class FlutterBinding extends HitTestTarget {
ui.window.onPointerPacket = _handlePointerPacket;
ui.window.onMetricsChanged = _handleMetricsChanged;
ui.window.onLocaleChanged = _handleLocaleChanged;
ui.window.onPopRoute = _handlePopRoute;
if (renderViewOverride == null) {
......@@ -244,6 +246,11 @@ class FlutterBinding extends HitTestTarget {
observer.didChangeSize(size);
}
void _handleLocaleChanged() {
for (BindingObserver observer in _observers)
observer.didChangeLocale(ui.window.locale);
}
void _handlePersistentFrameCallback(Duration timeStamp) {
beginFrame();
}
......
// 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 'framework.dart';
// Superclass for locale-specific data provided by the application.
class LocaleQueryData { }
class LocaleQuery<T extends LocaleQueryData> extends InheritedWidget {
LocaleQuery({
Key key,
this.data,
Widget child
}) : super(key: key, child: child) {
assert(child != null);
}
final T data;
static LocaleQueryData of(BuildContext context) {
LocaleQuery query = context.inheritFromWidgetOfType(LocaleQuery);
return query == null ? null : query.data;
}
bool updateShouldNotify(LocaleQuery old) => data != old.data;
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$data');
}
}
......@@ -19,6 +19,7 @@ export 'src/widgets/gesture_detector.dart';
export 'src/widgets/gridpaper.dart';
export 'src/widgets/heroes.dart';
export 'src/widgets/homogeneous_viewport.dart';
export 'src/widgets/locale_query.dart';
export 'src/widgets/media_query.dart';
export 'src/widgets/mimic.dart';
export 'src/widgets/mixed_viewport.dart';
......
......@@ -7,8 +7,8 @@ dependencies:
collection: '>=1.1.3 <2.0.0'
intl: '>=0.12.4+2 <0.13.0'
material_design_icons: '>=0.0.3 <0.1.0'
sky_engine: 0.0.67
sky_services: 0.0.67
sky_engine: 0.0.68
sky_services: 0.0.68
vector_math: '>=1.4.3 <2.0.0'
# To pin the transitive dependency through mojo_sdk.
......
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