Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions packages/flutter/lib/src/material/button_style_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,16 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
});
}

Color? effectiveIconColor() {
return widgetStyle?.iconColor?.resolve(statesController.value) ??
themeStyle?.iconColor?.resolve(statesController.value) ??
widgetStyle?.foregroundColor?.resolve(statesController.value) ??
themeStyle?.foregroundColor?.resolve(statesController.value) ??
defaultStyle.iconColor?.resolve(statesController.value) ??
// Fallback to foregroundColor if iconColor is null.
defaultStyle.foregroundColor?.resolve(statesController.value);
}

final double? resolvedElevation = resolve<double?>((ButtonStyle? style) => style?.elevation);
final TextStyle? resolvedTextStyle = resolve<TextStyle?>(
(ButtonStyle? style) => style?.textStyle,
Expand All @@ -409,7 +419,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
final Size? resolvedMinimumSize = resolve<Size?>((ButtonStyle? style) => style?.minimumSize);
final Size? resolvedFixedSize = resolve<Size?>((ButtonStyle? style) => style?.fixedSize);
final Size? resolvedMaximumSize = resolve<Size?>((ButtonStyle? style) => style?.maximumSize);
final Color? resolvedIconColor = resolve<Color?>((ButtonStyle? style) => style?.iconColor);
final Color? resolvedIconColor = effectiveIconColor();
final double? resolvedIconSize = resolve<double?>((ButtonStyle? style) => style?.iconSize);
final BorderSide? resolvedSide = resolve<BorderSide?>((ButtonStyle? style) => style?.side);
final OutlinedBorder? resolvedShape = resolve<OutlinedBorder?>(
Expand Down Expand Up @@ -551,10 +561,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
customBorder: resolvedShape!.copyWith(side: resolvedSide),
statesController: statesController,
child: IconTheme.merge(
data: IconThemeData(
color: resolvedIconColor ?? resolvedForegroundColor,
size: resolvedIconSize,
),
data: IconThemeData(color: resolvedIconColor, size: resolvedIconSize),
child: result,
),
);
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter/lib/src/material/elevated_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ class ElevatedButton extends ButtonStyleButton {
/// [ButtonStyle.iconColor] and [iconSize] is used to construct
/// [ButtonStyle.iconSize].
///
/// If [iconColor] is null, the button icon will use [foregroundColor]. If [foregroundColor] is also
/// null, the button icon will use the default icon color.
///
/// The button's elevations are defined relative to the [elevation]
/// parameter. The disabled elevation is the same as the parameter
/// value, [elevation] + 2 is used when the button is hovered
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter/lib/src/material/filled_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ class FilledButton extends ButtonStyleButton {
/// [ButtonStyle.iconColor] and [iconSize] is used to construct
/// [ButtonStyle.iconSize].
///
/// If [iconColor] is null, the button icon will use [foregroundColor]. If [foregroundColor] is also
/// null, the button icon will use the default icon color.
///
/// The button's elevations are defined relative to the [elevation]
/// parameter. The disabled elevation is the same as the parameter
/// value, [elevation] + 2 is used when the button is hovered
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter/lib/src/material/outlined_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ class OutlinedButton extends ButtonStyleButton {
/// [ButtonStyle.iconColor] and [iconSize] is used to construct
/// [ButtonStyle.iconSize].
///
/// If [iconColor] is null, the button icon will use [foregroundColor]. If [foregroundColor] is also
/// null, the button icon will use the default icon color.
///
/// If [overlayColor] is specified and its value is [Colors.transparent]
/// then the pressed/focused/hovered highlights are effectively defeated.
/// Otherwise a [WidgetStateProperty] with the same opacities as the
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter/lib/src/material/text_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ class TextButton extends ButtonStyleButton {
/// [ButtonStyle.iconColor] and [iconSize] is used to construct
/// [ButtonStyle.iconSize].
///
/// If [iconColor] is null, the button icon will use [foregroundColor]. If [foregroundColor] is also
/// null, the button icon will use the default icon color.
///
/// If [overlayColor] is specified and its value is [Colors.transparent]
/// then the pressed/focused/hovered highlights are effectively defeated.
/// Otherwise a [WidgetStateProperty] with the same opacities as the
Expand Down
23 changes: 23 additions & 0 deletions packages/flutter/test/material/elevated_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2510,4 +2510,27 @@ void main() {
final Offset iconTopRight = tester.getTopRight(find.byIcon(Icons.add));
expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets('ElevatedButton icon uses provided foregroundColor over default icon color', (
WidgetTester tester,
) async {
const Color foregroundColor = Color(0xFFFF1234);

await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(foregroundColor: foregroundColor),
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
),
),
),
);
expect(iconStyle(tester, Icons.add).color, foregroundColor);
});
}
40 changes: 38 additions & 2 deletions packages/flutter/test/material/elevated_button_theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
TextStyle iconStyle(WidgetTester tester, IconData icon) {
final RichText iconRichText = tester.widget<RichText>(
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
);
return iconRichText.text.style!;
}

test('ElevatedButtonThemeData lerp special cases', () {
expect(ElevatedButtonThemeData.lerp(null, null, 0), null);
const ElevatedButtonThemeData data = ElevatedButtonThemeData();
Expand Down Expand Up @@ -263,7 +270,7 @@ void main() {
);
});

testWidgets('Material3 - ElevatedButton repsects Theme shadowColor', (WidgetTester tester) async {
testWidgets('Material3 - ElevatedButton respects Theme shadowColor', (WidgetTester tester) async {
const ColorScheme colorScheme = ColorScheme.light();
const Color shadowColor = Color(0xff000001);
const Color overriddenColor = Color(0xff000002);
Expand Down Expand Up @@ -334,7 +341,7 @@ void main() {
expect(material.shadowColor, shadowColor);
});

testWidgets('Material2 - ElevatedButton repsects Theme shadowColor', (WidgetTester tester) async {
testWidgets('Material2 - ElevatedButton respects Theme shadowColor', (WidgetTester tester) async {
const ColorScheme colorScheme = ColorScheme.light();
const Color shadowColor = Color(0xff000001);
const Color overriddenColor = Color(0xff000002);
Expand Down Expand Up @@ -442,4 +449,33 @@ void main() {

expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets(
'ElevatedButton icon uses provided ElevatedButtonTheme foregroundColor over default icon color',
(WidgetTester tester) async {
const Color foregroundColor = Color(0xFFFFA500);

await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(foregroundColor: foregroundColor),
),
),
home: Material(
child: Center(
child: ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
),
),
),
);

expect(iconStyle(tester, Icons.add).color, foregroundColor);
},
);
}
34 changes: 34 additions & 0 deletions packages/flutter/test/material/filled_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2756,4 +2756,38 @@ void main() {
final Offset iconTopRight = tester.getTopRight(find.byIcon(Icons.add));
expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets('FilledButton icon uses provided foregroundColor over default icon color', (
WidgetTester tester,
) async {
const Color foregroundColor = Color(0xFFFF1234);

await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: Column(
children: <Widget>[
FilledButton.icon(
style: FilledButton.styleFrom(foregroundColor: foregroundColor),
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
FilledButton.tonalIcon(
style: FilledButton.styleFrom(foregroundColor: foregroundColor),
onPressed: () {},
icon: const Icon(Icons.mail),
label: const Text('Button'),
),
],
),
),
),
),
);
expect(iconStyle(tester, Icons.add).color, foregroundColor);
expect(iconStyle(tester, Icons.mail).color, foregroundColor);
});
}
46 changes: 46 additions & 0 deletions packages/flutter/test/material/filled_button_theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
TextStyle iconStyle(WidgetTester tester, IconData icon) {
final RichText iconRichText = tester.widget<RichText>(
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
);
return iconRichText.text.style!;
}

test('FilledButtonThemeData lerp special cases', () {
expect(FilledButtonThemeData.lerp(null, null, 0), null);
const FilledButtonThemeData data = FilledButtonThemeData();
Expand Down Expand Up @@ -360,4 +367,43 @@ void main() {

expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets(
'FilledButton icon uses provided FilledButtonTheme foregroundColor over default icon color',
(WidgetTester tester) async {
const Color foregroundColor = Color(0xFFFFA500);

await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(foregroundColor: foregroundColor),
),
),
home: Material(
child: Center(
child: Column(
children: <Widget>[
FilledButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
FilledButton.icon(
onPressed: () {},
icon: const Icon(Icons.mail),
label: const Text('Button'),
),
],
),
),
),
),
);

expect(iconStyle(tester, Icons.add).color, foregroundColor);
expect(iconStyle(tester, Icons.mail).color, foregroundColor);
},
);
}
23 changes: 23 additions & 0 deletions packages/flutter/test/material/outlined_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2854,4 +2854,27 @@ void main() {
final Offset iconTopRight = tester.getTopRight(find.byIcon(Icons.add));
expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets('OutlinedButton icon uses provided foregroundColor over default icon color', (
WidgetTester tester,
) async {
const Color foregroundColor = Color(0xFFFF1234);

await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: OutlinedButton.icon(
style: OutlinedButton.styleFrom(foregroundColor: foregroundColor),
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
),
),
),
);
expect(iconStyle(tester, Icons.add).color, foregroundColor);
});
}
36 changes: 36 additions & 0 deletions packages/flutter/test/material/outlined_button_theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
TextStyle iconStyle(WidgetTester tester, IconData icon) {
final RichText iconRichText = tester.widget<RichText>(
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
);
return iconRichText.text.style!;
}

test('OutlinedButtonThemeData lerp special cases', () {
expect(OutlinedButtonThemeData.lerp(null, null, 0), null);
const OutlinedButtonThemeData data = OutlinedButtonThemeData();
Expand Down Expand Up @@ -446,4 +453,33 @@ void main() {
expect(buttonTopRight.dx, iconTopRight.dx + 24.0);
},
);

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets(
'OutlinedButton icon uses provided OutlinedButtonTheme foregroundColor over default icon color',
(WidgetTester tester) async {
const Color foregroundColor = Color(0xFFFFA500);

await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(foregroundColor: foregroundColor),
),
),
home: Material(
child: Center(
child: OutlinedButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
),
),
),
);

expect(iconStyle(tester, Icons.add).color, foregroundColor);
},
);
}
23 changes: 23 additions & 0 deletions packages/flutter/test/material/text_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2547,4 +2547,27 @@ void main() {
final Offset iconTopRight = tester.getTopRight(find.byIcon(Icons.add));
expect(buttonTopRight.dx, iconTopRight.dx + 16.0);
});

// Regression test for https://github.com/flutter/flutter/issues/162839.
testWidgets('TextButton icon uses provided foregroundColor over default icon color', (
WidgetTester tester,
) async {
const Color foregroundColor = Color(0xFFFF1234);

await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextButton.icon(
style: TextButton.styleFrom(foregroundColor: foregroundColor),
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Button'),
),
),
),
),
);
expect(iconStyle(tester, Icons.add).color, foregroundColor);
});
}
Loading