Skip to content

Conversation

vinodsingh-dev-gsoc
Copy link

@vinodsingh-dev-gsoc vinodsingh-dev-gsoc commented Sep 30, 2025

Fixes #1558.
This change improves the user experience by displaying a consistent placeholder when an avatar image fails to load from its URL.
Adds an errorBuilder to the AvatarImage widget and includes a test case to verify the new behavior.
Co-authored-by: Chris Bobbe [email protected]

@vinodsingh-dev-gsoc vinodsingh-dev-gsoc force-pushed the fix/avatar-placeholder-1558 branch from 60b16e2 to 97f92e7 Compare October 1, 2025 16:17
@chrisbobbe
Copy link
Collaborator

Thanks for the PR! Please post before/after screenshots of the change. Please also change the commit sequence so the tests are added in the same commit that adds the behavior being tested.

@vinodsingh-dev-gsoc vinodsingh-dev-gsoc force-pushed the fix/avatar-placeholder-1558 branch from 97f92e7 to 3f69209 Compare October 2, 2025 06:36
@vinodsingh-dev-gsoc
Copy link
Author

Hi chrisbobbe! Thanks a lot for the detailed feedback. I'm currently working on your suggestions. I've gathered the before/after screenshots and am now in the process of squashing the commits and fixing the test suite to make the PR perfect. I'll push the updated changes shortly! 😊

@vinodsingh-dev-gsoc vinodsingh-dev-gsoc force-pushed the fix/avatar-placeholder-1558 branch from 3f69209 to 0b69fea Compare October 3, 2025 14:04
@vinodsingh-dev-gsoc vinodsingh-dev-gsoc force-pushed the fix/avatar-placeholder-1558 branch from 0b69fea to aa123be Compare October 3, 2025 14:27
@vinodsingh-dev-gsoc
Copy link
Author

status CombinedScreen DM List Profile Screen
Before before_fix_for_combined_list before_fix_for_dm_list before_fix_for_profile_page
After fix after_fix_for_combined_list after_fix_for_dm_list after_fix_profile_page

As you can see in the "After" screenshot, the fix ensures that a placeholder is now displayed whenever an avatar URL is null or fails to load, instead of showing a blank space. This provides a clearer and more consistent UI for the user.

Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Small comments below.

Comment on lines 18 to 23
class MockHttpClient extends Fake implements HttpClient {
@override
Future<HttpClientRequest> getUrl(Uri url) async {
throw const SocketException('test error');
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the kind of thing that FakeImageHttpClient is for, in test/test_images.dart. Can we use that?

Oh! Or maybe add a boolean success param to prepareBoringImageHttpClient in that file (defaulting to true), and pass false in this case to make it prepare an HttpStats.notFound response?

await tester.pump(); // Image fails to load
expect(find.byIcon(ZulipIcons.person), findsOneWidget);

expect(find.byType(DecoratedBox), findsOneWidget);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it could easily find a DecoratedBox that's not related to the behavior we're testing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about checking the icon in this way:

        check(find.descendant(
          of: find.byType(AvatarImage),
          matching: find.byIcon(ZulipIcons.person),
        )).findsOne();

(adding the import 'package:flutter_checks/flutter_checks.dart'; at the top as needed)

@chrisbobbe
Copy link
Collaborator

Also please update the commit message to mention the issue being fixed, according to our style.

@gnprice gnprice added the maintainer review PR ready for review by Zulip maintainers label Oct 3, 2025
@chrisbobbe
Copy link
Collaborator

I see you've pushed some changes, but I'm not sure if you intend them to be ready for review; I assume you'll comment here when ready. 🙂

@vinodsingh-dev-gsoc
Copy link
Author

Hi @chrisbobbe,

Thanks for the ping, and my apologies for the delay in updating you here.

I've addressed your suggestions and pushed the commits a few days ago. The PR should now be ready for another look.

Eager to hear your feedback. Thank you for your guidance!

@alya
Copy link
Collaborator

alya commented Oct 8, 2025

Please see our guide on how to demonstrate visual changes: https://zulip.readthedocs.io/en/latest/contributing/reviewable-prs.html#demonstrating-visual-changes. The before/after screenshots should be minimally different.

I would also like to see both placeholders and regular avatars in the same screenshot, and dark theme as well as light.

@vinodsingh-dev-gsoc
Copy link
Author

vinodsingh-dev-gsoc commented Oct 8, 2025

Please see our guide on how to demonstrate visual changes: https://zulip.readthedocs.io/en/latest/contributing/reviewable-prs.html#demonstrating-visual-changes. The before/after screenshots should be minimally different.

I would also like to see both placeholders and regular avatars in the same screenshot, and dark theme as well as light.

Hi @alya, thanks for the detailed feedback! That makes perfect sense. I will generate the new screenshots with both themes and mixed avatars as you suggested and will post them here shortly.

@vinodsingh-dev-gsoc
Copy link
Author

Before (Bot avatar URL fails) After Fix (Shows Placeholder)
before_fix_for_combined_list_bot_logo_not_loaded_light_mode after_fix_for_combined_list_bot_logo_not_loaded
before_fix_for_combined_list_bot_logo_not_loaded_dark_mode after_fix_for_combined_list_bot_logo_not_loaded_DarkMode

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maintainer review PR ready for review by Zulip maintainers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

For avatars that don't load, reuse muted-user placeholder?
4 participants