Source: perf analysis of reader → inbox back-navigation (user-reported: multiple-second delay + a brief "No messages" flash on return).
The ViewModel and its flows ARE retained across the round trip; the UI-side LazyPagingItems is recreated cold (itemCount == 0) on return. Two distinct root causes:
The flash — the unified list's empty-state gate at MailboxScreen.kt:297-305 suppresses "No messages" only while refresh is LoadState.Loading, not during the itemCount == 0 && refresh == NotLoading re-presentation window (Paging pushes the item snapshot and load-state on separate collectors), so the empty state renders for a frame.
The multi-second latency — opening an unread message writes setRead (MailRepositoryImpl.kt:135), invalidating the Room PagingSource; Paging cold-loads a new generation on return (the cache fills lazily and the mailbox has no collector while reading), amplified by concurrent sync/prefetch writes each re-invalidating the source.
Fixes (both):
Gate the empty state on itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReached.
Keep a live downstream collector on the cached paged flow across the reader visit so the post-setRead generation loads in the background and the return replays a full window with zero empty frames.
Sequencing: implement AFTER #214 (paged folder/search) lands — both rewrite the same MailboxScreen/MailboxViewModel paging code, and the empty-state gate + keep-alive should then apply uniformly to all paged lists.
**Source:** perf analysis of reader → inbox back-navigation (user-reported: multiple-second delay + a brief "No messages" flash on return).
The ViewModel and its flows ARE retained across the round trip; the UI-side `LazyPagingItems` is recreated cold (`itemCount == 0`) on return. Two distinct root causes:
1. **The flash** — the unified list's empty-state gate at `MailboxScreen.kt:297-305` suppresses "No messages" only while `refresh is LoadState.Loading`, not during the `itemCount == 0 && refresh == NotLoading` re-presentation window (Paging pushes the item snapshot and load-state on separate collectors), so the empty state renders for a frame.
2. **The multi-second latency** — opening an unread message writes `setRead` (`MailRepositoryImpl.kt:135`), invalidating the Room `PagingSource`; Paging cold-loads a new generation *on return* (the cache fills lazily and the mailbox has no collector while reading), amplified by concurrent sync/prefetch writes each re-invalidating the source.
**Fixes (both):**
- Gate the empty state on `itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReached`.
- Keep a live downstream collector on the cached paged flow across the reader visit so the post-`setRead` generation loads in the background and the return replays a full window with zero empty frames.
**Sequencing:** implement AFTER #214 (paged folder/search) lands — both rewrite the same `MailboxScreen`/`MailboxViewModel` paging code, and the empty-state gate + keep-alive should then apply uniformly to all paged lists.
PR #223 (issue #214) rewrote the mailbox list into a single paged render path and, in doing so, replaced the empty-state gate with the correct itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReached condition — i.e. it subsumes fix#1 (the empty-state flash) from this ticket.
Remaining scope for #219: the structural latency fix — keep a live downstream collector on the cached paged flow across the reader visit so the post-setRead generation loads in the background (no cold reload / blank window on return). To be implemented on top of #223.
PR #223 (issue #214) rewrote the mailbox list into a single paged render path and, in doing so, replaced the empty-state gate with the correct `itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReached` condition — i.e. it **subsumes fix #1 (the empty-state flash)** from this ticket.
Remaining scope for #219: the **structural latency fix** — keep a live downstream collector on the cached paged flow across the reader visit so the post-`setRead` generation loads in the background (no cold reload / blank window on return). To be implemented on top of #223.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Source: perf analysis of reader → inbox back-navigation (user-reported: multiple-second delay + a brief "No messages" flash on return).
The ViewModel and its flows ARE retained across the round trip; the UI-side
LazyPagingItemsis recreated cold (itemCount == 0) on return. Two distinct root causes:MailboxScreen.kt:297-305suppresses "No messages" only whilerefresh is LoadState.Loading, not during theitemCount == 0 && refresh == NotLoadingre-presentation window (Paging pushes the item snapshot and load-state on separate collectors), so the empty state renders for a frame.setRead(MailRepositoryImpl.kt:135), invalidating the RoomPagingSource; Paging cold-loads a new generation on return (the cache fills lazily and the mailbox has no collector while reading), amplified by concurrent sync/prefetch writes each re-invalidating the source.Fixes (both):
itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReached.setReadgeneration loads in the background and the return replays a full window with zero empty frames.Sequencing: implement AFTER #214 (paged folder/search) lands — both rewrite the same
MailboxScreen/MailboxViewModelpaging code, and the empty-state gate + keep-alive should then apply uniformly to all paged lists.PR #223 (issue #214) rewrote the mailbox list into a single paged render path and, in doing so, replaced the empty-state gate with the correct
itemCount == 0 && refresh is LoadState.NotLoading && append.endOfPaginationReachedcondition — i.e. it subsumes fix #1 (the empty-state flash) from this ticket.Remaining scope for #219: the structural latency fix — keep a live downstream collector on the cached paged flow across the reader visit so the post-
setReadgeneration loads in the background (no cold reload / blank window on return). To be implemented on top of #223.