🔄️ Improve conversation avatar caching - #6499
Merged
Merged
Conversation
AndyScherzinger
force-pushed
the
feat/noid/convoAvatarCaching
branch
from
August 16, 2026 10:04
27f49e3 to
e99ca60
Compare
AndyScherzinger
marked this pull request as ready for review
August 16, 2026 10:14
AndyScherzinger
force-pushed
the
feat/noid/convoAvatarCaching
branch
from
August 17, 2026 20:28
e99ca60 to
7cb05b8
Compare
AndyScherzinger
force-pushed
the
feat/noid/convoListUpdate
branch
from
August 18, 2026 22:40
1374082 to
883b385
Compare
AndyScherzinger
force-pushed
the
feat/noid/convoAvatarCaching
branch
from
August 18, 2026 22:48
7cb05b8 to
7462a23
Compare
AndyScherzinger
force-pushed
the
feat/noid/convoListUpdate
branch
from
August 19, 2026 05:03
883b385 to
f0b7da9
Compare
AndyScherzinger
force-pushed
the
feat/noid/convoAvatarCaching
branch
2 times, most recently
from
August 19, 2026 08:50
602b830 to
1aa4411
Compare
AndyScherzinger
force-pushed
the
feat/noid/convoListUpdate
branch
from
August 19, 2026 08:50
f0b7da9 to
7701c50
Compare
Conversation avatar responses are cacheable for one day only (the server sends private, max-age=86400, immutable), so once that lifetime expires every memory-cache miss goes back to the network although a versioned avatar URL cannot change - cold starts refetched long-known avatars and showed the fallback avatar in the meantime. Treat versioned conversation-avatar URLs as immutable content: the avatarVersion parameter is the invalidation token, so a dedicated avatar image loader ignores the cache headers and cached avatars never expire or revalidate - a new version changes the URL and forces the fetch, cold starts and offline serve straight from the disk cache. One-to-one rooms are deliberately outside this scheme: their avatarVersion is a server-side constant derived from a static icon path (the conversation avatar setters reject one-to-one rooms) and never changes when the peer updates their user avatar. With the avatar capability they use the conversation-avatar endpoint, which resolves the peer avatar and handles federation proxying, but without a version parameter and on the default header-respecting loader, so the one-day cache lifetime keeps picking up new peer avatars - matching what talk-ios does on purpose. Everything is gated on the avatar capability (Talk 17+; the app has no minimum Talk version, only the Nextcloud 17 EOL block, so far older servers remain supported): without it, one-to-one rooms keep the unversioned user-avatar endpoint and group/public rooms show themed default icons - which also fixes the previous behavior of unconditionally requesting the conversation-avatar endpoint that doesn't exist on such servers. The avatar content resolution moves to a testable top-level function with unit tests for the endpoint and capability selection. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
When an avatar's cache key changed (avatarVersion bump from a room list sync, theme switch) or a load transiently failed, the list flashed the generic fallback avatar until the fetch completed - even though the previous avatar had just been on screen. Every successful avatar load now also stores its bitmap under a stable per-room alias in the shared memory cache. New requests use that alias as both placeholder and error image, so a refresh renders as a crossfade from the old avatar to the new one and transient failures keep the last known avatar. The generic fallback only remains for avatars that were never shown, and for the rare coincidence of a cold start with a simultaneous version change, since the alias lives in memory only. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Scrolling the conversation list flashed the generic fallback avatar on rows entering the viewport for the first time in a session: the lazy list disposes off-screen rows, and re-entering rows without a memory cache entry showed the fallback as a de-facto loading indicator until the disk read or fetch completed. Render nothing while an avatar loads (the slot keeps its size and the avatar crossfades in), keep the last shown avatar as the placeholder when one is known, and reserve the fallback icon for what its name says: a failed load with no previously shown avatar. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
mahibi
force-pushed
the
feat/noid/convoAvatarCaching
branch
from
August 19, 2026 17:23
1aa4411 to
baea94a
Compare
Contributor
|
APK file: https://github.com/nextcloud/talk-android/actions/runs/32281286920/artifacts/9376490161 |
mahibi
approved these changes
Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Conversation avatars somtimes flashed the app-shipped fallback avatar (
account_circle_96dp) while scrolling / when loading before rendering the actual avatar - espesially after cold starts, sporadically during a session, and while scrolling. Three changes rework how avatars are fetched, cached and rendered.So this PR changes the avatar rendering berhavior and loading/caching logic.
Details
1. Versioned avatars are cached immutably
The avatar endpoints send
no-cacheheaders, so Coil revalidated avatars over the network on every memory-cache miss — every cold start refetched all list avatars. Since theavatarVersionURL parameter already is the invalidation token, versioned avatar URLs are immutable content:a dedicated avatar
ImageLoader(sharing memory/disk caches with the default one) now ignores the cache headers. Cached avatars never expire or revalidate; a newavatarVersionfrom the room list sync changes the URL and forces the fetch. Cold starts and offline usage render avatars straight from the disk cache.One-to-one conversations previously used the unversioned user-avatar endpoint, outside the version scheme. They now use the versioned conversation-avatar endpoint (which natively serves the peer's avatar), so their refresh is also driven purely by
avatarVersionchanges.Server compatibility: both changes are gated on the
avatarcapability (Talk 17+). On older servers, one-to-one rooms keep the unversioned user-avatar endpoint with header-driven revalidation, and group/public rooms show themed default icons — which also fixes the previous behavior of unconditionally requesting the conversation-avatar endpoint that does not exist there.2. A known avatar is never replaced by the fallback
Every successful avatar load also stores its bitmap under a stable per-room alias in the shared memory cache. Requests use that alias as placeholder and error image: an
avatarVersionbump or theme switch crossfades old → new, and transient load failures keep the last known avatar.3. The fallback icon is a fallback, not a loading indicator
While an avatar loads and no previous one is known (e.g. rows entering the viewport for the first time in a session while scrolling), nothing is rendered — the slot keeps its size and the avatar crossfades in. The fallback icon only appears when a load fails and no avatar was ever shown.
Resulting behavior
avatarcapability (pre Talk 17)Testing
ConversationAvatarContentTest), incl. the fallback matrix for servers without theavatarcapability.🏁 Checklist
/backport to stable-xx.x🤖 AI (if applicable)