When a folder is open and it is making a network request with no prior messages to display, it should show a wait spinner rather than showing "No messages to display" until the network request completes #149

Closed
opened 2026-07-02 20:00:26 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-07-02 20:00:26 +00:00 (Migrated from github.com)

Context

MailboxViewModel.selectFolder() (ui/mailbox/MailboxViewModel.kt, ~lines 363-369) kicks off a
background mailSyncer.syncFolder(...) fire-and-forget but exposes no loading flag for it —
_isRefreshing is only set by the explicit pull-to-refresh path (refresh(), ~lines 407-424).
The messages StateFlow (~lines 128-154) reads straight from the local Room cache via
observeFolderMessages, so opening a folder with no cached rows yet emits an empty list
immediately, before the background fetch has a chance to populate anything.

In MailboxScreen.kt's non-paged branch (the per-account/folder path, ~lines 331-338), an empty
messages list renders NoMessagesState unconditionally. This is inconsistent with the unified
inbox's paged branch just above it (~lines 296-304), which already holds the empty state back
while pagedMessages.loadState.refresh is LoadState.Loading. So per-account folder opens flash
"No messages to display" while the initial IMAP fetch for that folder is still in flight —
exactly the bug this ticket describes.

Scope

  • Expose a per-folder "syncing" flag from MailboxViewModel, set for the duration of the
    selectFolder-triggered syncFolder call (mirroring _isRefreshing's pattern; either a
    new flow or a generalization of _isRefreshing if the two cases turn out to be behaviorally
    equivalent — decide during implementation).
  • In MailboxScreen.kt's non-paged empty branch (~line 331), gate NoMessagesState on that
    flag the same way the paged branch already gates on loadState.refresh (~line 301), showing
    a CircularProgressIndicator while the initial fetch is in flight instead.
  • Make sure the flag clears once syncFolder completes regardless of outcome (success,
    failure, or cancellation from rapid folder switching), so a genuinely empty, already-synced
    folder still shows "No messages to display" rather than spinning forever.

Acceptance criteria

  • Opening a per-account folder for the first time (empty local cache) shows a spinner until the
    IMAP fetch completes, then either the fetched messages or, if the folder truly is empty,
    "No messages to display".
  • Pull-to-refresh and the unified-inbox paged path are unaffected.
  • Rapidly switching folders doesn't leave a stale spinner running for a folder no longer selected.

Relevant files

  • ui/mailbox/MailboxViewModel.kt (~lines 128-154, 363-369, 407-424),
    ui/mailbox/MailboxScreen.kt (~lines 290-338).
## Context `MailboxViewModel.selectFolder()` (`ui/mailbox/MailboxViewModel.kt`, ~lines 363-369) kicks off a background `mailSyncer.syncFolder(...)` fire-and-forget but exposes no loading flag for it — `_isRefreshing` is only set by the explicit pull-to-refresh path (`refresh()`, ~lines 407-424). The `messages` `StateFlow` (~lines 128-154) reads straight from the local Room cache via `observeFolderMessages`, so opening a folder with no cached rows yet emits an empty list immediately, before the background fetch has a chance to populate anything. In `MailboxScreen.kt`'s non-paged branch (the per-account/folder path, ~lines 331-338), an empty `messages` list renders `NoMessagesState` unconditionally. This is inconsistent with the unified inbox's paged branch just above it (~lines 296-304), which already holds the empty state back while `pagedMessages.loadState.refresh is LoadState.Loading`. So per-account folder opens flash "No messages to display" while the initial IMAP fetch for that folder is still in flight — exactly the bug this ticket describes. ## Scope - [ ] Expose a per-folder "syncing" flag from `MailboxViewModel`, set for the duration of the `selectFolder`-triggered `syncFolder` call (mirroring `_isRefreshing`'s pattern; either a new flow or a generalization of `_isRefreshing` if the two cases turn out to be behaviorally equivalent — decide during implementation). - [ ] In `MailboxScreen.kt`'s non-paged empty branch (~line 331), gate `NoMessagesState` on that flag the same way the paged branch already gates on `loadState.refresh` (~line 301), showing a `CircularProgressIndicator` while the initial fetch is in flight instead. - [ ] Make sure the flag clears once `syncFolder` completes regardless of outcome (success, failure, or cancellation from rapid folder switching), so a genuinely empty, already-synced folder still shows "No messages to display" rather than spinning forever. ## Acceptance criteria - Opening a per-account folder for the first time (empty local cache) shows a spinner until the IMAP fetch completes, then either the fetched messages or, if the folder truly is empty, "No messages to display". - Pull-to-refresh and the unified-inbox paged path are unaffected. - Rapidly switching folders doesn't leave a stale spinner running for a folder no longer selected. ## Relevant files - `ui/mailbox/MailboxViewModel.kt` (~lines 128-154, 363-369, 407-424), `ui/mailbox/MailboxScreen.kt` (~lines 290-338).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMail#149