Skip to content

Commit 0b69fea

Browse files
avatar: Show placeholder on image load error
1 parent 3013d4f commit 0b69fea

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

lib/widgets/user.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import 'package:flutter/material.dart';
2-
32
import '../api/model/model.dart';
43
import '../model/avatar_url.dart';
54
import '../model/binding.dart';
@@ -90,6 +89,9 @@ class AvatarImage extends StatelessWidget {
9089
avatarUrl.get(physicalSize),
9190
filterQuality: FilterQuality.medium,
9291
fit: BoxFit.cover,
92+
errorBuilder: (context, error, stackTrace) {
93+
return _AvatarPlaceholder(size: size);
94+
},
9395
);
9496
}
9597
}

test/widgets/user_test.dart

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/cupertino.dart';
33
import 'package:flutter/material.dart';
4+
import 'package:zulip/widgets/icons.dart';
45
import 'package:flutter/rendering.dart';
56
import 'package:flutter_test/flutter_test.dart';
67
import 'package:zulip/model/store.dart';
78
import 'package:zulip/widgets/content.dart';
89
import 'package:zulip/widgets/store.dart';
910
import 'package:zulip/widgets/user.dart';
10-
11+
import 'dart:io';
1112
import '../example_data.dart' as eg;
1213
import '../model/binding.dart';
1314
import '../model/test_store.dart';
1415
import '../stdlib_checks.dart';
1516
import '../test_images.dart';
17+
import 'test_app.dart';
18+
19+
class MockHttpClient extends Fake implements HttpClient {
20+
@override
21+
Future<HttpClientRequest> getUrl(Uri url) async {
22+
throw const SocketException('test error');
23+
}
24+
}
1625

1726
void main() {
1827
TestZulipBinding.ensureInitialized();
@@ -78,5 +87,28 @@ void main() {
7887
check(await actualUrl(tester, avatarUrl)).isNull();
7988
debugNetworkImageHttpClientProvider = null;
8089
});
90+
91+
testWidgets('shows placeholder when image URL gives error', (WidgetTester tester) async {
92+
await HttpOverrides.runZoned(() async {
93+
addTearDown(testBinding.reset);
94+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
95+
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
96+
final user = eg.user(avatarUrl: 'https://zulip.com/avatar.png');
97+
await store.addUser(user);
98+
99+
await tester.pumpWidget(
100+
TestZulipApp(
101+
accountId: eg.selfAccount.id,
102+
child: AvatarImage(userId: user.userId, size: 32),
103+
),
104+
);
105+
await tester.pump(); // Image provider is created
106+
await tester.pump(); // Image fails to load
107+
expect(find.byIcon(ZulipIcons.person), findsOneWidget);
108+
109+
expect(find.byType(DecoratedBox), findsOneWidget);
110+
111+
}, createHttpClient: (context) => MockHttpClient());
112+
});
81113
});
82114
}

0 commit comments

Comments
 (0)