Unverified Commit 119e0ea1 authored by Amit Patil's avatar Amit Patil Committed by GitHub

circleAvatar: foreground Image uses background Image as a fall-back (#71783)

* foregroundImage property added

* fixed documentaion nits

* test for fallback to background image on foreground image failover

* golden test
parent be8b6bf0
......@@ -17,8 +17,13 @@ import 'theme_data.dart';
/// such an image, the user's initials. A given user's initials should
/// always be paired with the same background color, for consistency.
///
/// If [foregroundImage] fails then [backgroundImage] is used. If
/// [backgroundImage] fails too, [backgroundColor] is used.
///
/// The [onBackgroundImageError] parameter must be null if the [backgroundImage]
/// is null.
/// The [onForegroundImageError] parameter must be null if the [foregroundImage]
/// is null.
///
/// {@tool snippet}
///
......@@ -60,13 +65,16 @@ class CircleAvatar extends StatelessWidget {
this.child,
this.backgroundColor,
this.backgroundImage,
this.foregroundImage,
this.onBackgroundImageError,
this.onForegroundImageError,
this.foregroundColor,
this.radius,
this.minRadius,
this.maxRadius,
}) : assert(radius == null || (minRadius == null && maxRadius == null)),
assert(backgroundImage != null || onBackgroundImageError == null),
assert(foregroundImage != null || onForegroundImageError== null),
super(key: key);
/// The widget below this widget in the tree.
......@@ -95,13 +103,24 @@ class CircleAvatar extends StatelessWidget {
/// The background image of the circle. Changing the background
/// image will cause the avatar to animate to the new image.
///
/// Typically used as a fallback image for [foregroundImage].
///
/// If the [CircleAvatar] is to have the user's initials, use [child] instead.
final ImageProvider? backgroundImage;
/// The foreground image of the circle.
///
/// Typically used as profile image. For fallback use [backgroundImage].
final ImageProvider? foregroundImage;
/// An optional error callback for errors emitted when loading
/// [backgroundImage].
final ImageErrorListener? onBackgroundImageError;
/// An optional error callback for errors emitted when loading
/// [foregroundImage].
final ImageErrorListener? onForegroundImageError;
/// The size of the avatar, expressed as the radius (half the diameter).
///
/// If [radius] is specified, then neither [minRadius] nor [maxRadius] may be
......@@ -217,6 +236,16 @@ class CircleAvatar extends StatelessWidget {
: null,
shape: BoxShape.circle,
),
foregroundDecoration: foregroundImage != null
? BoxDecoration(
image: DecorationImage(
image: foregroundImage!,
onError: onForegroundImageError,
fit: BoxFit.cover,
),
shape: BoxShape.circle,
)
: null,
child: child == null
? null
: Center(
......
......@@ -9,6 +9,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import '../image_data.dart';
import '../painting/mocks_for_image_cache.dart';
void main() {
testWidgets('CircleAvatar with dark background color', (WidgetTester tester) async {
......@@ -72,6 +73,51 @@ void main() {
expect(decoration.image!.fit, equals(BoxFit.cover));
});
testWidgets('CircleAvatar with image foreground', (WidgetTester tester) async {
await tester.pumpWidget(
wrap(
child: CircleAvatar(
foregroundImage: MemoryImage(Uint8List.fromList(kBlueRectPng)),
radius: 50.0,
),
),
);
final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
expect(box.size, equals(const Size(100.0, 100.0)));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.image!.fit, equals(BoxFit.cover));
});
testWidgets('CircleAvatar backgroundImage is used as a fallback for foregroundImage', (WidgetTester tester) async {
final ErrorImageProvider errorImage = ErrorImageProvider();
bool caughtForegroundImageError = false;
await tester.pumpWidget(
wrap(
child: RepaintBoundary(
child: CircleAvatar(
foregroundImage: errorImage,
backgroundImage: MemoryImage(Uint8List.fromList(kBlueRectPng)),
radius: 50.0,
onForegroundImageError: (_,__) => caughtForegroundImageError = true,
),
),
),
);
expect(caughtForegroundImageError, true);
final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
expect(box.size, equals(const Size(100.0, 100.0)));
final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
final BoxDecoration decoration = child.decoration as BoxDecoration;
expect(decoration.image!.fit, equals(BoxFit.cover));
await expectLater(
find.byType(CircleAvatar),
matchesGoldenFile('circle_avatar.fallback.png'),
);
});
testWidgets('CircleAvatar with foreground color', (WidgetTester tester) async {
final Color foregroundColor = Colors.red.shade100;
await tester.pumpWidget(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment