From 11b5e3142dafd7206dc176a2393bb68c62227125 Mon Sep 17 00:00:00 2001 From: Eilidh Date: Wed, 18 Jan 2023 14:55:34 +0000 Subject: [PATCH 1/5] theme override fix --- .../flutter/lib/src/material/app_bar.dart | 56 ++++++++-------- .../flutter/test/material/app_bar_test.dart | 67 +++++++++++++++++++ 2 files changed, 94 insertions(+), 29 deletions(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index da6f10f64dbc7..745aebc1a0849 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1023,39 +1023,37 @@ class _AppBarState extends State { } if (leading != null) { if (theme.useMaterial3) { - if (leading is IconButton) { - final IconButtonThemeData effectiveIconButtonTheme; - - // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no - // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate - // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only - // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] - if (overallIconTheme == defaults.iconTheme) { - effectiveIconButtonTheme = iconButtonTheme; - } else { - // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. - final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( - foregroundColor: overallIconTheme.color, - iconSize: overallIconTheme.size, - ); - - effectiveIconButtonTheme = IconButtonThemeData( - style: iconButtonTheme.style?.copyWith( - foregroundColor: leadingIconButtonStyle.foregroundColor, - overlayColor: leadingIconButtonStyle.overlayColor, - iconSize: leadingIconButtonStyle.iconSize, - ) - ); - } - - leading = Center( - child: IconButtonTheme( - data: effectiveIconButtonTheme, - child: leading + final IconButtonThemeData effectiveIconButtonTheme; + + // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no + // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate + // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only + // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] + if (overallIconTheme == defaults.iconTheme) { + effectiveIconButtonTheme = iconButtonTheme; + } else { + // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. + final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( + foregroundColor: overallIconTheme.color, + iconSize: overallIconTheme.size, + ); + + effectiveIconButtonTheme = IconButtonThemeData( + style: iconButtonTheme.style?.copyWith( + foregroundColor: leadingIconButtonStyle.foregroundColor, + overlayColor: leadingIconButtonStyle.overlayColor, + iconSize: leadingIconButtonStyle.iconSize, ) ); } + leading = Center( + child: IconButtonTheme( + data: effectiveIconButtonTheme, + child: leading + ) + ); + // Based on the Material Design 3 specs, the leading IconButton should have // a size of 48x48, and a highlight size of 40x40. Users can also put other // type of widgets on leading with the original config. diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 73aa1d12f7b49..a48f06b84b30a 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3235,6 +3235,39 @@ void main() { expect(actionIconButtonSize(), 30.0); }); + testWidgets('AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom( + foregroundColor: Colors.red, + iconSize: 32.0, + ), + ), + useMaterial3: true, + ); + + const IconThemeData overallIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + iconTheme: overallIconTheme, + leading: BackButton(onPressed: () {}), + title: const Text('title'), + ), + ), + ), + ); + + Color? leadingIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; + double? leadingIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + + expect(leadingIconButtonColor(), Colors.yellow); + expect(leadingIconButtonSize(), 30.0); + + }); + testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( @@ -3275,6 +3308,40 @@ void main() { expect(actionIconButtonSize(), 30.0); }); + testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom( + foregroundColor: Colors.red, + iconSize: 32.0, + ), + ), + useMaterial3: true, + ); + + const IconThemeData actionsIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + actionsIconTheme: actionsIconTheme, + title: const Text('title'), + actions: [ + BackButton(onPressed: () {}), + ], + ), + ), + ), + ); + + Color? actionIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; + double? actionIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + + expect(actionIconButtonColor(), Colors.yellow); + expect(actionIconButtonSize(), 30.0); + }); + testWidgets('The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( From ba39a70668c6175f27186fa24fe9ae1b4ec34fd3 Mon Sep 17 00:00:00 2001 From: Eilidh Date: Wed, 18 Jan 2023 19:33:24 +0000 Subject: [PATCH 2/5] add lerp condition and tests --- .../lib/src/material/checkbox_theme.dart | 4 +- .../test/material/checkbox_theme_test.dart | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/checkbox_theme.dart b/packages/flutter/lib/src/material/checkbox_theme.dart index b959683e6675c..70595fab930eb 100644 --- a/packages/flutter/lib/src/material/checkbox_theme.dart +++ b/packages/flutter/lib/src/material/checkbox_theme.dart @@ -192,10 +192,10 @@ class CheckboxThemeData with Diagnosticable { // Special case because BorderSide.lerp() doesn't support null arguments static BorderSide? _lerpSides(BorderSide? a, BorderSide? b, double t) { - if (a == null && b == null) { + if (a == null || b == null) { return null; } - return BorderSide.lerp(a!, b!, t); + return BorderSide.lerp(a, b, t); } } diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index b57ce852e9f64..d4eaa2dd3fedc 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -391,6 +391,77 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: localThemeFillColor)); expect(_getCheckboxMaterial(tester), paints..path(color: localThemeFillColor)..path(color: localThemeCheckColor)); }); + + test('CheckboxThemeData lerp with null parameters', () { + final CheckboxThemeData lerped = CheckboxThemeData.lerp(null, null, 0.25); + + expect(lerped.mouseCursor, null); + expect(lerped.fillColor, null); + expect(lerped.checkColor, null); + expect(lerped.overlayColor, null); + expect(lerped.splashRadius, null); + expect(lerped.materialTapTargetSize, null); + expect(lerped.visualDensity, null); + expect(lerped.shape, null); + expect(lerped.side, null); + }); + + test('CheckboxThemeData lerp with from populated to null parameters', () { + final CheckboxThemeData theme = CheckboxThemeData( + fillColor: MaterialStateProperty.all(const Color(0xfffffff0)), + checkColor: MaterialStateProperty.all(const Color(0xfffffff1)), + overlayColor: MaterialStateProperty.all(const Color(0xfffffff2)), + splashRadius: 3.0, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(vertical: 1.0, horizontal: 1.0), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), + side: const BorderSide(width: 4.0), + ); + final CheckboxThemeData lerped = CheckboxThemeData.lerp(theme, null, 0.5); + + expect(lerped.fillColor!.resolve({}), const Color(0x80fffff0)); + expect(lerped.checkColor!.resolve({}), const Color(0x80fffff1)); + expect(lerped.overlayColor!.resolve({}), const Color(0x80fffff2)); + expect(lerped.splashRadius, 1.5); + expect(lerped.materialTapTargetSize, null); + expect(lerped.visualDensity, null); + expect(lerped.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)))); + // Returns null if either lerp value is null. + expect(lerped.side, null); + }); + + test('CheckboxThemeData lerp with from populated parameters', () { + final CheckboxThemeData themeA = CheckboxThemeData( + fillColor: MaterialStateProperty.all(const Color(0xfffffff0)), + checkColor: MaterialStateProperty.all(const Color(0xfffffff1)), + overlayColor: MaterialStateProperty.all(const Color(0xfffffff2)), + splashRadius: 3.0, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(vertical: 1.0, horizontal: 1.0), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), + side: const BorderSide(width: 4.0), + ); + final CheckboxThemeData themeB = CheckboxThemeData( + fillColor: MaterialStateProperty.all(const Color(0xfffffff3)), + checkColor: MaterialStateProperty.all(const Color(0xfffffff4)), + overlayColor: MaterialStateProperty.all(const Color(0xfffffff5)), + splashRadius: 9.0, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(vertical: 2.0, horizontal: 2.0), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(1.0))), + side: const BorderSide(width: 3.0), + ); + final CheckboxThemeData lerped = CheckboxThemeData.lerp(themeA, themeB, 0.5); + + expect(lerped.fillColor!.resolve({}), const Color(0xfffffff1)); + expect(lerped.checkColor!.resolve({}), const Color(0xfffffff2)); + expect(lerped.overlayColor!.resolve({}), const Color(0xfffffff3)); + expect(lerped.splashRadius, 6); + expect(lerped.materialTapTargetSize, MaterialTapTargetSize.shrinkWrap); + expect(lerped.visualDensity, const VisualDensity(vertical: 2.0, horizontal: 2.0)); + expect(lerped.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.5)))); + expect(lerped.side, const BorderSide(width: 3.5)); + }); } Future _pointGestureToCheckbox(WidgetTester tester) async { From ffcea01cffdf4d50f6c59fffbb344e3df3c669cc Mon Sep 17 00:00:00 2001 From: Eilidh Date: Wed, 18 Jan 2023 20:05:28 +0000 Subject: [PATCH 3/5] remove unwanted changes --- .../flutter/lib/src/material/app_bar.dart | 58 ++++++++-------- .../flutter/test/material/app_bar_test.dart | 67 ------------------- 2 files changed, 30 insertions(+), 95 deletions(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 745aebc1a0849..71e89aa0c7a88 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1023,37 +1023,39 @@ class _AppBarState extends State { } if (leading != null) { if (theme.useMaterial3) { - final IconButtonThemeData effectiveIconButtonTheme; - - // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no - // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate - // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only - // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] - if (overallIconTheme == defaults.iconTheme) { - effectiveIconButtonTheme = iconButtonTheme; - } else { - // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. - final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( - foregroundColor: overallIconTheme.color, - iconSize: overallIconTheme.size, - ); - - effectiveIconButtonTheme = IconButtonThemeData( - style: iconButtonTheme.style?.copyWith( - foregroundColor: leadingIconButtonStyle.foregroundColor, - overlayColor: leadingIconButtonStyle.overlayColor, - iconSize: leadingIconButtonStyle.iconSize, + if (leading is IconButton) { + final IconButtonThemeData effectiveIconButtonTheme; + + // This comparison is to check if there is a custom [overallIconTheme]. If true, it means that no + // custom [overallIconTheme] is provided, so [iconButtonTheme] is applied. Otherwise, we generate + // a new [IconButtonThemeData] based on the values from [overallIconTheme]. If [iconButtonTheme] only + // has null values, the default [overallIconTheme] will be applied below by [IconTheme.merge] + if (overallIconTheme == defaults.iconTheme) { + effectiveIconButtonTheme = iconButtonTheme; + } else { + // The [IconButton.styleFrom] method is used to generate a correct [overlayColor] based on the [foregroundColor]. + final ButtonStyle leadingIconButtonStyle = IconButton.styleFrom( + foregroundColor: overallIconTheme.color, + iconSize: overallIconTheme.size, + ); + + effectiveIconButtonTheme = IconButtonThemeData( + style: iconButtonTheme.style?.copyWith( + foregroundColor: leadingIconButtonStyle.foregroundColor, + overlayColor: leadingIconButtonStyle.overlayColor, + iconSize: leadingIconButtonStyle.iconSize, + ) + ); + } + + leading = Center( + child: IconButtonTheme( + data: effectiveIconButtonTheme, + child: leading ) ); } - leading = Center( - child: IconButtonTheme( - data: effectiveIconButtonTheme, - child: leading - ) - ); - // Based on the Material Design 3 specs, the leading IconButton should have // a size of 48x48, and a highlight size of 40x40. Users can also put other // type of widgets on leading with the original config. @@ -2434,7 +2436,7 @@ class _AppBarDefaultsM2 extends AppBarTheme { // Design token database by the script: // dev/tools/gen_defaults/bin/gen_defaults.dart. -// Token database version: v0_152 +// Token database version: v0_150 class _AppBarDefaultsM3 extends AppBarTheme { _AppBarDefaultsM3(this.context) diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index a48f06b84b30a..73aa1d12f7b49 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3235,39 +3235,6 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { - final ThemeData themeData = ThemeData( - iconButtonTheme: IconButtonThemeData( - style: IconButton.styleFrom( - foregroundColor: Colors.red, - iconSize: 32.0, - ), - ), - useMaterial3: true, - ); - - const IconThemeData overallIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); - await tester.pumpWidget( - MaterialApp( - theme: themeData, - home: Scaffold( - appBar: AppBar( - iconTheme: overallIconTheme, - leading: BackButton(onPressed: () {}), - title: const Text('title'), - ), - ), - ), - ); - - Color? leadingIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; - double? leadingIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; - - expect(leadingIconButtonColor(), Colors.yellow); - expect(leadingIconButtonSize(), 30.0); - - }); - testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( @@ -3308,40 +3275,6 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { - final ThemeData themeData = ThemeData( - iconButtonTheme: IconButtonThemeData( - style: IconButton.styleFrom( - foregroundColor: Colors.red, - iconSize: 32.0, - ), - ), - useMaterial3: true, - ); - - const IconThemeData actionsIconTheme = IconThemeData(color: Colors.yellow, size: 30.0); - await tester.pumpWidget( - MaterialApp( - theme: themeData, - home: Scaffold( - appBar: AppBar( - actionsIconTheme: actionsIconTheme, - title: const Text('title'), - actions: [ - BackButton(onPressed: () {}), - ], - ), - ), - ), - ); - - Color? actionIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; - double? actionIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; - - expect(actionIconButtonColor(), Colors.yellow); - expect(actionIconButtonSize(), 30.0); - }); - testWidgets('The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( From e7eb2a3a9e14e0bbaaedb22732589aec2360a72c Mon Sep 17 00:00:00 2001 From: Eilidh Date: Wed, 18 Jan 2023 20:16:49 +0000 Subject: [PATCH 4/5] resolve app_bar token version --- packages/flutter/lib/src/material/app_bar.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 71e89aa0c7a88..da6f10f64dbc7 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -2436,7 +2436,7 @@ class _AppBarDefaultsM2 extends AppBarTheme { // Design token database by the script: // dev/tools/gen_defaults/bin/gen_defaults.dart. -// Token database version: v0_150 +// Token database version: v0_152 class _AppBarDefaultsM3 extends AppBarTheme { _AppBarDefaultsM3(this.context) From cbbda3b4885c93588c14bfd75c32d0cdc3f9227f Mon Sep 17 00:00:00 2001 From: Eilidh Date: Thu, 19 Jan 2023 23:09:22 +0000 Subject: [PATCH 5/5] update test names --- packages/flutter/test/material/checkbox_theme_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index d4eaa2dd3fedc..d2bf1fdb1e32f 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -406,7 +406,7 @@ void main() { expect(lerped.side, null); }); - test('CheckboxThemeData lerp with from populated to null parameters', () { + test('CheckboxThemeData lerp from populated to null parameters', () { final CheckboxThemeData theme = CheckboxThemeData( fillColor: MaterialStateProperty.all(const Color(0xfffffff0)), checkColor: MaterialStateProperty.all(const Color(0xfffffff1)), @@ -430,7 +430,7 @@ void main() { expect(lerped.side, null); }); - test('CheckboxThemeData lerp with from populated parameters', () { + test('CheckboxThemeData lerp from populated parameters', () { final CheckboxThemeData themeA = CheckboxThemeData( fillColor: MaterialStateProperty.all(const Color(0xfffffff0)), checkColor: MaterialStateProperty.all(const Color(0xfffffff1)),