Skip to content

Commit aa123be

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

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/cupertino.dart';
33
import 'package:flutter/material.dart';
4-
import 'package:flutter/rendering.dart';
4+
import 'package:zulip/widgets/icons.dart';
55
import 'package:flutter_test/flutter_test.dart';
66
import 'package:zulip/model/store.dart';
77
import 'package:zulip/widgets/content.dart';
88
import 'package:zulip/widgets/store.dart';
99
import 'package:zulip/widgets/user.dart';
10-
10+
import 'dart:io';
1111
import '../example_data.dart' as eg;
1212
import '../model/binding.dart';
1313
import '../model/test_store.dart';
1414
import '../stdlib_checks.dart';
1515
import '../test_images.dart';
16+
import 'test_app.dart';
17+
18+
class MockHttpClient extends Fake implements HttpClient {
19+
@override
20+
Future<HttpClientRequest> getUrl(Uri url) async {
21+
throw const SocketException('test error');
22+
}
23+
}
1624

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

0 commit comments

Comments
 (0)