Switch folder-view search to local SQLite (offline-first) #501

Closed
opened 2026-06-06 18:15:15 +00:00 by guettlibot · 1 comment
guettlibot commented 2026-06-06 18:15:15 +00:00 (Migrated from codeberg.org)

Problem

searchEmails in the folder view hits the live IMAP server on every search. This breaks offline use and also causes a mismatch: search results carry UIDs from the server while getEmail reads from the local DB, so the wrong email can open if the DB is stale.

The global search already uses local SQLite FTS5. Folder-view search should do the same.

Plan

  1. Remove the IMAP live search path in email_repository_impl.dart.
    Delete or gate-off the searchEmails IMAP implementation (lines 3050–3105).

  2. Implement local search filtered by mailbox_path.
    Reuse the existing FTS5 virtual table that backs searchEmailsGlobal, adding a WHERE mailbox_path = ? clause. If the FTS table does not already include mailbox_path as a column, add it.

  3. Update EmailRepository interface if the signature changes (it likely stays the same — same method, different backing store).

  4. Update EmailListScreen (_runSearch / _onSearchChanged):

    • Remove textInputAction: TextInputAction.search / onSubmitted if we now search live-as-you-type from local DB (instant, no network cost).
    • Or keep Enter-to-search but backed by local DB.
  5. Add/update widget tests — existing fake already supports onSearch; add a test that verifies search works when the repository is offline (no network call expected).

  6. Update FakeEmailRepository if the interface changes.

Acceptance Criteria

  • Searching in a folder works with no network connection.
  • Tapping a search result always opens the correct email (IDs now come from the local DB, same source as getEmail).
  • All existing search widget tests pass.
## Problem `searchEmails` in the folder view hits the live IMAP server on every search. This breaks offline use and also causes a mismatch: search results carry UIDs from the server while `getEmail` reads from the local DB, so the wrong email can open if the DB is stale. The global search already uses local SQLite FTS5. Folder-view search should do the same. ## Plan 1. **Remove the IMAP live search path** in `email_repository_impl.dart`. Delete or gate-off the `searchEmails` IMAP implementation (lines 3050–3105). 2. **Implement local search** filtered by `mailbox_path`. Reuse the existing FTS5 virtual table that backs `searchEmailsGlobal`, adding a `WHERE mailbox_path = ?` clause. If the FTS table does not already include `mailbox_path` as a column, add it. 3. **Update `EmailRepository` interface** if the signature changes (it likely stays the same — same method, different backing store). 4. **Update `EmailListScreen`** (`_runSearch` / `_onSearchChanged`): - Remove `textInputAction: TextInputAction.search` / `onSubmitted` if we now search live-as-you-type from local DB (instant, no network cost). - Or keep Enter-to-search but backed by local DB. 5. **Add/update widget tests** — existing fake already supports `onSearch`; add a test that verifies search works when the repository is offline (no network call expected). 6. **Update `FakeEmailRepository`** if the interface changes. ## Acceptance Criteria - Searching in a folder works with no network connection. - Tapping a search result always opens the correct email (IDs now come from the local DB, same source as `getEmail`). - All existing search widget tests pass.
guettlibot commented 2026-06-06 18:50:03 +00:00 (Migrated from codeberg.org)

The PR is up at https://codeberg.org/guettli/sharedinbox/pulls/503.

Here's what I did:

Problem: searchEmails in the folder view was hitting the IMAP server on every search, breaking offline use and causing ID mismatches (server UIDs vs. local DB IDs).

Changes:

  1. lib/data/repositories/email_repository_impl.dart: Replaced the IMAP searchEmails implementation (IMAP SEARCH + FETCH round-trips) with a local FTS5 query identical to searchEmailsGlobal but with an added AND e.mailbox_path = ? filter. Also removed the _toAddressList helper that was only used by the old IMAP path.

  2. lib/ui/screens/email_list_screen.dart: Updated two stale comments that referenced IMAP.

  3. test/unit/email_repository_impl_test.dart: Added a unit test searchEmails filters by mailboxPath using local FTS5 that seeds two mailboxes, runs a search against one, and verifies cross-mailbox results are excluded.

  4. test/widget/email_list_screen_test.dart: Added a widget test folder search returns results from local cache without any network call verifying the search path requires no network access.

All 498 tests pass.

The PR is up at https://codeberg.org/guettli/sharedinbox/pulls/503. Here's what I did: **Problem:** `searchEmails` in the folder view was hitting the IMAP server on every search, breaking offline use and causing ID mismatches (server UIDs vs. local DB IDs). **Changes:** 1. **`lib/data/repositories/email_repository_impl.dart`**: Replaced the IMAP `searchEmails` implementation (IMAP SEARCH + FETCH round-trips) with a local FTS5 query identical to `searchEmailsGlobal` but with an added `AND e.mailbox_path = ?` filter. Also removed the `_toAddressList` helper that was only used by the old IMAP path. 2. **`lib/ui/screens/email_list_screen.dart`**: Updated two stale comments that referenced IMAP. 3. **`test/unit/email_repository_impl_test.dart`**: Added a unit test `searchEmails filters by mailboxPath using local FTS5` that seeds two mailboxes, runs a search against one, and verifies cross-mailbox results are excluded. 4. **`test/widget/email_list_screen_test.dart`**: Added a widget test `folder search returns results from local cache without any network call` verifying the search path requires no network access. All 498 tests pass.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: guettli/sharedinbox#501