Make it possible to localize an app title (#12105)
This commit is contained in:
parent
9d59fb0c30
commit
e57d94c308
@ -85,6 +85,7 @@ class MaterialApp extends StatefulWidget {
|
||||
MaterialApp({ // can't be const because the asserts use methods on Map :-(
|
||||
Key key,
|
||||
this.title: '',
|
||||
this.onGenerateTitle,
|
||||
this.color,
|
||||
this.theme,
|
||||
this.home,
|
||||
@ -132,9 +133,30 @@ class MaterialApp extends StatefulWidget {
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
/// A one-line description of this app for use in the window manager.
|
||||
/// 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].
|
||||
///
|
||||
/// This value is passed unmodified to [WidgetsApp.title].
|
||||
final String title;
|
||||
|
||||
/// If non-null this function is called to produce the app's
|
||||
/// title string, otherwise [title] is used.
|
||||
///
|
||||
/// The [onGenerateTitle] `context` parameter includes the [WidgetApp]'s
|
||||
/// [Localizations] widget so that this callback can be used to produce a
|
||||
/// localized title.
|
||||
///
|
||||
/// This callback function must not return null.
|
||||
///
|
||||
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
|
||||
final GenerateAppTitle onGenerateTitle;
|
||||
|
||||
/// The colors to use for the application's widgets.
|
||||
final ThemeData theme;
|
||||
|
||||
@ -320,7 +342,7 @@ class MaterialApp extends StatefulWidget {
|
||||
/// configure this list to match the locales they support.
|
||||
///
|
||||
/// This list must not null. It's default value is just
|
||||
/// `[const Locale('en', 'US')]`. It is simply passed along to the
|
||||
/// `[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
|
||||
@ -508,6 +530,7 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
child: new WidgetsApp(
|
||||
key: new GlobalObjectKey(this),
|
||||
title: widget.title,
|
||||
onGenerateTitle: widget.onGenerateTitle,
|
||||
textStyle: _errorTextStyle,
|
||||
// blue is the primary color of the default theme
|
||||
color: widget.color ?? theme?.primaryColor ?? Colors.blue,
|
||||
|
@ -34,6 +34,16 @@ export 'dart:ui' show Locale;
|
||||
/// parameter is just the value of [WidgetApp.supportedLocales].
|
||||
typedef Locale LocaleResolutionCallback(Locale locale, Iterable<Locale> supportedLocales);
|
||||
|
||||
/// The signature of [WidgetsApp.onGenerateTitle].
|
||||
///
|
||||
/// Used to generate a value for the app's [Title.title], which the device uses
|
||||
/// to identify the app for the user. The `context` includes the [WidgetApp]'s
|
||||
/// [Localizations] widget so that this method can be used to produce a
|
||||
/// localized title.
|
||||
///
|
||||
/// This function must not return null.
|
||||
typedef String GenerateAppTitle(BuildContext context);
|
||||
|
||||
// Delegate that fetches the default (English) strings.
|
||||
class _WidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
|
||||
const _WidgetsLocalizationsDelegate();
|
||||
@ -71,6 +81,7 @@ class WidgetsApp extends StatefulWidget {
|
||||
@required this.onGenerateRoute,
|
||||
this.onUnknownRoute,
|
||||
this.title: '',
|
||||
this.onGenerateTitle,
|
||||
this.textStyle,
|
||||
@required this.color,
|
||||
this.navigatorObservers: const <NavigatorObserver>[],
|
||||
@ -99,9 +110,26 @@ class WidgetsApp extends StatefulWidget {
|
||||
assert(debugShowWidgetInspector != null),
|
||||
super(key: key);
|
||||
|
||||
/// A one-line description of this app for use in the window manager.
|
||||
/// 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].
|
||||
final String title;
|
||||
|
||||
/// If non-null this callback function is called to produce the app's
|
||||
/// title string, otherwise [title] is used.
|
||||
///
|
||||
/// The [onGenerateTitle] `context` parameter includes the [WidgetApp]'s
|
||||
/// [Localizations] widget so that this callback can be used to produce a
|
||||
/// localized title.
|
||||
///
|
||||
/// This callback function must not return null.
|
||||
final GenerateAppTitle onGenerateTitle;
|
||||
|
||||
/// The default text style for [Text] in the application.
|
||||
final TextStyle textStyle;
|
||||
|
||||
@ -465,10 +493,22 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
||||
child: new Localizations(
|
||||
locale: widget.locale ?? _locale,
|
||||
delegates: _localizationsDelegates.toList(),
|
||||
child: new Title(
|
||||
title: widget.title,
|
||||
color: widget.color,
|
||||
child: result,
|
||||
// This Builder exists to provide a context below the Localizations widget.
|
||||
// The onGenerateCallback() can refer to Localizations via its context
|
||||
// parameter.
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
String title = widget.title;
|
||||
if (widget.onGenerateTitle != null) {
|
||||
title = widget.onGenerateTitle(context);
|
||||
assert(title != null, 'onGenerateTitle must return a non-null String');
|
||||
}
|
||||
return new Title(
|
||||
title: title,
|
||||
color: widget.color,
|
||||
child: result,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
60
packages/flutter/test/widgets/app_title_test.dart
Normal file
60
packages/flutter/test/widgets/app_title_test.dart
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2017 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_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
const Color kTitleColor = const Color(0xFF333333);
|
||||
const String kTitleString = 'Hello World';
|
||||
|
||||
Future<Null> pumpApp(WidgetTester tester, { GenerateAppTitle onGenerateTitle }) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
supportedLocales: <Locale>[
|
||||
const Locale('en', 'US'),
|
||||
const Locale('en', 'GB'),
|
||||
],
|
||||
title: kTitleString,
|
||||
color: kTitleColor,
|
||||
onGenerateTitle: onGenerateTitle,
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new PageRouteBuilder<Null>(
|
||||
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||
return new Container();
|
||||
}
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('Specified title and color are used to build a Title', (WidgetTester tester) async {
|
||||
await pumpApp(tester);
|
||||
expect(tester.widget<Title>(find.byType(Title)).title, kTitleString);
|
||||
expect(tester.widget<Title>(find.byType(Title)).color, kTitleColor);
|
||||
});
|
||||
|
||||
testWidgets('onGenerateTitle handles changing locales', (WidgetTester tester) async {
|
||||
String generateTitle(BuildContext context) {
|
||||
return Localizations.localeOf(context).toString();
|
||||
}
|
||||
|
||||
await pumpApp(tester, onGenerateTitle: generateTitle);
|
||||
expect(tester.widget<Title>(find.byType(Title)).title, 'en_US');
|
||||
expect(tester.widget<Title>(find.byType(Title)).color, kTitleColor);
|
||||
|
||||
await tester.binding.setLocale('en', 'GB');
|
||||
await tester.pump();
|
||||
expect(tester.widget<Title>(find.byType(Title)).title, 'en_GB');
|
||||
expect(tester.widget<Title>(find.byType(Title)).color, kTitleColor);
|
||||
|
||||
// Not a supported locale, so we switch to supportedLocales[0], en_US
|
||||
await tester.binding.setLocale('fr', 'CA');
|
||||
await tester.pump();
|
||||
expect(tester.widget<Title>(find.byType(Title)).title, 'en_US');
|
||||
expect(tester.widget<Title>(find.byType(Title)).color, kTitleColor);
|
||||
});
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user