diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index fc64449a3d..5362a9852e 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -122,11 +122,13 @@ class ThemeData { indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor; hintColor ??= isDark ? const Color(0x42FFFFFF) : const Color(0x4C000000); errorColor ??= Colors.red[700]; - textTheme ??= isDark ? Typography.white : Typography.black; - primaryTextTheme ??= primaryIsDark ? Typography.white : Typography.black; iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); platform ??= defaultTargetPlatform; + + final Typography typography = new Typography(platform: platform); + primaryTextTheme ??= primaryIsDark ? typography.white : typography.black; + textTheme ??= isDark ? typography.white : typography.black; return new ThemeData.raw( brightness: brightness, primaryColor: primaryColor, diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart index 88e662dd1b..d611829467 100644 --- a/packages/flutter/lib/src/material/typography.dart +++ b/packages/flutter/lib/src/material/typography.dart @@ -3,7 +3,9 @@ // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; +import 'package:meta/meta.dart'; import 'colors.dart'; @@ -51,7 +53,7 @@ class TextTheme { this.button }); - const TextTheme._black() + const TextTheme._blackMountainView() : display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic), display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), @@ -64,7 +66,7 @@ class TextTheme { caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic); - const TextTheme._white() + const TextTheme._whiteMountainView() : display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic), display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), @@ -77,6 +79,32 @@ class TextTheme { caption = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), button = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic); + const TextTheme._blackCupertino() + : display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic), + display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), + display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), + display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), + headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic), + title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic), + subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic), + body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic), + body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic), + caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic), + button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic); + + const TextTheme._whiteCupertino() + : display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic), + display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), + display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), + display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), + headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic), + title = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic), + subhead = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic), + body2 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic), + body1 = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, color: Colors.white, textBaseline: TextBaseline.alphabetic), + caption = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic), + button = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.white, textBaseline: TextBaseline.alphabetic); + /// Extremely large text. /// /// The font size is 112 pixels. @@ -255,10 +283,10 @@ class TextTheme { /// The two material design text themes. /// -/// [Typography.black] and [Typography.white] define the two text themes used in -/// material design. 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 in light 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. @@ -269,11 +297,30 @@ class TextTheme { /// * [ThemeData] /// * class Typography { - 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._( + const TextTheme._blackMountainView(), + const TextTheme._whiteMountainView(), + ); + case TargetPlatform.iOS: + return const Typography._( + const TextTheme._blackCupertino(), + const TextTheme._whiteCupertino(), + ); + } + return null; + } + + const Typography._(this.black, this.white); /// A material design text theme with dark glyphs. - static const TextTheme black = const TextTheme._black(); + final TextTheme black; /// A material design text theme with light glyphs. - static const TextTheme white = const TextTheme._white(); + final TextTheme white; } diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart new file mode 100644 index 0000000000..8c5f9513ef --- /dev/null +++ b/packages/flutter/test/material/theme_data_test.dart @@ -0,0 +1,16 @@ +// Copyright 2016 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'; + +void main() { + test('Defaults to the default typography for the platform', () { + for (TargetPlatform platform in TargetPlatform.values) { + ThemeData theme = new ThemeData(platform: platform); + Typography typography = new Typography(platform: platform); + expect(theme.textTheme, typography.black, reason: 'Not using default typography for $platform'); + } + }); +} diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart new file mode 100644 index 0000000000..88d99d77ac --- /dev/null +++ b/packages/flutter/test/material/typography_test.dart @@ -0,0 +1,44 @@ +// Copyright 2016 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'; + +void main() { + test('Typography is defined for all target platforms', () { + for (TargetPlatform platform in TargetPlatform.values) { + Typography typography = new Typography(platform: platform); + expect(typography, isNotNull, reason: 'null typography for $platform'); + expect(typography.black, isNotNull, reason: 'null black typography for $platform'); + expect(typography.white, isNotNull, reason: 'null white typography for $platform'); + } + }); + + test('Typography on Android, Fuchsia defaults to Roboto', () { + expect(new Typography(platform: TargetPlatform.android).black.title.fontFamily, 'Roboto'); + expect(new Typography(platform: TargetPlatform.fuchsia).black.title.fontFamily, 'Roboto'); + }); + + test('Typography on iOS defaults to the correct SF font family based on size', () { + // Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/ + Matcher hasCorrectFont = predicate((TextStyle s) { + return s.fontFamily == (s.fontSize <= 19.0 ? '.SF UI Text' : '.SF UI Display'); + }, 'Uses SF Display font for font sizes over 19.0, otherwise SF Text font'); + + Typography typography = new Typography(platform: TargetPlatform.iOS); + for (TextTheme textTheme in [typography.black, typography.white]) { + expect(textTheme.display4, hasCorrectFont); + expect(textTheme.display3, hasCorrectFont); + expect(textTheme.display2, hasCorrectFont); + expect(textTheme.display1, hasCorrectFont); + expect(textTheme.headline, hasCorrectFont); + expect(textTheme.title, hasCorrectFont); + expect(textTheme.subhead, hasCorrectFont); + expect(textTheme.body2, hasCorrectFont); + expect(textTheme.body1, hasCorrectFont); + expect(textTheme.caption, hasCorrectFont); + expect(textTheme.button, hasCorrectFont); + } + }); +}