Revert "Reversion for roll (#22984)" (#23029)
This reverts commit 80f80ab08c0dad8551c91087cd1017aba094d22c.
diff --git a/dev/tools/gen_localizations.dart b/dev/tools/gen_localizations.dart
index 7419912..2142d6d 100644
--- a/dev/tools/gen_localizations.dart
+++ b/dev/tools/gen_localizations.dart
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This program generates a Dart "localizations" Map definition that combines
-// the contents of the arb files. The map can be used to lookup a localized
-// string: `localizations[localeString][resourceId]`.
+// This program generates a getTranslation() function that looks up the
+// translations contained by the arb files. The returned value is an
+// instance of GlobalMaterialLocalizations that corresponds to a single
+// locale.
//
// The *.arb files are in packages/flutter_localizations/lib/src/l10n.
//
@@ -273,6 +274,8 @@
switch (attributes['x-flutter-type']) {
case 'icuShortTimePattern':
return 'TimeOfDayFormat';
+ case 'scriptCategory':
+ return 'ScriptCategory';
}
}
return 'String';
@@ -308,6 +311,12 @@
'ah:mm': 'TimeOfDayFormat.a_space_h_colon_mm',
};
+const Map<String, String> _scriptCategoryToEnum = <String, String>{
+ 'English-like': 'ScriptCategory.englishLike',
+ 'dense': 'ScriptCategory.dense',
+ 'tall': 'ScriptCategory.tall',
+};
+
/// Returns the literal that describes the value returned by getters
/// with the given attributes.
///
@@ -330,6 +339,15 @@
);
}
return _icuTimeOfDayToEnum[value];
+ case 'scriptCategory':
+ if (!_scriptCategoryToEnum.containsKey(value)) {
+ throw Exception(
+ '"$value" is not one of the scriptCategory values supported '
+ 'by the material library. Here is the list of supported '
+ 'values:\n ' + _scriptCategoryToEnum.keys.join('\n ')
+ );
+ }
+ return _scriptCategoryToEnum[value];
}
}
return generateString(value);
diff --git a/examples/flutter_gallery/lib/demo/typography_demo.dart b/examples/flutter_gallery/lib/demo/typography_demo.dart
index fd2013d..a1e0314 100644
--- a/examples/flutter_gallery/lib/demo/typography_demo.dart
+++ b/examples/flutter_gallery/lib/demo/typography_demo.dart
@@ -57,7 +57,7 @@
TextStyleItem(name: 'Body 2', style: textTheme.body2, text: 'Medium 14sp'),
TextStyleItem(name: 'Body 1', style: textTheme.body1, text: 'Regular 14sp'),
TextStyleItem(name: 'Caption', style: textTheme.caption, text: 'Regular 12sp'),
- TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp')
+ TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp'),
];
if (MediaQuery.of(context).size.width > 500.0) {
diff --git a/examples/flutter_gallery/lib/gallery/themes.dart b/examples/flutter_gallery/lib/gallery/themes.dart
index 5cadd15..7376509 100644
--- a/examples/flutter_gallery/lib/gallery/themes.dart
+++ b/examples/flutter_gallery/lib/gallery/themes.dart
@@ -24,17 +24,23 @@
ThemeData _buildDarkTheme() {
const Color primaryColor = Color(0xFF0175c2);
+ const Color secondaryColor = Color(0xFF13B9FD);
final ThemeData base = ThemeData.dark();
+ final ColorScheme colorScheme = const ColorScheme.dark().copyWith(
+ primary: primaryColor,
+ secondary: secondaryColor,
+ );
return base.copyWith(
primaryColor: primaryColor,
buttonColor: primaryColor,
indicatorColor: Colors.white,
- accentColor: const Color(0xFF13B9FD),
+ accentColor: secondaryColor,
canvasColor: const Color(0xFF202124),
scaffoldBackgroundColor: const Color(0xFF202124),
backgroundColor: const Color(0xFF202124),
errorColor: const Color(0xFFB00020),
- buttonTheme: const ButtonThemeData(
+ buttonTheme: ButtonThemeData(
+ colorScheme: colorScheme,
textTheme: ButtonTextTheme.primary,
),
textTheme: _buildTextTheme(base.textTheme),
@@ -45,19 +51,26 @@
ThemeData _buildLightTheme() {
const Color primaryColor = Color(0xFF0175c2);
+ const Color secondaryColor = Color(0xFF13B9FD);
+ final ColorScheme colorScheme = const ColorScheme.light().copyWith(
+ primary: primaryColor,
+ secondary: secondaryColor,
+ );
final ThemeData base = ThemeData.light();
return base.copyWith(
+ colorScheme: colorScheme,
primaryColor: primaryColor,
buttonColor: primaryColor,
indicatorColor: Colors.white,
splashColor: Colors.white24,
splashFactory: InkRipple.splashFactory,
- accentColor: const Color(0xFF13B9FD),
+ accentColor: secondaryColor,
canvasColor: Colors.white,
scaffoldBackgroundColor: Colors.white,
backgroundColor: Colors.white,
errorColor: const Color(0xFFB00020),
- buttonTheme: const ButtonThemeData(
+ buttonTheme: ButtonThemeData(
+ colorScheme: colorScheme,
textTheme: ButtonTextTheme.primary,
),
textTheme: _buildTextTheme(base.textTheme),
diff --git a/examples/flutter_gallery/test/accessibility_test.dart b/examples/flutter_gallery/test/accessibility_test.dart
index ab4d345..27a3c51 100644
--- a/examples/flutter_gallery/test/accessibility_test.dart
+++ b/examples/flutter_gallery/test/accessibility_test.dart
@@ -649,12 +649,14 @@
handle.dispose();
});
- testWidgets('overscroll_demo $themeName', (WidgetTester tester) async {
- final SemanticsHandle handle = tester.ensureSemantics();
- await tester.pumpWidget(MaterialApp(theme: theme, home: const OverscrollDemo()));
- await expectLater(tester, meetsGuideline(textContrastGuideline));
- handle.dispose();
- });
+ testWidgets('overscroll_demo', (WidgetTester tester) async {
+ final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
+ binding.addTime(const Duration(seconds: 3));
+ final SemanticsHandle handle = tester.ensureSemantics();
+ await tester.pumpWidget(const MaterialApp(home: OverscrollDemo()));
+ await expectLater(tester, meetsGuideline(textContrastGuideline));
+ handle.dispose();
+ });
testWidgets('page_selector_demo $themeName', (WidgetTester tester) async {
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart
index 82daf1d..1abaa73 100644
--- a/packages/flutter/lib/material.dart
+++ b/packages/flutter/lib/material.dart
@@ -32,6 +32,7 @@
export 'src/material/chip.dart';
export 'src/material/chip_theme.dart';
export 'src/material/circle_avatar.dart';
+export 'src/material/color_scheme.dart';
export 'src/material/colors.dart';
export 'src/material/constants.dart';
export 'src/material/data_table.dart';
@@ -65,6 +66,7 @@
export 'src/material/input_decorator.dart';
export 'src/material/list_tile.dart';
export 'src/material/material.dart';
+export 'src/material/material_button.dart';
export 'src/material/material_localizations.dart';
export 'src/material/mergeable_material.dart';
export 'src/material/outline_button.dart';
@@ -95,6 +97,7 @@
export 'src/material/text_field.dart';
export 'src/material/text_form_field.dart';
export 'src/material/text_selection.dart';
+export 'src/material/text_theme.dart';
export 'src/material/theme.dart';
export 'src/material/theme_data.dart';
export 'src/material/time.dart';
diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart
index dec704f..b3883ae 100644
--- a/packages/flutter/lib/src/material/app_bar.dart
+++ b/packages/flutter/lib/src/material/app_bar.dart
@@ -19,8 +19,8 @@
import 'material_localizations.dart';
import 'scaffold.dart';
import 'tabs.dart';
+import 'text_theme.dart';
import 'theme.dart';
-import 'typography.dart';
// Examples can assume:
// void _airDress() { }
diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart
index 1512494..5840c0e 100644
--- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart
+++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart
@@ -14,8 +14,8 @@
import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
+import 'text_theme.dart';
import 'theme.dart';
-import 'typography.dart';
const double _kActiveFontSize = 14.0;
const double _kInactiveFontSize = 12.0;
diff --git a/packages/flutter/lib/src/material/button.dart b/packages/flutter/lib/src/material/button.dart
index 7f75ee4..e0c7706 100644
--- a/packages/flutter/lib/src/material/button.dart
+++ b/packages/flutter/lib/src/material/button.dart
@@ -9,7 +9,6 @@
import 'package:flutter/widgets.dart';
import 'button_theme.dart';
-import 'colors.dart';
import 'constants.dart';
import 'ink_well.dart';
import 'material.dart';
@@ -225,238 +224,6 @@
}
}
-/// A utility class for building Material buttons that depend on the
-/// ambient [ButtonTheme] and [Theme].
-///
-/// The button's size will expand to fit the child widget, if necessary.
-///
-/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
-/// an enabled button, make sure to pass a non-null value for onPressed.
-///
-/// Rather than using this class directly, consider using [FlatButton] or
-/// [RaisedButton], which configure this class with appropriate defaults that
-/// match the material design specification.
-///
-/// To create a button directly, without inheriting theme defaults, use
-/// [RawMaterialButton].
-///
-/// If you want an ink-splash effect for taps, but don't want to use a button,
-/// consider using [InkWell] directly.
-///
-/// See also:
-///
-/// * [IconButton], to create buttons that contain icons rather than text.
-class MaterialButton extends StatelessWidget {
- /// Creates a material button.
- ///
- /// Rather than creating a material button directly, consider using
- /// [FlatButton] or [RaisedButton]. To create a custom Material button
- /// consider using [RawMaterialButton].
- ///
- /// The [clipBehavior] argument must not be null.
- const MaterialButton({
- Key key,
- this.colorBrightness,
- this.textTheme,
- this.textColor,
- this.color,
- this.highlightColor,
- this.splashColor,
- this.elevation,
- this.highlightElevation,
- this.minWidth,
- this.height,
- this.padding,
- this.materialTapTargetSize,
- this.clipBehavior = Clip.none,
- @required this.onPressed,
- this.child
- }) : assert(clipBehavior != null), super(key: key);
-
- /// The theme brightness to use for this button.
- ///
- /// Defaults to the brightness from [ThemeData.brightness].
- final Brightness colorBrightness;
-
- /// Defines the button's base colors, and the defaults for the button's minimum
- /// size, internal padding, and shape.
- final ButtonTextTheme textTheme;
-
- /// The color to use for this button's text.
- final Color textColor;
-
- /// The button's fill color, displayed by its [Material], while the button
- /// is in its default (unpressed, enabled) state.
- ///
- /// Defaults to null, meaning that the color is automatically derived from the [Theme].
- ///
- /// Typically, a material design color will be used, as follows:
- ///
- /// ```dart
- /// MaterialButton(
- /// color: Colors.blue[500],
- /// onPressed: _handleTap,
- /// child: Text('DEMO'),
- /// ),
- /// ```
- final Color color;
-
- /// The primary color of the button when the button is in the down (pressed)
- /// state.
- ///
- /// The splash is represented as a circular overlay that appears above the
- /// [highlightColor] overlay. The splash overlay has a center point that
- /// matches the hit point of the user touch event. The splash overlay will
- /// expand to fill the button area if the touch is held for long enough time.
- /// If the splash color has transparency then the highlight and button color
- /// will show through.
- ///
- /// Defaults to the Theme's splash color, [ThemeData.splashColor].
- final Color splashColor;
-
- /// The secondary color of the button when the button is in the down (pressed)
- /// state.
- ///
- /// The highlight color is represented as a solid color that is overlaid over
- /// the button color (if any). If the highlight color has transparency, the
- /// button color will show through. The highlight fades in quickly as the
- /// button is held down.
- ///
- /// Defaults to the Theme's highlight color, [ThemeData.highlightColor].
- final Color highlightColor;
-
- /// The z-coordinate at which to place this button. This controls the size of
- /// the shadow below the button.
- ///
- /// Defaults to 0.
- ///
- /// See also:
- ///
- /// * [FlatButton], a material button specialized for the case where the
- /// elevation is zero.
- /// * [RaisedButton], a material button specialized for the case where the
- /// elevation is non-zero.
- final double elevation;
-
- /// The z-coordinate at which to place this button when highlighted. This
- /// controls the size of the shadow below the button.
- ///
- /// Defaults to 0.
- ///
- /// See also:
- ///
- /// * [elevation], the default elevation.
- final double highlightElevation;
-
- /// The smallest horizontal extent that the button will occupy.
- ///
- /// Defaults to the value from the current [ButtonTheme].
- final double minWidth;
-
- /// The vertical extent of the button.
- ///
- /// Defaults to the value from the current [ButtonTheme].
- final double height;
-
- /// The internal padding for the button's [child].
- ///
- /// Defaults to the value from the current [ButtonTheme],
- /// [ButtonThemeData.padding].
- final EdgeInsetsGeometry padding;
-
- /// The callback that is called when the button is tapped or otherwise activated.
- ///
- /// If this is set to null, the button will be disabled.
- final VoidCallback onPressed;
-
- /// The widget below this widget in the tree.
- ///
- /// {@macro flutter.widgets.child}
- final Widget child;
-
- /// Configures the minimum size of the tap target.
- ///
- /// Defaults to [ThemeData.materialTapTargetSize].
- ///
- /// See also:
- ///
- /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
- final MaterialTapTargetSize materialTapTargetSize;
-
- /// {@macro flutter.widgets.Clip}
- final Clip clipBehavior;
-
- /// Whether the button is enabled or disabled. Buttons are disabled by default. To
- /// enable a button, set its [onPressed] property to a non-null value.
- bool get enabled => onPressed != null;
-
- Brightness _getBrightness(ThemeData theme) {
- return colorBrightness ?? theme.brightness;
- }
-
- ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
- return textTheme ?? buttonTheme.textTheme;
- }
-
- Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
- if (textColor != null)
- return textColor;
-
- final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
- final bool fillIsDark = fillColor != null
- ? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
- : themeIsDark;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- return enabled
- ? (themeIsDark ? Colors.white : Colors.black87)
- : theme.disabledColor;
- case ButtonTextTheme.accent:
- return enabled
- ? theme.accentColor
- : theme.disabledColor;
- case ButtonTextTheme.primary:
- return enabled
- ? (fillIsDark ? Colors.white : Colors.black)
- : (themeIsDark ? Colors.white30 : Colors.black38);
- }
- return null;
- }
-
- @override
- Widget build(BuildContext context) {
- final ThemeData theme = Theme.of(context);
- final ButtonThemeData buttonTheme = ButtonTheme.of(context);
- final Color textColor = _getTextColor(theme, buttonTheme, color);
-
- return RawMaterialButton(
- onPressed: onPressed,
- fillColor: color,
- textStyle: theme.textTheme.button.copyWith(color: textColor),
- highlightColor: highlightColor ?? theme.highlightColor,
- splashColor: splashColor ?? theme.splashColor,
- elevation: elevation ?? 2.0,
- highlightElevation: highlightElevation ?? 8.0,
- padding: padding ?? buttonTheme.padding,
- constraints: buttonTheme.constraints.copyWith(
- minWidth: minWidth,
- minHeight: height,
- ),
- shape: buttonTheme.shape,
- child: child,
- materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
- clipBehavior: clipBehavior,
- );
- }
-
- @override
- void debugFillProperties(DiagnosticPropertiesBuilder properties) {
- super.debugFillProperties(properties);
- properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
- }
-}
-
/// A widget to pad the area around a [MaterialButton]'s inner [Material].
///
/// Redirect taps that occur in the padded area around the child to the center
diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart
index 7f4ae92..77ca466 100644
--- a/packages/flutter/lib/src/material/button_theme.dart
+++ b/packages/flutter/lib/src/material/button_theme.dart
@@ -5,7 +5,15 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
+import 'color_scheme.dart';
+import 'colors.dart';
+import 'constants.dart';
+import 'flat_button.dart';
+import 'material_button.dart';
+import 'outline_button.dart';
+import 'raised_button.dart';
import 'theme.dart';
+import 'theme_data.dart' show MaterialTapTargetSize;
/// Used with [ButtonTheme] and [ButtonThemeData] to define a button's base
/// colors, and the defaults for the button's minimum size, internal padding,
@@ -13,8 +21,8 @@
///
/// See also:
///
-/// * [RaisedButton], which styles itself based on the ambient [ButtonTheme].
-/// * [FlatButton], which styles itself based on the ambient [ButtonTheme].
+/// * [RaisedButton], [FlatButton], [OutlineButton], which are configured
+/// based on the ambient [ButtonTheme].
enum ButtonTextTheme {
/// Button text is black or white depending on [ThemeData.brightness].
normal,
@@ -46,30 +54,19 @@
/// can be overridden with [ButtonTheme].
///
/// The actual appearance of buttons depends on the button theme, the
-/// button's enabled state, its elevation (if any) and the overall Material
-/// theme.
+/// button's enabled state, its elevation (if any), and the overall [Theme].
///
/// See also:
///
-/// * [FlatButton] and [RaisedButton], which are styled based on the
-/// ambient button theme.
-/// * [ThemeData.textTheme], `button` is the default text style for button labels.
-/// * [ThemeData.buttonColor], the fill color for [RaisedButton]s unless the
-/// button theme's text theme is [ButtonTextTheme.primary].
-/// * [ThemeData.primaryColor], the fill or text color if a button theme's text
-/// theme is [ButtonTextTheme.primary].
-/// * [ThemeData.accentColor], the text color for buttons when button theme's
-/// text theme is [ButtonTextTheme.accent].
-/// * [ThemeData.disabled], the default text color for disabled buttons.
-/// * [ThemeData.brightness], used to select contrasting text and fill colors.
-/// * [ThemeData.highlightColor], a button [InkWell]'s default highlight color.
-/// * [ThemeData.splashColor], a button [InkWell]'s default splash color.
+/// * [FlatButton] [RaisedButton], and [OutlineButton], which are styled
+/// based on the ambient button theme.
/// * [RawMaterialButton], which can be used to configure a button that doesn't
/// depend on any inherited themes.
class ButtonTheme extends InheritedWidget {
/// Creates a button theme.
///
- /// The [textTheme], [minWidth], and [height] arguments must not be null.
+ /// The [textTheme], [minWidth], [height], and [colorScheme] arguments
+ /// must not be null.
ButtonTheme({
Key key,
ButtonTextTheme textTheme = ButtonTextTheme.normal,
@@ -79,6 +76,12 @@
EdgeInsetsGeometry padding,
ShapeBorder shape,
bool alignedDropdown = false,
+ Color buttonColor,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ ColorScheme colorScheme,
+ MaterialTapTargetSize materialTapTargetSize,
Widget child,
}) : assert(textTheme != null),
assert(minWidth != null && minWidth >= 0.0),
@@ -93,6 +96,12 @@
shape: shape,
alignedDropdown: alignedDropdown,
layoutBehavior: layoutBehavior,
+ buttonColor: buttonColor,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorScheme: colorScheme,
+ materialTapTargetSize: materialTapTargetSize,
),
super(key: key, child: child);
@@ -128,6 +137,11 @@
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0),
ShapeBorder shape,
bool alignedDropdown = false,
+ Color buttonColor,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ ColorScheme colorScheme,
Widget child,
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
}) : assert(textTheme != null),
@@ -142,6 +156,11 @@
shape: shape,
alignedDropdown: alignedDropdown,
layoutBehavior: layoutBehavior,
+ buttonColor: buttonColor,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorScheme: colorScheme,
),
super(key: key, child: child);
@@ -156,8 +175,19 @@
/// ButtonThemeData theme = ButtonTheme.of(context);
/// ```
static ButtonThemeData of(BuildContext context) {
- final ButtonTheme result = context.inheritFromWidgetOfExactType(ButtonTheme);
- return result?.data ?? Theme.of(context).buttonTheme;
+ final ButtonTheme inheritedButtonTheme = context.inheritFromWidgetOfExactType(ButtonTheme);
+ ButtonThemeData buttonTheme = inheritedButtonTheme?.data;
+ if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null
+ final ThemeData theme = Theme.of(context);
+ buttonTheme ??= theme.buttonTheme;
+ if (buttonTheme.colorScheme == null) {
+ buttonTheme = buttonTheme.copyWith(
+ colorScheme: theme.buttonTheme.colorScheme ?? theme.colorScheme,
+ );
+ assert(buttonTheme.colorScheme != null);
+ }
+ }
+ return buttonTheme;
}
@override
@@ -173,7 +203,13 @@
/// Create a button theme object that can be used with [ButtonTheme]
/// or [ThemeData].
///
- /// The [textTheme], [minWidth], and [height] parameters must not be null.
+ /// The [textTheme], [minWidth], [height], [alignedDropDown], and
+ /// [layoutBehavior] parameters must not be null. The [minWidth] and
+ /// [height] parameters must greater than or equal to zero.
+ ///
+ /// The ButtonTheme's methods that have a [MaterialButton] parameter and
+ /// have a name with a `get` prefix are used by [RaisedButton],
+ /// [OutlineButton], and [FlatButton] to configure a [RawMaterialButton].
const ButtonThemeData({
this.textTheme = ButtonTextTheme.normal,
this.minWidth = 88.0,
@@ -182,13 +218,24 @@
ShapeBorder shape,
this.layoutBehavior = ButtonBarLayoutBehavior.padded,
this.alignedDropdown = false,
+ Color buttonColor,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ this.colorScheme,
+ MaterialTapTargetSize materialTapTargetSize,
}) : assert(textTheme != null),
assert(minWidth != null && minWidth >= 0.0),
assert(height != null && height >= 0.0),
assert(alignedDropdown != null),
assert(layoutBehavior != null),
+ _buttonColor = buttonColor,
+ _disabledColor = disabledColor,
+ _highlightColor = highlightColor,
+ _splashColor = splashColor,
_padding = padding,
- _shape = shape;
+ _shape = shape,
+ _materialTapTargetSize = materialTapTargetSize;
/// The minimum width for buttons.
///
@@ -205,10 +252,13 @@
/// Defines a button's base colors, and the defaults for the button's minimum
/// size, internal padding, and shape.
+ ///
+ /// Despite the name, this property is not a [TextTheme], its value is not a
+ /// collection of [TextStyle]s.
final ButtonTextTheme textTheme;
- /// Defines whether a button bar should size itself with a minimum size
- /// constraint or padding.
+ /// Defines whether a [ButtonBar] should size itself with a minimum size
+ /// constraint or with padding.
///
/// Defaults to [ButtonBarLayoutBehavior.padded].
final ButtonBarLayoutBehavior layoutBehavior;
@@ -232,16 +282,22 @@
///
/// Defaults to 24.0 on the left and right if [textTheme] is
/// [ButtonTextTheme.primary], 16.0 on the left and right otherwise.
+ ///
+ /// See also:
+ ///
+ /// * [getPadding], which is used by [RaisedButton], [OutlineButton]
+ /// and [FlatButton].
EdgeInsetsGeometry get padding {
if (_padding != null)
return _padding;
- switch (textTheme) {
+ switch (textTheme) {
case ButtonTextTheme.normal:
case ButtonTextTheme.accent:
return const EdgeInsets.symmetric(horizontal: 16.0);
case ButtonTextTheme.primary:
- return const EdgeInsets.symmetric(horizontal: 24.0);
+ return const EdgeInsets.symmetric(horizontal: 24.0);
}
+ assert(false);
return EdgeInsets.zero;
}
final EdgeInsetsGeometry _padding;
@@ -255,6 +311,11 @@
/// Defaults to a rounded rectangle with circular corner radii of 4.0 if
/// [textTheme] is [ButtonTextTheme.primary], a rounded rectangle with
/// circular corner radii of 2.0 otherwise.
+ ///
+ /// See also:
+ ///
+ /// * [getShape], which is used by [RaisedButton], [OutlineButton]
+ /// and [FlatButton].
ShapeBorder get shape {
if (_shape != null)
return _shape;
@@ -284,23 +345,417 @@
/// This property only affects [DropdownButton] and its menu.
final bool alignedDropdown;
+ /// The background fill color for [RaisedButton]s.
+ ///
+ /// This property is null by default.
+ ///
+ /// See also:
+ ///
+ /// * [getFillColor], which is used by [RaisedButton] to compute its
+ /// background fill color.
+ final Color _buttonColor;
+
+ /// The background fill color for disabled [RaisedButton]s.
+ ///
+ /// This property is null by default.
+ ///
+ /// See also:
+ ///
+ /// * [getDisabledFillColor], which is used by [RaisedButton] to compute its
+ /// background fill color.
+ final Color _disabledColor;
+
+ /// The color of the overlay that appears when a button is pressed.
+ ///
+ /// This property is null by default.
+ ///
+ /// See also:
+ ///
+ /// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton]
+ /// and [FlatButton].
+ final Color _highlightColor;
+
+ /// The color of the ink "splash" overlay that appears when a button is tapped.
+ ///
+ /// This property is null by default.
+ ///
+ /// See also:
+ ///
+ /// * [getSplashColor], which is used by [RaisedButton], [OutlineButton]
+ /// and [FlatButton].
+ final Color _splashColor;
+
+ /// A set of thirteen colors that can be used to derive the button theme's
+ /// colors.
+ ///
+ /// This property was added much later than the theme's set of highly
+ /// specific colors, like [ThemeData.buttonColor], [ThemeData.highlightColor],
+ /// [ThemeData.splashColor] etc.
+ ///
+ /// The colors for new button classes can be defined exclusively in terms
+ /// of [colorScheme]. When it's possible, the existing buttons will
+ /// (continue to) gradually migrate to it.
+ final ColorScheme colorScheme;
+
+ // The minimum size of a button's tap target.
+ //
+ // This property is null by default.
+ //
+ // See also:
+ //
+ // * [getMaterialTargetTapSize], which is used by [RaisedButton],
+ // [OutlineButton] and [FlatButton].
+ final MaterialTapTargetSize _materialTapTargetSize;
+
+ /// The [button]'s overall brightness.
+ ///
+ /// Returns the button's [MaterialButton.colorBrightness] if it is non-null,
+ /// otherwise the color scheme's [ColorScheme.brightness] is returned.
+ Brightness getBrightness(MaterialButton button) {
+ return button.colorBrightness ?? colorScheme.brightness;
+ }
+
+ /// Defines the [button]'s base colors, and the defaults for the button's
+ /// minimum size, internal padding, and shape.
+ ///
+ /// Despite the name, this property is not the [TextTheme] whose
+ /// [TextTheme.button] is used as the button text's [TextStyle].
+ ButtonTextTheme getTextTheme(MaterialButton button) {
+ return button.textTheme ?? textTheme;
+ }
+
+ Color _getDisabledColor(MaterialButton button) {
+ return getBrightness(button) == Brightness.dark
+ ? colorScheme.onSurface.withOpacity(0.30) // default == Colors.white30
+ : colorScheme.onSurface.withOpacity(0.38); // default == Colors.black38;
+ }
+
+ /// The foreground color of the [button]'s text and icon when
+ /// [MaterialButton.onPressed] is null (when MaterialButton.enabled is false).
+ ///
+ /// Returns the button's [MaterialButton.disabledColor] if it is non-null.
+ /// Otherwise the color scheme's [ColorScheme.onSurface] color is returned
+ /// with its opacity set to 0.30 if [getBrightness] is dark, 0.38 otherwise.
+ Color getDisabledTextColor(MaterialButton button) {
+ if (button.disabledTextColor != null)
+ return button.disabledTextColor;
+ return _getDisabledColor(button);
+ }
+
+ /// The [button]'s background color when [MaterialButton.onPressed] is null
+ /// (when MaterialButton.enabled is false).
+ ///
+ /// Returns the button's [MaterialButton.disabledColor] if it is non-null.
+ ///
+ /// Otherwise the the value of the `disabledColor` constructor parameter
+ /// is returned, if it is non-null.
+ ///
+ /// Otherwise the color scheme's [ColorScheme.onSurface] color is returned
+ /// with its opacity set to 0.3 if [getBrightness] is dark, 0.38 otherwise.
+ Color getDisabledFillColor(MaterialButton button) {
+ if (button.disabledColor != null)
+ return button.disabledColor;
+ if (_disabledColor != null)
+ return _disabledColor;
+ return _getDisabledColor(button);
+ }
+
+ /// The button's background fill color or null for buttons that don't have
+ /// a background color.
+ ///
+ /// Returns [MaterialButton.color] if it is non-null and the button
+ /// is enabled.
+ ///
+ /// Otherwise, returns [MaterialButton.disabledColor] if it is non-null and
+ /// the button is disabled.
+ ///
+ /// Otherwise, if button is a [FlatButton] or an [OutlineButton] then null is
+ /// returned.
+ ///
+ /// Otherwise, if button is a [RaisedButton], returns the `buttonColor`
+ /// constructor parameter if it was non-null and the button is enabled.
+ ///
+ /// Otherwise the fill color depends on the value of [getTextTheme].
+ ///
+ /// * [ButtonTextTheme.normal] or [ButtonTextTheme.accent], the
+ /// color scheme's [ColorScheme.primary] color if the [button] is enabled
+ /// the value of [getDisabledFillColor] otherwise.
+ /// * [ButtonTextTheme.primary], if the [button] is enabled then the value
+ /// of the `buttonColor` constructor parameter if it is non-null,
+ /// otherwise the color scheme's ColorScheme.primary color. If the button
+ /// is not enabled then the colorScheme's [ColorScheme.onSurface] color
+ /// with opacity 0.12.
+ Color getFillColor(MaterialButton button) {
+ final Color fillColor = button.enabled ? button.color : button.disabledColor;
+ if (fillColor != null)
+ return fillColor;
+
+ if (button is FlatButton || button is OutlineButton)
+ return null;
+
+ if (button.enabled && button is RaisedButton && _buttonColor != null)
+ return _buttonColor;
+
+ switch (getTextTheme(button)) {
+ case ButtonTextTheme.normal:
+ case ButtonTextTheme.accent:
+ return button.enabled ? colorScheme.primary : getDisabledFillColor(button);
+ case ButtonTextTheme.primary:
+ return button.enabled
+ ? _buttonColor ?? colorScheme.primary
+ : colorScheme.onSurface.withOpacity(0.12);
+ }
+
+ assert(false);
+ return null;
+ }
+
+ /// The foreground color of the [button]'s text and icon.
+ ///
+ /// If [button] is not [MaterialButton.enabled], the value of
+ /// [getDisabledTextColor] is returned. If the button is enabled and
+ /// [buttonTextColor] is non-null, then [buttonTextColor] is returned.
+ ///
+ /// Otherwise the text color depends on the value of [getTextTheme]
+ /// and [getBrightness].
+ ///
+ /// * [ButtonTextTheme.normal], [Colors.white] if [getBrightness] is dark,
+ /// otherwise [Colors.black87].
+ /// * ButtonTextTheme.accent], [colorScheme.secondary].
+ /// * [ButtonTextTheme.primary], if [getFillColor] is dark then [Colors.white],
+ /// otherwise if [button] is a [FlatButton] or an [OutlineButton] then
+ /// [colorScheme.primary], otherwise [Colors.black].
+ Color getTextColor(MaterialButton button) {
+ if (!button.enabled)
+ return getDisabledTextColor(button);
+
+ if (button.textColor != null)
+ return button.textColor;
+
+ switch (getTextTheme(button)) {
+ case ButtonTextTheme.normal:
+ return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87;
+
+ case ButtonTextTheme.accent:
+ return colorScheme.secondary;
+
+ case ButtonTextTheme.primary: {
+ final Color fillColor = getFillColor(button);
+ final bool fillIsDark = fillColor != null
+ ? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
+ : getBrightness(button) == Brightness.dark;
+ if (fillIsDark)
+ return Colors.white;
+ if (button is FlatButton || button is OutlineButton)
+ return colorScheme.primary;
+ return Colors.black;
+ }
+ }
+
+ assert(false);
+ return null;
+ }
+
+ /// The color of the ink "splash" overlay that appears when the (enabled)
+ /// [button] is tapped.
+ ///
+ /// Returns the button's [MaterialButton.splashColor] if it is non-null.
+ ///
+ /// Otherwise, returns the value of the `splashColor` constructor parameter
+ /// it is non-null and [button] is a [RaisedButton] or an [OutlineButton].
+ ///
+ /// Otherwise, returns the value of the `splashColor` constructor parameter
+ /// if it is non-null and [button] is a [FlatButton] and
+ /// [getTextTheme] is not [ButtonTextTheme.primary]
+ ///
+ /// Otherwise, returns [getTextColor] with an opacity of 0.12.
+ Color getSplashColor(MaterialButton button) {
+ if (button.splashColor != null)
+ return button.splashColor;
+
+ if (_splashColor != null && (button is RaisedButton || button is OutlineButton))
+ return _splashColor;
+
+ if (_splashColor != null && button is FlatButton) {
+ switch (getTextTheme(button)) {
+ case ButtonTextTheme.normal:
+ case ButtonTextTheme.accent:
+ return _splashColor;
+ case ButtonTextTheme.primary:
+ break;
+ }
+ }
+
+ return getTextColor(button).withOpacity(0.12);
+ }
+
+ /// The color of the overlay that appears when the [button] is pressed.
+ ///
+ /// Returns the button's [MaterialButton.highlightColor] if it is non-null.
+ /// Otherwise the highlight color depends on [getTextTheme]:
+ ///
+ /// * [ButtonTextTheme.normal], [ButtonTextTheme.accent]: returns the
+ /// value of the `highlightColor` constructor parameter if it is non-null,
+ /// otherwise the value of [getTextColor] with opacity 0.16.
+ /// * [ButtonTextTheme.primary], returns [Colors.transparent].
+ Color getHighlightColor(MaterialButton button) {
+ if (button.highlightColor != null)
+ return button.highlightColor;
+
+ switch (getTextTheme(button)) {
+ case ButtonTextTheme.normal:
+ case ButtonTextTheme.accent:
+ return _highlightColor ?? getTextColor(button).withOpacity(0.16);
+ case ButtonTextTheme.primary:
+ return Colors.transparent;
+ }
+
+ assert(false);
+ return Colors.transparent;
+ }
+
+ /// The [button]'s elevation when it is enabled and has not been pressed.
+ ///
+ /// Returns the button's [MaterialButton.elevation] if it is non-null.
+ ///
+ /// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0.
+ double getElevation(MaterialButton button) {
+ if (button.elevation != null)
+ return button.elevation;
+ if (button is FlatButton)
+ return 0.0;
+ return 2.0;
+ }
+
+ /// The [button]'s elevation when it is enabled and has been pressed.
+ ///
+ /// Returns the button's [MaterialButton.highlightElevation] if it is non-null.
+ ///
+ /// If button is a [FlatButton] then the highlight elevation is 0.0, if it's
+ /// a [OutlineButton] then the highlight elevation is 2.0, otherise the
+ /// highlight elevation is 8.0.
+ double getHighlightElevation(MaterialButton button) {
+ if (button.highlightElevation != null)
+ return button.highlightElevation;
+ if (button is FlatButton)
+ return 0.0;
+ if (button is OutlineButton)
+ return 2.0;
+ return 8.0;
+ }
+
+ /// The [button]'s elevation when [MaterialButton.onPressed] is null (when
+ /// MaterialButton.enabled is false).
+ ///
+ /// Returns the button's [MaterialButton.elevation] if it is non-null.
+ ///
+ /// Otheriwse the disabled elevation is 0.0.
+ double getDisabledElevation(MaterialButton button) {
+ if (button.disabledElevation != null)
+ return button.disabledElevation;
+ return 0.0;
+ }
+
+ /// Padding for the [button]'s child (typically the button's label).
+ ///
+ /// Returns the button's [MaterialButton.padding] if it is non-null.
+ ///
+ /// If this is a button constructed with [RaisedButton.icon] or
+ /// [FlatButton.icon] or [OutlineButton.icon] then the padding is:
+ /// `EdgeInsetsDirectional.only(start: 12.0, end: 16.0)`.
+ ///
+ /// Otherwise, returns [padding] if it is non-null.
+ ///
+ /// Otherwise, returns horizontal padding of 24.0 on the left and right if
+ /// [getTextTheme] is [ButtonTextTheme.primary], 16.0 on the left and right
+ /// otherwise.
+ EdgeInsetsGeometry getPadding(MaterialButton button) {
+ if (button.padding != null)
+ return button.padding;
+
+ if (button is MaterialButtonWithIconMixin)
+ return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0);
+
+ if (_padding != null)
+ return _padding;
+
+ switch (getTextTheme(button)) {
+ case ButtonTextTheme.normal:
+ case ButtonTextTheme.accent:
+ return const EdgeInsets.symmetric(horizontal: 16.0);
+ case ButtonTextTheme.primary:
+ return const EdgeInsets.symmetric(horizontal: 24.0);
+ }
+ assert(false);
+ return EdgeInsets.zero;
+ }
+
+ /// The shape of the [button]'s [Material].
+ ///
+ /// Returns the button's [MaterialButton.shape] if it is non-null, otherwise
+ /// [shape] is returned.
+ ShapeBorder getShape(MaterialButton button) {
+ return button.shape ?? shape;
+ }
+
+ /// The duration of the [button]'s highlight animation.
+ ///
+ /// Returns the button's [MaterialButton.animationDuration] it if is non-null,
+ /// otherwise 200ms.
+ Duration getAnimationDuration(MaterialButton button) {
+ return button.animationDuration ?? kThemeChangeDuration;
+ }
+
+ /// The [BoxConstraints] that the define the [button]'s size.
+ ///
+ /// By default this method just returns [constraints]. Subclasses
+ /// could override this method to return a value that was,
+ /// for example, based on the button's type.
+ BoxConstraints getConstraints(MaterialButton button) => constraints;
+
+ /// The minimum size of the [button]'s tap target.
+ ///
+ /// Returns the button's [MaterialButton.tapTargetSize] if it is non-null.
+ ///
+ /// Otherwise the value of the [materialTapTargetSize] constructor
+ /// parameter is returned if that's non-null.
+ ///
+ /// Otherwise [MaterialTapTargetSize.padded] is returned.
+ MaterialTapTargetSize getMaterialTapTargetSize(MaterialButton button) {
+ return button.materialTapTargetSize ?? _materialTapTargetSize ?? MaterialTapTargetSize.padded;
+ }
+
/// Creates a copy of this button theme data object with the matching fields
/// replaced with the non-null parameter values.
ButtonThemeData copyWith({
ButtonTextTheme textTheme,
+ ButtonBarLayoutBehavior layoutBehavior,
double minWidth,
double height,
EdgeInsetsGeometry padding,
ShapeBorder shape,
bool alignedDropdown,
+ Color buttonColor,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ ColorScheme colorScheme,
+ MaterialTapTargetSize materialTapTargetSize,
}) {
return ButtonThemeData(
textTheme: textTheme ?? this.textTheme,
+ layoutBehavior: layoutBehavior ?? this.layoutBehavior,
minWidth: minWidth ?? this.minWidth,
height: height ?? this.height,
padding: padding ?? this.padding,
shape: shape ?? this.shape,
alignedDropdown: alignedDropdown ?? this.alignedDropdown,
+ buttonColor: buttonColor ?? _buttonColor,
+ disabledColor: disabledColor ?? _disabledColor,
+ highlightColor: highlightColor ?? _highlightColor,
+ splashColor: splashColor ?? _splashColor,
+ colorScheme: colorScheme ?? this.colorScheme,
+ materialTapTargetSize: materialTapTargetSize ?? _materialTapTargetSize,
);
}
@@ -314,7 +769,13 @@
&& height == typedOther.height
&& padding == typedOther.padding
&& shape == typedOther.shape
- && alignedDropdown == typedOther.alignedDropdown;
+ && alignedDropdown == typedOther.alignedDropdown
+ && _buttonColor == typedOther._buttonColor
+ && _disabledColor == typedOther._disabledColor
+ && _highlightColor == typedOther._highlightColor
+ && _splashColor == typedOther._splashColor
+ && colorScheme == typedOther.colorScheme
+ && _materialTapTargetSize == typedOther._materialTapTargetSize;
}
@override
@@ -326,6 +787,12 @@
padding,
shape,
alignedDropdown,
+ _buttonColor,
+ _disabledColor,
+ _highlightColor,
+ _splashColor,
+ colorScheme,
+ _materialTapTargetSize,
);
}
@@ -343,5 +810,11 @@
defaultValue: defaultTheme.alignedDropdown,
ifTrue: 'dropdown width matches button',
));
+ properties.add(DiagnosticsProperty<Color>('buttonColor', _buttonColor, defaultValue: null));
+ properties.add(DiagnosticsProperty<Color>('disabledColor', _disabledColor, defaultValue: null));
+ properties.add(DiagnosticsProperty<Color>('highlightColor', _highlightColor, defaultValue: null));
+ properties.add(DiagnosticsProperty<Color>('splashColor', _splashColor, defaultValue: null));
+ properties.add(DiagnosticsProperty<ColorScheme>('colorScheme', colorScheme, defaultValue: defaultTheme.colorScheme));
+ properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', _materialTapTargetSize, defaultValue: null));
}
}
diff --git a/packages/flutter/lib/src/material/color_scheme.dart b/packages/flutter/lib/src/material/color_scheme.dart
new file mode 100644
index 0000000..b3f289f
--- /dev/null
+++ b/packages/flutter/lib/src/material/color_scheme.dart
@@ -0,0 +1,324 @@
+// 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/foundation.dart';
+import 'package:flutter/services.dart' show Brightness;
+import 'package:flutter/widgets.dart';
+
+import 'colors.dart';
+import 'theme_data.dart';
+
+/// A set of twelve colors based on the
+/// [Material spec](https://material.io/design/color/the-color-system.html)
+/// that can be used to configure the color properties of most components.
+///
+/// The [Theme] has a color scheme, [ThemeData.colorScheme], which is constructed
+/// with [ColorScheme.fromSwatch].
+@immutable
+class ColorScheme extends Diagnosticable {
+ /// Create a ColorScheme instance.
+ const ColorScheme({
+ @required this.primary,
+ @required this.primaryVariant,
+ @required this.secondary,
+ @required this.secondaryVariant,
+ @required this.surface,
+ @required this.background,
+ @required this.error,
+ @required this.onPrimary,
+ @required this.onSecondary,
+ @required this.onSurface,
+ @required this.onBackground,
+ @required this.onError,
+ @required this.brightness,
+ }) : assert(primary != null),
+ assert(primaryVariant != null),
+ assert(secondary != null),
+ assert(secondaryVariant != null),
+ assert(surface != null),
+ assert(background != null),
+ assert(error != null),
+ assert(onPrimary != null),
+ assert(onSecondary != null),
+ assert(onSurface != null),
+ assert(onBackground != null),
+ assert(onError != null),
+ assert(brightness != null);
+
+ /// Create a ColorScheme based on a purple primary color that matches the
+ /// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation).
+ const ColorScheme.light({
+ this.primary = const Color(0xff6200ee),
+ this.primaryVariant = const Color(0xff3700b3),
+ this.secondary = const Color(0xff03dac6),
+ this.secondaryVariant = const Color(0xff018786),
+ this.surface = Colors.white,
+ this.background = Colors.white,
+ this.error = const Color(0xffb00020),
+ this.onPrimary = Colors.white,
+ this.onSecondary = Colors.black,
+ this.onSurface = Colors.black,
+ this.onBackground = Colors.black,
+ this.onError = Colors.white,
+ this.brightness = Brightness.light,
+ }) : assert(primary != null),
+ assert(primaryVariant != null),
+ assert(secondary != null),
+ assert(secondaryVariant != null),
+ assert(surface != null),
+ assert(background != null),
+ assert(error != null),
+ assert(onPrimary != null),
+ assert(onSecondary != null),
+ assert(onSurface != null),
+ assert(onBackground != null),
+ assert(onError != null),
+ assert(brightness != null);
+
+ /// Create dark version of the
+ /// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation).
+ const ColorScheme.dark({
+ this.primary = const Color(0xffbb86fc),
+ this.primaryVariant = const Color(0xff4b01d0),
+ this.secondary = const Color(0xff03dac6),
+ this.secondaryVariant = const Color(0xff03dac6),
+ this.surface = Colors.black,
+ this.background = Colors.black,
+ this.error = const Color(0xffb00020),
+ this.onPrimary = Colors.black,
+ this.onSecondary = Colors.black,
+ this.onSurface = Colors.white,
+ this.onBackground = Colors.white,
+ this.onError = Colors.black,
+ this.brightness = Brightness.dark,
+ }) : assert(primary != null),
+ assert(primaryVariant != null),
+ assert(secondary != null),
+ assert(secondaryVariant != null),
+ assert(surface != null),
+ assert(background != null),
+ assert(error != null),
+ assert(onPrimary != null),
+ assert(onSecondary != null),
+ assert(onSurface != null),
+ assert(onBackground != null),
+ assert(onError != null),
+ assert(brightness != null);
+
+ /// Create a color scheme from a [MaterialColor] swatch.
+ ///
+ /// This constructor is used by [ThemeData] to create its default
+ /// color scheme.
+ factory ColorScheme.fromSwatch({
+ MaterialColor primarySwatch = Colors.blue,
+ Color primaryColorDark,
+ Color accentColor,
+ Color cardColor,
+ Color backgroundColor,
+ Color errorColor,
+ Brightness brightness = Brightness.light,
+ }) {
+ assert(primarySwatch != null);
+ assert(brightness != null);
+
+ final bool isDark = brightness == Brightness.dark;
+ final bool primaryIsDark = _brightnessFor(primarySwatch) == Brightness.dark;
+ final Color secondary = accentColor ?? (isDark ? Colors.tealAccent[200] : primarySwatch);
+ final bool secondaryIsDark = _brightnessFor(secondary) == Brightness.dark;
+
+ return ColorScheme(
+ primary: primarySwatch,
+ primaryVariant: primaryColorDark ?? (isDark ? Colors.black : primarySwatch[700]),
+ secondary: secondary,
+ secondaryVariant: isDark ? Colors.tealAccent[700] : primarySwatch[700],
+ surface: cardColor ?? (isDark ? Colors.grey[800] : Colors.white),
+ background: backgroundColor ?? (isDark ? Colors.grey[700] : primarySwatch[200]),
+ error: errorColor ?? Colors.red[700],
+ onPrimary: primaryIsDark ? Colors.white : Colors.black,
+ onSecondary: secondaryIsDark ? Colors.white : Colors.black,
+ onSurface: isDark ? Colors.white : Colors.black,
+ onBackground: primaryIsDark ? Colors.white : Colors.black,
+ onError: isDark ? Colors.black : Colors.white,
+ brightness: brightness,
+ );
+ }
+
+ static Brightness _brightnessFor(Color color) => ThemeData.estimateBrightnessForColor(color);
+
+ /// The color displayed most frequently across your app’s screens and components.
+ final Color primary;
+
+ /// A darker version of the primary color.
+ final Color primaryVariant;
+
+ /// An accent color that, when used sparingly, calls attention to parts
+ /// of your app.
+ final Color secondary;
+
+ /// A darker version of the secondary color.
+ final Color secondaryVariant;
+
+ /// The background color for widgets like [Card].
+ final Color surface;
+
+ /// A color that typically appears behind scrollable content.
+ final Color background;
+
+ /// The color to use for input validation errors, e.g. for
+ /// [InputDecoration.errorText].
+ final Color error;
+
+ /// A color that's clearly legible when drawn on [primary].
+ ///
+ /// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [primary]
+ /// and [onPrimary] is recommended. See
+ /// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
+ final Color onPrimary;
+
+ /// A color that's clearly legible when drawn on [secondary].
+ ///
+ /// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [secondary]
+ /// and [onSecondary] is recommended. See
+ /// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
+ final Color onSecondary;
+
+ /// A color that's clearly legible when drawn on [surface].
+ ///
+ /// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [surface]
+ /// and [onSurface] is recommended. See
+ /// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
+ final Color onSurface;
+
+ /// A color that's clearly legible when drawn on [background].
+ ///
+ /// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [background]
+ /// and [onBackground] is recommended. See
+ /// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
+ final Color onBackground;
+
+ /// A color that's clearly legible when drawn on [error].
+ ///
+ /// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [error]
+ /// and [onError] is recommended. See
+ /// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
+ final Color onError;
+
+ /// The overall brightness of this color scheme.
+ final Brightness brightness;
+
+ /// Creates a copy of this color scheme with the given fields
+ /// replaced by the non-null parameter values.
+ ColorScheme copyWith({
+ Color primary,
+ Color primaryVariant,
+ Color secondary,
+ Color secondaryVariant,
+ Color surface,
+ Color background,
+ Color error,
+ Color onPrimary,
+ Color onSecondary,
+ Color onSurface,
+ Color onBackground,
+ Color onError,
+ Brightness brightness,
+ }) {
+ return ColorScheme(
+ primary: primary ?? this.primary,
+ primaryVariant: primaryVariant ?? this.primaryVariant,
+ secondary: secondary ?? this.secondary,
+ secondaryVariant: secondaryVariant ?? this.secondaryVariant,
+ surface: surface ?? this.surface,
+ background: background ?? this.background,
+ error: error ?? this.error,
+ onPrimary: onPrimary ?? this.onPrimary,
+ onSecondary: onSecondary ?? this.onSecondary,
+ onSurface: onSurface ?? this.onSurface,
+ onBackground: onBackground ?? this.onBackground,
+ onError: onError ?? this.onError,
+ brightness: brightness ?? this.brightness,
+ );
+ }
+
+ /// Linearly interpolate between two [ColorScheme] objects.
+ ///
+ /// {@macro flutter.material.themeData.lerp}
+ static ColorScheme lerp(ColorScheme a, ColorScheme b, double t) {
+ return ColorScheme(
+ primary: Color.lerp(a.primary, b.primary, t),
+ primaryVariant: Color.lerp(a.primaryVariant, b.primaryVariant, t),
+ secondary: Color.lerp(a.secondary, b.secondary, t),
+ secondaryVariant: Color.lerp(a.secondaryVariant, b.secondaryVariant, t),
+ surface: Color.lerp(a.surface, b.surface, t),
+ background: Color.lerp(a.background, b.background, t),
+ error: Color.lerp(a.error, b.error, t),
+ onPrimary: Color.lerp(a.onPrimary, b.onPrimary, t),
+ onSecondary: Color.lerp(a.onSecondary, b.onSecondary, t),
+ onSurface: Color.lerp(a.onSurface, b.onSurface, t),
+ onBackground: Color.lerp(a.onBackground, b.onBackground, t),
+ onError: Color.lerp(a.onError, b.onError, t),
+ brightness: t < 0.5 ? a.brightness : b.brightness,
+ );
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other))
+ return true;
+ if (other.runtimeType != runtimeType)
+ return false;
+ final ColorScheme otherScheme = other;
+ return otherScheme.primary == primary
+ && otherScheme.primaryVariant == primaryVariant
+ && otherScheme.secondary == secondary
+ && otherScheme.secondaryVariant == secondaryVariant
+ && otherScheme.surface == surface
+ && otherScheme.background == background
+ && otherScheme.error == error
+ && otherScheme.onPrimary == onPrimary
+ && otherScheme.onSecondary == onSecondary
+ && otherScheme.onSurface == onSurface
+ && otherScheme.onBackground == onBackground
+ && otherScheme.onError == onError
+ && otherScheme.brightness == brightness;
+ }
+
+ @override
+ int get hashCode {
+ return hashValues(
+ primary,
+ primaryVariant,
+ secondary,
+ secondaryVariant,
+ surface,
+ background,
+ error,
+ onPrimary,
+ onSecondary,
+ onSurface,
+ onBackground,
+ onError,
+ brightness,
+ );
+ }
+
+ @override
+ void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+ super.debugFillProperties(properties);
+ const ColorScheme defaultScheme = ColorScheme.light();
+ properties.add(DiagnosticsProperty<Color>('primary', primary, defaultValue: defaultScheme.primary));
+ properties.add(DiagnosticsProperty<Color>('primaryVariant', primaryVariant, defaultValue: defaultScheme.primaryVariant));
+ properties.add(DiagnosticsProperty<Color>('secondary', secondary, defaultValue: defaultScheme.secondary));
+ properties.add(DiagnosticsProperty<Color>('secondaryVariant', secondaryVariant, defaultValue: defaultScheme.secondaryVariant));
+ properties.add(DiagnosticsProperty<Color>('surface', surface, defaultValue: defaultScheme.surface));
+ properties.add(DiagnosticsProperty<Color>('background', background, defaultValue: defaultScheme.background));
+ properties.add(DiagnosticsProperty<Color>('error', error, defaultValue: defaultScheme.error));
+ properties.add(DiagnosticsProperty<Color>('onPrimary', onPrimary, defaultValue: defaultScheme.onPrimary));
+ properties.add(DiagnosticsProperty<Color>('onSecondary', onSecondary, defaultValue: defaultScheme.onSecondary));
+ properties.add(DiagnosticsProperty<Color>('onSurface', onSurface, defaultValue: defaultScheme.onSurface));
+ properties.add(DiagnosticsProperty<Color>('onBackground', onBackground, defaultValue: defaultScheme.onBackground));
+ properties.add(DiagnosticsProperty<Color>('onError', onError, defaultValue: defaultScheme.onError));
+ properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: defaultScheme.brightness));
+ }
+}
diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart
index 53b172c..98eef2d 100644
--- a/packages/flutter/lib/src/material/date_picker.dart
+++ b/packages/flutter/lib/src/material/date_picker.dart
@@ -21,8 +21,8 @@
import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
+import 'text_theme.dart';
import 'theme.dart';
-import 'typography.dart';
/// Initial display mode of the date picker dialog.
///
diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart
index f4268ab..2059c74 100644
--- a/packages/flutter/lib/src/material/dialog.dart
+++ b/packages/flutter/lib/src/material/dialog.dart
@@ -625,4 +625,4 @@
transitionDuration: const Duration(milliseconds: 150),
transitionBuilder: _buildMaterialDialogTransitions,
);
-}
\ No newline at end of file
+}
diff --git a/packages/flutter/lib/src/material/flat_button.dart b/packages/flutter/lib/src/material/flat_button.dart
index 65048a1..d7d09f1 100644
--- a/packages/flutter/lib/src/material/flat_button.dart
+++ b/packages/flutter/lib/src/material/flat_button.dart
@@ -7,7 +7,7 @@
import 'button.dart';
import 'button_theme.dart';
-import 'colors.dart';
+import 'material_button.dart';
import 'theme.dart';
import 'theme_data.dart';
@@ -49,26 +49,43 @@
/// * [InkWell], which implements the ink splash part of a flat button.
/// * [RawMaterialButton], the widget this widget is based on.
/// * <https://material.google.com/components/buttons.html>
-class FlatButton extends StatelessWidget {
+class FlatButton extends MaterialButton {
/// Create a simple text button.
const FlatButton({
Key key,
- @required this.onPressed,
- this.onHighlightChanged,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.disabledColor,
- this.highlightColor,
- this.splashColor,
- this.colorBrightness,
- this.padding,
- this.shape,
- this.clipBehavior = Clip.none,
- this.materialTapTargetSize,
- @required this.child,
- }) : assert(clipBehavior != null), super(key: key);
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior = Clip.none,
+ MaterialTapTargetSize materialTapTargetSize,
+ @required Widget child,
+ }) : super(
+ key: key,
+ onPressed: onPressed,
+ onHighlightChanged: onHighlightChanged,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorBrightness: colorBrightness,
+ padding: padding,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ materialTapTargetSize: materialTapTargetSize,
+ child: child,
+ );
/// Create a text button from a pair of widgets that serve as the button's
/// [icon] and [label].
@@ -77,244 +94,47 @@
/// at the start, and 16 at the end, with an 8 pixel gap in between.
///
/// The [icon], [label], and [clipBehavior] arguments must not be null.
- FlatButton.icon({
+ factory FlatButton.icon({
Key key,
- @required this.onPressed,
- this.onHighlightChanged,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.disabledColor,
- this.highlightColor,
- this.splashColor,
- this.colorBrightness,
- this.shape,
- this.clipBehavior = Clip.none,
- this.materialTapTargetSize,
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior,
+ MaterialTapTargetSize materialTapTargetSize,
@required Widget icon,
@required Widget label,
- }) : assert(icon != null),
- assert(label != null),
- assert(clipBehavior != null),
- padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
- child = Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- icon,
- const SizedBox(width: 8.0),
- label,
- ],
- ),
- super(key: key);
-
- /// Called when the button is tapped or otherwise activated.
- ///
- /// If this is set to null, the button will be disabled, see [enabled].
- final VoidCallback onPressed;
-
- /// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
- /// callback.
- final ValueChanged<bool> onHighlightChanged;
-
- /// Defines the button's base colors, and the defaults for the button's minimum
- /// size, internal padding, and shape.
- ///
- /// Defaults to `ButtonTheme.of(context).textTheme`.
- final ButtonTextTheme textTheme;
-
- /// The color to use for this button's text.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default text color depends on the button theme's text theme,
- /// [ButtonThemeData.textTheme].
- ///
- /// See also:
- /// * [disabledTextColor], the text color to use when the button has been
- /// disabled.
- final Color textColor;
-
- /// The color to use for this button's text when the button is disabled.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default value is the theme's disabled color,
- /// [ThemeData.disabledColor].
- ///
- /// See also:
- /// * [textColor] - The color to use for this button's text when the button is [enabled].
- final Color disabledTextColor;
-
- /// The button's fill color, displayed by its [Material], while it
- /// is in its default (unpressed, enabled) state.
- ///
- /// Typically not specified for [FlatButton]s.
- ///
- /// The default is null.
- final Color color;
-
- /// The fill color of the button when the button is disabled.
- ///
- /// Typically not specified for [FlatButton]s.
- ///
- /// The default is null.
- final Color disabledColor;
-
- /// The splash color of the button's [InkWell].
- ///
- /// The ink splash indicates that the button has been touched. It
- /// appears on top of the button's child and spreads in an expanding
- /// circle beginning where the touch occurred.
- ///
- /// If [textTheme] is [ButtonTextTheme.primary], the default splash color is
- /// is based on the theme's primary color [ThemeData.primaryColor],
- /// otherwise it's the current theme's splash color, [ThemeData.splashColor].
- ///
- /// The appearance of the splash can be configured with the theme's splash
- /// factory, [ThemeData.splashFactory].
- final Color splashColor;
-
- /// The highlight color of the button's [InkWell].
- ///
- /// The highlight indicates that the button is actively being pressed. It
- /// appears on top of the button's child and quickly spreads to fill
- /// the button, and then fades out.
- ///
- /// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
- /// transparent (in other words the highlight doesn't appear). Otherwise it's
- /// the current theme's highlight color, [ThemeData.highlightColor].
- final Color highlightColor;
-
- /// The theme brightness to use for this button.
- ///
- /// Defaults to the theme's brightness, [ThemeData.brightness].
- final Brightness colorBrightness;
-
- /// Configures the minimum size of the tap target.
- ///
- /// Defaults to [ThemeData.materialTapTargetSize].
- ///
- /// See also:
- ///
- /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
- final MaterialTapTargetSize materialTapTargetSize;
-
- /// The widget below this widget in the tree.
- ///
- /// Typically a [Text] widget in all caps.
- final Widget child;
-
- /// Whether the button is enabled or disabled.
- ///
- /// Buttons are disabled by default. To enable a button, set its [onPressed]
- /// property to a non-null value.
- bool get enabled => onPressed != null;
-
- /// The internal padding for the button's [child].
- ///
- /// Defaults to the value from the current [ButtonTheme],
- /// [ButtonThemeData.padding].
- final EdgeInsetsGeometry padding;
-
- /// The shape of the button's [Material].
- ///
- /// The button's highlight and splash are clipped to this shape. If the
- /// button has an elevation, then its drop shadow is defined by this
- /// shape as well.
- final ShapeBorder shape;
-
- /// {@macro flutter.widgets.Clip}
- final Clip clipBehavior;
-
- Brightness _getBrightness(ThemeData theme) {
- return colorBrightness ?? theme.brightness;
- }
-
- ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
- return textTheme ?? buttonTheme.textTheme;
- }
-
- Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
- final Color color = enabled ? textColor : disabledTextColor;
- if (color != null)
- return color;
-
- final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
- final bool fillIsDark = fillColor == null
- ? themeIsDark
- : ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- return enabled
- ? (themeIsDark ? Colors.white : Colors.black87)
- : theme.disabledColor;
- case ButtonTextTheme.accent:
- return enabled
- ? theme.accentColor
- : theme.disabledColor;
- case ButtonTextTheme.primary:
- return enabled
- ? (fillIsDark ? Colors.white : theme.primaryColor)
- : (themeIsDark ? Colors.white30 : Colors.black38);
- }
- return null;
- }
-
- Color _getSplashColor(ThemeData theme, ButtonThemeData buttonTheme) {
- if (splashColor != null)
- return splashColor;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- case ButtonTextTheme.accent:
- return theme.splashColor;
- case ButtonTextTheme.primary:
- return _getBrightness(theme) == Brightness.dark
- ? Colors.white12
- : theme.primaryColor.withOpacity(0.12);
- }
- return Colors.transparent;
- }
-
- Color _getHighlightColor(ThemeData theme, ButtonThemeData buttonTheme) {
- if (highlightColor != null)
- return highlightColor;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- case ButtonTextTheme.accent:
- return theme.highlightColor;
- case ButtonTextTheme.primary:
- return Colors.transparent;
- }
- return Colors.transparent;
- }
+ }) = _FlatButtonWithIcon;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
- final Color fillColor = enabled ? color : disabledColor;
- final Color textColor = _getTextColor(theme, buttonTheme, fillColor);
return RawMaterialButton(
onPressed: onPressed,
onHighlightChanged: onHighlightChanged,
- fillColor: fillColor,
- textStyle: theme.textTheme.button.copyWith(color: textColor),
- highlightColor: _getHighlightColor(theme, buttonTheme),
- splashColor: _getSplashColor(theme, buttonTheme),
- elevation: 0.0,
- highlightElevation: 0.0,
- materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
- padding: padding ?? buttonTheme.padding,
- constraints: buttonTheme.constraints,
- shape: shape ?? buttonTheme.shape,
- clipBehavior: clipBehavior,
+ clipBehavior: clipBehavior ?? Clip.none,
+ fillColor: buttonTheme.getFillColor(this),
+ textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
+ highlightColor: buttonTheme.getHighlightColor(this),
+ splashColor: buttonTheme.getSplashColor(this),
+ elevation: buttonTheme.getElevation(this),
+ highlightElevation: buttonTheme.getHighlightElevation(this),
+ disabledElevation: buttonTheme.getDisabledElevation(this),
+ padding: buttonTheme.getPadding(this),
+ constraints: buttonTheme.getConstraints(this),
+ shape: buttonTheme.getShape(this),
+ animationDuration: buttonTheme.getAnimationDuration(this),
+ materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
child: child,
);
}
@@ -336,3 +156,56 @@
properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize, defaultValue: null));
}
}
+
+/// The type of of FlatButtons created with [FlatButton.icon].
+///
+/// This class only exists to give FlatButtons created with [FlatButton.icon]
+/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
+class _FlatButtonWithIcon extends FlatButton implements MaterialButtonWithIconMixin {
+ _FlatButtonWithIcon({
+ Key key,
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior,
+ MaterialTapTargetSize materialTapTargetSize,
+ @required Widget icon,
+ @required Widget label,
+ }) : assert(icon != null),
+ assert(label != null),
+ super(
+ key: key,
+ onPressed: onPressed,
+ onHighlightChanged: onHighlightChanged,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorBrightness: colorBrightness,
+ padding: padding,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ materialTapTargetSize: materialTapTargetSize,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: <Widget>[
+ icon,
+ const SizedBox(width: 8.0),
+ label,
+ ],
+ ),
+ );
+
+}
diff --git a/packages/flutter/lib/src/material/material_button.dart b/packages/flutter/lib/src/material/material_button.dart
new file mode 100644
index 0000000..17ed76b
--- /dev/null
+++ b/packages/flutter/lib/src/material/material_button.dart
@@ -0,0 +1,287 @@
+// 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/foundation.dart';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/widgets.dart';
+
+import 'button.dart';
+import 'button_theme.dart';
+import 'constants.dart';
+import 'ink_well.dart';
+import 'material.dart';
+import 'theme.dart';
+import 'theme_data.dart';
+
+/// A utility class for building Material buttons that depend on the
+/// ambient [ButtonTheme] and [Theme].
+///
+/// The button's size will expand to fit the child widget, if necessary.
+///
+/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
+/// an enabled button, make sure to pass a non-null value for onPressed.
+///
+/// Rather than using this class directly, consider using [FlatButton],
+/// OutlineButton, or [RaisedButton], which configure this class with
+/// appropriate defaults that match the material design specification.
+///
+/// To create a button directly, without inheriting theme defaults, use
+/// [RawMaterialButton].
+///
+/// If you want an ink-splash effect for taps, but don't want to use a button,
+/// consider using [InkWell] directly.
+///
+/// See also:
+///
+/// * [IconButton], to create buttons that contain icons rather than text.
+class MaterialButton extends StatelessWidget {
+ /// Creates a material button.
+ ///
+ /// Rather than creating a material button directly, consider using
+ /// [FlatButton] or [RaisedButton]. To create a custom Material button
+ /// consider using [RawMaterialButton].
+ ///
+ /// The [clipBehavior] argument must not be null.
+ const MaterialButton({
+ Key key,
+ @required this.onPressed,
+ this.onHighlightChanged,
+ this.textTheme,
+ this.textColor,
+ this.disabledTextColor,
+ this.color,
+ this.disabledColor,
+ this.highlightColor,
+ this.splashColor,
+ this.colorBrightness,
+ this.elevation,
+ this.highlightElevation,
+ this.disabledElevation,
+ this.padding,
+ this.shape,
+ this.clipBehavior = Clip.none,
+ this.materialTapTargetSize,
+ this.animationDuration,
+ this.minWidth,
+ this.height,
+ this.child,
+ }) : super(key: key);
+
+ /// The callback that is called when the button is tapped or otherwise activated.
+ ///
+ /// If this is set to null, the button will be disabled.
+ final VoidCallback onPressed;
+
+ /// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
+ /// callback.
+ final ValueChanged<bool> onHighlightChanged;
+
+ /// Defines the button's base colors, and the defaults for the button's minimum
+ /// size, internal padding, and shape.
+ ///
+ /// Defaults to `ButtonTheme.of(context).textTheme`.
+ final ButtonTextTheme textTheme;
+
+ /// The color to use for this button's text.
+ ///
+ /// The button's [Material.textStyle] will be the current theme's button
+ /// text style, [ThemeData.textTheme.button], configured with this color.
+ ///
+ /// The default text color depends on the button theme's text theme,
+ /// [ButtonThemeData.textTheme].
+ ///
+ /// See also:
+ /// * [disabledTextColor], the text color to use when the button has been
+ /// disabled.
+ final Color textColor;
+
+ /// The color to use for this button's text when the button is disabled.
+ ///
+ /// The button's [Material.textStyle] will be the current theme's button
+ /// text style, [ThemeData.textTheme.button], configured with this color.
+ ///
+ /// The default value is the theme's disabled color,
+ /// [ThemeData.disabledColor].
+ ///
+ /// See also:
+ /// * [textColor] - The color to use for this button's text when the button is [enabled].
+ final Color disabledTextColor;
+
+ /// The button's fill color, displayed by its [Material], while it
+ /// is in its default (unpressed, [enabled]) state.
+ ///
+ /// The default fill color is the theme's button color, [ThemeData.buttonColor].
+ ///
+ /// See also:
+ /// * [disabledColor] - the fill color of the button when the button is disabled.
+ final Color color;
+
+ /// The fill color of the button when the button is disabled.
+ ///
+ /// The default value of this color is the theme's disabled color,
+ /// [ThemeData.disabledColor].
+ ///
+ /// See also:
+ /// * [color] - the fill color of the button when the button is [enabled].
+ final Color disabledColor;
+
+ /// The splash color of the button's [InkWell].
+ ///
+ /// The ink splash indicates that the button has been touched. It
+ /// appears on top of the button's child and spreads in an expanding
+ /// circle beginning where the touch occurred.
+ ///
+ /// The default splash color is the current theme's splash color,
+ /// [ThemeData.splashColor].
+ ///
+ /// The appearance of the splash can be configured with the theme's splash
+ /// factory, [ThemeData.splashFactory].
+ final Color splashColor;
+
+ /// The highlight color of the button's [InkWell].
+ ///
+ /// The highlight indicates that the button is actively being pressed. It
+ /// appears on top of the button's child and quickly spreads to fill
+ /// the button, and then fades out.
+ ///
+ /// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
+ /// transparent (in other words the highlight doesn't appear). Otherwise it's
+ /// the current theme's highlight color, [ThemeData.highlightColor].
+ final Color highlightColor;
+
+ /// The z-coordinate at which to place this button. This controls the size of
+ /// the shadow below the raised button.
+ ///
+ /// Defaults to 2, the appropriate elevation for raised buttons.
+ ///
+ /// See also:
+ ///
+ /// * [FlatButton], a button with no elevation or fill color.
+ /// * [disabledElevation], the elevation when the button is disabled.
+ /// * [highlightElevation], the elevation when the button is pressed.
+ final double elevation;
+
+ /// The elevation for the button's [Material] when the button
+ /// is [enabled] and pressed.
+ ///
+ /// This controls the size of the shadow below the button. When a tap
+ /// down gesture occurs within the button, its [InkWell] displays a
+ /// [highlightColor] "highlight".
+ ///
+ /// Defaults to 8.0.
+ ///
+ /// See also:
+ ///
+ /// * [elevation], the default elevation.
+ /// * [disabledElevation], the elevation when the button is disabled.
+ final double highlightElevation;
+
+ /// The elevation for the button's [Material] when the button
+ /// is not [enabled].
+ ///
+ /// Defaults to 0.0.
+ ///
+ /// See also:
+ ///
+ /// * [elevation], the default elevation.
+ /// * [highlightElevation], the elevation when the button is pressed.
+ final double disabledElevation;
+
+ /// The theme brightness to use for this button.
+ ///
+ /// Defaults to the theme's brightness, [ThemeData.brightness].
+ final Brightness colorBrightness;
+
+ /// The button's label.
+ ///
+ /// Often a [Text] widget in all caps.
+ final Widget child;
+
+ /// Whether the button is enabled or disabled.
+ ///
+ /// Buttons are disabled by default. To enable a button, set its [onPressed]
+ /// property to a non-null value.
+ bool get enabled => onPressed != null;
+
+ /// The internal padding for the button's [child].
+ ///
+ /// Defaults to the value from the current [ButtonTheme],
+ /// [ButtonThemeData.padding].
+ final EdgeInsetsGeometry padding;
+
+ /// The shape of the button's [Material].
+ ///
+ /// The button's highlight and splash are clipped to this shape. If the
+ /// button has an elevation, then its drop shadow is defined by this
+ /// shape as well.
+ final ShapeBorder shape;
+
+ /// {@macro flutter.widgets.Clip}
+ final Clip clipBehavior;
+
+ /// Defines the duration of animated changes for [shape] and [elevation].
+ ///
+ /// The default value is [kThemeChangeDuration].
+ final Duration animationDuration;
+
+ /// Configures the minimum size of the tap target.
+ ///
+ /// Defaults to [ThemeData.materialTapTargetSize].
+ ///
+ /// See also:
+ ///
+ /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
+ final MaterialTapTargetSize materialTapTargetSize;
+
+ /// The smallest horizontal extent that the button will occupy.
+ ///
+ /// Defaults to the value from the current [ButtonTheme].
+ final double minWidth;
+
+ /// The vertical extent of the button.
+ ///
+ /// Defaults to the value from the current [ButtonTheme].
+ final double height;
+
+ @override
+ Widget build(BuildContext context) {
+ final ThemeData theme = Theme.of(context);
+ final ButtonThemeData buttonTheme = ButtonTheme.of(context);
+
+ return RawMaterialButton(
+ onPressed: onPressed,
+ fillColor: color,
+ textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
+ highlightColor: highlightColor ?? theme.highlightColor,
+ splashColor: splashColor ?? theme.splashColor,
+ elevation: buttonTheme.getElevation(this),
+ highlightElevation: buttonTheme.getHighlightElevation(this),
+ padding: buttonTheme.getPadding(this),
+ constraints: buttonTheme.getConstraints(this).copyWith(
+ minWidth: minWidth,
+ minHeight: height,
+ ),
+ shape: buttonTheme.shape,
+ clipBehavior: clipBehavior ?? Clip.none,
+ animationDuration: buttonTheme.getAnimationDuration(this),
+ child: child,
+ materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
+ );
+ }
+
+ @override
+ void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+ super.debugFillProperties(properties);
+ properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
+ }
+}
+
+/// The type of [MaterialButton]s created with [RaisedButton.icon], [FlatButton.icon],
+/// and [OutlineButton.icon].
+///
+/// This mixin only exists to give the "label and icon" button widgets a distinct
+/// type for the sake of [ButtonTheme].
+abstract class MaterialButtonWithIconMixin {
+ MaterialButtonWithIconMixin._();
+}
diff --git a/packages/flutter/lib/src/material/material_localizations.dart b/packages/flutter/lib/src/material/material_localizations.dart
index 19eaa08..5927243 100644
--- a/packages/flutter/lib/src/material/material_localizations.dart
+++ b/packages/flutter/lib/src/material/material_localizations.dart
@@ -7,6 +7,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
+import 'text_theme.dart';
import 'time.dart';
import 'typography.dart';
@@ -34,6 +35,10 @@
//
// 5. If you are a Google employee, you should then also follow the instructions
// at go/flutter-l10n. If you're not, don't worry about it.
+//
+// 6. If you're adding a String for the sake of Flutter, not for an app-specific
+// version of this interface, you are making a breaking API change. See
+// https://flutter.io/design-principles/#handling-breaking-changes.
/// Defines the localized resource values used by the Material widgets.
///
@@ -168,22 +173,17 @@
/// each supported layout.
TimeOfDayFormat timeOfDayFormat({ bool alwaysUse24HourFormat = false });
- /// Provides geometric text preferences for the current locale.
+ /// Defines the localized [TextStyle] geometry for [ThemeData.textTheme].
///
- /// 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 [scriptCategory] defines the overall geometry of a [TextTheme] for
+ /// the static [MaterialTextGeometry.localizedFor] method in terms of the
+ /// three language categories defined in https://material.io/go/design-typography.
///
- /// Typically a complete theme is obtained via [Theme.of], which can be
- /// localized using the [Localizations] widget.
- ///
- /// The text styles provided by this theme are expected to have their
- /// [TextStyle.inherit] property set to false, so that the [ThemeData]
- /// obtained from [Theme.of] no longer inherits text style properties and
- /// contains a complete set of properties needed to style a [Text] widget.
- ///
- /// See also: https://material.io/go/design-typography
- TextTheme get localTextGeometry;
+ /// Generally speaking, font sizes for [ScriptCategory.tall] and
+ /// [ScriptCategory.dense] scripts - for text styles that are smaller than the
+ /// title style - are one unit larger than they are for
+ /// [ScriptCategory.englishLike] scripts.
+ ScriptCategory get scriptCategory;
/// Formats [number] as a decimal, inserting locale-appropriate thousands
/// separators as necessary.
@@ -653,16 +653,15 @@
String get modalBarrierDismissLabel => 'Dismiss';
@override
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
+
+ @override
TimeOfDayFormat timeOfDayFormat({ bool alwaysUse24HourFormat = false }) {
return alwaysUse24HourFormat
? TimeOfDayFormat.HH_colon_mm
: TimeOfDayFormat.h_colon_mm_space_a;
}
- /// Looks up text geometry defined in [MaterialTextGeometry].
- @override
- TextTheme get localTextGeometry => MaterialTextGeometry.englishLike;
-
@override
String get signedInLabel => 'Signed in';
diff --git a/packages/flutter/lib/src/material/outline_button.dart b/packages/flutter/lib/src/material/outline_button.dart
index 9380cf9..ef4321f 100644
--- a/packages/flutter/lib/src/material/outline_button.dart
+++ b/packages/flutter/lib/src/material/outline_button.dart
@@ -7,6 +7,7 @@
import 'button_theme.dart';
import 'colors.dart';
+import 'material_button.dart';
import 'raised_button.dart';
import 'theme.dart';
@@ -48,31 +49,44 @@
/// * [IconButton], to create buttons that just contain icons.
/// * [InkWell], which implements the ink splash part of a flat button.
/// * <https://material.google.com/components/buttons.html>
-class OutlineButton extends StatefulWidget {
+class OutlineButton extends MaterialButton {
/// Create a filled button.
///
/// The [highlightElevation], [borderWidth], and [clipBehavior]
/// arguments must not be null.
const OutlineButton({
Key key,
- @required this.onPressed,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.highlightColor,
- this.splashColor,
- this.highlightElevation = 2.0,
+ @required VoidCallback onPressed,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color highlightColor,
+ Color splashColor,
+ double highlightElevation,
this.borderSide,
this.disabledBorderColor,
this.highlightedBorderColor,
- this.padding,
- this.shape,
- this.clipBehavior = Clip.none,
- this.child,
- }) : assert(highlightElevation != null && highlightElevation >= 0.0),
- assert(clipBehavior != null),
- super(key: key);
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior = Clip.none,
+ Widget child,
+ }) : assert(highlightElevation == null || highlightElevation >= 0.0),
+ super(
+ key: key,
+ onPressed: onPressed,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ highlightElevation: highlightElevation,
+ padding: padding,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ child: child,
+ );
/// Create an outline button from a pair of widgets that serve as the button's
/// [icon] and [label].
@@ -82,125 +96,25 @@
///
/// The [highlightElevation], [icon], [label], and [clipBehavior] must not be
/// null.
- OutlineButton.icon({
+ factory OutlineButton.icon({
Key key,
- @required this.onPressed,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.highlightColor,
- this.splashColor,
- this.highlightElevation = 2.0,
- this.borderSide,
- this.disabledBorderColor,
- this.highlightedBorderColor,
- this.shape,
- this.clipBehavior = Clip.none,
+ @required VoidCallback onPressed,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color highlightColor,
+ Color splashColor,
+ double highlightElevation,
+ Color highlightedBorderColor,
+ Color disabledBorderColor,
+ BorderSide borderSide,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior,
@required Widget icon,
@required Widget label,
- }) : assert(highlightElevation != null && highlightElevation >= 0.0),
- assert(icon != null),
- assert(label != null),
- assert(clipBehavior != null),
- padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
- child = Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- icon,
- const SizedBox(width: 8.0),
- label,
- ],
- ),
- super(key: key);
-
- /// Called when the button is tapped or otherwise activated.
- ///
- /// If this is set to null, the button will be disabled, see [enabled].
- final VoidCallback onPressed;
-
- /// Defines the button's base colors, and the defaults for the button's minimum
- /// size, internal padding, and shape.
- ///
- /// Defaults to `ButtonTheme.of(context).textTheme`.
- final ButtonTextTheme textTheme;
-
- /// The color to use for this button's text.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default text color depends on the button theme's text theme,
- /// [ButtonThemeData.textTheme].
- ///
- /// See also:
- ///
- /// * [disabledTextColor], the text color to use when the button has been
- /// disabled.
- final Color textColor;
-
- /// The color to use for this button's text when the button is disabled.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default value is the theme's disabled color,
- /// [ThemeData.disabledColor].
- ///
- /// See also:
- ///
- /// * [textColor], which specifies the color to use for this button's text
- /// when the button is [enabled].
- final Color disabledTextColor;
-
- /// The button's opaque fill color when it's [enabled] and has been pressed.
- ///
- /// If null this value defaults to white for light themes (see
- /// [ThemeData.brightness]), and black for dark themes.
- final Color color;
-
- /// The splash color of the button's [InkWell].
- ///
- /// The ink splash indicates that the button has been touched. It
- /// appears on top of the button's child and spreads in an expanding
- /// circle beginning where the touch occurred.
- ///
- /// If [textTheme] is [ButtonTextTheme.primary], the default splash color is
- /// is based on the theme's primary color [ThemeData.primaryColor],
- /// otherwise it's the current theme's splash color, [ThemeData.splashColor].
- ///
- /// The appearance of the splash can be configured with the theme's splash
- /// factory, [ThemeData.splashFactory].
- final Color splashColor;
-
- /// The highlight color of the button's [InkWell].
- ///
- /// The highlight indicates that the button is actively being pressed. It
- /// appears on top of the button's child and quickly spreads to fill
- /// the button, and then fades out.
- ///
- /// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
- /// transparent (in other words the highlight doesn't appear). Otherwise it's
- /// the current theme's highlight color, [ThemeData.highlightColor].
- final Color highlightColor;
-
- /// The elevation of the button when it's [enabled] and has been pressed.
- ///
- /// If null, this value defaults to 2.0.
- ///
- /// The elevation of an outline button is always 0.0 unless its enabled
- /// and has been pressed.
- final double highlightElevation;
-
- /// Defines the color of the border when the button is enabled but not
- /// pressed, and the border outline's width and style in general.
- ///
- /// If the border side's [BorderSide.style] is [BorderStyle.none], then
- /// an outline is not drawn.
- ///
- /// If null the default border's style is [BorderStyle.solid], its
- /// [BorderSide.width] is 2.0, and its color is a light shade of grey.
- final BorderSide borderSide;
+ }) = _OutlineButtonWithIcon;
/// The outline border's color when the button is [enabled] and pressed.
///
@@ -215,36 +129,38 @@
/// dark themes.
final Color disabledBorderColor;
- /// The internal padding for the button's [child].
+ /// Defines the color of the border when the button is enabled but not
+ /// pressed, and the border outline's width and style in general.
///
- /// Defaults to the value from the current [ButtonTheme],
- /// [ButtonThemeData.padding].
- final EdgeInsetsGeometry padding;
-
- /// The shape of the button's [Material] and its outline.
+ /// If the border side's [BorderSide.style] is [BorderStyle.none], then
+ /// an outline is not drawn.
///
- /// The button's highlight and splash are clipped to this shape. If the
- /// button has a [highlightElevation], then its drop shadow is defined by this
- /// shape as well.
- final ShapeBorder shape;
-
- /// {@macro flutter.widgets.Clip}
- final Clip clipBehavior;
-
- /// The button's label.
- ///
- /// Often a [Text] widget in all caps.
- final Widget child;
-
- /// Whether the button is enabled or disabled.
- ///
- /// Buttons are disabled by default. To enable a button, set its [onPressed]
- /// property to a non-null value.
- bool get enabled => onPressed != null;
+ /// If null the default border's style is [BorderStyle.solid], its
+ /// [BorderSide.width] is 2.0, and its color is a light shade of grey.
+ final BorderSide borderSide;
@override
- _OutlineButtonState createState() => _OutlineButtonState();
-
+ Widget build(BuildContext context) {
+ final ButtonThemeData buttonTheme = ButtonTheme.of(context);
+ return _OutlineButton(
+ onPressed: onPressed,
+ brightness: buttonTheme.getBrightness(this),
+ textTheme: textTheme,
+ textColor: buttonTheme.getTextColor(this),
+ disabledTextColor: buttonTheme.getDisabledTextColor(this),
+ color: color,
+ highlightColor: buttonTheme.getHighlightColor(this),
+ splashColor: buttonTheme.getSplashColor(this),
+ highlightElevation: buttonTheme.getHighlightElevation(this),
+ borderSide: borderSide,
+ disabledBorderColor: disabledBorderColor,
+ highlightedBorderColor: highlightedBorderColor ?? buttonTheme.colorScheme.primary,
+ padding: buttonTheme.getPadding(this),
+ shape: buttonTheme.getShape(this),
+ clipBehavior: clipBehavior,
+ child: child,
+ );
+ }
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -256,7 +172,7 @@
properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: null));
properties.add(DiagnosticsProperty<Color>('highlightColor', highlightColor, defaultValue: null));
properties.add(DiagnosticsProperty<Color>('splashColor', splashColor, defaultValue: null));
- properties.add(DiagnosticsProperty<double>('highlightElevation', highlightElevation, defaultValue: 2.0));
+ properties.add(DiagnosticsProperty<double>('highlightElevation', highlightElevation, defaultValue: null));
properties.add(DiagnosticsProperty<BorderSide>('borderSide', borderSide, defaultValue: null));
properties.add(DiagnosticsProperty<Color>('disabledBorderColor', disabledBorderColor, defaultValue: null));
properties.add(DiagnosticsProperty<Color>('highlightedBorderColor', highlightedBorderColor, defaultValue: null));
@@ -265,7 +181,107 @@
}
}
-class _OutlineButtonState extends State<OutlineButton> with SingleTickerProviderStateMixin {
+// The type of of OutlineButtons created with [OutlineButton.icon].
+//
+// This class only exists to give RaisedButtons created with [RaisedButton.icon]
+// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
+class _OutlineButtonWithIcon extends OutlineButton implements MaterialButtonWithIconMixin {
+ _OutlineButtonWithIcon({
+ Key key,
+ @required VoidCallback onPressed,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color highlightColor,
+ Color splashColor,
+ double highlightElevation,
+ Color highlightedBorderColor,
+ Color disabledBorderColor,
+ BorderSide borderSide,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior,
+ @required Widget icon,
+ @required Widget label,
+ }) : assert(highlightElevation == null || highlightElevation >= 0.0),
+ assert(icon != null),
+ assert(label != null),
+ super(
+ key: key,
+ onPressed: onPressed,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ highlightElevation: highlightElevation,
+ disabledBorderColor: disabledBorderColor,
+ highlightedBorderColor: highlightedBorderColor,
+ borderSide: borderSide,
+ padding: padding,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: <Widget>[
+ icon,
+ const SizedBox(width: 8.0),
+ label,
+ ],
+ ),
+ );
+}
+
+class _OutlineButton extends StatefulWidget {
+ const _OutlineButton({
+ Key key,
+ @required this.onPressed,
+ this.brightness,
+ this.textTheme,
+ this.textColor,
+ this.disabledTextColor,
+ this.color,
+ this.highlightColor,
+ this.splashColor,
+ @required this.highlightElevation,
+ this.borderSide,
+ this.disabledBorderColor,
+ @required this.highlightedBorderColor,
+ this.padding,
+ this.shape,
+ this.clipBehavior,
+ this.child,
+ }) : assert(highlightElevation != null && highlightElevation >= 0.0),
+ assert(highlightedBorderColor != null),
+ super(key: key);
+
+ final VoidCallback onPressed;
+ final Brightness brightness;
+ final ButtonTextTheme textTheme;
+ final Color textColor;
+ final Color disabledTextColor;
+ final Color color;
+ final Color splashColor;
+ final Color highlightColor;
+ final double highlightElevation;
+ final BorderSide borderSide;
+ final Color disabledBorderColor;
+ final Color highlightedBorderColor;
+ final EdgeInsetsGeometry padding;
+ final ShapeBorder shape;
+ final Clip clipBehavior;
+ final Widget child;
+
+ bool get enabled => onPressed != null;
+
+ @override
+ _OutlineButtonState createState() => _OutlineButtonState();
+}
+
+
+class _OutlineButtonState extends State<_OutlineButton> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _fillAnimation;
Animation<double> _elevationAnimation;
@@ -305,36 +321,8 @@
super.dispose();
}
- ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
- return widget.textTheme ?? buttonTheme.textTheme;
- }
-
- // TODO(hmuller): this method is the same as FlatButton
- Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme) {
- final Color color = widget.enabled ? widget.textColor : widget.disabledTextColor;
- if (color != null)
- return color;
-
- final bool themeIsDark = theme.brightness == Brightness.dark;
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- return widget.enabled
- ? (themeIsDark ? Colors.white : Colors.black87)
- : theme.disabledColor;
- case ButtonTextTheme.accent:
- return widget.enabled
- ? theme.accentColor
- : theme.disabledColor;
- case ButtonTextTheme.primary:
- return widget.enabled
- ? theme.buttonColor
- : (themeIsDark ? Colors.white30 : Colors.black38);
- }
- return null;
- }
-
- Color _getFillColor(ThemeData theme) {
- final bool themeIsDark = theme.brightness == Brightness.dark;
+ Color _getFillColor() {
+ final bool themeIsDark = widget.brightness == Brightness.dark;
final Color color = widget.color ?? (themeIsDark
? const Color(0x00000000)
: const Color(0x00FFFFFF));
@@ -345,35 +333,18 @@
return colorTween.evaluate(_fillAnimation);
}
- // TODO(hmuller): this method is the same as FlatButton
- Color _getSplashColor(ThemeData theme, ButtonThemeData buttonTheme) {
- if (widget.splashColor != null)
- return widget.splashColor;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- case ButtonTextTheme.accent:
- return theme.splashColor;
- case ButtonTextTheme.primary:
- return theme.brightness == Brightness.dark
- ? Colors.white12
- : theme.primaryColor.withOpacity(0.12);
- }
- return Colors.transparent;
- }
-
- BorderSide _getOutline(ThemeData theme, ButtonThemeData buttonTheme) {
- final bool themeIsDark = theme.brightness == Brightness.dark;
+ BorderSide _getOutline() {
+ final bool isDark = widget.brightness == Brightness.dark;
if (widget.borderSide?.style == BorderStyle.none)
return widget.borderSide;
final Color color = widget.enabled
? (_pressed
- ? widget.highlightedBorderColor ?? theme.primaryColor
+ ? widget.highlightedBorderColor
: (widget.borderSide?.color ??
- (themeIsDark ? Colors.grey[600] : Colors.grey[200])))
+ (isDark ? Colors.grey[600] : Colors.grey[200])))
: (widget.disabledBorderColor ??
- (themeIsDark ? Colors.grey[800] : Colors.grey[100]));
+ (isDark ? Colors.grey[800] : Colors.grey[100]));
return BorderSide(
color: color,
@@ -390,19 +361,14 @@
@override
Widget build(BuildContext context) {
- final ThemeData theme = Theme.of(context);
- final ButtonThemeData buttonTheme = ButtonTheme.of(context);
- final Color textColor = _getTextColor(theme, buttonTheme);
- final Color splashColor = _getSplashColor(theme, buttonTheme);
-
return AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return RaisedButton(
- textColor: textColor,
+ textColor: widget.textColor,
disabledTextColor: widget.disabledTextColor,
- color: _getFillColor(theme),
- splashColor: splashColor,
+ color: _getFillColor(),
+ splashColor: widget.splashColor,
highlightColor: widget.highlightColor,
disabledColor: Colors.transparent,
onPressed: widget.onPressed,
@@ -420,8 +386,8 @@
},
padding: widget.padding,
shape: _OutlineBorder(
- shape: widget.shape ?? buttonTheme.shape,
- side: _getOutline(theme, buttonTheme),
+ shape: widget.shape,
+ side: _getOutline(),
),
clipBehavior: widget.clipBehavior,
animationDuration: _kElevationDuration,
diff --git a/packages/flutter/lib/src/material/raised_button.dart b/packages/flutter/lib/src/material/raised_button.dart
index c67e603..a0bc45d 100644
--- a/packages/flutter/lib/src/material/raised_button.dart
+++ b/packages/flutter/lib/src/material/raised_button.dart
@@ -7,8 +7,7 @@
import 'button.dart';
import 'button_theme.dart';
-import 'colors.dart';
-import 'constants.dart';
+import 'material_button.dart';
import 'theme.dart';
import 'theme_data.dart';
@@ -41,38 +40,57 @@
/// * [InkWell], which implements the ink splash part of a flat button.
/// * [RawMaterialButton], the widget this widget is based on.
/// * <https://material.google.com/components/buttons.html>
-class RaisedButton extends StatelessWidget {
+class RaisedButton extends MaterialButton {
/// Create a filled button.
///
/// The [elevation], [highlightElevation], [disabledElevation], and
/// [clipBehavior] arguments must not be null.
const RaisedButton({
Key key,
- @required this.onPressed,
- this.onHighlightChanged,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.disabledColor,
- this.highlightColor,
- this.splashColor,
- this.colorBrightness,
- this.elevation = 2.0,
- this.highlightElevation = 8.0,
- this.disabledElevation = 0.0,
- this.padding,
- this.shape,
- this.clipBehavior = Clip.none,
- this.materialTapTargetSize,
- this.animationDuration = kThemeChangeDuration,
- this.child,
- }) : assert(elevation != null),
- assert(highlightElevation != null),
- assert(disabledElevation != null),
- assert(animationDuration != null),
- assert(clipBehavior != null),
- super(key: key);
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ double elevation,
+ double highlightElevation,
+ double disabledElevation,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior = Clip.none,
+ MaterialTapTargetSize materialTapTargetSize,
+ Duration animationDuration,
+ Widget child,
+ }) : assert(elevation == null || elevation >= 0.0),
+ assert(highlightElevation == null || highlightElevation >= 0.0),
+ assert(disabledElevation == null || disabledElevation >= 0.0),
+ super(
+ key: key,
+ onPressed: onPressed,
+ onHighlightChanged: onHighlightChanged,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorBrightness: colorBrightness,
+ elevation: elevation,
+ highlightElevation: highlightElevation,
+ disabledElevation: disabledElevation,
+ padding: padding,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ materialTapTargetSize: materialTapTargetSize,
+ animationDuration: animationDuration,
+ child: child,
+ );
/// Create a filled button from a pair of widgets that serve as the button's
/// [icon] and [label].
@@ -82,325 +100,51 @@
///
/// The [elevation], [highlightElevation], [disabledElevation], [icon],
/// [label], and [clipBehavior] arguments must not be null.
- RaisedButton.icon({
+ factory RaisedButton.icon({
Key key,
- @required this.onPressed,
- this.onHighlightChanged,
- this.textTheme,
- this.textColor,
- this.disabledTextColor,
- this.color,
- this.disabledColor,
- this.highlightColor,
- this.splashColor,
- this.colorBrightness,
- this.elevation = 2.0,
- this.highlightElevation = 8.0,
- this.disabledElevation = 0.0,
- this.shape,
- this.clipBehavior = Clip.none,
- this.materialTapTargetSize,
- this.animationDuration = kThemeChangeDuration,
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ double elevation,
+ double highlightElevation,
+ double disabledElevation,
+ ShapeBorder shape,
+ Clip clipBehavior,
+ MaterialTapTargetSize materialTapTargetSize,
+ Duration animationDuration,
@required Widget icon,
@required Widget label,
- }) : assert(elevation != null),
- assert(highlightElevation != null),
- assert(disabledElevation != null),
- assert(icon != null),
- assert(label != null),
- assert(animationDuration != null),
- assert(clipBehavior != null),
- padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
- child = Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- icon,
- const SizedBox(width: 8.0),
- label,
- ],
- ),
- super(key: key);
+ }) = _RaisedButtonWithIcon;
- /// Called when the button is tapped or otherwise activated.
- ///
- /// If this is set to null, the button will be disabled, see [enabled].
- final VoidCallback onPressed;
-
- /// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
- /// callback.
- final ValueChanged<bool> onHighlightChanged;
-
- /// Defines the button's base colors, and the defaults for the button's minimum
- /// size, internal padding, and shape.
- ///
- /// Defaults to `ButtonTheme.of(context).textTheme`.
- final ButtonTextTheme textTheme;
-
- /// The color to use for this button's text.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default text color depends on the button theme's text theme,
- /// [ButtonThemeData.textTheme].
- ///
- /// See also:
- /// * [disabledTextColor], the text color to use when the button has been
- /// disabled.
- final Color textColor;
-
- /// The color to use for this button's text when the button is disabled.
- ///
- /// The button's [Material.textStyle] will be the current theme's button
- /// text style, [ThemeData.textTheme.button], configured with this color.
- ///
- /// The default value is the theme's disabled color,
- /// [ThemeData.disabledColor].
- ///
- /// See also:
- /// * [textColor] - The color to use for this button's text when the button is [enabled].
- final Color disabledTextColor;
-
- /// The button's fill color, displayed by its [Material], while it
- /// is in its default (unpressed, [enabled]) state.
- ///
- /// The default fill color is the theme's button color, [ThemeData.buttonColor].
- ///
- /// Typically the default color will be overidden with a Material color,
- /// for example:
- ///
- /// ```dart
- /// RaisedButton(
- /// color: Colors.blue,
- /// onPressed: _handleTap,
- /// child: Text('DEMO'),
- /// ),
- /// ```
- ///
- /// See also:
- /// * [disabledColor] - the fill color of the button when the button is disabled.
- final Color color;
-
- /// The fill color of the button when the button is disabled.
- ///
- /// The default value of this color is the theme's disabled color,
- /// [ThemeData.disabledColor].
- ///
- /// See also:
- /// * [color] - the fill color of the button when the button is [enabled].
- final Color disabledColor;
-
- /// The splash color of the button's [InkWell].
- ///
- /// The ink splash indicates that the button has been touched. It
- /// appears on top of the button's child and spreads in an expanding
- /// circle beginning where the touch occurred.
- ///
- /// The default splash color is the current theme's splash color,
- /// [ThemeData.splashColor].
- ///
- /// The appearance of the splash can be configured with the theme's splash
- /// factory, [ThemeData.splashFactory].
- final Color splashColor;
-
- /// The highlight color of the button's [InkWell].
- ///
- /// The highlight indicates that the button is actively being pressed. It
- /// appears on top of the button's child and quickly spreads to fill
- /// the button, and then fades out.
- ///
- /// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
- /// transparent (in other words the highlight doesn't appear). Otherwise it's
- /// the current theme's highlight color, [ThemeData.highlightColor].
- final Color highlightColor;
-
- /// The z-coordinate at which to place this button. This controls the size of
- /// the shadow below the raised button.
- ///
- /// Defaults to 2, the appropriate elevation for raised buttons.
- ///
- /// See also:
- ///
- /// * [FlatButton], a button with no elevation or fill color.
- /// * [disabledElevation], the elevation when the button is disabled.
- /// * [highlightElevation], the elevation when the button is pressed.
- final double elevation;
-
- /// The elevation for the button's [Material] when the button
- /// is [enabled] but not pressed.
- ///
- /// Defaults to 2.0.
- ///
- /// See also:
- ///
- /// * [highlightElevation], the default elevation.
- /// * [disabledElevation], the elevation when the button is disabled.
-
- /// The elevation for the button's [Material] when the button
- /// is [enabled] and pressed.
- ///
- /// This controls the size of the shadow below the button. When a tap
- /// down gesture occurs within the button, its [InkWell] displays a
- /// [highlightColor] "highlight".
- ///
- /// Defaults to 8.0.
- ///
- /// See also:
- ///
- /// * [elevation], the default elevation.
- /// * [disabledElevation], the elevation when the button is disabled.
- final double highlightElevation;
-
- /// The elevation for the button's [Material] when the button
- /// is not [enabled].
- ///
- /// Defaults to 0.0.
- ///
- /// See also:
- ///
- /// * [elevation], the default elevation.
- /// * [highlightElevation], the elevation when the button is pressed.
- final double disabledElevation;
-
- /// The theme brightness to use for this button.
- ///
- /// Defaults to the theme's brightness, [ThemeData.brightness].
- final Brightness colorBrightness;
-
- /// The button's label.
- ///
- /// Often a [Text] widget in all caps.
- final Widget child;
-
- /// Whether the button is enabled or disabled.
- ///
- /// Buttons are disabled by default. To enable a button, set its [onPressed]
- /// property to a non-null value.
- bool get enabled => onPressed != null;
-
- /// The internal padding for the button's [child].
- ///
- /// Defaults to the value from the current [ButtonTheme],
- /// [ButtonThemeData.padding].
- final EdgeInsetsGeometry padding;
-
- /// The shape of the button's [Material].
- ///
- /// The button's highlight and splash are clipped to this shape. If the
- /// button has an elevation, then its drop shadow is defined by this
- /// shape as well.
- final ShapeBorder shape;
-
- /// {@macro flutter.widgets.Clip}
- final Clip clipBehavior;
-
- /// Defines the duration of animated changes for [shape] and [elevation].
- ///
- /// The default value is [kThemeChangeDuration].
- final Duration animationDuration;
-
- /// Configures the minimum size of the tap target.
- ///
- /// Defaults to [ThemeData.materialTapTargetSize].
- ///
- /// See also:
- ///
- /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
- final MaterialTapTargetSize materialTapTargetSize;
-
- Brightness _getBrightness(ThemeData theme) {
- return colorBrightness ?? theme.brightness;
- }
-
- ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
- return textTheme ?? buttonTheme.textTheme;
- }
-
- Color _getFillColor(ThemeData theme, ButtonThemeData buttonTheme) {
- final Color fillColor = enabled ? color : disabledColor;
- if (fillColor != null)
- return fillColor;
-
- final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- case ButtonTextTheme.accent:
- return enabled
- ? theme.buttonColor
- : theme.disabledColor;
- case ButtonTextTheme.primary:
- return enabled
- ? theme.buttonColor
- : (themeIsDark ? Colors.white12 : Colors.black12);
- }
- return null;
- }
-
- Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
- final Color color = enabled ? textColor : disabledTextColor;
- if (color != null)
- return color;
-
- final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
- final bool fillIsDark = fillColor != null
- ? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
- : themeIsDark;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- return enabled
- ? (themeIsDark ? Colors.white : Colors.black87)
- : theme.disabledColor;
- case ButtonTextTheme.accent:
- return enabled
- ? theme.accentColor
- : theme.disabledColor;
- case ButtonTextTheme.primary:
- return enabled
- ? (fillIsDark ? Colors.white : Colors.black)
- : (themeIsDark ? Colors.white30 : Colors.black38);
- }
- return null;
- }
-
- Color _getHighlightColor(ThemeData theme, ButtonThemeData buttonTheme) {
- if (highlightColor != null)
- return highlightColor;
-
- switch (_getTextTheme(buttonTheme)) {
- case ButtonTextTheme.normal:
- case ButtonTextTheme.accent:
- return theme.highlightColor;
- case ButtonTextTheme.primary:
- return Colors.transparent;
- }
- return Colors.transparent;
- }
-
- @override
+ @override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
- final Color fillColor = _getFillColor(theme, buttonTheme);
- final Color textColor = _getTextColor(theme, buttonTheme, fillColor);
return RawMaterialButton(
onPressed: onPressed,
onHighlightChanged: onHighlightChanged,
- fillColor: fillColor,
- textStyle: theme.textTheme.button.copyWith(color: textColor),
- highlightColor: _getHighlightColor(theme, buttonTheme),
- splashColor: splashColor ?? theme.splashColor,
- elevation: elevation,
- highlightElevation: highlightElevation,
- disabledElevation: disabledElevation,
- padding: padding ?? buttonTheme.padding,
- constraints: buttonTheme.constraints,
- shape: shape ?? buttonTheme.shape,
- clipBehavior: clipBehavior,
- animationDuration: animationDuration,
+ clipBehavior: clipBehavior ?? Clip.none,
+ fillColor: buttonTheme.getFillColor(this),
+ textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
+ highlightColor: buttonTheme.getHighlightColor(this),
+ splashColor: buttonTheme.getSplashColor(this),
+ elevation: buttonTheme.getElevation(this),
+ highlightElevation: buttonTheme.getHighlightElevation(this),
+ disabledElevation: buttonTheme.getDisabledElevation(this),
+ padding: buttonTheme.getPadding(this),
+ constraints: buttonTheme.getConstraints(this),
+ shape: buttonTheme.getShape(this),
+ animationDuration: buttonTheme.getAnimationDuration(this),
+ materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
child: child,
- materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
);
}
@@ -422,3 +166,64 @@
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
}
}
+
+/// The type of of RaisedButtons created with [RaisedButton.icon].
+///
+/// This class only exists to give RaisedButtons created with [RaisedButton.icon]
+/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
+class _RaisedButtonWithIcon extends RaisedButton implements MaterialButtonWithIconMixin {
+ _RaisedButtonWithIcon({
+ Key key,
+ @required VoidCallback onPressed,
+ ValueChanged<bool> onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ double elevation,
+ double highlightElevation,
+ double disabledElevation,
+ ShapeBorder shape,
+ Clip clipBehavior = Clip.none,
+ MaterialTapTargetSize materialTapTargetSize,
+ Duration animationDuration,
+ @required Widget icon,
+ @required Widget label,
+ }) : assert(elevation == null || elevation >= 0.0),
+ assert(highlightElevation == null || highlightElevation >= 0.0),
+ assert(disabledElevation == null || disabledElevation >= 0.0),
+ assert(icon != null),
+ assert(label != null),
+ super(
+ key: key,
+ onPressed: onPressed,
+ onHighlightChanged: onHighlightChanged,
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorBrightness: colorBrightness,
+ elevation: elevation,
+ highlightElevation: highlightElevation,
+ disabledElevation: disabledElevation,
+ shape: shape,
+ clipBehavior: clipBehavior,
+ materialTapTargetSize: materialTapTargetSize,
+ animationDuration: animationDuration,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: <Widget>[
+ icon,
+ const SizedBox(width: 8.0),
+ label,
+ ],
+ ),
+ );
+}
diff --git a/packages/flutter/lib/src/material/stepper.dart b/packages/flutter/lib/src/material/stepper.dart
index ccce366..d091855 100644
--- a/packages/flutter/lib/src/material/stepper.dart
+++ b/packages/flutter/lib/src/material/stepper.dart
@@ -12,8 +12,8 @@
import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
+import 'text_theme.dart';
import 'theme.dart';
-import 'typography.dart';
// TODO(dragostis): Missing functionality:
// * mobile horizontal mode with adding/removing steps
diff --git a/packages/flutter/lib/src/material/text_theme.dart b/packages/flutter/lib/src/material/text_theme.dart
new file mode 100644
index 0000000..9d21e5e
--- /dev/null
+++ b/packages/flutter/lib/src/material/text_theme.dart
@@ -0,0 +1,540 @@
+// 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/foundation.dart';
+import 'package:flutter/painting.dart';
+
+import 'typography.dart';
+
+/// Material design text theme.
+///
+/// Definitions for the various typographical styles found in material design
+/// (e.g., button, caption). Rather than creating a [TextTheme] directly,
+/// you can obtain an instance as [Typography.black] or [Typography.white].
+///
+/// To obtain the current text theme, call [Theme.of] with the current
+/// [BuildContext] and read the [ThemeData.textTheme] property.
+///
+/// The Material Design typography scheme was signficantly changed in the
+/// current (2018) version of the specification
+/// (https://material.io/design/typography).
+///
+/// The 2018 spec has thirteen text styles:
+/// ```
+/// NAME SIZE WEIGHT SPACING
+/// headline1 96.0 light -1.5
+/// headline2 60.0 light -0.5
+/// headline3 48.0 normal 0.0
+/// headline4 34.0 normal 0.25
+/// headline5 24.0 normal 0.0
+/// headline6 20.0 medium 0.15
+/// subtitle1 16.0 normal 0.15
+/// subtitle2 14.0 medium 0.1
+/// body1 16.0 normal 0.5
+/// body2 14.0 normal 0.25
+/// button 14.0 medium 0.75
+/// caption 12.0 normal 0.4
+/// overline 10.0 normal 1.5
+///
+/// ```
+/// Where "light" is `FontWeight.w300`, "normal" is `FontWeight.w400` and
+/// "medium" is `FontWeight.w500`.
+///
+/// The [TextTheme] API is based on the original material (2014)
+/// design spec, which used different text style names. For backwards
+/// compatability's sake, this API continues to use the original
+/// names. The table below should help with understanding the API in
+/// terms of the 2018 material spec.
+///
+/// Each of the [TextTheme] text styles corresponds to one of the
+/// styles from 2018 spec. By default, the font sizes, font weights
+/// and letter spacings have not changed from their original,
+/// 2014, values.
+/// ```
+/// NAME SIZE WEIGHT SPACING 2018 NAME
+/// display4 112.0 thin 0.0 headline1
+/// display3 56.0 normal 0.0 headline2
+/// display2 45.0 normal 0.0 headline3
+/// display1 34.0 normal 0.0 headline4
+/// headline 24.0 normal 0.0 headline5
+/// title 20.0 medium 0.0 headline6
+/// subhead 16.0 normal 0.0 subtitle1
+/// body2 14.0 medium 0.0 body1
+/// body1 14.0 normal 0.0 body2
+/// caption 12.0 normal 0.0 caption
+/// button 14.0 medium 0.0 button
+/// subtitle 14.0 medium 0.0 subtitle2
+/// overline 10.0 normal 0.0 overline
+/// ```
+///
+/// Where "thin" is `FontWeight.w100`, "normal" is `FontWeight.w400` and
+/// "medium" is `FontWeight.w500`. Letter spacing for all of the original
+/// text styles was 0.0.
+///
+/// To configure a [Theme] for the new sizes, weights, and letter spacings,
+/// initialize its [ThemeData.typography] value with a [Typography] that
+/// object that specifies the 2018 versions of the geometry themes:
+/// [Typography.englishLike2018], [Typography.dense2018],
+/// and [Typography.tall2018].
+///
+/// The following image [from the material design
+/// specification](https://material.io/go/design-typography#typography-styles)
+/// shows the recommended styles for each of the properties of a [TextTheme].
+/// This image uses the `Roboto` font, which is the font used on Android. On
+/// iOS, the [San Francisco
+/// font](https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/)
+/// is automatically used instead.
+///
+/// 
+///
+/// See also:
+///
+/// * [Typography], the class that generates [TextTheme]s appropriate for a platform.
+/// * [Theme], for other aspects of a material design application that can be
+/// globally adjusted, such as the color scheme.
+/// * <http://material.google.com/style/typography.html>
+@immutable
+class TextTheme extends Diagnosticable {
+ /// Creates a text theme that uses the given values.
+ ///
+ /// Rather than creating a new text theme, consider using [Typography.black]
+ /// or [Typography.white], which implement the typography styles in the
+ /// material design specification:
+ ///
+ /// <https://material.google.com/style/typography.html#typography-styles>
+ ///
+ /// If you do decide to create your own text theme, consider using one of
+ /// those predefined themes as a starting point for [copyWith] or [apply].
+ const TextTheme({
+ this.display4,
+ this.display3,
+ this.display2,
+ this.display1,
+ this.headline,
+ this.title,
+ this.subhead,
+ this.body2,
+ this.body1,
+ this.caption,
+ this.button,
+ this.subtitle,
+ this.overline,
+ });
+
+ /// Extremely large text.
+ ///
+ /// The font size is 112 pixels.
+ final TextStyle display4;
+
+ /// Very, very large text.
+ ///
+ /// Used for the date in the dialog shown by [showDatePicker].
+ final TextStyle display3;
+
+ /// Very large text.
+ final TextStyle display2;
+
+ /// Large text.
+ final TextStyle display1;
+
+ /// Used for large text in dialogs (e.g., the month and year in the dialog
+ /// shown by [showDatePicker]).
+ final TextStyle headline;
+
+ /// Used for the primary text in app bars and dialogs (e.g., [AppBar.title]
+ /// and [AlertDialog.title]).
+ final TextStyle title;
+
+ /// Used for the primary text in lists (e.g., [ListTile.title]).
+ final TextStyle subhead;
+
+ /// Used for emphasizing text that would otherwise be [body1].
+ final TextStyle body2;
+
+ /// Used for the default text style for [Material].
+ final TextStyle body1;
+
+ /// Used for auxiliary text associated with images.
+ final TextStyle caption;
+
+ /// Used for text on [RaisedButton] and [FlatButton].
+ final TextStyle button;
+
+ /// For medium emphasis text that's a little smaller than [subhead].
+ final TextStyle subtitle;
+
+ /// The smallest style,
+ ///
+ /// Typically used for captions or to introduce a (larger) headline.
+ final TextStyle overline;
+
+ /// Creates a copy of this text theme but with the given fields replaced with
+ /// the new values.
+ ///
+ /// Consider using [Typography.black] or [Typography.white], which implement
+ /// the typography styles in the material design specification, as a starting
+ /// point.
+ ///
+ /// ## Sample code
+ ///
+ /// ```dart
+ /// /// A Widget that sets the ambient theme's title text color for its
+ /// /// descendants, while leaving other ambient theme attributes alone.
+ /// class TitleColorThemeCopy extends StatelessWidget {
+ /// TitleColorThemeCopy({Key key, this.child, this.titleColor}) : super(key: key);
+ ///
+ /// final Color titleColor;
+ /// final Widget child;
+ ///
+ /// @override
+ /// Widget build(BuildContext context) {
+ /// final ThemeData theme = Theme.of(context);
+ /// return Theme(
+ /// data: theme.copyWith(
+ /// textTheme: theme.textTheme.copyWith(
+ /// title: theme.textTheme.title.copyWith(
+ /// color: titleColor,
+ /// ),
+ /// ),
+ /// ),
+ /// child: child,
+ /// );
+ /// }
+ /// }
+ /// ```
+ ///
+ /// See also:
+ ///
+ /// * [merge] is used instead of [copyWith] when you want to merge all
+ /// of the fields of a TextTheme instead of individual fields.
+ TextTheme copyWith({
+ TextStyle display4,
+ TextStyle display3,
+ TextStyle display2,
+ TextStyle display1,
+ TextStyle headline,
+ TextStyle title,
+ TextStyle subhead,
+ TextStyle body2,
+ TextStyle body1,
+ TextStyle caption,
+ TextStyle button,
+ TextStyle subtitle,
+ TextStyle overline,
+ }) {
+ return TextTheme(
+ display4: display4 ?? this.display4,
+ display3: display3 ?? this.display3,
+ display2: display2 ?? this.display2,
+ display1: display1 ?? this.display1,
+ headline: headline ?? this.headline,
+ title: title ?? this.title,
+ subhead: subhead ?? this.subhead,
+ body2: body2 ?? this.body2,
+ body1: body1 ?? this.body1,
+ caption: caption ?? this.caption,
+ button: button ?? this.button,
+ subtitle: subtitle ?? this.subtitle,
+ overline: overline ?? this.overline,
+ );
+ }
+
+ /// Creates a new [TextTheme] where each text style from this object has been
+ /// merged with the matching text style from the `other` object.
+ ///
+ /// The merging is done by calling [TextStyle.merge] on each respective pair
+ /// of text styles from this and the [other] text themes and is subject to
+ /// the value of [TextStyle.inherit] flag. For more details, see the
+ /// documentation on [TextStyle.merge] and [TextStyle.inherit].
+ ///
+ /// If this theme, or the `other` theme has members that are null, then the
+ /// non-null one (if any) is used. If the `other` theme is itself null, then
+ /// this [TextTheme] is returned unchanged. If values in both are set, then
+ /// the values are merged using [TextStyle.merge].
+ ///
+ /// This is particularly useful if one [TextTheme] defines one set of
+ /// properties and another defines a different set, e.g. having colors
+ /// defined in one text theme and font sizes in another, or when one
+ /// [TextTheme] has only some fields defined, and you want to define the rest
+ /// by merging it with a default theme.
+ ///
+ /// ## Sample code
+ ///
+ /// ```dart
+ /// /// A Widget that sets the ambient theme's title text color for its
+ /// /// descendants, while leaving other ambient theme attributes alone.
+ /// class TitleColorTheme extends StatelessWidget {
+ /// TitleColorTheme({Key key, this.child, this.titleColor}) : super(key: key);
+ ///
+ /// final Color titleColor;
+ /// final Widget child;
+ ///
+ /// @override
+ /// Widget build(BuildContext context) {
+ /// ThemeData theme = Theme.of(context);
+ /// // This partialTheme is incomplete: it only has the title style
+ /// // defined. Just replacing theme.textTheme with partialTheme would
+ /// // set the title, but everything else would be null. This isn't very
+ /// // useful, so merge it with the existing theme to keep all of the
+ /// // preexisting definitions for the other styles.
+ /// TextTheme partialTheme = TextTheme(title: TextStyle(color: titleColor));
+ /// theme = theme.copyWith(textTheme: theme.textTheme.merge(partialTheme));
+ /// return Theme(data: theme, child: child);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// See also:
+ ///
+ /// * [copyWith] is used instead of [merge] when you wish to override
+ /// individual fields in the [TextTheme] instead of merging all of the
+ /// fields of two [TextTheme]s.
+ TextTheme merge(TextTheme other) {
+ if (other == null)
+ return this;
+ return copyWith(
+ display4: display4?.merge(other.display4) ?? other.display4,
+ display3: display3?.merge(other.display3) ?? other.display3,
+ display2: display2?.merge(other.display2) ?? other.display2,
+ display1: display1?.merge(other.display1) ?? other.display1,
+ headline: headline?.merge(other.headline) ?? other.headline,
+ title: title?.merge(other.title) ?? other.title,
+ subhead: subhead?.merge(other.subhead) ?? other.subhead,
+ body2: body2?.merge(other.body2) ?? other.body2,
+ body1: body1?.merge(other.body1) ?? other.body1,
+ caption: caption?.merge(other.caption) ?? other.caption,
+ button: button?.merge(other.button) ?? other.button,
+ subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle,
+ overline: overline?.merge(other.overline) ?? other.overline,
+ );
+ }
+
+ /// Creates a copy of this text theme but with the given field replaced in
+ /// each of the individual text styles.
+ ///
+ /// The `displayColor` is applied to [display4], [display3], [display2],
+ /// [display1], and [caption]. The `bodyColor` is applied to the remaining
+ /// text styles.
+ ///
+ /// Consider using [Typography.black] or [Typography.white], which implement
+ /// the typography styles in the material design specification, as a starting
+ /// point.
+ TextTheme apply({
+ String fontFamily,
+ double fontSizeFactor = 1.0,
+ double fontSizeDelta = 0.0,
+ Color displayColor,
+ Color bodyColor,
+ TextDecoration decoration,
+ Color decorationColor,
+ TextDecorationStyle decorationStyle,
+ }) {
+ return TextTheme(
+ display4: display4.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ display3: display3.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ display2: display2.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ display1: display1.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ headline: headline.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ title: title.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ subhead: subhead.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ body2: body2.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ body1: body1.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ caption: caption.apply(
+ color: displayColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ button: button.apply(
+ color: bodyColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ subtitle: subtitle.apply(
+ color: bodyColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ overline: overline.apply(
+ color: bodyColor,
+ decoration: decoration,
+ decorationColor: decorationColor,
+ decorationStyle: decorationStyle,
+ fontFamily: fontFamily,
+ fontSizeFactor: fontSizeFactor,
+ fontSizeDelta: fontSizeDelta,
+ ),
+ );
+ }
+
+ /// Linearly interpolate between two text themes.
+ ///
+ /// The arguments must not be null.
+ ///
+ /// {@macro flutter.material.themeData.lerp}
+ static TextTheme lerp(TextTheme a, TextTheme b, double t) {
+ assert(a != null);
+ assert(b != null);
+ assert(t != null);
+ return TextTheme(
+ display4: TextStyle.lerp(a.display4, b.display4, t),
+ display3: TextStyle.lerp(a.display3, b.display3, t),
+ display2: TextStyle.lerp(a.display2, b.display2, t),
+ display1: TextStyle.lerp(a.display1, b.display1, t),
+ headline: TextStyle.lerp(a.headline, b.headline, t),
+ title: TextStyle.lerp(a.title, b.title, t),
+ subhead: TextStyle.lerp(a.subhead, b.subhead, t),
+ body2: TextStyle.lerp(a.body2, b.body2, t),
+ body1: TextStyle.lerp(a.body1, b.body1, t),
+ caption: TextStyle.lerp(a.caption, b.caption, t),
+ button: TextStyle.lerp(a.button, b.button, t),
+ subtitle: TextStyle.lerp(a.subtitle, b.subtitle, t),
+ overline: TextStyle.lerp(a.overline, b.overline, t),
+ );
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ if (identical(this, other))
+ return true;
+ if (other.runtimeType != runtimeType)
+ return false;
+ final TextTheme typedOther = other;
+ return display4 == typedOther.display4
+ && display3 == typedOther.display3
+ && display2 == typedOther.display2
+ && display1 == typedOther.display1
+ && headline == typedOther.headline
+ && title == typedOther.title
+ && subhead == typedOther.subhead
+ && body2 == typedOther.body2
+ && body1 == typedOther.body1
+ && caption == typedOther.caption
+ && button == typedOther.button
+ && subtitle == typedOther.subtitle
+ && overline == typedOther.overline;
+ }
+
+ @override
+ int get hashCode {
+ // The hashValues() function supports up to 20 arguments.
+ return hashValues(
+ display4,
+ display3,
+ display2,
+ display1,
+ headline,
+ title,
+ subhead,
+ body2,
+ body1,
+ caption,
+ button,
+ subtitle,
+ overline,
+ );
+ }
+
+ @override
+ void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+ super.debugFillProperties(properties);
+ final TextTheme defaultTheme = Typography(platform: defaultTargetPlatform).black;
+ properties.add(DiagnosticsProperty<TextStyle>('display4', display4, defaultValue: defaultTheme.display4));
+ properties.add(DiagnosticsProperty<TextStyle>('display3', display3, defaultValue: defaultTheme.display3));
+ properties.add(DiagnosticsProperty<TextStyle>('display2', display2, defaultValue: defaultTheme.display2));
+ properties.add(DiagnosticsProperty<TextStyle>('display1', display1, defaultValue: defaultTheme.display1));
+ properties.add(DiagnosticsProperty<TextStyle>('headline', headline, defaultValue: defaultTheme.headline));
+ properties.add(DiagnosticsProperty<TextStyle>('title', title, defaultValue: defaultTheme.title));
+ properties.add(DiagnosticsProperty<TextStyle>('subhead', subhead, defaultValue: defaultTheme.subhead));
+ properties.add(DiagnosticsProperty<TextStyle>('body2', body2, defaultValue: defaultTheme.body2));
+ properties.add(DiagnosticsProperty<TextStyle>('body1', body1, defaultValue: defaultTheme.body1));
+ properties.add(DiagnosticsProperty<TextStyle>('caption', caption, defaultValue: defaultTheme.caption));
+ properties.add(DiagnosticsProperty<TextStyle>('button', button, defaultValue: defaultTheme.button));
+ properties.add(DiagnosticsProperty<TextStyle>('subtitle)', subtitle, defaultValue: defaultTheme.subtitle));
+ properties.add(DiagnosticsProperty<TextStyle>('overline', overline, defaultValue: defaultTheme.overline));
+ }
+}
diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart
index 081e5e9..dc52326 100644
--- a/packages/flutter/lib/src/material/theme.dart
+++ b/packages/flutter/lib/src/material/theme.dart
@@ -124,18 +124,17 @@
/// }
/// ```
static ThemeData of(BuildContext context, { bool shadowThemeOnly = false }) {
- final _InheritedTheme inheritedTheme =
- context.inheritFromWidgetOfExactType(_InheritedTheme);
+ final _InheritedTheme inheritedTheme = context.inheritFromWidgetOfExactType(_InheritedTheme);
if (shadowThemeOnly) {
if (inheritedTheme == null || inheritedTheme.theme.isMaterialAppTheme)
return null;
return inheritedTheme.theme.data;
}
- 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);
+ final ScriptCategory category = localizations?.scriptCategory ?? ScriptCategory.englishLike;
+ final ThemeData theme = inheritedTheme?.theme?.data ?? _kFallbackTheme;
+ return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
}
@override
diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart
index 5bf3eb7..e6639e2 100644
--- a/packages/flutter/lib/src/material/theme_data.dart
+++ b/packages/flutter/lib/src/material/theme_data.dart
@@ -10,6 +10,7 @@
import 'button_theme.dart';
import 'chip_theme.dart';
+import 'color_scheme.dart';
import 'colors.dart';
import 'ink_splash.dart';
import 'ink_well.dart' show InteractiveInkFeatureFactory;
@@ -17,6 +18,7 @@
import 'page_transitions_theme.dart';
import 'slider_theme.dart';
import 'tab_bar_theme.dart';
+import 'text_theme.dart';
import 'typography.dart';
export 'package:flutter/services.dart' show Brightness;
@@ -147,8 +149,9 @@
TargetPlatform platform,
MaterialTapTargetSize materialTapTargetSize,
PageTransitionsTheme pageTransitionsTheme,
+ ColorScheme colorScheme,
+ Typography typography,
}) {
- materialTapTargetSize ??= MaterialTapTargetSize.padded;
brightness ??= Brightness.light;
final bool isDark = brightness == Brightness.dark;
primarySwatch ??= Colors.blue;
@@ -166,14 +169,22 @@
bottomAppBarColor ??= isDark ? Colors.grey[800] : Colors.white;
cardColor ??= isDark ? Colors.grey[800] : Colors.white;
dividerColor ??= isDark ? const Color(0x1FFFFFFF) : const Color(0x1F000000);
- highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
- splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
+
+ // Create a ColorScheme that is backwards compatible as possible
+ // with the existing default ThemeData color values.
+ colorScheme ??= ColorScheme.fromSwatch(
+ primarySwatch: primarySwatch,
+ primaryColorDark: primaryColorDark,
+ accentColor: accentColor,
+ cardColor: cardColor,
+ backgroundColor: backgroundColor,
+ errorColor: errorColor,
+ brightness: brightness,
+ );
+
splashFactory ??= InkSplash.splashFactory;
selectedRowColor ??= Colors.grey[100];
unselectedWidgetColor ??= isDark ? Colors.white70 : Colors.black54;
- disabledColor ??= isDark ? Colors.white30 : Colors.black38;
- buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
- buttonTheme ??= const ButtonThemeData();
// Spec doesn't specify a dark theme secondaryHeaderColor, this is a guess.
secondaryHeaderColor ??= isDark ? Colors.grey[700] : primarySwatch[50];
textSelectionColor ??= isDark ? accentColor : primarySwatch[200];
@@ -191,18 +202,35 @@
accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black87);
platform ??= defaultTargetPlatform;
- final Typography typography = Typography(platform: platform);
+ typography ??= Typography(platform: platform);
final TextTheme defaultTextTheme = isDark ? typography.white : typography.black;
textTheme = defaultTextTheme.merge(textTheme);
final TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black;
primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme);
final TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black;
accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme);
+ materialTapTargetSize ??= MaterialTapTargetSize.padded;
if (fontFamily != null) {
textTheme = textTheme.apply(fontFamily: fontFamily);
primaryTextTheme = primaryTextTheme.apply(fontFamily: fontFamily);
accentTextTheme = accentTextTheme.apply(fontFamily: fontFamily);
}
+
+ // Used as the default color (fill color) for RaisedButtons. Computing the
+ // default for ButtonThemeData for the sake of backwards compatibility.
+ buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
+ buttonTheme ??= ButtonThemeData(
+ colorScheme: colorScheme,
+ buttonColor: buttonColor,
+ disabledColor: disabledColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ materialTapTargetSize: materialTapTargetSize,
+ );
+ disabledColor ??= isDark ? Colors.white30 : Colors.black38;
+ highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
+ splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
+
sliderTheme ??= SliderThemeData.fromPrimaryColors(
primaryColor: primaryColor,
primaryColorLight: primaryColorLight,
@@ -235,9 +263,9 @@
selectedRowColor: selectedRowColor,
unselectedWidgetColor: unselectedWidgetColor,
disabledColor: disabledColor,
+ buttonTheme: buttonTheme,
buttonColor: buttonColor,
toggleableActiveColor: toggleableActiveColor,
- buttonTheme: buttonTheme,
secondaryHeaderColor: secondaryHeaderColor,
textSelectionColor: textSelectionColor,
cursorColor: cursorColor,
@@ -260,6 +288,8 @@
platform: platform,
materialTapTargetSize: materialTapTargetSize,
pageTransitionsTheme: pageTransitionsTheme,
+ colorScheme: colorScheme,
+ typography: typography,
);
}
@@ -278,9 +308,9 @@
@required this.primaryColorBrightness,
@required this.primaryColorLight,
@required this.primaryColorDark,
+ @required this.canvasColor,
@required this.accentColor,
@required this.accentColorBrightness,
- @required this.canvasColor,
@required this.scaffoldBackgroundColor,
@required this.bottomAppBarColor,
@required this.cardColor,
@@ -291,8 +321,8 @@
@required this.selectedRowColor,
@required this.unselectedWidgetColor,
@required this.disabledColor,
- @required this.buttonColor,
@required this.buttonTheme,
+ @required this.buttonColor,
@required this.secondaryHeaderColor,
@required this.textSelectionColor,
@required this.cursorColor,
@@ -316,6 +346,8 @@
@required this.platform,
@required this.materialTapTargetSize,
@required this.pageTransitionsTheme,
+ @required this.colorScheme,
+ @required this.typography,
}) : assert(brightness != null),
assert(primaryColor != null),
assert(primaryColorBrightness != null),
@@ -357,7 +389,13 @@
assert(chipTheme != null),
assert(platform != null),
assert(materialTapTargetSize != null),
- assert(pageTransitionsTheme != null);
+ assert(pageTransitionsTheme != null),
+ assert(colorScheme != null),
+ assert(typography != null);
+
+ // Warning: make sure these properties are in the exact same order as in
+ // hashValues() and in the raw constructor and in the order of fields in
+ // the class and in the lerp() method.
/// A default light blue theme.
///
@@ -407,6 +445,9 @@
/// A darker version of the [primaryColor].
final Color primaryColorDark;
+ /// The default color of [MaterialType.canvas] [Material].
+ final Color canvasColor;
+
/// The foreground color for widgets (knobs, text, overscroll edge effect, etc).
final Color accentColor;
@@ -415,9 +456,6 @@
/// action button).
final Brightness accentColorBrightness;
- /// The default color of [MaterialType.canvas] [Material].
- final Color canvasColor;
-
/// The default color of the [Material] that underlies the [Scaffold]. The
/// background color for a typical material app or a page within the app.
final Color scaffoldBackgroundColor;
@@ -467,17 +505,13 @@
/// checked or unchecked).
final Color disabledColor;
- /// The default fill color of the [Material] used in [RaisedButton]s.
- final Color buttonColor;
-
- /// The color used to highlight the active states of toggleable widgets like
- /// [Switch], [Radio], and [Checkbox].
- final Color toggleableActiveColor;
-
/// Defines the default configuration of button widgets, like [RaisedButton]
/// and [FlatButton].
final ButtonThemeData buttonTheme;
+ /// The default fill color of the [Material] used in [RaisedButton]s.
+ final Color buttonColor;
+
/// The color of the header of a [PaginatedDataTable] when there are selected rows.
// According to the spec for data tables:
// https://material.google.com/components/data-tables.html#data-tables-tables-within-cards
@@ -510,6 +544,10 @@
/// The color to use for input validation errors, e.g. in [TextField] fields.
final Color errorColor;
+ /// The color used to highlight the active states of toggleable widgets like
+ /// [Switch], [Radio], and [Checkbox].
+ final Color toggleableActiveColor;
+
/// Text with a color that contrasts with the card and canvas colors.
final TextTheme textTheme;
@@ -569,6 +607,20 @@
/// builder is not found, a builder whose platform is null is used.
final PageTransitionsTheme pageTransitionsTheme;
+ /// A set of thirteen colors that can be used to configure the
+ /// color properties of most components.
+ ///
+ /// This property was added much later than the theme's set of highly
+ /// specific colors, like [cardColor], [buttonColor], [canvasColor] etc.
+ /// New components can be defined exclusively in terms of [colorScheme].
+ /// Existing components will gradually migrate to it, to the extent
+ /// that is possible without significant backwards compatibility breaks.
+ final ColorScheme colorScheme;
+
+ /// The color and geometry [TextTheme] values used to configure [textTheme],
+ /// [primaryTextTheme], and [accentTextTheme].
+ final Typography typography;
+
/// Creates a copy of this theme but with the given fields replaced with the new values.
ThemeData copyWith({
Brightness brightness,
@@ -589,8 +641,8 @@
Color selectedRowColor,
Color unselectedWidgetColor,
Color disabledColor,
- Color buttonColor,
ButtonThemeData buttonTheme,
+ Color buttonColor,
Color secondaryHeaderColor,
Color textSelectionColor,
Color cursorColor,
@@ -614,6 +666,8 @@
TargetPlatform platform,
MaterialTapTargetSize materialTapTargetSize,
PageTransitionsTheme pageTransitionsTheme,
+ ColorScheme colorScheme,
+ Typography typography,
}) {
return ThemeData.raw(
brightness: brightness ?? this.brightness,
@@ -659,6 +713,8 @@
platform: platform ?? this.platform,
materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize,
pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme,
+ colorScheme: colorScheme ?? this.colorScheme,
+ typography: typography ?? this.typography,
);
}
@@ -736,6 +792,9 @@
assert(a != null);
assert(b != null);
assert(t != null);
+ // Warning: make sure these properties are in the exact same order as in
+ // hashValues() and in the raw constructor and in the order of fields in
+ // the class and in the lerp() method.
return ThemeData.raw(
brightness: t < 0.5 ? a.brightness : b.brightness,
primaryColor: Color.lerp(a.primaryColor, b.primaryColor, t),
@@ -755,9 +814,8 @@
selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t),
unselectedWidgetColor: Color.lerp(a.unselectedWidgetColor, b.unselectedWidgetColor, t),
disabledColor: Color.lerp(a.disabledColor, b.disabledColor, t),
- buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t),
- toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t),
buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme,
+ buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t),
secondaryHeaderColor: Color.lerp(a.secondaryHeaderColor, b.secondaryHeaderColor, t),
textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t),
cursorColor: Color.lerp(a.cursorColor, b.cursorColor, t),
@@ -767,6 +825,7 @@
indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t),
hintColor: Color.lerp(a.hintColor, b.hintColor, t),
errorColor: Color.lerp(a.errorColor, b.errorColor, t),
+ toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t),
textTheme: TextTheme.lerp(a.textTheme, b.textTheme, t),
primaryTextTheme: TextTheme.lerp(a.primaryTextTheme, b.primaryTextTheme, t),
accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t),
@@ -780,6 +839,8 @@
platform: t < 0.5 ? a.platform : b.platform,
materialTapTargetSize: t < 0.5 ? a.materialTapTargetSize : b.materialTapTargetSize,
pageTransitionsTheme: t < 0.5 ? a.pageTransitionsTheme : b.pageTransitionsTheme,
+ colorScheme: ColorScheme.lerp(a.colorScheme, b.colorScheme, t),
+ typography: Typography.lerp(a.typography, b.typography, t),
);
}
@@ -809,9 +870,8 @@
(otherData.selectedRowColor == selectedRowColor) &&
(otherData.unselectedWidgetColor == unselectedWidgetColor) &&
(otherData.disabledColor == disabledColor) &&
- (otherData.buttonColor == buttonColor) &&
- (otherData.toggleableActiveColor == toggleableActiveColor) &&
(otherData.buttonTheme == buttonTheme) &&
+ (otherData.buttonColor == buttonColor) &&
(otherData.secondaryHeaderColor == secondaryHeaderColor) &&
(otherData.textSelectionColor == textSelectionColor) &&
(otherData.cursorColor == cursorColor) &&
@@ -821,6 +881,7 @@
(otherData.indicatorColor == indicatorColor) &&
(otherData.hintColor == hintColor) &&
(otherData.errorColor == errorColor) &&
+ (otherData.toggleableActiveColor == toggleableActiveColor) &&
(otherData.textTheme == textTheme) &&
(otherData.primaryTextTheme == primaryTextTheme) &&
(otherData.accentTextTheme == accentTextTheme) &&
@@ -833,7 +894,9 @@
(otherData.chipTheme == chipTheme) &&
(otherData.platform == platform) &&
(otherData.materialTapTargetSize == materialTapTargetSize) &&
- (otherData.pageTransitionsTheme == pageTransitionsTheme);
+ (otherData.pageTransitionsTheme == pageTransitionsTheme) &&
+ (otherData.colorScheme == colorScheme) &&
+ (otherData.typography == typography);
}
@override
@@ -860,9 +923,11 @@
splashFactory,
selectedRowColor,
unselectedWidgetColor,
- buttonColor,
+ disabledColor,
buttonTheme,
hashValues(
+ buttonColor,
+ toggleableActiveColor,
secondaryHeaderColor,
textSelectionColor,
cursorColor,
@@ -872,7 +937,6 @@
indicatorColor,
hintColor,
errorColor,
- toggleableActiveColor,
textTheme,
primaryTextTheme,
accentTextTheme,
@@ -881,12 +945,14 @@
primaryIconTheme,
accentIconTheme,
sliderTheme,
- tabBarTheme,
hashValues(
+ tabBarTheme,
chipTheme,
platform,
materialTapTargetSize,
pageTransitionsTheme,
+ colorScheme,
+ typography,
),
),
);
@@ -936,6 +1002,8 @@
properties.add(DiagnosticsProperty<ChipThemeData>('chipTheme', chipTheme));
properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize));
properties.add(DiagnosticsProperty<PageTransitionsTheme>('pageTransitionsTheme', pageTransitionsTheme));
+ properties.add(DiagnosticsProperty<ColorScheme>('colorScheme', colorScheme, defaultValue: defaultData.colorScheme));
+ properties.add(DiagnosticsProperty<Typography>('typography', typography, defaultValue: defaultData.typography));
}
}
diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart
index d9739a9..b22c593 100644
--- a/packages/flutter/lib/src/material/time_picker.dart
+++ b/packages/flutter/lib/src/material/time_picker.dart
@@ -16,10 +16,10 @@
import 'feedback.dart';
import 'flat_button.dart';
import 'material_localizations.dart';
+import 'text_theme.dart';
import 'theme.dart';
import 'theme_data.dart';
import 'time.dart';
-import 'typography.dart';
const Duration _kDialAnimateDuration = Duration(milliseconds: 200);
const double _kTwoPi = 2 * math.pi;
diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart
index e10a44a..baa49d9 100644
--- a/packages/flutter/lib/src/material/typography.dart
+++ b/packages/flutter/lib/src/material/typography.dart
@@ -6,623 +6,447 @@
import 'package:flutter/painting.dart';
import 'colors.dart';
+import 'text_theme.dart';
+/// A characterization of the of a [TextTheme]'s glyphs that is used to define
+/// its localized [TextStyle] geometry for [ThemeData.textTheme].
+///
+/// The script category defines the overall geometry of a [TextTheme] for
+/// the static [MaterialTextGeometry.localizedFor] method in terms of the
+/// three language categories defined in <https://material.io/go/design-typography>.
+///
+/// Generally speaking, font sizes for [ScriptCategory.tall] and
+/// [ScriptCategory.dense] scripts - for text styles that are smaller than the
+/// title style - are one unit larger than they are for
+/// [ScriptCategory.englishLike] scripts.
+enum ScriptCategory {
+ /// The languages of Western, Central, and Eastern Europe and much of
+ /// Africa are typically written in the Latin alphabet. Vietnamese is a
+ /// notable exception in that, while it uses a localized form of the Latin
+ /// writing system, its accented glyphs can be much taller than those
+ /// found in Western European languages. The Greek and Cyrillic writing
+ /// systems are very similar to Latin.
+ englishLike,
+ /// Language scripts that require extra line height to accommodate larger
+ /// glyphs, including Chinese, Japanese, and Korean.
+ dense,
-/// Material design text theme.
+ /// Language scripts that require extra line height to accommodate
+ /// larger glyphs, including South and Southeast Asian and
+ /// Middle-Eastern languages, like Arabic, Hindi, Telugu, Thai, and
+ /// Vietnamese.
+ tall,
+}
+
+/// The color and geometry [TextThemes] for Material apps.
///
-/// Definitions for the various typographical styles found in material design
-/// (e.g., headline, caption). Rather than creating a [TextTheme] directly,
-/// you can obtain an instance as [Typography.black] or [Typography.white].
+/// The text themes provided by the overall [Theme], like
+/// [ThemeData.textTheme], are based on the current locale's
+/// [MaterialLocalizations.scriptCategory] and are created
+/// by merging a color text theme, [black] or [white]
+/// and a geometry text theme, one of [englishLike], [dense],
+/// or [tall], depending on the locale.
///
-/// To obtain the current text theme, call [Theme.of] with the current
-/// [BuildContext] and read the [ThemeData.textTheme] property.
+/// To lookup a localized text theme use
+/// `Theme.of(context).textTheme` or
+/// `Theme.of(context).primaryTextTheme` or
+/// `Theme.of(context).accentTextTheme`.
///
-/// The following image [from the material design
-/// specification](https://material.io/go/design-typography#typography-styles)
-/// shows the recommended styles for each of the properties of a [TextTheme].
-/// This image uses the `Roboto` font, which is the font used on Android. On
-/// iOS, the [San Francisco
-/// font](https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/)
-/// is automatically used instead.
+/// The color text themes are [blackMountainView],
+/// [whiteMountainView], and [blackCupertino] and [whiteCupertino]. The
+/// Mountain View theme [TextStyles] are based on the Roboto fonts and the
+/// Cupertino themes are based on the San Francisco fonts.
///
-/// 
+/// Two sets of geometry themes are provided: 2014 and 2018. The 2014 themes
+/// correspond to the original version of the Material Design spec and are
+/// the defaults. The 2018 themes correspond the second iteration of the
+/// specification and feature different font sizes, font weights, and
+/// letter spacing values.
+///
+/// By default, [ThemeData.typography] is
+/// `Typography(platform: platform)` which uses [englishLike2014],
+/// [dense2014] and [tall2014]. To use the 2018 text theme
+/// geometries, specify a typography value:
+/// ```
+/// Typography(
+/// platorm: platform,
+/// englishLike: Typography.englishLike2018,
+/// dense: Typography.dense2018,
+/// tall: Typography.tall2018,
+/// )
+/// ```
///
/// See also:
///
-/// * [Typography], the class that generates [TextTheme]s appropriate for a platform.
-/// * [Theme], for other aspects of a material design application that can be
-/// globally adjusted, such as the color scheme.
-/// * <http://material.google.com/style/typography.html>
+/// * [ThemeData.typography], which can be used to configure the
+/// text themes used to create [ThemeData.textTheme],
+/// [ThemeData.primaryTextTheme], [ThemeData.accentTextTheme].
+/// * <https://material.io/design/typography/>
@immutable
-class TextTheme extends Diagnosticable {
- /// Creates a text theme that uses the given values.
+class Typography extends Diagnosticable {
+ /// Creates a typography instance.
///
- /// Rather than creating a new text theme, consider using [Typography.black]
- /// or [Typography.white], which implement the typography styles in the
- /// material design specification:
+ /// If [platform] is specified, the default values for [black] and [white]
+ /// are [blackCupertino] and [whiteCupertino] respectively. Otherwise
+ /// they are [blackMountainView] and [whiteMoutainView].
///
- /// <https://material.google.com/style/typography.html#typography-styles>
- ///
- /// If you do decide to create your own text theme, consider using one of
- /// those predefined themes as a starting point for [copyWith] or [apply].
- const TextTheme({
- this.display4,
- this.display3,
- this.display2,
- this.display1,
- this.headline,
- this.title,
- this.subhead,
- this.body2,
- this.body1,
- this.caption,
- this.button,
- });
-
- /// Extremely large text.
- ///
- /// The font size is 112 pixels.
- final TextStyle display4;
-
- /// Very, very large text.
- ///
- /// Used for the date in the dialog shown by [showDatePicker].
- final TextStyle display3;
-
- /// Very large text.
- final TextStyle display2;
-
- /// Large text.
- final TextStyle display1;
-
- /// Used for large text in dialogs (e.g., the month and year in the dialog
- /// shown by [showDatePicker]).
- final TextStyle headline;
-
- /// Used for the primary text in app bars and dialogs (e.g., [AppBar.title]
- /// and [AlertDialog.title]).
- final TextStyle title;
-
- /// Used for the primary text in lists (e.g., [ListTile.title]).
- final TextStyle subhead;
-
- /// Used for emphasizing text that would otherwise be [body1].
- final TextStyle body2;
-
- /// Used for the default text style for [Material].
- final TextStyle body1;
-
- /// Used for auxiliary text associated with images.
- final TextStyle caption;
-
- /// Used for text on [RaisedButton] and [FlatButton].
- final TextStyle button;
-
- /// Creates a copy of this text theme but with the given fields replaced with
- /// the new values.
- ///
- /// Consider using [Typography.black] or [Typography.white], which implement
- /// the typography styles in the material design specification, as a starting
- /// point.
- ///
- /// ## Sample code
- ///
- /// ```dart
- /// /// A Widget that sets the ambient theme's title text color for its
- /// /// descendants, while leaving other ambient theme attributes alone.
- /// class TitleColorThemeCopy extends StatelessWidget {
- /// TitleColorThemeCopy({Key key, this.child, this.titleColor}) : super(key: key);
- ///
- /// final Color titleColor;
- /// final Widget child;
- ///
- /// @override
- /// Widget build(BuildContext context) {
- /// final ThemeData theme = Theme.of(context);
- /// return Theme(
- /// data: theme.copyWith(
- /// textTheme: theme.textTheme.copyWith(
- /// title: theme.textTheme.title.copyWith(
- /// color: titleColor,
- /// ),
- /// ),
- /// ),
- /// child: child,
- /// );
- /// }
- /// }
- /// ```
- ///
- /// See also:
- ///
- /// * [merge] is used instead of [copyWith] when you want to merge all
- /// of the fields of a TextTheme instead of individual fields.
- TextTheme copyWith({
- TextStyle display4,
- TextStyle display3,
- TextStyle display2,
- TextStyle display1,
- TextStyle headline,
- TextStyle title,
- TextStyle subhead,
- TextStyle body2,
- TextStyle body1,
- TextStyle caption,
- TextStyle button,
+ /// The default values for [englishLike], [dense], and [tall] are
+ /// [englishLike2014], [dense2014], and [tall2014].
+ factory Typography({
+ TargetPlatform platform,
+ TextTheme black,
+ TextTheme white,
+ TextTheme englishLike,
+ TextTheme dense,
+ TextTheme tall,
}) {
- return TextTheme(
- display4: display4 ?? this.display4,
- display3: display3 ?? this.display3,
- display2: display2 ?? this.display2,
- display1: display1 ?? this.display1,
- headline: headline ?? this.headline,
- title: title ?? this.title,
- subhead: subhead ?? this.subhead,
- body2: body2 ?? this.body2,
- body1: body1 ?? this.body1,
- caption: caption ?? this.caption,
- button: button ?? this.button,
- );
+ switch (platform) {
+ case TargetPlatform.iOS:
+ black ??= blackCupertino;
+ white ??= whiteCupertino;
+ break;
+ case TargetPlatform.android:
+ case TargetPlatform.fuchsia:
+ black ??= blackMountainView;
+ white ??= whiteMountainView;
+ }
+ englishLike ??= englishLike2014;
+ dense ??= dense2014;
+ tall ??= tall2014;
+ return Typography._(black, white, englishLike, dense, tall);
}
- /// Creates a new [TextTheme] where each text style from this object has been
- /// merged with the matching text style from the `other` object.
+ const Typography._(this.black, this.white, this.englishLike, this.dense, this.tall)
+ : assert(black != null),
+ assert(white != null),
+ assert(englishLike != null),
+ assert(dense != null),
+ assert(tall != null);
+
+ /// A material design text theme with dark glyphs.
///
- /// The merging is done by calling [TextStyle.merge] on each respective pair
- /// of text styles from this and the [other] text themes and is subject to
- /// the value of [TextStyle.inherit] flag. For more details, see the
- /// documentation on [TextStyle.merge] and [TextStyle.inherit].
+ /// This [TextTheme] should provide color but not geometry (font size,
+ /// weight, etc). A text theme's geometry depends on the locale. To look
+ /// up a localized [TextTheme], use the the overall [Theme], for example:
+ /// `Theme.of(context).textTheme`.
///
- /// If this theme, or the `other` theme has members that are null, then the
- /// non-null one (if any) is used. If the `other` theme is itself null, then
- /// this [TextTheme] is returned unchanged. If values in both are set, then
- /// the values are merged using [TextStyle.merge].
+ /// The [englishLike], [dense], and [tall] text theme's provide locale-specific
+ /// geometry.
+ final TextTheme black;
+
+ /// A material design text theme with light glyphs.
///
- /// This is particularly useful if one [TextTheme] defines one set of
- /// properties and another defines a different set, e.g. having colors
- /// defined in one text theme and font sizes in another, or when one
- /// [TextTheme] has only some fields defined, and you want to define the rest
- /// by merging it with a default theme.
+ /// This [TextTheme] provides color but not geometry (font size, weight, etc).
+ /// A text theme's geometry depends on the locale. To look up a localized
+ /// [TextTheme], use the the overall [Theme], for example:
+ /// `Theme.of(context).textTheme`.
///
- /// ## Sample code
+ /// The [englishLike], [dense], and [tall] text theme's provide locale-specific
+ /// geometry.
+ final TextTheme white;
+
+ /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as
+ /// English, French, Russian, etc.
///
- /// ```dart
- /// /// A Widget that sets the ambient theme's title text color for its
- /// /// descendants, while leaving other ambient theme attributes alone.
- /// class TitleColorTheme extends StatelessWidget {
- /// TitleColorTheme({Key key, this.child, this.titleColor}) : super(key: key);
+ /// This text theme is merged with either [black] or [white], depending
+ /// on the overall [ThemeData.brightness], when the current locale's
+ /// [MaterialLocalizations.scriptCategory] is [ScriptCategory.englishLike].
///
- /// final Color titleColor;
- /// final Widget child;
+ /// To look up a localized [TextTheme], use the the overall [Theme], for
+ /// example: `Theme.of(context).textTheme`.
+ final TextTheme englishLike;
+
+ /// Defines text geometry for dense scripts, such as Chinese, Japanese
+ /// and Korean.
///
- /// @override
- /// Widget build(BuildContext context) {
- /// ThemeData theme = Theme.of(context);
- /// // This partialTheme is incomplete: it only has the title style
- /// // defined. Just replacing theme.textTheme with partialTheme would
- /// // set the title, but everything else would be null. This isn't very
- /// // useful, so merge it with the existing theme to keep all of the
- /// // preexisting definitions for the other styles.
- /// TextTheme partialTheme = TextTheme(title: TextStyle(color: titleColor));
- /// theme = theme.copyWith(textTheme: theme.textTheme.merge(partialTheme));
- /// return Theme(data: theme, child: child);
- /// }
- /// }
- /// ```
+ /// This text theme is merged with either [black] or [white], depending
+ /// on the overall [ThemeData.brightness], when the current locale's
+ /// [MaterialLocalizations.scriptCategory] is [ScriptCategory.dense].
///
- /// See also:
+ /// To look up a localized [TextTheme], use the the overall [Theme], for
+ /// example: `Theme.of(context).textTheme`.
+ final TextTheme dense;
+
+ /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai.
///
- /// * [copyWith] is used instead of [merge] when you wish to override
- /// individual fields in the [TextTheme] instead of merging all of the
- /// fields of two [TextTheme]s.
- TextTheme merge(TextTheme other) {
- if (other == null)
- return this;
- return copyWith(
- display4: display4?.merge(other.display4) ?? other.display4,
- display3: display3?.merge(other.display3) ?? other.display3,
- display2: display2?.merge(other.display2) ?? other.display2,
- display1: display1?.merge(other.display1) ?? other.display1,
- headline: headline?.merge(other.headline) ?? other.headline,
- title: title?.merge(other.title) ?? other.title,
- subhead: subhead?.merge(other.subhead) ?? other.subhead,
- body2: body2?.merge(other.body2) ?? other.body2,
- body1: body1?.merge(other.body1) ?? other.body1,
- caption: caption?.merge(other.caption) ?? other.caption,
- button: button?.merge(other.button) ?? other.button,
- );
+ /// This text theme is merged with either [black] or [white], depending
+ /// on the overall [ThemeData.brightness], when the current locale's
+ /// [MaterialLocalizations.scriptCategory] is [ScriptCategory.tall].
+ ///
+ /// To look up a localized [TextTheme], use the the overall [Theme], for
+ /// example: `Theme.of(context).textTheme`.
+ final TextTheme tall;
+
+ /// Returns one of [englishLike], [dense], or [tall].
+ TextTheme geometryThemeFor(ScriptCategory category) {
+ assert(category != null);
+ switch (category) {
+ case ScriptCategory.englishLike:
+ return englishLike;
+ case ScriptCategory.dense:
+ return dense;
+ case ScriptCategory.tall:
+ return tall;
+ }
+ return null;
}
- /// Creates a copy of this text theme but with the given field replaced in
- /// each of the individual text styles.
- ///
- /// The `displayColor` is applied to [display4], [display3], [display2],
- /// [display1], and [caption]. The `bodyColor` is applied to the remaining
- /// text styles.
- ///
- /// Consider using [Typography.black] or [Typography.white], which implement
- /// the typography styles in the material design specification, as a starting
- /// point.
- TextTheme apply({
- String fontFamily,
- double fontSizeFactor = 1.0,
- double fontSizeDelta = 0.0,
- Color displayColor,
- Color bodyColor,
- TextDecoration decoration,
- Color decorationColor,
- TextDecorationStyle decorationStyle,
+ /// Creates a copy of this [Typography] with the given fields
+ /// replaced by the non-null parameter values.
+ Typography copyWith({
+ TextTheme black,
+ TextTheme white,
+ TextTheme englishLike,
+ TextTheme dense,
+ TextTheme tall,
}) {
- return TextTheme(
- display4: display4.apply(
- color: displayColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- display3: display3.apply(
- color: displayColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- display2: display2.apply(
- color: displayColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- display1: display1.apply(
- color: displayColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- headline: headline.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- title: title.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- subhead: subhead.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- body2: body2.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- body1: body1.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- caption: caption.apply(
- color: displayColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
- button: button.apply(
- color: bodyColor,
- decoration: decoration,
- decorationColor: decorationColor,
- decorationStyle: decorationStyle,
- fontFamily: fontFamily,
- fontSizeFactor: fontSizeFactor,
- fontSizeDelta: fontSizeDelta,
- ),
+ return Typography(
+ black: black ?? this.black,
+ white: white ?? this.white,
+ englishLike: englishLike ?? this.englishLike,
+ dense: dense ?? this.dense,
+ tall: tall ?? this.tall,
);
}
- /// Linearly interpolate between two text themes.
- ///
- /// The arguments must not be null.
+ /// Linearly interpolate between two [Typography] objects.
///
/// {@macro flutter.painting.gradient.lerp}
- static TextTheme lerp(TextTheme a, TextTheme b, double t) {
- assert(a != null);
- assert(b != null);
- assert(t != null);
- return TextTheme(
- display4: TextStyle.lerp(a.display4, b.display4, t),
- display3: TextStyle.lerp(a.display3, b.display3, t),
- display2: TextStyle.lerp(a.display2, b.display2, t),
- display1: TextStyle.lerp(a.display1, b.display1, t),
- headline: TextStyle.lerp(a.headline, b.headline, t),
- title: TextStyle.lerp(a.title, b.title, t),
- subhead: TextStyle.lerp(a.subhead, b.subhead, t),
- body2: TextStyle.lerp(a.body2, b.body2, t),
- body1: TextStyle.lerp(a.body1, b.body1, t),
- caption: TextStyle.lerp(a.caption, b.caption, t),
- button: TextStyle.lerp(a.button, b.button, t),
+ static Typography lerp(Typography a, Typography b, double t) {
+ return Typography(
+ black: TextTheme.lerp(a.black, b.black, t),
+ white: TextTheme.lerp(a.white, b.white, t),
+ englishLike: TextTheme.lerp(a.englishLike, b.englishLike, t),
+ dense: TextTheme.lerp(a.dense, b.dense, t),
+ tall: TextTheme.lerp(a.tall, b.tall, t),
);
}
@override
- bool operator ==(dynamic other) {
+ bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
- final TextTheme typedOther = other;
- return display4 == typedOther.display4 &&
- display3 == typedOther.display3 &&
- display2 == typedOther.display2 &&
- display1 == typedOther.display1 &&
- headline == typedOther.headline &&
- title == typedOther.title &&
- subhead == typedOther.subhead &&
- body2 == typedOther.body2 &&
- body1 == typedOther.body1 &&
- caption == typedOther.caption &&
- button == typedOther.button;
+ final Typography otherTypography = other;
+ return otherTypography.black == black
+ && otherTypography.white == white
+ && otherTypography.englishLike == englishLike
+ && otherTypography.dense == dense
+ && otherTypography.tall == tall;
}
@override
int get hashCode {
return hashValues(
- display4,
- display3,
- display2,
- display1,
- headline,
- title,
- subhead,
- body2,
- body1,
- caption,
- button,
+ black,
+ white,
+ englishLike,
+ dense,
+ tall,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
- final TextTheme defaultTheme = Typography(platform: defaultTargetPlatform).black;
- properties.add(DiagnosticsProperty<TextStyle>('display4', display4, defaultValue: defaultTheme.display4));
- properties.add(DiagnosticsProperty<TextStyle>('display3', display3, defaultValue: defaultTheme.display3));
- properties.add(DiagnosticsProperty<TextStyle>('display2', display2, defaultValue: defaultTheme.display2));
- properties.add(DiagnosticsProperty<TextStyle>('display1', display1, defaultValue: defaultTheme.display1));
- properties.add(DiagnosticsProperty<TextStyle>('headline', headline, defaultValue: defaultTheme.headline));
- properties.add(DiagnosticsProperty<TextStyle>('title', title, defaultValue: defaultTheme.title));
- properties.add(DiagnosticsProperty<TextStyle>('subhead', subhead, defaultValue: defaultTheme.subhead));
- properties.add(DiagnosticsProperty<TextStyle>('body2', body2, defaultValue: defaultTheme.body2));
- properties.add(DiagnosticsProperty<TextStyle>('body1', body1, defaultValue: defaultTheme.body1));
- properties.add(DiagnosticsProperty<TextStyle>('caption', caption, defaultValue: defaultTheme.caption));
- properties.add(DiagnosticsProperty<TextStyle>('button', button, defaultValue: defaultTheme.button));
- }
-}
-
-/// The two material design text themes.
-///
-/// Material design defines two text themes: [black] and [white]. The black
-/// text theme, which uses dark glyphs, is used on light backgrounds in light
-/// themes. The white text theme, which uses light glyphs, is used in dark
-/// themes and on dark backgrounds in light themes.
-///
-/// To obtain the current text theme, call [Theme.of] with the current
-/// [BuildContext] and read the [ThemeData.textTheme] property.
-///
-/// See also:
-///
-/// * [TextTheme], which shows what the text styles in a theme look like.
-/// * [Theme], for other aspects of a material design application that can be
-/// globally adjusted, such as the color scheme.
-/// * <http://material.google.com/style/typography.html>
-class Typography {
- /// Creates the default typography for the specified platform.
- factory Typography({@required TargetPlatform platform}) {
- assert(platform != null);
- switch (platform) {
- case TargetPlatform.android:
- case TargetPlatform.fuchsia:
- return const Typography._(
- _MaterialTextColorThemes.blackMountainView,
- _MaterialTextColorThemes.whiteMountainView,
- );
- case TargetPlatform.iOS:
- return const Typography._(
- _MaterialTextColorThemes.blackCupertino,
- _MaterialTextColorThemes.whiteCupertino,
- );
- }
- return null;
+ final Typography defaultTypography = Typography();
+ properties.add(DiagnosticsProperty<TextTheme>('black', black, defaultValue: defaultTypography.black));
+ properties.add(DiagnosticsProperty<TextTheme>('white', white, defaultValue: defaultTypography.white));
+ properties.add(DiagnosticsProperty<TextTheme>('englishLike', englishLike, defaultValue: defaultTypography.englishLike));
+ properties.add(DiagnosticsProperty<TextTheme>('dense', dense, defaultValue: defaultTypography.dense));
+ properties.add(DiagnosticsProperty<TextTheme>('tall', tall, defaultValue: defaultTypography.tall));
}
- const Typography._(this.black, this.white);
-
- /// A material design text theme with dark glyphs.
- final TextTheme black;
-
- /// 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/go/design-typography
-// TODO(yjbanov): implement font fallback (see "Font stack" at https://material.io/go/design-typography)
-class _MaterialTextColorThemes {
+ /// A material design text theme with dark glyphs based on Roboto.
+ ///
+ /// This [TextTheme] provides color but not geometry (font size, weight, etc).
static const TextTheme blackMountainView = TextTheme(
- display4: TextStyle(debugLabel: 'blackMountainView display4', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display3: TextStyle(debugLabel: 'blackMountainView display3', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display2: TextStyle(debugLabel: 'blackMountainView display2', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display1: TextStyle(debugLabel: 'blackMountainView display1', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- headline: TextStyle(debugLabel: 'blackMountainView headline', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- title : TextStyle(debugLabel: 'blackMountainView title', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- subhead : TextStyle(debugLabel: 'blackMountainView subhead', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- body2 : TextStyle(debugLabel: 'blackMountainView body2', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- body1 : TextStyle(debugLabel: 'blackMountainView body1', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- caption : TextStyle(debugLabel: 'blackMountainView caption', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- button : TextStyle(debugLabel: 'blackMountainView button', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ display4 : TextStyle(debugLabel: 'blackMountainView display4', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display3 : TextStyle(debugLabel: 'blackMountainView display3', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display2 : TextStyle(debugLabel: 'blackMountainView display2', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display1 : TextStyle(debugLabel: 'blackMountainView display1', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ headline : TextStyle(debugLabel: 'blackMountainView headline', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ title : TextStyle(debugLabel: 'blackMountainView title', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ subhead : TextStyle(debugLabel: 'blackMountainView subhead', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ body2 : TextStyle(debugLabel: 'blackMountainView body2', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ body1 : TextStyle(debugLabel: 'blackMountainView body1', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ caption : TextStyle(debugLabel: 'blackMountainView caption', fontFamily: 'Roboto', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ button : TextStyle(debugLabel: 'blackMountainView button', fontFamily: 'Roboto', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ subtitle : TextStyle(debugLabel: 'blackMountainView subtitle', fontFamily: 'Roboto', inherit: true, color: Colors.black, decoration: TextDecoration.none),
+ overline : TextStyle(debugLabel: 'blackMountainView overline', fontFamily: 'Roboto', inherit: true, color: Colors.black, decoration: TextDecoration.none),
);
+ /// A material design text theme with light glyphs based on Roboto.
+ ///
+ /// This [TextTheme] provides color but not geometry (font size, weight, etc).
static const TextTheme whiteMountainView = TextTheme(
- display4: TextStyle(debugLabel: 'whiteMountainView display4', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display3: TextStyle(debugLabel: 'whiteMountainView display3', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display2: TextStyle(debugLabel: 'whiteMountainView display2', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display1: TextStyle(debugLabel: 'whiteMountainView display1', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- headline: TextStyle(debugLabel: 'whiteMountainView headline', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- title : TextStyle(debugLabel: 'whiteMountainView title', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- subhead : TextStyle(debugLabel: 'whiteMountainView subhead', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- body2 : TextStyle(debugLabel: 'whiteMountainView body2', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- body1 : TextStyle(debugLabel: 'whiteMountainView body1', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- caption : TextStyle(debugLabel: 'whiteMountainView caption', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- button : TextStyle(debugLabel: 'whiteMountainView button', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ display4 : TextStyle(debugLabel: 'whiteMountainView display4', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display3 : TextStyle(debugLabel: 'whiteMountainView display3', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display2 : TextStyle(debugLabel: 'whiteMountainView display2', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display1 : TextStyle(debugLabel: 'whiteMountainView display1', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ headline : TextStyle(debugLabel: 'whiteMountainView headline', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ title : TextStyle(debugLabel: 'whiteMountainView title', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ subhead : TextStyle(debugLabel: 'whiteMountainView subhead', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ body2 : TextStyle(debugLabel: 'whiteMountainView body2', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ body1 : TextStyle(debugLabel: 'whiteMountainView body1', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ caption : TextStyle(debugLabel: 'whiteMountainView caption', fontFamily: 'Roboto', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ button : TextStyle(debugLabel: 'whiteMountainView button', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ subtitle : TextStyle(debugLabel: 'whiteMountainView subtitle', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ overline : TextStyle(debugLabel: 'whiteMountainView overline', fontFamily: 'Roboto', inherit: true, color: Colors.white, decoration: TextDecoration.none),
);
+ /// A material design text theme with dark glyphs based on San Francisco.
+ ///
+ /// This [TextTheme] provides color but not geometry (font size, weight, etc).
static const TextTheme blackCupertino = TextTheme(
- display4: TextStyle(debugLabel: 'blackCupertino display4', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display3: TextStyle(debugLabel: 'blackCupertino display3', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display2: TextStyle(debugLabel: 'blackCupertino display2', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- display1: TextStyle(debugLabel: 'blackCupertino display1', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- headline: TextStyle(debugLabel: 'blackCupertino headline', fontFamily: '.SF UI Display', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- title : TextStyle(debugLabel: 'blackCupertino title', fontFamily: '.SF UI Display', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- subhead : TextStyle(debugLabel: 'blackCupertino subhead', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- body2 : TextStyle(debugLabel: 'blackCupertino body2', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- body1 : TextStyle(debugLabel: 'blackCupertino body1', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
- caption : TextStyle(debugLabel: 'blackCupertino caption', fontFamily: '.SF UI Text', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
- button : TextStyle(debugLabel: 'blackCupertino button', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ display4 : TextStyle(debugLabel: 'blackCupertino display4', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display3 : TextStyle(debugLabel: 'blackCupertino display3', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display2 : TextStyle(debugLabel: 'blackCupertino display2', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ display1 : TextStyle(debugLabel: 'blackCupertino display1', fontFamily: '.SF UI Display', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ headline : TextStyle(debugLabel: 'blackCupertino headline', fontFamily: '.SF UI Display', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ title : TextStyle(debugLabel: 'blackCupertino title', fontFamily: '.SF UI Display', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ subhead : TextStyle(debugLabel: 'blackCupertino subhead', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ body2 : TextStyle(debugLabel: 'blackCupertino body2', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ body1 : TextStyle(debugLabel: 'blackCupertino body1', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ caption : TextStyle(debugLabel: 'blackCupertino caption', fontFamily: '.SF UI Text', inherit: true, color: Colors.black54, decoration: TextDecoration.none),
+ button : TextStyle(debugLabel: 'blackCupertino button', fontFamily: '.SF UI Text', inherit: true, color: Colors.black87, decoration: TextDecoration.none),
+ subtitle : TextStyle(debugLabel: 'blackCupertino subtitle', fontFamily: '.SF UI Text', inherit: true, color: Colors.black, decoration: TextDecoration.none),
+ overline : TextStyle(debugLabel: 'blackCupertino overline', fontFamily: '.SF UI Text', inherit: true, color: Colors.black, decoration: TextDecoration.none),
);
+ /// A material design text theme with light glyphs based on San Francisco.
+ ///
+ /// This [TextTheme] provides color but not geometry (font size, weight, etc).
static const TextTheme whiteCupertino = TextTheme(
- display4: TextStyle(debugLabel: 'whiteCupertino display4', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display3: TextStyle(debugLabel: 'whiteCupertino display3', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display2: TextStyle(debugLabel: 'whiteCupertino display2', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- display1: TextStyle(debugLabel: 'whiteCupertino display1', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- headline: TextStyle(debugLabel: 'whiteCupertino headline', fontFamily: '.SF UI Display', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- title : TextStyle(debugLabel: 'whiteCupertino title', fontFamily: '.SF UI Display', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- subhead : TextStyle(debugLabel: 'whiteCupertino subhead', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- body2 : TextStyle(debugLabel: 'whiteCupertino body2', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- body1 : TextStyle(debugLabel: 'whiteCupertino body1', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- caption : TextStyle(debugLabel: 'whiteCupertino caption', fontFamily: '.SF UI Text', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
- button : TextStyle(debugLabel: 'whiteCupertino button', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
- );
-}
-
-/// Defines text geometries for the three language categories defined in
-/// https://material.io/go/design-typography.
-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 = <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 = TextTheme(
- display4: TextStyle(debugLabel: 'englishLike display4', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.alphabetic),
- display3: TextStyle(debugLabel: 'englishLike display3', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- display2: TextStyle(debugLabel: 'englishLike display2', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- display1: TextStyle(debugLabel: 'englishLike display1', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- headline: TextStyle(debugLabel: 'englishLike headline', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- title : TextStyle(debugLabel: 'englishLike title', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
- subhead : TextStyle(debugLabel: 'englishLike subhead', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- body2 : TextStyle(debugLabel: 'englishLike body2', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
- body1 : TextStyle(debugLabel: 'englishLike body1', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- caption : TextStyle(debugLabel: 'englishLike caption', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- button : TextStyle(debugLabel: 'englishLike button', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ display4 : TextStyle(debugLabel: 'whiteCupertino display4', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display3 : TextStyle(debugLabel: 'whiteCupertino display3', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display2 : TextStyle(debugLabel: 'whiteCupertino display2', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ display1 : TextStyle(debugLabel: 'whiteCupertino display1', fontFamily: '.SF UI Display', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ headline : TextStyle(debugLabel: 'whiteCupertino headline', fontFamily: '.SF UI Display', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ title : TextStyle(debugLabel: 'whiteCupertino title', fontFamily: '.SF UI Display', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ subhead : TextStyle(debugLabel: 'whiteCupertino subhead', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ body2 : TextStyle(debugLabel: 'whiteCupertino body2', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ body1 : TextStyle(debugLabel: 'whiteCupertino body1', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ caption : TextStyle(debugLabel: 'whiteCupertino caption', fontFamily: '.SF UI Text', inherit: true, color: Colors.white70, decoration: TextDecoration.none),
+ button : TextStyle(debugLabel: 'whiteCupertino button', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ subtitle : TextStyle(debugLabel: 'whiteCupertino subtitle', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
+ overline : TextStyle(debugLabel: 'whiteCupertino overline', fontFamily: '.SF UI Text', inherit: true, color: Colors.white, decoration: TextDecoration.none),
);
- /// Defines text geometry for dense scripts, such as Chinese, Japanese, Korean, etc.
- static const TextTheme dense = TextTheme(
- display4: TextStyle(debugLabel: 'dense display4', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic),
- display3: TextStyle(debugLabel: 'dense display3', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- display2: TextStyle(debugLabel: 'dense display2', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- display1: TextStyle(debugLabel: 'dense display1', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- headline: TextStyle(debugLabel: 'dense headline', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- title : TextStyle(debugLabel: 'dense title', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
- subhead : TextStyle(debugLabel: 'dense subhead', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- body2 : TextStyle(debugLabel: 'dense body2', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
- body1 : TextStyle(debugLabel: 'dense body1', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- caption : TextStyle(debugLabel: 'dense caption', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
- button : TextStyle(debugLabel: 'dense button', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as
+ /// English, French, Russian, etc.
+ static const TextTheme englishLike2014 = TextTheme(
+ display4 : TextStyle(debugLabel: 'englishLike display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.alphabetic),
+ display3 : TextStyle(debugLabel: 'englishLike display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display2 : TextStyle(debugLabel: 'englishLike display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display1 : TextStyle(debugLabel: 'englishLike display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ headline : TextStyle(debugLabel: 'englishLike headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ title : TextStyle(debugLabel: 'englishLike title 2014', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ subhead : TextStyle(debugLabel: 'englishLike subhead 2014', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ body2 : TextStyle(debugLabel: 'englishLike body2 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ body1 : TextStyle(debugLabel: 'englishLike body1 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ caption : TextStyle(debugLabel: 'englishLike caption 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ button : TextStyle(debugLabel: 'englishLike button 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ subtitle : TextStyle(debugLabel: 'englishLike subtitle 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1),
+ overline : TextStyle(debugLabel: 'englishLike overline 2014', inherit: false, fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5),
);
- /// Defines text geometry for tall scripts, such as Farsi, Hindi, Thai, etc.
- static const TextTheme tall = TextTheme(
- display4: TextStyle(debugLabel: 'tall display4', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- display3: TextStyle(debugLabel: 'tall display3', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- display2: TextStyle(debugLabel: 'tall display2', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- display1: TextStyle(debugLabel: 'tall display1', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- headline: TextStyle(debugLabel: 'tall headline', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- title : TextStyle(debugLabel: 'tall title', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
- subhead : TextStyle(debugLabel: 'tall subhead', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- body2 : TextStyle(debugLabel: 'tall body2', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
- body1 : TextStyle(debugLabel: 'tall body1', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- caption : TextStyle(debugLabel: 'tall caption', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
- button : TextStyle(debugLabel: 'tall button', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as
+ /// English, French, Russian, etc.
+ ///
+ /// The font sizes, weights, and letter spacings in this version match the
+ /// [latest Material Design specification](https://material.io/go/design-typography#typography-styles).
+ static const TextTheme englishLike2018 = TextTheme(
+ display4 : TextStyle(debugLabel: 'englishLike display4 2018', fontSize: 96.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -1.5),
+ display3 : TextStyle(debugLabel: 'englishLike display3 2018', fontSize: 60.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -0.5),
+ display2 : TextStyle(debugLabel: 'englishLike display2 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0),
+ display1 : TextStyle(debugLabel: 'englishLike display1 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25),
+ headline : TextStyle(debugLabel: 'englishLike headline 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0),
+ title : TextStyle(debugLabel: 'englishLike title 2018', fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15),
+ subhead : TextStyle(debugLabel: 'englishLike subhead 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15),
+ body2 : TextStyle(debugLabel: 'englishLike body2 2018', fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25),
+ body1 : TextStyle(debugLabel: 'englishLike body1 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.5),
+ button : TextStyle(debugLabel: 'englishLike button 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.75),
+ caption : TextStyle(debugLabel: 'englishLike caption 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.4),
+ subtitle : TextStyle(debugLabel: 'englishLike subtitle 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1),
+ overline : TextStyle(debugLabel: 'englishLike overline 2018', fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5),
+ );
+
+ /// Defines text geometry for dense scripts, such as Chinese, Japanese
+ /// and Korean.
+ static const TextTheme dense2014 = TextTheme(
+ display4 : TextStyle(debugLabel: 'dense display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic),
+ display3 : TextStyle(debugLabel: 'dense display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ display2 : TextStyle(debugLabel: 'dense display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ display1 : TextStyle(debugLabel: 'dense display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ headline : TextStyle(debugLabel: 'dense headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ title : TextStyle(debugLabel: 'dense title 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ subhead : TextStyle(debugLabel: 'dense subhead 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ body2 : TextStyle(debugLabel: 'dense body2 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ body1 : TextStyle(debugLabel: 'dense body1 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ caption : TextStyle(debugLabel: 'dense caption 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ button : TextStyle(debugLabel: 'dense button 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ subtitle : TextStyle(debugLabel: 'dense subtitle 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ overline : TextStyle(debugLabel: 'dense overline 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ );
+
+ /// Defines text geometry for dense scripts, such as Chinese, Japanese
+ /// and Korean.
+ ///
+ /// The font sizes, weights, and letter spacings in this version match the
+ /// latest [Material Design specification](https://material.io/go/design-typography#typography-styles).
+ static const TextTheme dense2018 = TextTheme(
+ display4 : TextStyle(debugLabel: 'dense display4 2018', fontSize: 96.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic),
+ display3 : TextStyle(debugLabel: 'dense display3 2018', fontSize: 60.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic),
+ display2 : TextStyle(debugLabel: 'dense display2 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ display1 : TextStyle(debugLabel: 'dense display1 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ headline : TextStyle(debugLabel: 'dense headline 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ title : TextStyle(debugLabel: 'dense title 2018', fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ subhead : TextStyle(debugLabel: 'dense subhead 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ body2 : TextStyle(debugLabel: 'dense body2 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ body1 : TextStyle(debugLabel: 'dense body1 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ caption : TextStyle(debugLabel: 'dense caption 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ button : TextStyle(debugLabel: 'dense button 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ subtitle : TextStyle(debugLabel: 'dense subtitle 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic),
+ overline : TextStyle(debugLabel: 'dense overline 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic),
+ );
+
+ /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai.
+ static const TextTheme tall2014 = TextTheme(
+ display4 : TextStyle(debugLabel: 'tall display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display3 : TextStyle(debugLabel: 'tall display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display2 : TextStyle(debugLabel: 'tall display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display1 : TextStyle(debugLabel: 'tall display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ headline : TextStyle(debugLabel: 'tall headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ title : TextStyle(debugLabel: 'tall title 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ subhead : TextStyle(debugLabel: 'tall subhead 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ body2 : TextStyle(debugLabel: 'tall body2 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ body1 : TextStyle(debugLabel: 'tall body1 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ caption : TextStyle(debugLabel: 'tall caption 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ button : TextStyle(debugLabel: 'tall button 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ subtitle : TextStyle(debugLabel: 'tall subtitle 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ overline : TextStyle(debugLabel: 'tall overline 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ );
+
+ /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai.
+ ///
+ /// The font sizes, weights, and letter spacings in this version match the
+ /// latest [Material Design specification](https://material.io/go/design-typography#typography-styles).
+ static const TextTheme tall2018 = TextTheme(
+ display4 : TextStyle(debugLabel: 'tall display4 2018', fontSize: 96.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display3 : TextStyle(debugLabel: 'tall display3 2018', fontSize: 60.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display2 : TextStyle(debugLabel: 'tall display2 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ display1 : TextStyle(debugLabel: 'tall display1 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ headline : TextStyle(debugLabel: 'tall headline 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ title : TextStyle(debugLabel: 'tall title 2018', fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ subhead : TextStyle(debugLabel: 'tall subhead 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ body2 : TextStyle(debugLabel: 'tall body2 2018', fontSize: 17.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ body1 : TextStyle(debugLabel: 'tall body1 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ button : TextStyle(debugLabel: 'tall button 2018', fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic),
+ caption : TextStyle(debugLabel: 'tall caption 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
+ subtitle : TextStyle(debugLabel: 'tall subtitle 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic),
+ overline : TextStyle(debugLabel: 'tall overline 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic),
);
}
diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart
index 6b34769..5a2e80d 100644
--- a/packages/flutter/test/material/button_bar_test.dart
+++ b/packages/flutter/test/material/button_bar_test.dart
@@ -64,4 +64,56 @@
final Finder buttonBar = find.byType(ButtonBar);
expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 26.0);
});
+
+ testWidgets('ButtonBar FlatButton inherits Theme accentColor', (WidgetTester tester) async {
+ // Regression test for https://github.com/flutter/flutter/issues/22789
+
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData(accentColor: const Color(1)),
+ home: Builder(
+ builder: (BuildContext context) {
+ return Center(
+ child: ButtonTheme.bar(
+ child: ButtonBar(
+ children: <Widget>[
+ FlatButton(
+ child: const Text('button'),
+ onPressed: () {
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return AlertDialog( // puts its actions in a ButtonBar
+ actions: <Widget>[
+ FlatButton(
+ onPressed: () { },
+ child: const Text('enabled'),
+ ),
+ ],
+ );
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ );
+
+ expect(tester.widget<RawMaterialButton>(find.byType(RawMaterialButton)).textStyle.color, const Color(1));
+
+ // Show the dialog
+ await tester.tap(find.text('button'));
+ await tester.pumpAndSettle();
+
+ final Finder dialogButton = find.ancestor(
+ of: find.text('enabled'),
+ matching: find.byType(RawMaterialButton),
+ );
+ expect(tester.widget<RawMaterialButton>(dialogButton).textStyle.color, const Color(1));
+ });
}
diff --git a/packages/flutter/test/material/button_theme_test.dart b/packages/flutter/test/material/button_theme_test.dart
index b8e6fa1..eab8a93 100644
--- a/packages/flutter/test/material/button_theme_test.dart
+++ b/packages/flutter/test/material/button_theme_test.dart
@@ -36,9 +36,12 @@
testWidgets('ButtonTheme defaults', (WidgetTester tester) async {
ButtonTextTheme textTheme;
+ ButtonBarLayoutBehavior layoutBehavior;
BoxConstraints constraints;
EdgeInsets padding;
ShapeBorder shape;
+ bool alignedDropdown;
+ ColorScheme colorScheme;
await tester.pumpWidget(
ButtonTheme(
@@ -49,13 +52,16 @@
constraints = theme.constraints;
padding = theme.padding;
shape = theme.shape;
+ layoutBehavior = theme.layoutBehavior;
+ colorScheme = theme.colorScheme;
+ alignedDropdown = theme.alignedDropdown;
return Container(
alignment: Alignment.topLeft,
- child: const Directionality(
+ child: Directionality(
textDirection: TextDirection.ltr,
child: FlatButton(
- onPressed: null,
- child: Text('b'), // intrinsic width < minimum width
+ onPressed: () { },
+ child: const Text('b'), // intrinsic width < minimum width
),
),
);
@@ -65,12 +71,14 @@
);
expect(textTheme, ButtonTextTheme.normal);
+ expect(layoutBehavior, ButtonBarLayoutBehavior.padded);
expect(constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0));
expect(padding, const EdgeInsets.symmetric(horizontal: 16.0));
expect(shape, const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)),
));
-
+ expect(alignedDropdown, false);
+ expect(colorScheme, ThemeData.light().colorScheme);
expect(tester.widget<Material>(find.byType(Material)).shape, shape);
expect(tester.getSize(find.byType(Material)), const Size(88.0, 36.0));
});
@@ -78,26 +86,33 @@
test('ButtonThemeData.copyWith', () {
ButtonThemeData theme = const ButtonThemeData().copyWith();
expect(theme.textTheme, ButtonTextTheme.normal);
+ expect(theme.layoutBehavior, ButtonBarLayoutBehavior.padded);
expect(theme.constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0));
expect(theme.padding, const EdgeInsets.symmetric(horizontal: 16.0));
expect(theme.shape, const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)),
));
expect(theme.alignedDropdown, false);
+ expect(theme.colorScheme, null);
theme = const ButtonThemeData().copyWith(
textTheme: ButtonTextTheme.primary,
+ layoutBehavior: ButtonBarLayoutBehavior.constrained,
minWidth: 100.0,
height: 200.0,
padding: EdgeInsets.zero,
shape: const StadiumBorder(),
alignedDropdown: true,
+ colorScheme: const ColorScheme.dark(),
+ materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
expect(theme.textTheme, ButtonTextTheme.primary);
+ expect(theme.layoutBehavior, ButtonBarLayoutBehavior.constrained);
expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0));
expect(theme.padding, EdgeInsets.zero);
expect(theme.shape, const StadiumBorder());
expect(theme.alignedDropdown, true);
+ expect(theme.colorScheme, const ColorScheme.dark());
});
testWidgets('Theme buttonTheme defaults', (WidgetTester tester) async {
@@ -107,10 +122,12 @@
EdgeInsets padding;
ShapeBorder shape;
+ const Color disabledColor = Color(0xFF00FF00);
await tester.pumpWidget(
Theme(
data: lightTheme.copyWith(
- disabledColor: const Color(0xFF00FF00), // disabled RaisedButton fill color
+ disabledColor: disabledColor, // disabled RaisedButton fill color
+ buttonTheme: const ButtonThemeData(disabledColor: disabledColor),
textTheme: lightTheme.textTheme.copyWith(
button: lightTheme.textTheme.button.copyWith(
// The button's height will match because there's no
@@ -149,7 +166,7 @@
));
expect(tester.widget<Material>(find.byType(Material)).shape, shape);
- expect(tester.widget<Material>(find.byType(Material)).color, const Color(0xFF00FF00));
+ expect(tester.widget<Material>(find.byType(Material)).color, disabledColor);
expect(tester.getSize(find.byType(Material)), const Size(88.0, 48.0));
});
@@ -169,6 +186,7 @@
minWidth: 100.0,
height: 200.0,
padding: EdgeInsets.zero,
+ buttonColor: const Color(0xFF00FF00), // enabled RaisedButton fill color
shape: const RoundedRectangleBorder(),
child: Builder(
builder: (BuildContext context) {
diff --git a/packages/flutter/test/material/buttons_test.dart b/packages/flutter/test/material/buttons_test.dart
index 8d4d7f2..070f2e8 100644
--- a/packages/flutter/test/material/buttons_test.dart
+++ b/packages/flutter/test/material/buttons_test.dart
@@ -330,7 +330,7 @@
expect(text.text.style.color, Colors.black38);
});
- testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async {
+ testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
final Rect expectedButtonSize = Rect.fromLTRB(0.0, 0.0, 116.0, 48.0);
@@ -409,6 +409,73 @@
semantics.dispose();
});
+ testWidgets('MaterialButton minWidth and height parameters', (WidgetTester tester) async {
+ Widget buildFrame({ double minWidth, double height, EdgeInsets padding = EdgeInsets.zero, Widget child }) {
+ return Directionality(
+ textDirection: TextDirection.ltr,
+ child: Center(
+ child: MaterialButton(
+ padding: padding,
+ minWidth: minWidth,
+ height: height,
+ onPressed: null,
+ materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ child: child,
+ ),
+ ),
+ );
+ }
+
+ await tester.pumpWidget(buildFrame(minWidth: 8.0, height: 24.0));
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 24.0));
+
+ await tester.pumpWidget(buildFrame(minWidth: 8.0));
+ // Default minHeight constraint is 36, see RawMaterialButton.
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 36.0));
+
+ await tester.pumpWidget(buildFrame(height: 8.0));
+ // Default minWidth constraint is 88, see RawMaterialButton.
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 8.0));
+
+ await tester.pumpWidget(buildFrame());
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 36.0));
+
+ await tester.pumpWidget(buildFrame(padding: const EdgeInsets.all(4.0)));
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 36.0));
+
+ // Size is defined by the padding.
+ await tester.pumpWidget(
+ buildFrame(
+ minWidth: 0.0,
+ height: 0.0,
+ padding: const EdgeInsets.all(4.0),
+ ),
+ );
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 8.0));
+
+ // Size is defined by the padded child.
+ await tester.pumpWidget(
+ buildFrame(
+ minWidth: 0.0,
+ height: 0.0,
+ padding: const EdgeInsets.all(4.0),
+ child: const SizedBox(width: 8.0, height: 8.0),
+ ),
+ );
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(16.0, 16.0));
+
+ // Size is defined by the minWidth, height constraints.
+ await tester.pumpWidget(
+ buildFrame(
+ minWidth: 18.0,
+ height: 18.0,
+ padding: const EdgeInsets.all(4.0),
+ child: const SizedBox(width: 8.0, height: 8.0),
+ ),
+ );
+ expect(tester.getSize(find.byType(MaterialButton)), const Size(18.0, 18.0));
+ });
+
testWidgets('MaterialButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async {
final Key key1 = UniqueKey();
await tester.pumpWidget(
diff --git a/packages/flutter/test/material/outline_button_test.dart b/packages/flutter/test/material/outline_button_test.dart
index b3685a1..cf47182 100644
--- a/packages/flutter/test/material/outline_button_test.dart
+++ b/packages/flutter/test/material/outline_button_test.dart
@@ -89,7 +89,7 @@
// Expect that the button is disabled and painted with the disabled border color.
expect(tester.widget<OutlineButton>(outlineButton).enabled, false);
expect(
- outlineButton,
+ outlineButton, //find.byType(OutlineButton),
paints
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
..path(color: disabledBorderColor, strokeWidth: borderWidth));
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 0124ede..b12527a 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -915,7 +915,7 @@
);
final Text helperText = tester.widget(find.text('helper text'));
expect(helperText.style.color, themeData.hintColor);
- expect(helperText.style.fontSize, MaterialTextGeometry.englishLike.caption.fontSize);
+ expect(helperText.style.fontSize, Typography.englishLike2014.caption.fontSize);
});
testWidgets('TextField with specified helperStyle', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/theme_defaults_test.dart b/packages/flutter/test/material/theme_defaults_test.dart
new file mode 100644
index 0000000..0f4d678
--- /dev/null
+++ b/packages/flutter/test/material/theme_defaults_test.dart
@@ -0,0 +1,186 @@
+// 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/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+const ShapeBorder defaultButtonShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)));
+const EdgeInsets defaultButtonPadding = EdgeInsets.only(left: 16.0, right: 16.0);
+const BoxConstraints defaultButtonConstraints = BoxConstraints(minWidth: 88.0, minHeight: 36.0);
+const Duration defaultButtonDuration = Duration(milliseconds: 200);
+
+void main() {
+ group('RaisedButton', () {
+ testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: Center(
+ child: RaisedButton(
+ onPressed: () { }, // button.enabled == true
+ child: const Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0xdd000000));
+ expect(raw.fillColor, const Color(0xffe0e0e0));
+ expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
+ expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
+ expect(raw.elevation, 2.0);
+ expect(raw.highlightElevation, 8.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ expect(raw.shape, defaultButtonShape);
+ expect(raw.animationDuration, defaultButtonDuration);
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+
+ testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: const Center(
+ child: RaisedButton(
+ onPressed: null, // button.enabled == false
+ child: Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0x61000000));
+ expect(raw.fillColor, const Color(0x61000000));
+ // highlightColor, disabled button can't be pressed
+ // splashColor, disabled button doesn't splash
+ expect(raw.elevation, 2.0);
+ expect(raw.highlightElevation, 8.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ expect(raw.shape, defaultButtonShape);
+ expect(raw.animationDuration, defaultButtonDuration);
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+ });
+
+ group('FlatButton', () {
+ testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: Center(
+ child: FlatButton(
+ onPressed: () { }, // button.enabled == true
+ child: const Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0xdd000000));
+ expect(raw.fillColor, null);
+ expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
+ expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
+ expect(raw.elevation, 0.0);
+ expect(raw.highlightElevation, 0.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ expect(raw.shape, defaultButtonShape);
+ expect(raw.animationDuration, defaultButtonDuration);
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+
+ testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: const Center(
+ child: FlatButton(
+ onPressed: null, // button.enabled == false
+ child: Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0x61000000));
+ expect(raw.fillColor, null);
+ // highlightColor, disabled button can't be pressed
+ // splashColor, disabled button doesn't splash
+ expect(raw.elevation, 0.0);
+ expect(raw.highlightElevation, 0.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ expect(raw.shape, defaultButtonShape);
+ expect(raw.animationDuration, const Duration(milliseconds: 200));
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+ });
+
+ group('OutlineButton', () {
+ testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: Center(
+ child: OutlineButton(
+ onPressed: () { }, // button.enabled == true
+ child: const Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0xdd000000));
+ expect(raw.fillColor, const Color(0x00ffffff));
+ expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
+ expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
+ expect(raw.elevation, 0.0);
+ expect(raw.highlightElevation, 0.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ // animationDuration can't be configed by the theme/constructor
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+
+ testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ theme: ThemeData.light(),
+ home: const Center(
+ child: OutlineButton(
+ onPressed: null, // button.enabled == false
+ child: Text('button'),
+ )
+ ),
+ ),
+ );
+
+ final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
+ expect(raw.textStyle.color, const Color(0x61000000));
+ expect(raw.fillColor, const Color(0x00000000));
+ // highlightColor, disabled button can't be pressed
+ // splashColor, disabled button doesn't splash
+ expect(raw.elevation, 0.0);
+ expect(raw.highlightElevation, 0.0);
+ expect(raw.disabledElevation, 0.0);
+ expect(raw.constraints, defaultButtonConstraints);
+ expect(raw.padding, defaultButtonPadding);
+ // animationDuration can't be configed by the theme/constructor
+ expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
+ });
+ });
+
+}
diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart
index 81f060d..b4a2872 100644
--- a/packages/flutter/test/material/theme_test.dart
+++ b/packages/flutter/test/material/theme_test.dart
@@ -9,6 +9,8 @@
import 'package:flutter_test/flutter_test.dart';
void main() {
+ const TextTheme defaultGeometryTheme = Typography.englishLike2014;
+
test('ThemeDataTween control test', () {
final ThemeData light = ThemeData.light();
final ThemeData dark = ThemeData.dark();
@@ -55,7 +57,7 @@
)
);
- expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(), MaterialTextGeometry.englishLike)));
+ expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(), defaultGeometryTheme)));
expect(Theme.of(capturedContext, shadowThemeOnly: true), isNull);
});
@@ -65,20 +67,20 @@
// Same input, same output.
expect(
- ThemeData.localize(light, MaterialTextGeometry.englishLike),
- same(ThemeData.localize(light, MaterialTextGeometry.englishLike)),
+ ThemeData.localize(light, defaultGeometryTheme),
+ same(ThemeData.localize(light, defaultGeometryTheme)),
);
// Different text geometry, different output.
expect(
- ThemeData.localize(light, MaterialTextGeometry.englishLike),
- isNot(same(ThemeData.localize(light, MaterialTextGeometry.tall))),
+ ThemeData.localize(light, defaultGeometryTheme),
+ isNot(same(ThemeData.localize(light, Typography.tall2014))),
);
// Different base theme, different output.
expect(
- ThemeData.localize(light, MaterialTextGeometry.englishLike),
- isNot(same(ThemeData.localize(dark, MaterialTextGeometry.englishLike))),
+ ThemeData.localize(light, defaultGeometryTheme),
+ isNot(same(ThemeData.localize(dark, defaultGeometryTheme))),
);
});
@@ -408,7 +410,7 @@
}
}
- expect(theme.textTheme.display4.debugLabel, '(englishLike display4).merge(blackMountainView display4)');
+ expect(theme.textTheme.display4.debugLabel, '(englishLike display4 2014).merge(blackMountainView display4)');
});
}
diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart
index d933363..4032378 100644
--- a/packages/flutter/test/material/typography_test.dart
+++ b/packages/flutter/test/material/typography_test.dart
@@ -74,6 +74,8 @@
expect(textTheme.body1, isTextFont);
expect(textTheme.caption, isTextFont);
expect(textTheme.button, isTextFont);
+ expect(textTheme.subtitle, isTextFont);
+ expect(textTheme.overline, isTextFont);
}
});
}
diff --git a/packages/flutter_localizations/lib/src/l10n/README.md b/packages/flutter_localizations/lib/src/l10n/README.md
index 12c9bd0..34961c5 100644
--- a/packages/flutter_localizations/lib/src/l10n/README.md
+++ b/packages/flutter_localizations/lib/src/l10n/README.md
@@ -138,11 +138,11 @@
has this value labeled as `"x-flutter-type": "icuShortTimePattern"`.
The value of `scriptCategory` is based on the
-[Language categories reference](https://material.io/go/design-typography#typography-language-categories-reference)
+[Language categories reference](https://material.io/design/typography/language-support.html#language-categories-reference)
section in the Material spec. The `scriptCategory` value is used when looking up
the `TextTheme`, see the
-[MaterialTextGeometry](https://docs.flutter.io/flutter/material/MaterialTextGeometry/forScriptCategory.html)
-class.
+[MaterialTextGeometry](https://docs.flutter.io/flutter/material/MaterialTextGeometry/localizedFor.html)
+method.
### Generated file localizations.dart: all of the localizations as a Map
diff --git a/packages/flutter_localizations/lib/src/l10n/localizations.dart b/packages/flutter_localizations/lib/src/l10n/localizations.dart
index f3a0091..ff3ea4f 100644
--- a/packages/flutter_localizations/lib/src/l10n/localizations.dart
+++ b/packages/flutter_localizations/lib/src/l10n/localizations.dart
@@ -171,7 +171,7 @@
String get rowsPerPageTitle => r'عدد الصفوف في الصفحة:';
@override
- String get scriptCategory => r'tall';
+ ScriptCategory get scriptCategory => ScriptCategory.tall;
@override
String get searchFieldLabel => r'بحث';
@@ -372,7 +372,7 @@
String get rowsPerPageTitle => r'Редове на страница:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Търсене';
@@ -573,7 +573,7 @@
String get rowsPerPageTitle => r'Redaka po stranici:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Pretražite';
@@ -774,7 +774,7 @@
String get rowsPerPageTitle => r'Files per pàgina:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Cerca';
@@ -975,7 +975,7 @@
String get rowsPerPageTitle => r'Počet řádků na stránku:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Hledat';
@@ -1176,7 +1176,7 @@
String get rowsPerPageTitle => r'Rækker pr. side:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Søg';
@@ -1377,7 +1377,7 @@
String get rowsPerPageTitle => r'Zeilen pro Seite:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Suchen';
@@ -1608,7 +1608,7 @@
String get rowsPerPageTitle => r'Σειρές ανά σελίδα:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Αναζήτηση';
@@ -1809,7 +1809,7 @@
String get rowsPerPageTitle => r'Rows per page:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Search';
@@ -2313,7 +2313,7 @@
String get rowsPerPageTitle => r'Filas por página:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Buscar';
@@ -4137,7 +4137,7 @@
String get rowsPerPageTitle => r'Ridu lehe kohta:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Otsing';
@@ -4338,7 +4338,7 @@
String get rowsPerPageTitle => r'ردیف در هر صفحه:';
@override
- String get scriptCategory => r'tall';
+ ScriptCategory get scriptCategory => ScriptCategory.tall;
@override
String get searchFieldLabel => r'جستجو';
@@ -4539,7 +4539,7 @@
String get rowsPerPageTitle => r'Riviä/sivu:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Haku';
@@ -4740,7 +4740,7 @@
String get rowsPerPageTitle => r'Mga row bawat page:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Maghanap';
@@ -4941,7 +4941,7 @@
String get rowsPerPageTitle => r'Lignes par page :';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Rechercher';
@@ -5169,7 +5169,7 @@
String get rowsPerPageTitle => r'Zeilen pro Seite:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Suchen';
@@ -5370,7 +5370,7 @@
String get rowsPerPageTitle => r'שורות בכל דף:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'חיפוש';
@@ -5571,7 +5571,7 @@
String get rowsPerPageTitle => r'हर पेज में पंक्तियों की संख्या:';
@override
- String get scriptCategory => r'dense';
+ ScriptCategory get scriptCategory => ScriptCategory.dense;
@override
String get searchFieldLabel => r'खोजें';
@@ -5772,7 +5772,7 @@
String get rowsPerPageTitle => r'Redaka po stranici:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Pretražite';
@@ -5973,7 +5973,7 @@
String get rowsPerPageTitle => r'Oldalankénti sorszám:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Keresés';
@@ -6174,7 +6174,7 @@
String get rowsPerPageTitle => r'Baris per halaman:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Telusuri';
@@ -6375,7 +6375,7 @@
String get rowsPerPageTitle => r'Righe per pagina:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Cerca';
@@ -6576,7 +6576,7 @@
String get rowsPerPageTitle => r'ページあたりの行数:';
@override
- String get scriptCategory => r'dense';
+ ScriptCategory get scriptCategory => ScriptCategory.dense;
@override
String get searchFieldLabel => r'検索';
@@ -6777,7 +6777,7 @@
String get rowsPerPageTitle => r'ជួរមុខ:';
@override
- String get scriptCategory => r'dense';
+ ScriptCategory get scriptCategory => ScriptCategory.dense;
@override
String get searchFieldLabel => r'ស្វែងរក';
@@ -6978,7 +6978,7 @@
String get rowsPerPageTitle => r'페이지당 행 수:';
@override
- String get scriptCategory => r'dense';
+ ScriptCategory get scriptCategory => ScriptCategory.dense;
@override
String get searchFieldLabel => r'검색';
@@ -7179,7 +7179,7 @@
String get rowsPerPageTitle => r'Eilučių puslapyje:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Paieška';
@@ -7380,7 +7380,7 @@
String get rowsPerPageTitle => r'Rindas lapā:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Meklēt';
@@ -7581,7 +7581,7 @@
String get rowsPerPageTitle => r'Baris setiap halaman:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Cari';
@@ -7782,7 +7782,7 @@
String get rowsPerPageTitle => r'Rader per side:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Søk';
@@ -7983,7 +7983,7 @@
String get rowsPerPageTitle => r'Rijen per pagina:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Zoeken';
@@ -8184,7 +8184,7 @@
String get rowsPerPageTitle => r'Wiersze na stronie:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Szukaj';
@@ -8385,7 +8385,7 @@
String get rowsPerPageTitle => r'د هرې پاڼې پاڼې:';
@override
- String get scriptCategory => r'tall';
+ ScriptCategory get scriptCategory => ScriptCategory.tall;
@override
String get searchFieldLabel => r'لټون';
@@ -8586,7 +8586,7 @@
String get rowsPerPageTitle => r'Linhas por página:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Pesquisa';
@@ -8871,7 +8871,7 @@
String get rowsPerPageTitle => r'Rânduri pe pagină:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Căutați';
@@ -9072,7 +9072,7 @@
String get rowsPerPageTitle => r'Строк на странице:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Поиск';
@@ -9273,7 +9273,7 @@
String get rowsPerPageTitle => r'Počet riadkov na stránku:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Hľadať';
@@ -9474,7 +9474,7 @@
String get rowsPerPageTitle => r'Vrstice na stran:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Iskanje';
@@ -9675,7 +9675,7 @@
String get rowsPerPageTitle => r'Редова по страници:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Претражите';
@@ -10053,7 +10053,7 @@
String get rowsPerPageTitle => r'Rader per sida:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Sök';
@@ -10254,7 +10254,7 @@
String get rowsPerPageTitle => r'แถวต่อหน้า:';
@override
- String get scriptCategory => r'tall';
+ ScriptCategory get scriptCategory => ScriptCategory.tall;
@override
String get searchFieldLabel => r'ค้นหา';
@@ -10455,7 +10455,7 @@
String get rowsPerPageTitle => r'Mga row bawat page:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Maghanap';
@@ -10656,7 +10656,7 @@
String get rowsPerPageTitle => r'Sayfa başına satır sayısı:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Ara';
@@ -10857,7 +10857,7 @@
String get rowsPerPageTitle => r'Рядків на сторінці:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Пошук';
@@ -11058,7 +11058,7 @@
String get rowsPerPageTitle => r'قطاریں فی صفحہ:';
@override
- String get scriptCategory => r'tall';
+ ScriptCategory get scriptCategory => ScriptCategory.tall;
@override
String get searchFieldLabel => r'تلاش';
@@ -11259,7 +11259,7 @@
String get rowsPerPageTitle => r'Số hàng mỗi trang:';
@override
- String get scriptCategory => r'English-like';
+ ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => r'Tìm kiếm';
@@ -11460,7 +11460,7 @@
String get rowsPerPageTitle => r'每页行数:';
@override
- String get scriptCategory => r'dense';
+ ScriptCategory get scriptCategory => ScriptCategory.dense;
@override
String get searchFieldLabel => r'搜索';
diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb
index d72ca74..79e4a56 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_en.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb
@@ -1,7 +1,8 @@
{
"scriptCategory": "English-like",
"@scriptCategory": {
- "description": "The name of the language's script category (see https://material.io/go/design-typography#typography-language-categories-reference)."
+ "description": "The name of the language's script category (see https://material.io/design/typography/language-support.html#language-categories-reference).",
+ "x-flutter-type": "scriptCategory"
},
"timeOfDayFormat": "h:mm a",
diff --git a/packages/flutter_localizations/lib/src/material_localizations.dart b/packages/flutter_localizations/lib/src/material_localizations.dart
index 61debf8..b33bbd8 100644
--- a/packages/flutter_localizations/lib/src/material_localizations.dart
+++ b/packages/flutter_localizations/lib/src/material_localizations.dart
@@ -502,18 +502,8 @@
).replaceFirst(r'$remainingCount', formatDecimal(remainingCount));
}
- /// The script category used by [localTextGeometry]. Must be one of the strings
- /// declared in [MaterialTextGeometry].
- //
- // TODO(ianh): make this return a TextTheme from MaterialTextGeometry.
- // TODO(ianh): drop the constructor on MaterialTextGeometry.
- // TODO(ianh): drop the strings on MaterialTextGeometry.
- @protected
- String get scriptCategory;
-
- /// Looks up text geometry defined in [MaterialTextGeometry].
@override
- TextTheme get localTextGeometry => MaterialTextGeometry.forScriptCategory(scriptCategory);
+ ScriptCategory get scriptCategory;
/// A [LocalizationsDelegate] that uses [GlobalMaterialLocalizations.load]
/// to create an instance of this class.