- Schema v33: add error_stack_trace and is_permanent columns to sync_logs
- SyncLogEntry gains stackTrace and isPermanent fields; SyncLogRepository.log()
gains matching optional parameters; IMAP and JMAP sync loops forward the
stack trace string and isPermanent flag when writing error entries
- New lib/ui/utils/about_markdown.dart utility shared by AboutScreen and the
sync log copy feature; builds the markdown table including Android device
info (manufacturer, model, OS version) via device_info_plus
- AboutScreen uses the utility and adds Android device info row
- SyncLogScreen: subtitle shows "Error (permanent)" for permanent errors;
expanded view shows stack trace in red monospace; each tile has a Copy
button that copies a markdown summary of the entry plus the About section
- Migration test updated for v33; new repo test for stackTrace/isPermanent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add LocalSieveApplied table (schema v32) keyed by (accountId, messageId)
so each email is processed by Sieve at most once, even across restarts.
- Implement EmailRepository.applySieveRules(): loads the active local Sieve
script, runs the interpreter against new INBOX emails, and queues pending
move/delete/flag_seen changes for any matched rules.
- Wire applySieveRules() into both _AccountSync._sync() and
_JmapAccountSync._sync() after the per-mailbox email sync loop.
- Make _flushPendingChangesImap() treat NONEXISTENT / not-found errors as
silent no-ops (counts as flushed) so a second device racing on the same
email does not accumulate retries.
- Add migration test assertions and a dedicated unit test suite covering
rule matching, deduplication, discard, and multi-email processing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes for the UndoLog:
1. Don't delete the original undo log entry when undo is performed.
The entry stays in the log alongside the new inverse action, so
the user can retry the undo if it was silently reverted by an
IMAP sync.
2. Fix IMAP UID mismatch: after an IMAP move is applied on the server
the email gets a new UID in the destination folder. The undo service
now looks up the email by its RFC 2822 Message-ID when the original
row is gone, so the reverse-move pending change carries the correct
UID and actually succeeds on the server.
Add findEmailByMessageId to EmailRepository interface and impl.
Add a regression test that simulates the UID change scenario.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of reconstructing the message from the local DB, fetch the
original bytes live from IMAP (BODY.PEEK[]) or JMAP (Email/get blobId
→ downloadBlob) so the view shows the true unmodified message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds RawAutocomplete<EmailAddress> to the To and Cc fields in the
compose screen. As the user types (minimum 2 chars), suggestions are
fetched from the local DB by searching from/to/cc columns of cached
emails. Selecting a suggestion appends it to any existing addresses
already in the field (comma-separated).
New repository method searchAddresses() returns deduplicated
EmailAddress objects matching the query string.
Closes#11
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>