Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Update CircleAvatar to support Material 3 (#114812)
Browse files Browse the repository at this point in the history
  • Loading branch information
TahaTesser authored Nov 9, 2022
1 parent 92f10ed commit d3dcd7d
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 37 deletions.
19 changes: 14 additions & 5 deletions packages/flutter/lib/src/material/circle_avatar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ class CircleAvatar extends StatelessWidget {
/// The color with which to fill the circle. Changing the background
/// color will cause the avatar to animate to the new color.
///
/// If a [backgroundColor] is not specified, the theme's
/// If a [backgroundColor] is not specified and [ThemeData.useMaterial3] is true,
/// [ColorScheme.primaryContainer] will be used, otherwise the theme's
/// [ThemeData.primaryColorLight] is used with dark foreground colors, and
/// [ThemeData.primaryColorDark] with light foreground colors.
final Color? backgroundColor;
Expand All @@ -94,7 +95,9 @@ class CircleAvatar extends StatelessWidget {
/// Defaults to the primary text theme color if no [backgroundColor] is
/// specified.
///
/// Defaults to [ThemeData.primaryColorLight] for dark background colors, and
/// If a [foregroundColor] is not specified and [ThemeData.useMaterial3] is true,
/// [ColorScheme.onPrimaryContainer] will be used, otherwise the theme's
/// [ThemeData.primaryColorLight] for dark background colors, and
/// [ThemeData.primaryColorDark] for light background colors.
final Color? foregroundColor;

Expand Down Expand Up @@ -192,8 +195,14 @@ class CircleAvatar extends StatelessWidget {
Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context));
final ThemeData theme = Theme.of(context);
TextStyle textStyle = theme.primaryTextTheme.titleMedium!.copyWith(color: foregroundColor);
Color? effectiveBackgroundColor = backgroundColor;
final Color? effectiveForegroundColor = foregroundColor
?? (theme.useMaterial3 ? theme.colorScheme.onPrimaryContainer : null);
final TextStyle effectiveTextStyle = theme.useMaterial3
? theme.textTheme.titleMedium!
: theme.primaryTextTheme.titleMedium!;
TextStyle textStyle = effectiveTextStyle.copyWith(color: effectiveForegroundColor);
Color? effectiveBackgroundColor = backgroundColor
?? (theme.useMaterial3 ? theme.colorScheme.primaryContainer : null);
if (effectiveBackgroundColor == null) {
switch (ThemeData.estimateBrightnessForColor(textStyle.color!)) {
case Brightness.dark:
Expand All @@ -203,7 +212,7 @@ class CircleAvatar extends StatelessWidget {
effectiveBackgroundColor = theme.primaryColorDark;
break;
}
} else if (foregroundColor == null) {
} else if (effectiveForegroundColor == null) {
switch (ThemeData.estimateBrightnessForColor(backgroundColor!)) {
case Brightness.dark:
textStyle = textStyle.copyWith(color: theme.primaryColorLight);
Expand Down
91 changes: 59 additions & 32 deletions packages/flutter/test/material/circle_avatar_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,36 +144,8 @@ void main() {
expect(paragraph.text.style!.color, equals(foregroundColor));
});

testWidgets('CircleAvatar with light theme', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
primaryColor: Colors.grey.shade100,
primaryColorBrightness: Brightness.light,
);
await tester.pumpWidget(
wrap(
child: Theme(
data: theme,
child: const CircleAvatar(
child: Text('Z'),
),
),
),
);

final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.color, equals(theme.primaryColorLight));

final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
});

testWidgets('CircleAvatar with dark theme', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
primaryColor: Colors.grey.shade800,
primaryColorBrightness: Brightness.dark,
);
testWidgets('CircleAvatar default colors', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true);
await tester.pumpWidget(
wrap(
child: Theme(
Expand All @@ -188,10 +160,10 @@ void main() {
final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.color, equals(theme.primaryColorDark));
expect(decoration.color, equals(theme.colorScheme.primaryContainer));

final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
expect(paragraph.text.style!.color, equals(theme.colorScheme.onPrimaryContainer));
});

testWidgets('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async {
Expand Down Expand Up @@ -306,6 +278,61 @@ void main() {
final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight));
});

group('Material 2', () {
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
// is turned on by default, these tests can be removed.

testWidgets('CircleAvatar default colors with light theme', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
primaryColor: Colors.grey.shade100,
primaryColorBrightness: Brightness.light,
);
await tester.pumpWidget(
wrap(
child: Theme(
data: theme,
child: const CircleAvatar(
child: Text('Z'),
),
),
),
);

final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.color, equals(theme.primaryColorLight));

final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
});

testWidgets('CircleAvatar default colors with dark theme', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
primaryColor: Colors.grey.shade800,
primaryColorBrightness: Brightness.dark,
);
await tester.pumpWidget(
wrap(
child: Theme(
data: theme,
child: const CircleAvatar(
child: Text('Z'),
),
),
),
);

final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.color, equals(theme.primaryColorDark));

final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
});
});
}

Widget wrap({ required Widget child }) {
Expand Down

0 comments on commit d3dcd7d

Please sign in to comment.