Commit b9e1be9a authored by Yegor's avatar Yegor Committed by GitHub

introduce localized text geometry in MaterialLocalizations (#11829)

* introduce localized text geometry in MaterialLocalizations

* remove geometry from color text themes

* fix merge conflict

* optional Localizations

* fix fallback; test; docs
parent f4f20c29
......@@ -12,6 +12,7 @@
/// This variable is used by [MaterialLocalizations].
const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {
"ar": const <String, String>{
"scriptCategory": r"tall",
"timeOfDayFormat": r"h:mm a",
"openAppDrawerTooltip": r"افتح قائمة التنقل",
"backButtonTooltip": r"الى الخلف",
......@@ -40,6 +41,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"postMeridiemAbbreviation": r"م",
},
"de": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"Navigationsmenü öffnen",
"backButtonTooltip": r"Zurück",
......@@ -68,6 +70,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"LIZENZEN ANZEIGEN",
},
"en": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"h:mm a",
"openAppDrawerTooltip": r"Open navigation menu",
"backButtonTooltip": r"Back",
......@@ -107,6 +110,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"timeOfDayFormat": r"HH:mm",
},
"es": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"H:mm",
"openAppDrawerTooltip": r"Abrir el menú de navegación",
"backButtonTooltip": r"Espalda",
......@@ -140,6 +144,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"postMeridiemAbbreviation": r"PM",
},
"fa": const <String, String>{
"scriptCategory": r"tall",
"timeOfDayFormat": r"H:mm",
"openAppDrawerTooltip": r"منوی ناوبری را باز کنید",
"backButtonTooltip": r"بازگشت",
......@@ -166,6 +171,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"مشاهده مجوز",
},
"fr": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"Ouvrir le menu de navigation",
"backButtonTooltip": r"Retour",
......@@ -197,6 +203,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"timeOfDayFormat": r"HH 'h' mm",
},
"he": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"H:mm",
"openAppDrawerTooltip": r"פתח תפריט ניווט",
"backButtonTooltip": r"אחורה",
......@@ -223,6 +230,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"ראה רישיונות",
},
"it": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"Apri il menu di navigazione",
"backButtonTooltip": r"Indietro",
......@@ -249,6 +257,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"VEDI LE LICENZE",
},
"ja": const <String, String>{
"scriptCategory": r"dense",
"timeOfDayFormat": r"H:mm",
"openAppDrawerTooltip": r"ナビゲーションメニューを開く",
"backButtonTooltip": r"戻る",
......@@ -275,6 +284,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"ライセンス表記",
},
"ps": const <String, String>{
"scriptCategory": r"tall",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"د پرانیستی نیینګ مینو",
"backButtonTooltip": r"شاته",
......@@ -301,6 +311,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"لیدلس وګورئ",
},
"pt": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"Abrir menu de navegação",
"backButtonTooltip": r"Costas",
......@@ -327,6 +338,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"VER LICENÇAS",
},
"ru": const <String, String>{
"scriptCategory": r"English-like",
"timeOfDayFormat": r"H:mm",
"openAppDrawerTooltip": r"Открыть меню навигации",
"backButtonTooltip": r"Назад",
......@@ -355,6 +367,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"ПРОСМОТРЕТЬ ЛИЦЕНЗИИ",
},
"sd": const <String, String>{
"scriptCategory": r"tall",
"timeOfDayFormat": r"HH:mm",
"openAppDrawerTooltip": r"اوپن جي مينڊيٽ مينيو",
"backButtonTooltip": r"پوئتي",
......@@ -381,6 +394,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"viewLicensesButtonLabel": r"لائسنس ڏسو",
},
"ur": const <String, String>{
"scriptCategory": r"tall",
"timeOfDayFormat": r"h:mm a",
"openAppDrawerTooltip": r"کھولیں نیویگیشن مینو",
"backButtonTooltip": r"واپس",
......@@ -409,6 +423,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"postMeridiemAbbreviation": r"PM",
},
"zh": const <String, String>{
"scriptCategory": r"dense",
"timeOfDayFormat": r"ah:mm",
"openAppDrawerTooltip": r"打开导航菜单",
"backButtonTooltip": r"返回",
......
{
"scriptCategory": "tall",
"timeOfDayFormat": "h:mm a",
"openAppDrawerTooltip": "افتح قائمة التنقل",
"backButtonTooltip": "الى الخلف",
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "German time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "German time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"@scriptCategory": {
"description": "The name of the language's script category (see https://material.io/guidelines/style/typography.html#typography-language-categories-reference)",
"type": "text"
},
"timeOfDayFormat": "h:mm a",
"@timeOfDayFormat": {
"description": "The ICU 'Short Time' pattern, such as 'HH:mm', 'h:mm a', 'H:mm'. See: http://demo.icu-project.org/icu-bin/locexp?d_=en&_=en_US",
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "H:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Standard Spanish time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Standard Spanish time format does not use p.m. indicator" },
......
{
"scriptCategory": "tall",
"timeOfDayFormat": "H:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Farsi time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Farsi time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "French time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "French time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "H:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Hebrew time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Hebrew time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Italian time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Italian time format does not use p.m. indicator" },
......
{
"scriptCategory": "dense",
"timeOfDayFormat": "H:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Japanese time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Japanese time format does not use p.m. indicator" },
......
{
"scriptCategory": "tall",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Pashto time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Pashto time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Portuguese time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Portuguese time format does not use p.m. indicator" },
......
{
"scriptCategory": "English-like",
"timeOfDayFormat": "H:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Russian time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Russian time format does not use p.m. indicator" },
......
{
"scriptCategory": "tall",
"timeOfDayFormat": "HH:mm",
"@anteMeridiemAbbreviation": { "notUsed": "Sindhi time format does not use a.m. indicator" },
"@postMeridiemAbbreviation": { "notUsed": "Sindhi time format does not use p.m. indicator" },
......
{
"scriptCategory": "tall",
"timeOfDayFormat": "h:mm a",
"openAppDrawerTooltip": "کھولیں نیویگیشن مینو",
"backButtonTooltip": "واپس",
......
{
"scriptCategory": "dense",
"timeOfDayFormat": "ah:mm",
"openAppDrawerTooltip": "打开导航菜单",
"backButtonTooltip": "返回",
......
......@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart' as intl;
import 'i18n/localizations.dart';
import 'typography.dart';
/// Defines the localized resource values used by the Material widgets.
///
......@@ -95,6 +96,19 @@ abstract class MaterialLocalizations {
/// each supported layout.
TimeOfDayFormat get timeOfDayFormat;
/// Provides geometric text preferences for the current locale.
///
/// This text theme is incomplete. For example, it lacks text color
/// information. This theme must be merged with another text theme that
/// provides the missing values. The text styles provided by this theme have
/// their [TextStyle.inherit] property set to `true`.
///
/// Typically a complete theme is obtained via [Theme.of], which can be
/// localized using the [Localizations] widget.
///
/// See also: https://material.io/guidelines/style/typography.html
TextTheme get localTextGeometry;
/// The `MaterialLocalizations` from the closest [Localizations] instance
/// that encloses the given context.
///
......@@ -287,6 +301,10 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
return _icuTimeOfDayToEnum[icuShortTimePattern];
}
/// Looks up text geometry defined in [MaterialTextGeometry].
@override
TextTheme get localTextGeometry => MaterialTextGeometry.forScriptCategory(_nameToValue["scriptCategory"]);
/// Creates an object that provides localized resource values for the
/// for the widgets of the material library.
///
......
......@@ -5,7 +5,9 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'material_localizations.dart';
import 'theme_data.dart';
import 'typography.dart';
export 'theme_data.dart' show Brightness, ThemeData;
......@@ -65,6 +67,10 @@ class Theme extends StatelessWidget {
/// The data from the closest [Theme] instance that encloses the given
/// context.
///
/// If the given context is enclosed in a [Localizations] widget providing
/// [MaterialLocalizations], the returned data is localized according to the
/// nearest available [MaterialLocalizations].
///
/// Defaults to [new ThemeData.fallback] if there is no [Theme] in the given
/// build context.
///
......@@ -123,7 +129,11 @@ class Theme extends StatelessWidget {
return null;
return inheritedTheme.theme.data;
}
return (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
final ThemeData colorTheme = (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
final TextTheme geometryTheme = localizations?.localTextGeometry ?? MaterialTextGeometry.englishLike;
return ThemeData.localize(colorTheme, geometryTheme);
}
@override
......
......@@ -48,7 +48,6 @@ const Color _kDarkThemeSplashColor = const Color(0x40CCCCCC);
/// Use this class to configure a [Theme] widget.
///
/// To obtain the current theme, use [Theme.of].
@immutable
class ThemeData {
/// Create a ThemeData given a set of preferred values.
///
......@@ -248,14 +247,26 @@ class ThemeData {
assert(platform != null);
/// A default light blue theme.
///
/// This theme does not contain text geometry. Instead, it is expected that
/// this theme is localized using text geometry using [ThemeData.localize].
factory ThemeData.light() => new ThemeData(brightness: Brightness.light);
/// A default dark theme with a teal accent color.
///
/// This theme does not contain text geometry. Instead, it is expected that
/// this theme is localized using text geometry using [ThemeData.localize].
factory ThemeData.dark() => new ThemeData(brightness: Brightness.dark);
/// The default theme. Same as [new ThemeData.light].
/// The default color theme. Same as [new ThemeData.light].
///
/// This is used by [Theme.of] when no theme has been specified.
///
/// This theme does not contain text geometry. Instead, it is expected that
/// this theme is localized using text geometry using [ThemeData.localize].
///
/// Most applications would use [Theme.of], which provides correct localized
/// text geometry.
factory ThemeData.fallback() => new ThemeData.light();
/// The brightness of the overall theme of the application. Used by widgets
......@@ -407,40 +418,52 @@ class ThemeData {
IconThemeData accentIconTheme,
TargetPlatform platform,
}) {
return new ThemeData.raw(
brightness: brightness ?? this.brightness,
primaryColor: primaryColor ?? this.primaryColor,
primaryColorBrightness: primaryColorBrightness ?? this.primaryColorBrightness,
accentColor: accentColor ?? this.accentColor,
accentColorBrightness: accentColorBrightness ?? this.accentColorBrightness,
canvasColor: canvasColor ?? this.canvasColor,
scaffoldBackgroundColor: scaffoldBackgroundColor ?? this.scaffoldBackgroundColor,
cardColor: cardColor ?? this.cardColor,
dividerColor: dividerColor ?? this.dividerColor,
highlightColor: highlightColor ?? this.highlightColor,
splashColor: splashColor ?? this.splashColor,
selectedRowColor: selectedRowColor ?? this.selectedRowColor,
unselectedWidgetColor: unselectedWidgetColor ?? this.unselectedWidgetColor,
disabledColor: disabledColor ?? this.disabledColor,
buttonColor: buttonColor ?? this.buttonColor,
secondaryHeaderColor: secondaryHeaderColor ?? this.secondaryHeaderColor,
textSelectionColor: textSelectionColor ?? this.textSelectionColor,
textSelectionHandleColor: textSelectionHandleColor ?? this.textSelectionHandleColor,
backgroundColor: backgroundColor ?? this.backgroundColor,
dialogBackgroundColor: dialogBackgroundColor ?? this.dialogBackgroundColor,
indicatorColor: indicatorColor ?? this.indicatorColor,
hintColor: hintColor ?? this.hintColor,
errorColor: errorColor ?? this.errorColor,
textTheme: textTheme ?? this.textTheme,
primaryTextTheme: primaryTextTheme ?? this.primaryTextTheme,
accentTextTheme: accentTextTheme ?? this.accentTextTheme,
iconTheme: iconTheme ?? this.iconTheme,
primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme,
accentIconTheme: accentIconTheme ?? this.accentIconTheme,
platform: platform ?? this.platform,
return _copyThemeDataWith(
this,
brightness: brightness,
primaryColor: primaryColor,
primaryColorBrightness: primaryColorBrightness,
accentColor: accentColor,
accentColorBrightness: accentColorBrightness,
canvasColor: canvasColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
cardColor: cardColor,
dividerColor: dividerColor,
highlightColor: highlightColor,
splashColor: splashColor,
selectedRowColor: selectedRowColor,
unselectedWidgetColor: unselectedWidgetColor,
disabledColor: disabledColor,
buttonColor: buttonColor,
secondaryHeaderColor: secondaryHeaderColor,
textSelectionColor: textSelectionColor,
textSelectionHandleColor: textSelectionHandleColor,
backgroundColor: backgroundColor,
dialogBackgroundColor: dialogBackgroundColor,
indicatorColor: indicatorColor,
hintColor: hintColor,
errorColor: errorColor,
textTheme: textTheme,
primaryTextTheme: primaryTextTheme,
accentTextTheme: accentTextTheme,
iconTheme: iconTheme,
primaryIconTheme: primaryIconTheme,
accentIconTheme: accentIconTheme,
platform: platform,
);
}
/// Returns a new theme built by merging [baseTheme] into the text geometry
/// provided by the [localTextGeometry].
///
/// The [TextStyle.inherit] field in the text styles provided by
/// [localTextGeometry] must be set to `true`.
static ThemeData localize(ThemeData baseTheme, TextTheme localTextGeometry) {
assert(baseTheme != null);
assert(localTextGeometry != null);
return new _LocalizedThemeData(baseTheme, localTextGeometry);
}
// See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
static double _linearizeColorComponent(double component) {
if (component <= 0.03928)
......@@ -590,3 +613,246 @@ class ThemeData {
@override
String toString() => '$runtimeType(${ platform != defaultTargetPlatform ? "$platform " : ''}$brightness $primaryColor etc...)';
}
/// A lazily evaluated theme that provides the properties of the given
/// [delegate] theme localized using the properties of the given
/// [localTextGeometry].
///
/// The localization is done by merging of the [TextTheme] fields of the
/// [delegate] into the [localTextGeometry] and caching the results.
class _LocalizedThemeData implements ThemeData {
_LocalizedThemeData(this.delegate, this.localTextGeometry);
final ThemeData delegate;
final TextTheme localTextGeometry;
@override
Color get accentColor => delegate.accentColor;
@override
Brightness get accentColorBrightness => delegate.accentColorBrightness;
@override
IconThemeData get accentIconTheme => delegate.accentIconTheme;
@override
Color get backgroundColor => delegate.backgroundColor;
@override
Brightness get brightness => delegate.brightness;
@override
Color get buttonColor => delegate.buttonColor;
@override
Color get canvasColor => delegate.canvasColor;
@override
Color get cardColor => delegate.cardColor;
@override
Color get dialogBackgroundColor => delegate.dialogBackgroundColor;
@override
Color get disabledColor => delegate.disabledColor;
@override
Color get dividerColor => delegate.dividerColor;
@override
Color get errorColor => delegate.errorColor;
@override
Color get highlightColor => delegate.highlightColor;
@override
Color get hintColor => delegate.hintColor;
@override
IconThemeData get iconTheme => delegate.iconTheme;
@override
Color get indicatorColor => delegate.indicatorColor;
@override
TargetPlatform get platform => delegate.platform;
@override
Color get primaryColor => delegate.primaryColor;
@override
Brightness get primaryColorBrightness => delegate.primaryColorBrightness;
@override
IconThemeData get primaryIconTheme => delegate.primaryIconTheme;
@override
Color get scaffoldBackgroundColor => delegate.scaffoldBackgroundColor;
@override
Color get secondaryHeaderColor => delegate.secondaryHeaderColor;
@override
Color get selectedRowColor => delegate.selectedRowColor;
@override
Color get splashColor => delegate.splashColor;
@override
Color get textSelectionColor => delegate.textSelectionColor;
@override
Color get textSelectionHandleColor => delegate.textSelectionHandleColor;
@override
Color get unselectedWidgetColor => delegate.unselectedWidgetColor;
@override
TextTheme get primaryTextTheme => _primaryTextTheme ??= delegate.primaryTextTheme.merge(localTextGeometry);
TextTheme _primaryTextTheme;
@override
TextTheme get accentTextTheme => _accentTextTheme ??= delegate.accentTextTheme.merge(localTextGeometry);
TextTheme _accentTextTheme;
@override
TextTheme get textTheme => _textTheme ??= delegate.textTheme.merge(localTextGeometry);
TextTheme _textTheme;
/// This should be identical to [ThemeData.copyWith].
@override
ThemeData copyWith({
Brightness brightness,
Color primaryColor,
Brightness primaryColorBrightness,
Color accentColor,
Brightness accentColorBrightness,
Color canvasColor,
Color scaffoldBackgroundColor,
Color cardColor,
Color dividerColor,
Color highlightColor,
Color splashColor,
Color selectedRowColor,
Color unselectedWidgetColor,
Color disabledColor,
Color buttonColor,
Color secondaryHeaderColor,
Color textSelectionColor,
Color textSelectionHandleColor,
Color backgroundColor,
Color dialogBackgroundColor,
Color indicatorColor,
Color hintColor,
Color errorColor,
TextTheme textTheme,
TextTheme primaryTextTheme,
TextTheme accentTextTheme,
IconThemeData iconTheme,
IconThemeData primaryIconTheme,
IconThemeData accentIconTheme,
TargetPlatform platform,
}) {
return _copyThemeDataWith(
this,
brightness: brightness,
primaryColor: primaryColor,
primaryColorBrightness: primaryColorBrightness,
accentColor: accentColor,
accentColorBrightness: accentColorBrightness,
canvasColor: canvasColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
cardColor: cardColor,
dividerColor: dividerColor,
highlightColor: highlightColor,
splashColor: splashColor,
selectedRowColor: selectedRowColor,
unselectedWidgetColor: unselectedWidgetColor,
disabledColor: disabledColor,
buttonColor: buttonColor,
secondaryHeaderColor: secondaryHeaderColor,
textSelectionColor: textSelectionColor,
textSelectionHandleColor: textSelectionHandleColor,
backgroundColor: backgroundColor,
dialogBackgroundColor: dialogBackgroundColor,
indicatorColor: indicatorColor,
hintColor: hintColor,
errorColor: errorColor,
textTheme: textTheme,
primaryTextTheme: primaryTextTheme,
accentTextTheme: accentTextTheme,
iconTheme: iconTheme,
primaryIconTheme: primaryIconTheme,
accentIconTheme: accentIconTheme,
platform: platform,
);
}
}
/// Implementation of [ThemeData.copyWith], shared with [_LocalizedThemeData.copyWith].
ThemeData _copyThemeDataWith(
ThemeData base, {
@required Brightness brightness,
@required Color primaryColor,
@required Brightness primaryColorBrightness,
@required Color accentColor,
@required Brightness accentColorBrightness,
@required Color canvasColor,
@required Color scaffoldBackgroundColor,
@required Color cardColor,
@required Color dividerColor,
@required Color highlightColor,
@required Color splashColor,
@required Color selectedRowColor,
@required Color unselectedWidgetColor,
@required Color disabledColor,
@required Color buttonColor,
@required Color secondaryHeaderColor,
@required Color textSelectionColor,
@required Color textSelectionHandleColor,
@required Color backgroundColor,
@required Color dialogBackgroundColor,
@required Color indicatorColor,
@required Color hintColor,
@required Color errorColor,
@required TextTheme textTheme,
@required TextTheme primaryTextTheme,
@required TextTheme accentTextTheme,
@required IconThemeData iconTheme,
@required IconThemeData primaryIconTheme,
@required IconThemeData accentIconTheme,
@required TargetPlatform platform,
}) {
return new ThemeData.raw(
brightness: brightness ?? base.brightness,
primaryColor: primaryColor ?? base.primaryColor,
primaryColorBrightness: primaryColorBrightness ?? base.primaryColorBrightness,
accentColor: accentColor ?? base.accentColor,
accentColorBrightness: accentColorBrightness ?? base.accentColorBrightness,
canvasColor: canvasColor ?? base.canvasColor,
scaffoldBackgroundColor: scaffoldBackgroundColor ?? base.scaffoldBackgroundColor,
cardColor: cardColor ?? base.cardColor,
dividerColor: dividerColor ?? base.dividerColor,
highlightColor: highlightColor ?? base.highlightColor,
splashColor: splashColor ?? base.splashColor,
selectedRowColor: selectedRowColor ?? base.selectedRowColor,
unselectedWidgetColor: unselectedWidgetColor ?? base.unselectedWidgetColor,
disabledColor: disabledColor ?? base.disabledColor,
buttonColor: buttonColor ?? base.buttonColor,
secondaryHeaderColor: secondaryHeaderColor ?? base.secondaryHeaderColor,
textSelectionColor: textSelectionColor ?? base.textSelectionColor,
textSelectionHandleColor: textSelectionHandleColor ?? base.textSelectionHandleColor,
backgroundColor: backgroundColor ?? base.backgroundColor,
dialogBackgroundColor: dialogBackgroundColor ?? base.dialogBackgroundColor,
indicatorColor: indicatorColor ?? base.indicatorColor,
hintColor: hintColor ?? base.hintColor,
errorColor: errorColor ?? base.errorColor,
textTheme: textTheme ?? base.textTheme,
primaryTextTheme: primaryTextTheme ?? base.primaryTextTheme,
accentTextTheme: accentTextTheme ?? base.accentTextTheme,
iconTheme: iconTheme ?? base.iconTheme,
primaryIconTheme: primaryIconTheme ?? base.primaryIconTheme,
accentIconTheme: accentIconTheme ?? base.accentIconTheme,
platform: platform ?? base.platform,
);
}
......@@ -7,10 +7,6 @@ import 'package:flutter/painting.dart';
import 'colors.dart';
// TODO(eseidel): Font weights are supposed to be language relative.
// TODO(jackson): Baseline should be language relative.
// TODO(ianh): These values are for English-like text.
/// Material design text theme.
///
/// Definitions for the various typographical styles found in material design
......@@ -62,58 +58,6 @@ class TextTheme {
this.button,
});
const TextTheme._blackMountainView()
: display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display1 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
headline = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
title = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
subhead = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
body2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
body1 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
const TextTheme._whiteMountainView()
: display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display1 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
headline = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
title = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
subhead = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
body2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
body1 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic);
const TextTheme._blackCupertino()
: display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
const TextTheme._whiteCupertino()
: display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic),
body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic),
caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic);
/// Extremely large text.
///
/// The font size is 112 pixels.
......@@ -187,6 +131,24 @@ class TextTheme {
);
}
TextTheme merge(TextTheme other) {
if (other == null)
return this;
return copyWith(
display4: display4.merge(other.display4),
display3: display3.merge(other.display3),
display2: display2.merge(other.display2),
display1: display1.merge(other.display1),
headline: headline.merge(other.headline),
title: title.merge(other.title),
subhead: subhead.merge(other.subhead),
body2: body2.merge(other.body2),
body1: body1.merge(other.body1),
caption: caption.merge(other.caption),
button: button.merge(other.button),
);
}
/// Creates a copy of this text theme but with the given field replaced in
/// each of the individual text styles.
///
......@@ -353,13 +315,13 @@ class Typography {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
return const Typography._(
const TextTheme._blackMountainView(),
const TextTheme._whiteMountainView(),
_MaterialTextColorThemes.blackMountainView,
_MaterialTextColorThemes.whiteMountainView,
);
case TargetPlatform.iOS:
return const Typography._(
const TextTheme._blackCupertino(),
const TextTheme._whiteCupertino(),
_MaterialTextColorThemes.blackCupertino,
_MaterialTextColorThemes.whiteCupertino,
);
}
return null;
......@@ -373,3 +335,149 @@ class Typography {
/// A material design text theme with light glyphs.
final TextTheme white;
}
/// Provides default text theme colors compliant with the Material Design
/// specification.
///
/// The geometric font properties are missing in these color themes. App are
/// expected to use [Theme.of] to get [TextTheme] objects fully populated with
/// font properties.
///
/// See also: https://material.io/guidelines/style/typography.html
// TODO(yjbanov): implement font fallback (see "Font stack" at https://material.io/guidelines/style/typography.html)
class _MaterialTextColorThemes {
static const TextTheme blackMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
);
static const TextTheme whiteMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
);
static const TextTheme blackCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black54),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
);
static const TextTheme whiteCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white70),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
);
}
/// Defines text geometries for the three language categories defined in
/// https://material.io/guidelines/style/typography.html.
class MaterialTextGeometry {
/// The name of the English-like script category.
static const String englishLikeCategory = 'English-like';
/// The name of the dense script category.
static const String denseCategory = 'dense';
/// The name of the tall script category.
static const String tallCategory = 'tall';
/// The mapping from script category names to text themes.
static const Map<String, TextTheme> _categoryToTextTheme = const <String, TextTheme>{
englishLikeCategory: englishLike,
denseCategory: dense,
tallCategory: tall,
};
/// Looks up text geometry corresponding to the given [scriptCategoryName].
///
/// Most apps would not call this method directly, but rather call [Theme.of]
/// and use the [TextTheme] fields of the returned [ThemeData] object.
///
/// [scriptCategoryName] must be one of [englishLikeCategory], [denseCategory]
/// and [tallCategory].
///
/// See also:
///
/// * [DefaultMaterialLocalizations.localTextGeometry], which uses this
/// method to look-up text geometry for the current locale.
static TextTheme forScriptCategory(String scriptCategoryName) => _categoryToTextTheme[scriptCategoryName];
/// Defines text geometry for English-like scripts, such as English, French, Russian, etc.
static const TextTheme englishLike = const TextTheme(
display4: const TextStyle(fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.alphabetic),
display3: const TextStyle(fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
display2: const TextStyle(fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
display1: const TextStyle(fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
headline: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
title : const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
subhead : const TextStyle(fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
body2 : const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
body1 : const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
caption : const TextStyle(fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
button : const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
);
/// Defines text geometry for dense scripts, such as Chinese, Japanese, Korean, etc.
static const TextTheme dense = const TextTheme(
display4: const TextStyle(fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic),
display3: const TextStyle(fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
display2: const TextStyle(fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
display1: const TextStyle(fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
headline: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
title : const TextStyle(fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
subhead : const TextStyle(fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
body2 : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
body1 : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
caption : const TextStyle(fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
button : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
);
/// Defines text geometry for tall scripts, such as Farsi, Hindi, Thai, etc.
static const TextTheme tall = const TextTheme(
display4: const TextStyle(fontSize: 112.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
display3: const TextStyle(fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
display2: const TextStyle(fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
display1: const TextStyle(fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
headline: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
title : const TextStyle(fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
subhead : const TextStyle(fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
body2 : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
body1 : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
caption : const TextStyle(fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
button : const TextStyle(fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
);
}
......@@ -401,10 +401,13 @@ class Localizations extends StatefulWidget {
return new List<LocalizationsDelegate<dynamic>>.from(scope.localizationsState.widget.delegates);
}
/// Returns the 'type' localized resources for the widget tree that
/// corresponds to [BuildContext] `context`.
/// Returns the localized resources object of the given `type` for the widget
/// tree that corresponds to the given `context`.
///
/// Returns `null` if no resources object of the given `type` exists within
/// the given `context`.
///
/// This method is typically used by a static factory method on the 'type'
/// This method is typically used by a static factory method on the `type`
/// class. For example Flutter's MaterialLocalizations class looks up Material
/// resources with a method defined like this:
///
......@@ -417,8 +420,7 @@ class Localizations extends StatefulWidget {
assert(context != null);
assert(type != null);
final _LocalizationsScope scope = context.inheritFromWidgetOfExactType(_LocalizationsScope);
assert(scope != null, 'a Localizations ancestor was not found');
return scope.localizationsState.resourcesFor<T>(type);
return scope?.localizationsState?.resourcesFor<T>(type);
}
@override
......
// 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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
void main() {
testWidgets('$MaterialLocalizations localizes text inside the tree', (WidgetTester tester) async {
await tester.pumpWidget(new MaterialApp(
home: new ListView(
children: <Widget>[
new LocalizationTracker(key: const ValueKey<String>('outer')),
new Localizations(
locale: const Locale('zh', 'CN'),
delegates: <LocalizationsDelegate<dynamic>>[
new _MaterialLocalizationsDelegate(
new DefaultMaterialLocalizations(const Locale('zh', 'CN')),
),
const DefaultWidgetsLocalizationsDelegate(),
],
child: new LocalizationTracker(key: const ValueKey<String>('inner')),
),
],
),
));
final LocalizationTrackerState outerTracker = tester.state(find.byKey(const ValueKey<String>('outer')));
expect(outerTracker.captionFontSize, 12.0);
final LocalizationTrackerState innerTracker = tester.state(find.byKey(const ValueKey<String>('inner')));
expect(innerTracker.captionFontSize, 13.0);
});
}
class LocalizationTracker extends StatefulWidget {
LocalizationTracker({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => new LocalizationTrackerState();
}
class LocalizationTrackerState extends State<LocalizationTracker> {
double captionFontSize;
@override
Widget build(BuildContext context) {
captionFontSize = Theme.of(context).textTheme.caption.fontSize;
return new Container();
}
}
// Same as _MaterialLocalizationsDelegate in widgets/app.dart
class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
const _MaterialLocalizationsDelegate(this.localizations);
final MaterialLocalizations localizations;
@override
Future<MaterialLocalizations> load(Locale locale) {
return new SynchronousFuture<MaterialLocalizations>(localizations);
}
@override
bool shouldReload(_MaterialLocalizationsDelegate old) => false;
}
// Same as _WidgetsLocalizationsDelegate in widgets/app.dart
class DefaultWidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
const DefaultWidgetsLocalizationsDelegate();
@override
Future<WidgetsLocalizations> load(Locale locale) {
return new SynchronousFuture<WidgetsLocalizations>(new DefaultWidgetsLocalizations(locale));
}
@override
bool shouldReload(DefaultWidgetsLocalizationsDelegate old) => false;
}
......@@ -4,8 +4,8 @@
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
......@@ -789,8 +789,11 @@ void main() {
});
testWidgets('TextField with default helperStyle', (WidgetTester tester) async {
final ThemeData themeData = new ThemeData(
hintColor: Colors.blue[500],
final ThemeData themeData = ThemeData.localize(
new ThemeData(
hintColor: Colors.blue[500],
),
MaterialTextGeometry.forScriptCategory(MaterialTextGeometry.englishLikeCategory),
);
await tester.pumpWidget(
......
......@@ -53,7 +53,9 @@ void main() {
)
);
expect(Theme.of(capturedContext), equals(new ThemeData.fallback()));
final dynamic localizedTheme = Theme.of(capturedContext);
expect('${localizedTheme.runtimeType}', '_LocalizedThemeData');
expect(localizedTheme.delegate, equals(new ThemeData.fallback()));
expect(Theme.of(capturedContext, shadowThemeOnly: true), isNull);
});
......
......@@ -30,23 +30,27 @@ void main() {
test('Typography on iOS defaults to the correct SF font family based on size', () {
// Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
final Matcher hasCorrectFont = predicate((TextStyle s) {
return s.fontFamily == (s.fontSize <= 19.0 ? '.SF UI Text' : '.SF UI Display');
}, 'Uses SF Display font for font sizes over 19.0, otherwise SF Text font');
final Matcher isDisplayFont = predicate((TextStyle s) {
return s.fontFamily == '.SF UI Display';
}, 'Uses SF Display font');
final Matcher isTextFont = predicate((TextStyle s) {
return s.fontFamily == '.SF UI Text';
}, 'Uses SF Text font');
final Typography typography = new Typography(platform: TargetPlatform.iOS);
for (TextTheme textTheme in <TextTheme>[typography.black, typography.white]) {
expect(textTheme.display4, hasCorrectFont);
expect(textTheme.display3, hasCorrectFont);
expect(textTheme.display2, hasCorrectFont);
expect(textTheme.display1, hasCorrectFont);
expect(textTheme.headline, hasCorrectFont);
expect(textTheme.title, hasCorrectFont);
expect(textTheme.subhead, hasCorrectFont);
expect(textTheme.body2, hasCorrectFont);
expect(textTheme.body1, hasCorrectFont);
expect(textTheme.caption, hasCorrectFont);
expect(textTheme.button, hasCorrectFont);
expect(textTheme.display4, isDisplayFont);
expect(textTheme.display3, isDisplayFont);
expect(textTheme.display2, isDisplayFont);
expect(textTheme.display1, isDisplayFont);
expect(textTheme.headline, isDisplayFont);
expect(textTheme.title, isDisplayFont);
expect(textTheme.subhead, isTextFont);
expect(textTheme.body2, isTextFont);
expect(textTheme.body1, isTextFont);
expect(textTheme.caption, isTextFont);
expect(textTheme.button, isTextFont);
}
});
}
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