Adds three related capabilities to the mailbox, built on the existing IMAP / repository / folder-role layers.
Long-press multi-select (contextual action bar)
Long-press a message to enter selection; the top bar becomes a contextual action bar showing the selected count.
Actions: Archive, Delete, Spam, Move, Select All, plus Reply, Reply All, Forward — the latter three shown only when exactly one message is selected, and removed the moment a second is selected.
Confirmation dialogs for Reply All, Spam, and Delete; deleting from Trash/Spam adds a "this permanently deletes the message" warning.
Delete → Trash, Spam → Spam folder; a permanent IMAP expunge happens only when deleting a message already in Trash/Spam. Archive/Spam/Delete resolve the destination folder per account (the unified inbox works); Move is offered only for single-account selections.
Reply/Reply All/Forward force a fresh server fetch of the original (recipients + body via BODY.PEEK, so it doesn't mark the message read), build a quoted draft, and open compose; a spinner shows during the fetch and they snackbar-error if the server is unreachable.
Aggressive fetch (new top-level setting)
Message downloading: Always fetch all (default) / Fetch all on Wi-Fi / Always on-demand.
Aggressive mode pre-caches full bodies and all attachment bytes during sync — outside the sync lock, cancellable, and without marking mail read — into a persistent per-part attachment cache, so messages and attachments open instantly and offline.
Fetch all on Wi-Fi gates prefetch on an unmetered network; Always on-demand keeps the prior lazy behavior.
Download indicators
"Available offline" mark on cached rows in the list; per-attachment "Downloaded" check in the reader.
Notable change
Extracted a Syncer interface (MailSyncer implements it; MailboxViewModel depends on it) so the mailbox can be driven end-to-end in tests. Behavior-preserving.
Testing
66 unit tests and 27 instrumented tests — all passing.
The instrumented suite was run for real on the API 37 emulator (connectedDebugAndroidTest): 27/27 pass, including the 8 new E2E tests — CAB selection/single-vs-multi gating/delete-confirm→trash/move-picker/offline indicator, the settings policy → DataStore round-trip, and the reader downloaded indicator.
## Summary
Adds three related capabilities to the mailbox, built on the existing IMAP / repository / folder-role layers.
### Long-press multi-select (contextual action bar)
- Long-press a message to enter selection; the top bar becomes a contextual action bar showing the selected count.
- Actions: **Archive, Delete, Spam, Move, Select All**, plus **Reply, Reply All, Forward** — the latter three shown only when exactly one message is selected, and removed the moment a second is selected.
- **Confirmation dialogs** for Reply All, Spam, and Delete; deleting from Trash/Spam adds a "this permanently deletes the message" warning.
- **Delete → Trash**, **Spam → Spam folder**; a permanent IMAP expunge happens *only* when deleting a message already in Trash/Spam. Archive/Spam/Delete resolve the destination folder **per account** (the unified inbox works); Move is offered only for single-account selections.
- Reply/Reply All/Forward **force a fresh server fetch** of the original (recipients + body via `BODY.PEEK`, so it doesn't mark the message read), build a quoted draft, and open compose; a spinner shows during the fetch and they snackbar-error if the server is unreachable.
### Aggressive fetch (new top-level setting)
- **Message downloading**: *Always fetch all* (default) / *Fetch all on Wi-Fi* / *Always on-demand*.
- Aggressive mode pre-caches full bodies **and all attachment bytes** during sync — outside the sync lock, cancellable, and without marking mail read — into a persistent per-part attachment cache, so messages and attachments open instantly and offline.
- *Fetch all on Wi-Fi* gates prefetch on an unmetered network; *Always on-demand* keeps the prior lazy behavior.
### Download indicators
- "Available offline" mark on cached rows in the list; per-attachment "Downloaded" check in the reader.
## Notable change
- Extracted a `Syncer` interface (`MailSyncer` implements it; `MailboxViewModel` depends on it) so the mailbox can be driven end-to-end in tests. Behavior-preserving.
## Testing
- **66 unit tests** and **27 instrumented tests** — all passing.
- The instrumented suite was run for real on the **API 37 emulator** (`connectedDebugAndroidTest`): **27/27 pass**, including the 8 new E2E tests — CAB selection/single-vs-multi gating/delete-confirm→trash/move-picker/offline indicator, the settings policy → DataStore round-trip, and the reader downloaded indicator.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
Summary
Adds three related capabilities to the mailbox, built on the existing IMAP / repository / folder-role layers.
Long-press multi-select (contextual action bar)
BODY.PEEK, so it doesn't mark the message read), build a quoted draft, and open compose; a spinner shows during the fetch and they snackbar-error if the server is unreachable.Aggressive fetch (new top-level setting)
Download indicators
Notable change
Syncerinterface (MailSyncerimplements it;MailboxViewModeldepends on it) so the mailbox can be driven end-to-end in tests. Behavior-preserving.Testing
connectedDebugAndroidTest): 27/27 pass, including the 8 new E2E tests — CAB selection/single-vs-multi gating/delete-confirm→trash/move-picker/offline indicator, the settings policy → DataStore round-trip, and the reader downloaded indicator.🤖 Generated with Claude Code