Commit Graph
211 Commits
Author SHA1 Message Date
Thomas SharedInboxandClaude Sonnet 4.6 fdafe799eb fix(tests): suppress ink_sparkle shader crash in crash screen and about screen
CrashScreen creates its own MaterialApp which was loading InkSparkle
on first tap. Also fixes about_screen_test._buildScreen to use a
themed MaterialApp with NoSplash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 04:03:30 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 f1f4171306 fix(ci): fix YAML parse error in Print runner wait time step
The multi-line python3 -c block had unindented Python code that
terminated the YAML block scalar, causing a preExecutionError on every
CI run. Inline the Python as a one-liner.

Also apply dart format to email_repository_impl.dart and
email_repository_impl_test.dart (reformatted by CI container).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 03:29:40 +02:00
Thomas SharedInbox 92161f74fc Merge remote-tracking branch 'origin/main' into fix-518 2026-06-07 03:16:43 +02:00
Bot of Thomas Güttler f5abe9132b fix(test): sync before searching in second searchEmails IMAP test (#519) 2026-06-07 02:49:53 +02:00
ClaudeandClaude Sonnet 4.6 5de1030899 fix(ci): exclude chaos_monkey_test from regular CI (TestBackend)
Tag chaos_monkey_test.dart with @Tags(['nightly']) and add
--exclude-tags=nightly to TestBackend so it no longer runs on every
PR push. ChaosMonkeyBackend keeps --tags=nightly to ensure the
nightly workflow still exercises the test.

Closes #505

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:43:29 +00:00
Bot of Thomas Güttler d92cfac761 feat(search): include email notes in search results (#512) 2026-06-07 01:58:22 +02:00
57b266a82b fix(lint): move sqlite3 to dependencies, use close() instead of dispose()
- sqlite3 is now imported in lib/ (production code), so it must be a
  regular dependency, not a dev_dependency
- Replace deprecated conn.dispose() with conn.close() in the test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:32:13 +02:00
916fc4bc6b fix: swallow SQLITE_BUSY when setting WAL mode to prevent crash on startup (#508)
A WorkManager background task may have the database open when the
foreground app starts.  Executing PRAGMA journal_mode = WAL on the
second connection then fails with SQLITE_BUSY_SNAPSHOT (extended code
261, primary code 5), crashing the app before it renders.

Two changes:
1. Move PRAGMA busy_timeout = 5000 before the WAL pragma so SQLite
   auto-retries plain SQLITE_BUSY (code 5) for up to 5 s.
2. Extract setup logic into _setupPragmas and catch SqliteException
   with resultCode == 5 (covers both SQLITE_BUSY and SQLITE_BUSY_SNAPSHOT).
   SQLITE_BUSY_SNAPSHOT only occurs when the DB is already in WAL mode,
   so the pragma is a no-op and it is safe to continue.

Adds a regression test that opens a second connection while a read
transaction holds a WAL snapshot open and verifies setupPragmasForTesting
does not throw.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:32:13 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 a67b707a41 fix(test): sync before searching in searchEmails IMAP test
searchEmails now queries local SQLite FTS5 instead of IMAP directly
(since 65173d3). The test must call syncEmails first to populate the
local index before searching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:28:41 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 e22322166c feat: linkify #NNN references in ChangeLog to Codeberg issues
Closes #472

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 21:51:13 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 65173d323c feat: switch folder-view search from IMAP to local SQLite FTS5
Closes #501

searchEmails now queries the local email_fts virtual table filtered by
mailbox_path instead of doing a live IMAP SEARCH. This makes folder-view
search work offline and ensures tapped results always open the correct
email (IDs come from the same local DB that getEmail reads from).

Reuses the existing FTS5 infrastructure (_toFtsQuery + the email_fts
content-table join) from searchEmailsGlobal, adding only the
`AND e.mailbox_path = ?` filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 20:43:53 +02:00
72f634dd90 fix(tests): remove stale search-toggle test and fix ink_sparkle shader crash
The 'tapping search icon shows search bar' test was stale: the SearchBar is
now permanently visible in AppBar.bottom, so both its assertions held before
any tap. Deleted it; the existing 'SearchBar is always visible in the AppBar'
test already covers the same intent.

Added NoSplash.splashFactory to the widget-test ThemeData to prevent Flutter
from loading the pre-compiled ink_sparkle.frag shader, which was built for an
older SDK version and caused an INVALID_ARGUMENT crash on Flutter 3.44.0.

Closes #486

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 18:19:10 +02:00
Bot of Thomas Güttler 4712e768ea fix: prevent Enter key from re-running a settled search (#473) 2026-06-06 18:02:50 +02:00
Bot of Thomas Güttler 7985caa9b4 fix: discard stale search results when a newer query supersedes them (#468) 2026-06-06 10:32:37 +02:00
Bot of Thomas Güttler e28996cf86 feat: track installed versions and annotate ChangeLog with install dates (#457) 2026-06-06 10:31:06 +02:00
6a60c8d73b fix: resolve dart analyze failures in chaos_monkey_test.dart (#458)
## Summary

Fixes CI failures introduced by PR #455 (chaos monkey backend test).

The `dart analyze --fatal-infos` step in CI was failing because `test/backend/chaos_monkey_test.dart` had:

- **`avoid_print`** (5 instances): replaced `print(...)` with `stdout.writeln(...)` — `dart:io` is already imported
- **`avoid_redundant_argument_values`**: removed redundant `''` from `_env('CHAOS_SEED', '')` since `''` is the parameter default
- **`dart format`**: applied formatter fixes (trailing commas, line wrapping for long `connectToServer` calls)

## Verification

```
$ nix develop --command bash -c "fvm dart analyze --fatal-infos"
Analyzing 456...
No issues found!

$ nix develop --command bash -c "fvm dart format --output=none --set-exit-if-changed test/backend/chaos_monkey_test.dart"
Formatted 1 file (0 changed) in 0.01 seconds.
```

Closes #456

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/458
2026-06-06 05:29:40 +02:00
Bot of Thomas Güttler 8446b05601 feat: add per-email notes stored on IMAP/JMAP server (#443) 2026-06-05 19:31:35 +02:00
Bot of Thomas Güttler 3bd404f0cf feat: add 'Create new folder' option to Move To Folder dialog (#423) 2026-06-05 18:53:36 +02:00
Thomas Güttler 59a9ed9109 Implement bug report uploading backend and Flutter client UI (#421) 2026-06-04 22:14:04 +02:00
4ef441ab1b ci: run non-golden widget tests in CI coverage (#416)
This PR includes widget tests (excluding golden tests) in the CI coverage run, ensuring widget layout and UI logic are tested automatically.

Co-authored-by: Thomas Güttler <thomas.guettler@syself.com>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/416
2026-06-04 19:34:53 +02:00
Thomas SharedInbox 4a07a175b9 remove debug banner on screenshots. 2026-06-04 16:42:42 +02:00
Thomas SharedInbox 2137d25d6d screen resolution. 2026-06-04 16:36:57 +02:00
Thomas SharedInbox d03ee8b555 fix missing fonts. 2026-06-04 15:04:19 +02:00
Thomas SharedInbox a82927cae8 create screenshots. 2026-06-04 14:53:50 +02:00
Thomas SharedInbox 771ac691d9 misc. 2026-06-04 13:35:38 +02:00
Thomas Güttler 65ac023622 fix wiget tests. 2026-06-04 12:08:48 +02:00
674d402ff9 feat: pre-fetch email bodies for offline access (#400)
Closes #373

## Summary

- **Schema v38**: two new columns on `user_preferences` — `prefetch_mode` (default `wifiOnly`) and `body_cache_limit_mb` (default 100 MB).
- **`BodyCacheService`**: queries for emails that have no cached body, fetches them newest-first in batches of 20, and evicts the oldest cached bodies when the configured size limit is exceeded.
- **Separate WorkManager task** (`si_bg_prefetch`): runs hourly with `NetworkType.unmetered` (Wi-Fi) or `NetworkType.connected` (any) depending on the user's choice. The task is cancelled when prefetch is disabled.
- **App startup**: reads the stored preference from the DB and re-registers the WorkManager task with the correct constraint.
- **Preferences screen**: radio group for prefetch mode (Wi-Fi only / Any network / Disabled) and a dropdown for cache size limit (50 / 100 / 200 / 500 MB).

## What is NOT downloaded

Binary attachments are never fetched — `getEmailBody()` stores only `textBody` and `htmlBody`. The cache size limit + per-run batch cap (20 emails) keep storage bounded even on large mailboxes.

## Test plan

- [x] `task analyze` — no issues
- [x] `task test` — all 492 tests pass (incl. updated migration_test.dart for v38)

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/400
2026-06-04 06:15:00 +02:00
Bot of Thomas Güttler c1d314a621 feat: combined inbox as the default startup view (#376) (#379) 2026-06-04 02:46:59 +02:00
692fa14d4d feat: remember show images per sender (#378)
## Summary

Closes #377

- Adds a new `ImageTrustedSenders` Drift table (schema v37) that stores email addresses for which remote images are loaded automatically (per device, not per account)
- When the user taps "Load remote images", the sender's address is saved and a 3-second snackbar appears with a "Settings" hyperlink to undo the choice in preferences
- Both `EmailDetailScreen` and `ThreadDetailScreen` check the trusted senders list on open and auto-load images for known senders
- The Preferences screen gains a new "Trusted image senders" section listing all saved senders with individual remove buttons

## Test plan

- [x] `dart run build_runner build` regenerates `database.g.dart` cleanly (schema v37)
- [x] `flutter analyze` — no issues
- [x] Migration test updated: checks `image_trusted_senders` table exists after upgrade and fresh install
- [x] `FakeUserPreferencesRepository` updated with three new interface methods
- [x] All 490 unit + widget tests pass (1 pre-existing golden test failure unrelated to this change)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/378
2026-06-04 01:41:50 +02:00
5e029a1365 feat: prioritise sent-folder addresses in To/Cc/Bcc autocomplete (#380)
## What changed

`searchAddresses` (used by the To/Cc/Bcc autocomplete) now runs two passes over the candidate email rows:

1. **Sent-folder rows first** — the mailboxes table is queried for mailboxes with `role='sent'`; any email row whose `mailboxPath` matches gets processed before inbox/other rows. Within this group addresses are ordered by `receivedAt` DESC as before.
2. **All other rows** — processed after sent rows, also by `receivedAt` DESC.

Within sent-folder rows, `toAddresses` and `ccJson` are checked before `fromJson` (the sender in a sent email is our own address, not a useful suggestion). For non-sent rows the original order (`fromJson`, `toAddresses`, `ccJson`) is kept.

This means: if you wrote to `info@foo.de` yesterday and received spam from `info@spam.de` today, typing "i" surfaces `info@foo.de` first.

## How verified

- All 492 unit tests pass (`task test`).
- Added a dedicated test `searchAddresses prioritises sent-folder addresses over newer received` that inserts an older sent email and a newer received email matching the same query prefix and asserts the sent-folder address is returned first.

Closes #375

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/380
2026-06-04 00:27:04 +02:00
Thomas Güttler 8ea8d71f42 fix: format, analyze-fix and update mocks 2026-06-02 17:10:16 +02:00
Thomas Güttler 1e2d1b6063 chore: migrate to SOPS and SSH for Dagger engine access 2026-06-02 11:10:29 +02:00
Bot of Thomas Güttler 91083218d4 fix: diff from last deployed SHA to catch all changes since last deploy (#320) (#332) 2026-05-29 17:34:21 +02:00
Bot of Thomas Güttler 05d00bdf09 fix: move overflow actions into popup menu so three-dot menu is always visible (#312) (#323) 2026-05-28 07:19:11 +02:00
Bot of Thomas Güttler c45775be92 fix: move sync health report to own row below each account (#311) (#322) 2026-05-28 06:53:11 +02:00
Bot of Thomas Güttler f0f210e5ab feat: configurable next action after single mail view (#300) (#308) 2026-05-27 23:33:14 +02:00
Bot of Thomas Güttler 41550eb4b5 feat: configurable menu bar position for mailbox view (#298) (#303) 2026-05-27 22:07:12 +02:00
Bot of Thomas Güttler 633fc5d9da fix: show full discrepancy details in account list (#296) (#301) 2026-05-27 21:20:19 +02:00
Bot of Thomas Güttler 14f64cd2a5 feat: show URL tooltip on long-press of unsubscribe chip (#294) (#295) 2026-05-27 21:02:30 +02:00
Bot of Thomas Güttler e2b08e07b7 fix: prevent HTML email content from being cut off (#288) (#292) 2026-05-27 19:52:14 +02:00
Bot of Thomas Güttler c0dd13be5d feat: align single and multi-mail actions, add archive (#287) (#291) 2026-05-27 19:36:13 +02:00
Bot of Thomas Güttler 4e32984ecc fix: prompt to create or pick folder when archive is missing (#286) (#290) 2026-05-27 19:06:37 +02:00
Bot of Thomas Güttler f57a8c502d feat: syncLog add Copy button, stack trace, isPermanent (#266) (#269) 2026-05-26 07:55:07 +02:00
Bot of Thomas Güttler 8709e9f38d feat: add Locale, Text Scale, DB Schema Version, Device Model to About page (#258) (#263) 2026-05-25 22:18:09 +02:00
Bot of Thomas Güttler 7997ff0980 feat: Reply All dialog on Reply button, add Mark as Spam (#260) (#261) 2026-05-25 21:51:08 +02:00
Bot of Thomas Güttler a7783d46cf fix: disable Save button when no password available; fix changelog fetch-depth (#246, #229) (#248) 2026-05-25 14:47:25 +02:00
Bot of Thomas Güttler 3868c160d3 fix: disable Try connection button when no password is available (#235) (#247) 2026-05-25 14:30:13 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 94b20f50be style: format edit_account_screen_test.dart
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 12:49:29 +02:00
Thomas SharedInboxandClaude Sonnet 4.6 885906b204 fix: show password required error instead of crashing when no stored password (#235)
During _load(), check whether a password exists in secure storage and track the result
in _hasStoredPassword. The password field validator now requires user input when no
password is stored, so _tryConnection() fails fast at form validation instead of
throwing an unhandled StateError.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 12:49:29 +02:00
Bot of Thomas Güttler e03c7708ba feat: show app version as link on crash screen and in MD report (#236) (#245) 2026-05-25 11:40:53 +02:00