Skip to content

chore: loading state blinking (WPB-23296)#4597

Open
sbakhtiarov wants to merge 1 commit intodevelopfrom
chore/loading-state-blinking
Open

chore: loading state blinking (WPB-23296)#4597
sbakhtiarov wants to merge 1 commit intodevelopfrom
chore/loading-state-blinking

Conversation

@sbakhtiarov
Copy link
Contributor

@sbakhtiarov sbakhtiarov commented Feb 12, 2026

https://wearezeta.atlassian.net/browse/WPB-23296

https://wearezeta.atlassian.net/browse/WPB-23296

What's new in this PR?

Issues

When a user has no conversations and opens the app, the conversations screen blinks between the loading shimmer and the empty state one or two times before settling on the empty state.

Causes (Optional)

The conversation list uses Paging 3 with SQLDelight's QueryPagingSource, which automatically invalidates whenever the underlying database tables are written to. At app startup, sync operations (WebSocket connection, background sync) write to conversation-related tables — even when no new conversations arrive (e.g. metadata, members, user info updates).

Each table write invalidates the PagingSource, causing the Pager to emit a fresh PagingData. When LazyPagingItems receives a new PagingData, it resets loadState.refresh to Loading and itemCount to 0. The loading condition in ConversationsScreenContent:

val showLoading = lazyPagingItems.loadState.refresh == LoadState.Loading && lazyPagingItems.itemCount == 0

becomes true again, briefly switching from the empty content back to the loading shimmer. When the re-query completes (still 0 items), it switches back to empty — producing a visible blink. This repeats for each sync-triggered invalidation.

Users with conversations are unaffected because enablePlaceholders = true keeps itemCount > 0 during refresh, so the showLoading guard never fires after the initial load.

Solution

Track whether the initial paging load has completed. After the first successful load (LoadState.NotLoading), never show the loading indicator again for the same composition — show the empty state directly instead.

The flag is scoped to remember, so it correctly resets when the composition is recreated (e.g. switching conversation filters via Crossfade). Error states don't set the flag, so a retry after a failed initial load still shows the loading indicator as expected.

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants