feat: long-press multi-select, aggressive prefetch, and download indicators #5

Merged
JMR-dev merged 1 commits from feat-long-press-select into main 2026-06-30 22:29:54 +00:00
JMR-dev commented 2026-06-30 22:21:20 +00:00 (Migrated from github.com)

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

## 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)
Sign in to join this conversation.