From 36924d381d87c6a1ff704ab81c24ae0234cf252d Mon Sep 17 00:00:00 2001 From: Rydmike Date: Fri, 17 Jun 2022 23:58:05 +0300 Subject: [PATCH] Playground app: Workaround for issue https://github.com/flutter/flutter/issues/103864 --- CHANGELOG.md | 19 +++- example/lib/example5/main.dart | 8 +- .../lib/example5/theme/flex_theme_dark.dart | 18 ++++ .../lib/example5/theme/flex_theme_light.dart | 18 ++++ ...ta_from_dark.dart => theme_data_dark.dart} | 49 ++++++--- ..._from_light.dart => theme_data_light.dart} | 49 ++++++--- example/lib/shared/const/app_data.dart | 99 +++++++++++++++++++ lib/src/flex_color_scheme.dart | 6 +- lib/src/flex_sub_themes.dart | 2 +- lib/src/flex_sub_themes_data.dart | 3 +- 10 files changed, 237 insertions(+), 34 deletions(-) rename example/lib/example5/theme/{theme_data_from_dark.dart => theme_data_dark.dart} (53%) rename example/lib/example5/theme/{theme_data_from_light.dart => theme_data_light.dart} (53%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 550cf71e..ac64d451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the **FlexColorScheme** package are documented here. -## v5.1.0 - June 14, 2022 +## v5.1.0 - June 17, 2022 * Updated to support Flutter 3.0.0, Dart 2.17 and latest Flutter package dependencies in example apps. Requires at least Flutter 3.0.0 and Dart 2.17.0 @@ -80,13 +80,28 @@ All notable changes to the **FlexColorScheme** package are documented here. switches, added the "Use Material 3" toggle. Previously this toggle was only available on the introduction page/panel. +* Themes Playground: Added a complex workaround to avoid issue + [#103864](https://github.com/flutter/flutter/issues/103864) in the Playground app. The workaround + is done by always using 2021 Typography but simulating 2018 Typography in the app when by using + an EnglishLike 2018 TextTheme, but with the 2021 Typography, to simulate how an app looks + that uses other than 2021 Typography. The Playground App actually always stays in 2021 + Typography, but looks like it switches it. Switching Typography dynamically in ThemeData is broken + due to above issue, and if it is done and error ignore the app becomes unstable eventually. + This workaround is needed because the Playground app has toggles that may switch Typography + frequently, and it will eventually crash. With this workaround it never switches Typography, it + just looks like it does, but app stays in 2021 Typography all the time. The output code that + creates the configured THemeData uses the actual configured effective Typography mode. This is + fine, since that app will likely never switch used Typography. If it does, it will of course face + the same issue the Playground app did, but the issue is a Flutter SDK issue that FlexColorScheme + cannot fix. Most likely 99% of apps will never run into this issue. + ## v5.0.1 - April 29, 2022 **FIX** * For the custom and temporary `m3TextTheme`: Fixed the Typography letterSpacing for bodyLarge to match corrected M3 spec that had wrong specification on the M3 website 0.15 -> 0.5. See - Flutter SDK [issue 102121](https://github.com/flutter/flutter/issues/102121). + Flutter SDK issue [#102121](https://github.com/flutter/flutter/issues/102121). * Themes Playground: Fix wrong color code copied to clipboard when tapping input color. * Themes Playground: Make prettier default constructor for FlexSubThemesData() if that is all that was defined in Themes Playground config. diff --git a/example/lib/example5/main.dart b/example/lib/example5/main.dart index 478320ca..f23e6da3 100644 --- a/example/lib/example5/main.dart +++ b/example/lib/example5/main.dart @@ -6,8 +6,8 @@ import '../shared/services/theme_service_hive.dart'; import '../shared/utils/app_scroll_behavior.dart'; import 'theme/flex_theme_dark.dart'; import 'theme/flex_theme_light.dart'; -import 'theme/theme_data_from_dark.dart'; -import 'theme/theme_data_from_light.dart'; +import 'theme/theme_data_dark.dart'; +import 'theme/theme_data_light.dart'; import 'widgets/pages/home_page.dart'; // ----------------------------------------------------------------------------- @@ -109,10 +109,10 @@ class DemoApp extends StatelessWidget { // FlexColorScheme object that produces the ThemeData object. theme: controller.useFlexColorScheme ? flexThemeLight(controller) - : themeDataFromLight(controller), + : themeDataLight(controller), darkTheme: controller.useFlexColorScheme ? flexThemeDark(controller) - : themeDataFromDark(controller), + : themeDataDark(controller), // Use the dark or light theme based on controller setting. themeMode: controller.themeMode, // Pass the controller to the HomePage where we use it to change diff --git a/example/lib/example5/theme/flex_theme_dark.dart b/example/lib/example5/theme/flex_theme_dark.dart index 39245659..213221f9 100644 --- a/example/lib/example5/theme/flex_theme_dark.dart +++ b/example/lib/example5/theme/flex_theme_dark.dart @@ -46,6 +46,17 @@ FlexColorScheme flexColorSchemeDark(ThemeController controller) { final int flexScheme = controller.schemeIndex - 3; final bool useScheme = useBuiltIn && !controller.useToDarkMethod; + // Workaround for issue https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + final bool useFakeTypo2018 = + (controller.useSubThemes && !controller.useTextTheme) || + (!controller.useSubThemes && !controller.useMaterial3); + final TextTheme? fakeM2TypographyTextTheme = + useFakeTypo2018 ? AppData.m2TextTheme : null; + final Typography alwaysM3Typography = + Typography.material2021(platform: controller.platform); + // End of fix variables for issue #10386 + return FlexColorScheme.dark( // Use scheme based config, when we are using a built-in `FlexScheme` // based schemes. @@ -203,5 +214,12 @@ FlexColorScheme flexColorSchemeDark(ThemeController controller) { fontFamily: controller.useAppFont ? AppData.font : null, platform: controller.platform, useMaterial3: controller.useMaterial3, + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + typography: alwaysM3Typography, + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + textTheme: fakeM2TypographyTextTheme, + primaryTextTheme: fakeM2TypographyTextTheme, ); } diff --git a/example/lib/example5/theme/flex_theme_light.dart b/example/lib/example5/theme/flex_theme_light.dart index fe0f075e..2cfc7c85 100644 --- a/example/lib/example5/theme/flex_theme_light.dart +++ b/example/lib/example5/theme/flex_theme_light.dart @@ -39,6 +39,17 @@ FlexColorScheme flexColorSchemeLight(ThemeController controller) { // Get the enum index of scheme final int flexScheme = controller.schemeIndex - 3; + // Workaround for issue https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + final bool useFakeTypo2018 = + (controller.useSubThemes && !controller.useTextTheme) || + (!controller.useSubThemes && !controller.useMaterial3); + final TextTheme? fakeM2TypographyTextTheme = + useFakeTypo2018 ? AppData.m2TextTheme : null; + final Typography alwaysM3Typography = + Typography.material2021(platform: controller.platform); + // End of fix variables for issue #10386 + return FlexColorScheme.light( // Use controller to get current scheme colors, use custom "colors" // property only if we use an index where we have custom colors in use. @@ -274,5 +285,12 @@ FlexColorScheme flexColorSchemeLight(ThemeController controller) { // with FlexColorScheme too, and in this demo we can see its // impact easily. useMaterial3: controller.useMaterial3, + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + typography: alwaysM3Typography, + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + textTheme: fakeM2TypographyTextTheme, + primaryTextTheme: fakeM2TypographyTextTheme, ); } diff --git a/example/lib/example5/theme/theme_data_from_dark.dart b/example/lib/example5/theme/theme_data_dark.dart similarity index 53% rename from example/lib/example5/theme/theme_data_from_dark.dart rename to example/lib/example5/theme/theme_data_dark.dart index 5a00fe10..acae7cc5 100644 --- a/example/lib/example5/theme/theme_data_from_dark.dart +++ b/example/lib/example5/theme/theme_data_dark.dart @@ -6,17 +6,17 @@ import 'flex_theme_dark.dart'; // ignore_for_file: comment_references -/// Return a Flutter SDK standard [ThemeData.from] created [ThemeData] object, +/// Return a Flutter SDK standard created [ThemeData] object, /// using the [ColorScheme] colors created by the current configuration /// in our [FlexColorScheme] object as configured by the [ThemeController]. /// /// Here we do NOT use FlexColorScheme to make the theme. We use the SDK -/// ThemeData.from factory to make the theme instead. This is used in the demo +/// ThemeData factory to make the theme instead. This is used in the demo /// so you can toggle FlexColorScheme on/off and see the differences. /// /// We use active [ColorScheme] by grabbing it from active FlexColorScheme /// using its toScheme method. Which gives us a standard ColorScheme that we -/// can use with ThemeData.from to create the ThemeData from the exact same +/// can use with ThemeData to create the ThemeData from the exact same /// colors. The [ColorScheme] it creates also contains the blends, M3 seeded /// color etc, but since [ColorScheme], only contains surface and background /// colors and is missing [FlexColorScheme] custom Scaffold and dialog color, @@ -33,26 +33,51 @@ import 'flex_theme_dark.dart'; /// ThemeData, using the same same ColorScheme or colors from it, as your /// ThemeData is created with, thus using the same colors in your custom /// sub-themes. -ThemeData themeDataFromDark(ThemeController controller) { - return ThemeData.from( - textTheme: ThemeData( - brightness: Brightness.dark, - fontFamily: controller.useAppFont ? AppData.font : null, - ).textTheme, +ThemeData themeDataDark(ThemeController controller) { + // Workaround for issue https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + final Typography alwaysM3Typography = + Typography.material2021(platform: controller.platform); + final TextTheme? fakeM2TypographyTextTheme = + controller.useMaterial3 ? null : AppData.m2TextTheme; + final ColorScheme colorScheme = flexColorSchemeDark(controller).toScheme; + final TextTheme? fakeM2TypographyPrimTextTheme = + controller.useMaterial3 ? null : AppData.m2TextTheme; + final bool primaryIsDark = + ThemeData.estimateBrightnessForColor(colorScheme.primary) == + Brightness.dark; + final TextTheme defPrimaryText = + primaryIsDark ? alwaysM3Typography.white : alwaysM3Typography.black; + final TextTheme effectivePrimaryTextTheme = + defPrimaryText.merge(fakeM2TypographyPrimTextTheme); + // End of fix for workaround for issue #10386 + + return ThemeData( + brightness: Brightness.dark, + fontFamily: controller.useAppFont ? AppData.font : null, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + textTheme: fakeM2TypographyTextTheme, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + primaryTextTheme: effectivePrimaryTextTheme, // The ColorScheme we get here is the same one you can also generate // Copy/paste code for in the ThemesPlayground UI, and it represent the // effective scheme in the Playground app. - colorScheme: flexColorSchemeDark(controller).toScheme, - ).copyWith( + colorScheme: colorScheme, // To our ThemeData we also apply the visual density, typography, selected // platform and useMaterial3 flag, that we used in FlexColorScheme created // ThemeData. We do this so created themes will be using the same features. visualDensity: AppData.visualDensity, - typography: Typography.material2018(platform: controller.platform), platform: controller.platform, // The Flutter SDK new `useMaterial3` flag that is available in the UI, // still does very little in Flutter 2.10.x, but in later versions we can // use it to see what it changes. useMaterial3: controller.useMaterial3, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + typography: alwaysM3Typography, + // Typography used before workaround needed. + // typography: Typography.material2018(platform: controller.platform), ); } diff --git a/example/lib/example5/theme/theme_data_from_light.dart b/example/lib/example5/theme/theme_data_light.dart similarity index 53% rename from example/lib/example5/theme/theme_data_from_light.dart rename to example/lib/example5/theme/theme_data_light.dart index 5547ab21..e8f2c4fe 100644 --- a/example/lib/example5/theme/theme_data_from_light.dart +++ b/example/lib/example5/theme/theme_data_light.dart @@ -6,17 +6,17 @@ import 'flex_theme_light.dart'; // ignore_for_file: comment_references -/// Return a Flutter SDK standard [ThemeData.from] created [ThemeData] object, +/// Return a Flutter SDK standard created [ThemeData] object, /// using the [ColorScheme] colors created by the current configuration /// in our [FlexColorScheme] object as configured by the [ThemeController]. /// /// Here we do NOT use FlexColorScheme to make the theme. We use the SDK -/// ThemeData.from factory to make the theme instead. This is used in the demo +/// ThemeData factory to make the theme instead. This is used in the demo /// so you can toggle FlexColorScheme on/off and see the differences. /// /// We use active [ColorScheme] by grabbing it from active FlexColorScheme /// using its toScheme method. Which gives us a standard ColorScheme that we -/// can use with ThemeData.from to create the ThemeData from the exact same +/// can use with ThemeData to create the ThemeData from the exact same /// colors. The [ColorScheme] it creates also contains the blends, M3 seeded /// color etc, but since [ColorScheme], only contains surface and background /// colors and is missing [FlexColorScheme] custom Scaffold and dialog color, @@ -33,26 +33,51 @@ import 'flex_theme_light.dart'; /// ThemeData, using the same same ColorScheme or colors from it, as your /// ThemeData is created with, thus using the same colors in your custom /// sub-themes. -ThemeData themeDataFromLight(ThemeController controller) { - return ThemeData.from( - textTheme: ThemeData( - brightness: Brightness.light, - fontFamily: controller.useAppFont ? AppData.font : null, - ).textTheme, +ThemeData themeDataLight(ThemeController controller) { + // Workaround for issue https://github.com/flutter/flutter/issues/103864. + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + final Typography alwaysM3Typography = + Typography.material2021(platform: controller.platform); + final TextTheme? fakeM2TypographyTextTheme = + controller.useMaterial3 ? null : AppData.m2TextTheme; + final ColorScheme colorScheme = flexColorSchemeLight(controller).toScheme; + final TextTheme? fakeM2TypographyPrimTextTheme = + controller.useMaterial3 ? null : AppData.m2TextTheme; + final bool primaryIsDark = + ThemeData.estimateBrightnessForColor(colorScheme.primary) == + Brightness.dark; + final TextTheme defPrimaryText = + primaryIsDark ? alwaysM3Typography.white : alwaysM3Typography.black; + final TextTheme effectivePrimaryTextTheme = + defPrimaryText.merge(fakeM2TypographyPrimTextTheme); + // End of fix for workaround for issue #10386 + + return ThemeData( + brightness: Brightness.light, + fontFamily: controller.useAppFont ? AppData.font : null, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + textTheme: fakeM2TypographyTextTheme, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + primaryTextTheme: effectivePrimaryTextTheme, // The ColorScheme we get here is the same one you can also generate // Copy/paste code for in the ThemesPlayground UI, and it represent the // effective scheme in the Playground app. - colorScheme: flexColorSchemeLight(controller).toScheme, - ).copyWith( + colorScheme: colorScheme, // To our ThemeData we also apply the visual density, typography, selected // platform and useMaterial3 flag, that we used in FlexColorScheme created // ThemeData. We do this so created themes will be using the same features. visualDensity: AppData.visualDensity, - typography: Typography.material2018(platform: controller.platform), platform: controller.platform, // The Flutter SDK new `useMaterial3` flag that is available in the UI, // still does very little in Flutter 2.10.x, but in later versions we can // use it to see what it changes. useMaterial3: controller.useMaterial3, + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Workaround for issue: https://github.com/flutter/flutter/issues/103864. + typography: alwaysM3Typography, + // Typography used before workaround needed. + // typography: Typography.material2018(platform: controller.platform), ); } diff --git a/example/lib/shared/const/app_data.dart b/example/lib/shared/const/app_data.dart index e3ad7f26..648c445c 100644 --- a/example/lib/shared/const/app_data.dart +++ b/example/lib/shared/const/app_data.dart @@ -185,4 +185,103 @@ class AppData { icon: Icons.replay_outlined, ), ]; + + // TODO(rydmike): Remove when fix for issue #10386 has landed in stable. + // Used as a workaround to provide a M2 like TextTheme using M3 Typography, + // so we do not have to switch between 2021 and 2018 (or 2014) Typography + // in the app dynamically. Instead is always uses M3 2021 Typography and + // simulates 2018 Typography. This is done to avoid issue: + // https://github.com/flutter/flutter/issues/103864 + static const TextTheme m2TextTheme = TextTheme( + displayLarge: TextStyle( + debugLabel: 'englishLike displayLarge 2018', + fontSize: 96.0, + fontWeight: FontWeight.w300, + textBaseline: TextBaseline.alphabetic, + letterSpacing: -1.5), + displayMedium: TextStyle( + debugLabel: 'englishLike displayMedium 2018', + fontSize: 60.0, + fontWeight: FontWeight.w300, + textBaseline: TextBaseline.alphabetic, + letterSpacing: -0.5), + displaySmall: TextStyle( + debugLabel: 'englishLike displaySmall 2018', + fontSize: 48.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.0), + headlineLarge: TextStyle( + debugLabel: 'englishLike headlineLarge 2018', + fontSize: 40.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.25), + headlineMedium: TextStyle( + debugLabel: 'englishLike headlineMedium 2018', + fontSize: 34.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.25), + headlineSmall: TextStyle( + debugLabel: 'englishLike headlineSmall 2018', + fontSize: 24.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.0), + titleLarge: TextStyle( + debugLabel: 'englishLike titleLarge 2018', + fontSize: 20.0, + fontWeight: FontWeight.w500, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.15), + titleMedium: TextStyle( + debugLabel: 'englishLike titleMedium 2018', + fontSize: 16.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.15), + titleSmall: TextStyle( + debugLabel: 'englishLike titleSmall 2018', + fontSize: 14.0, + fontWeight: FontWeight.w500, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.1), + bodyLarge: TextStyle( + debugLabel: 'englishLike bodyLarge 2018', + fontSize: 16.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.5), + bodyMedium: TextStyle( + debugLabel: 'englishLike bodyMedium 2018', + fontSize: 14.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.25), + bodySmall: TextStyle( + debugLabel: 'englishLike bodySmall 2018', + fontSize: 12.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 0.4), + labelLarge: TextStyle( + debugLabel: 'englishLike labelLarge 2018', + fontSize: 14.0, + fontWeight: FontWeight.w500, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 1.25), + labelMedium: TextStyle( + debugLabel: 'englishLike labelMedium 2018', + fontSize: 11.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 1.5), + labelSmall: TextStyle( + debugLabel: 'englishLike labelSmall 2018', + fontSize: 10.0, + fontWeight: FontWeight.w400, + textBaseline: TextBaseline.alphabetic, + letterSpacing: 1.5), + ); } diff --git a/lib/src/flex_color_scheme.dart b/lib/src/flex_color_scheme.dart index 9980676a..ad5d04ea 100644 --- a/lib/src/flex_color_scheme.dart +++ b/lib/src/flex_color_scheme.dart @@ -4538,7 +4538,7 @@ class FlexColorScheme with Diagnosticable { height: 1.22, textBaseline: TextBaseline.alphabetic, leadingDistribution: TextLeadingDistribution.even), - // M3 headlineMedium, M2 . In Material2018 no equivalent exists. + // M3 headlineLarge, M2 . In Material2018 no equivalent exists. headlineLarge: TextStyle( debugLabel: 'englishLike headlineLarge 2021', fontSize: 32.0, @@ -6573,7 +6573,9 @@ class FlexColorScheme with Diagnosticable { // TODO(rydmike): Consider improving FCS inversePrimary algorithm. /// FlexColorScheme default for inversePrimary color, when not using seeds. /// - /// Not the best one in the world, but simple and works fairly well for light + /// When using real M3 ColorScheme's that are seeded, this color is not used. + /// + /// Not the best algo in the world, but simple and works fairly well for light /// Brightness, but should be better for dark. static Color _inversePrimary( Brightness brightness, Color primary, Color surface) { diff --git a/lib/src/flex_sub_themes.dart b/lib/src/flex_sub_themes.dart index e6e67d22..5c209da6 100644 --- a/lib/src/flex_sub_themes.dart +++ b/lib/src/flex_sub_themes.dart @@ -1906,7 +1906,7 @@ class FlexSubThemes { /// the effective default styles for undefined inputs become: /// /// ``` - /// FCS defaults Flutter defaults + /// FCS defaults M2 defaults /// useFlutterDefaults false true /// - background background surface, + onSurface overlay elev 3. /// - height 62 80 diff --git a/lib/src/flex_sub_themes_data.dart b/lib/src/flex_sub_themes_data.dart index 11e24886..61a1b463 100644 --- a/lib/src/flex_sub_themes_data.dart +++ b/lib/src/flex_sub_themes_data.dart @@ -1517,7 +1517,8 @@ class FlexSubThemesData with Diagnosticable { /// Opacity used on the [NavigationBar] indicator. /// - /// If undefined defaults to 24%. + /// If undefined and [ThemeData.useMaterial3] is false then it defaults to + /// 24%. /// /// The default opacity is computed from [kNavigationBarIndicatorAlpha] 0x3D, /// which is 61 giving 24% opacity.