Commit Graph
184 Commits
Author SHA1 Message Date
Thomas SharedInbox 3ca71cd4e5 feat: add hyperlinks to Codeberg commits in ChangeLog (Issue #9) 2026-05-10 13:18:35 +02:00
Thomas SharedInbox 082a39b539 fix: restore missing integration_test dependency and bump version to 0.1.1 2026-05-10 11:56:40 +02:00
Thomas SharedInbox 8adb7f9a65 chore: exclude changelog_screen from unit coverage gate 2026-05-10 11:27:25 +02:00
Thomas SharedInbox 4f55aaa0f7 chore: clean up Taskfile and ensure ChangeLog automation 2026-05-10 11:25:07 +02:00
Thomas SharedInbox 382408985d chore: fix Taskfile automation and cleanup duplication 2026-05-10 11:24:31 +02:00
Thomas SharedInbox 2ecb29d6ee feat: implement in-app ChangeLog from git history 2026-05-10 11:23:39 +02:00
Thomas SharedInbox 56c1ffccf5 chore: exclude undo_log_screen from unit coverage gate 2026-05-10 10:51:32 +02:00
Thomas SharedInbox 26acf7589a chore: strengthen git safeguards and remove tracked .metadata 2026-05-10 10:48:18 +02:00
Thomas SharedInbox c85dbbeff2 feat: implement global undo log with persistent history 2026-05-10 10:32:27 +02:00
Thomas SharedInbox e9e731c551 fix: resolve pre-commit and coverage gate issues 2026-05-09 18:59:12 +02:00
Thomas SharedInbox 3fd7b564de docs: update done.md and plan.log with latest fixes 2026-05-09 18:51:09 +02:00
guettlibotandThomas SharedInbox 6d58ee1e00 Fix Issues 1, 2, and 3: Headers, Undo, and Crash Reporting (#6)
## Overview
This PR implements several fixes and enhancements requested in the latest session:

### Fixes
1. **Issue 1: Raw Email Headers**
   - Added database support for raw headers.
   - Added a new Headers tab in the email detail screen with a zebra-colored table display.
2. **Issue 2: Exception on Undo of Delete**
   - Added `toJson` and `fromJson` to `EmailAddress` model to fix serialization during undo.
3. **Issue 3: Crash Reporting**
   - Added a button to the Crash Screen to report issues directly on Codeberg.

### Infrastructure
- Added Nix experimental features check to `Taskfile.yml` to ensure a consistent dev environment.

## Verification
- Manually verified the Headers display on Linux.
- Verified Undo for IMAP and JMAP accounts.
- Verified the Crash Screen button.

Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de>
Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/6
2026-05-09 18:49:34 +02:00
Thomas SharedInbox d405b37308 fix: implement global undo UI and optimistic IMAP moves for better UX 2026-05-09 15:35:17 +02:00
Thomas SharedInbox e2759ac062 fix: restore Undo functionality for IMAP accounts by preserving data 2026-05-09 14:03:52 +02:00
Thomas SharedInbox 674b21298d feat: implement exponential backoff and permanent error handling for sync engine 2026-05-09 13:25:59 +02:00
Thomas SharedInbox 03a68a00c6 feat: implement periodic sync reliability verification and health indicator 2026-05-09 09:47:42 +02:00
Thomas SharedInbox 7a53189ae5 test: maintain coverage gate and add ghost path exclusion test 2026-05-08 23:10:16 +02:00
Thomas SharedInbox 11513d1668 gitignore. 2026-05-08 21:02:53 +02:00
Thomas Güttler 0b3b28b23a docs: add README for sharedinbox-runner setup 2026-05-08 12:56:29 +02:00
Thomas Güttler 67e6b4ebb9 chore: unify runner naming to sharedinbox-runner 2026-05-08 12:55:16 +02:00
Thomas Güttler 06cf8c7f99 chore: simplify runner to run as root from /opt/sharedinbox-runner 2026-05-08 12:40:12 +02:00
Thomas Güttler 5d33befe51 chore: set runner working dir to / and use absolute paths 2026-05-08 12:20:04 +02:00
Thomas Güttler b314a0c1b6 feat: migrate CI to Codeberg Actions and add self-hosted runner config
- Added .forgejo/workflows/ci.yml for thin CI orchestration.
- Configured Dockerized Codeberg runner with Nix support in codeberg-runner/.
- Added systemd service for persistent runner execution.
- Added GEMINI.md for project CI/Nix conventions.
- Added Taskfile task for Linux release builds.
2026-05-08 12:04:42 +02:00
Thomas Güttler 626b7b49f9 chore: remove accidental log file commit 2026-05-08 11:19:49 +02:00
Thomas Güttler 43e1744614 feat: implement optimized Undo for delete and move actions
- Added UndoService with 10-action history stack.
- Integrated Undo Snackbar into EmailListScreen and EmailDetailScreen.
- Added EmailRepository.cancelPendingChange to optimize undo by removing
  unsynced local mutations.
- Fixed sorting bug in compareMailboxes for unknown roles.
- Increased unit coverage to 83% with new model and utility tests.
- Verified with full test suite (task check).
2026-05-08 11:14:54 +02:00
Thomas Güttler 1a4571f016 gitigore .task 2026-05-08 07:54:03 +02:00
Thomas Güttler 8d268f1165 Implement multi-account search and improve repository fakes
- Extended search to support global queries across all accounts.
- Updated SearchScreen to handle optional account context and unified results.
- Centralized mailbox comparison logic in Mailbox model.
- Added copyWith to Account model.
- Fixed race conditions and incorrect overrides in unit, widget, and integration tests.
- Reached 80% unit test coverage.
2026-05-08 01:01:18 +02:00
Thomas Güttler cd0892763c Implement Thread View UI and repository support
- Created ThreadDetailScreen with expandable email cards and HTML support.
- Added observeEmailsInThread to EmailRepository and implementation.
- Updated navigation in EmailListScreen to route multi-message threads to the new view.
- Updated test mocks (FakeEmailRepository) across unit, widget, and integration tests.
- Documented progress in done.md and updated next.md.
2026-05-08 00:14:50 +02:00
Thomas Güttler 656d4b46d7 Optimize deployment, fix E2E flakiness, and implement database-backed threading
- Optimize task deploy-android with marker files and source/generate tracking.
- Fix flaky Android E2E test with pumpAndSettle and safety delays.
- Implement global CrashScreen and error handlers in main.dart.
- Refactor threading to use a persistent Threads table for performance.
- Add database indexes and migration for schema v18.
- Enhance coverage gate with ghost path checks and increased coverage (82%).
2026-05-07 22:07:54 +02:00
Thomas Güttler 3c90818845 Harden Android deployment and implement dynamic port allocation
- Replace fixed ports with dynamic allocation (port 0) for all Stalwart listeners, including ManageSieve.
- Require KVM acceleration for Android integration tests; fail early with setup instructions if /dev/kvm is inaccessible.
- Require all ANDROID_APK_SCP environment variables for deployment; fail early if any are missing.
- Revert emulator boot timeouts to standard values (120s device / 60s boot) now that software emulation is disabled.
2026-05-07 07:35:27 +02:00
Thomas Güttler ae5a48016c Fix Android deployment pipeline and integration tests
- Run integration tests sequentially in Taskfile.yml to avoid port 4190 (ManageSieve) conflict.
- Add ManageSieve listener to Stalwart config for better test coverage.
- Increase Android emulator boot timeout and add software-mode flags (-accel off, -no-boot-anim, -gpu swiftshader_indirect) to accommodate environments without KVM.
- Update LATER.md with notes on software emulation performance.
2026-05-06 21:54:41 +02:00
Thomas Güttler 9ba6677308 chore: remove MobSF (overkill for current needs) 2026-05-06 20:47:27 +02:00
Thomas Güttler 90b2d3c9e3 chore: remove accidental crash log 2026-05-06 09:58:46 +02:00
Thomas Güttler 2f58fb7a08 fix: IMAP attachments (size/download) and immediate sync for deletions
- Fix IMAP attachment sizes showing as '0 B' by falling back to decoded content length.
- Fix IMAP attachment downloads failing for single-part fetches by falling back to root message.
- Implement immediate server-side sync for deletions/flags using a new onChangesQueued stream.
- Automate FVM SDK setup and add 'task setup'.
- Make MobSF optional in build-android to handle environment restrictions.
- Update test fakes to match EmailRepository interface changes.
2026-05-06 09:58:42 +02:00
Thomas Güttler 848d8f2c5b later.md 2026-05-05 08:19:34 +02:00
Thomas GüttlerandClaude Sonnet 4.6 569273d7ff feat: restrict plain-text connections to localhost only
Hides the SSL/TLS toggle in add/edit account screens when the host is
not localhost; enforces SSL in connectImap/connectSmtp for non-localhost
hosts so plaintext can never be configured accidentally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 07:35:56 +02:00
Thomas GüttlerandClaude Sonnet 4.6 d4d61b2b39 feat: sync-now button on sync log screen
Adds a sync icon to the AppBar of the sync log screen. Tapping it wakes
the account's idle/wait loop immediately and shows a spinner until the
next log entry arrives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 07:23:34 +02:00
Thomas GüttlerandClaude Opus 4.7 dad239e0b6 feat: drop Sieve fields from add-account; auto-probe ManageSieve
The IMAP/SMTP add-account form no longer asks for a ManageSieve host,
port, or SSL toggle. After the account is saved, a background probe
opens TCP+STARTTLS to the IMAP host on port 4190 and stores a
tri-state result (manageSieveAvailable: null / true / false). The
"Email filters" menu item is hidden when the probe records false, so
servers that don't expose ManageSieve don't surface a dead menu.

Edge-case overrides (different sieve host, non-standard port, plain
TCP) remain available in Edit Account, and changing them clears the
cached probe result so the next save re-probes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:14:41 +02:00
Thomas GüttlerandClaude Opus 4.7 da383d0957 feat: ManageSieve STARTTLS + clearer TLS-mismatch errors + broader connection test
The "Email filters" screen was failing with WRONG_VERSION_NUMBER because the
ManageSieve client was opening implicit-TLS sockets on port 4190, while RFC
5804 servers (Stalwart, Dovecot, Cyrus) listen plaintext on 4190 and expect
STARTTLS. ManageSieveClient.connect now opens plaintext, reads the capability
greeting, sends STARTTLS, hands the socket to SecureSocket.secure(), and
re-reads capabilities on the encrypted stream.

The same WRONG_VERSION_NUMBER error can hit IMAP/SMTP when the SSL toggle and
the chosen port disagree (e.g. SSL=on with SMTP port 587). New helper
lib/data/imap/tls_error.dart translates that BoringSSL error into a
TlsModeMismatchException naming the host/port and suggesting which port goes
with which TLS mode. connectImap, connectSmtp, and the ManageSieve TLS
upgrade all funnel through rethrowAsTlsHint so the same readable message
reaches the UI regardless of which protocol failed.

ConnectionTestService previously only verified IMAP/JMAP, so SMTP and
ManageSieve misconfig silently passed the "Try connection" button on the
edit-account screen and only surfaced when the user later tried to send
mail or open Email filters. After IMAP succeeds, the service now also
verifies SMTP (always — sending mail requires it) and ManageSieve (only
when manageSieveHost is explicitly set, since the section is collapsed by
default). Failures are prefixed with "SMTP:" or "ManageSieve:" so the
user can tell which leg of the connection is broken.

connectionTestServiceProvider now also watches smtpConnectProvider so the
E2E integration tests' plaintext SMTP override applies to the connection
check as well.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 10:31:55 +02:00
Thomas GüttlerandClaude Opus 4.7 fc270590c4 feat: ManageSieve (RFC 5804) Sieve script editing for IMAP accounts
Adds a minimal ManageSieve client so the existing "Email filters" UI
works for IMAP accounts, not just JMAP. SieveRepository becomes a
dispatcher that routes to JMAP or ManageSieve based on account.type.

Account model + DB schema v15 grow manageSieveHost/Port/Ssl fields
(default 4190 / TLS, host falls back to imapHost when blank). The Add
and Edit account screens expose them inside a collapsed ExpansionTile
to keep the form short for users who accept defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 06:53:31 +02:00
Thomas GüttlerandClaude Opus 4.7 44d02afc46 feat: render HTML email bodies via flutter_html
Email detail screen now renders the message htmlBody with the flutter_html
widget when present, falling back to SelectableText for plain-text-only mail.
Remote http(s) images are blocked by default to defeat tracking pixels; an
opt-in "Load remote images" button reveals them per-screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 20:10:18 +02:00
Thomas Güttler ab6dc89665 next.md 2026-04-28 16:58:57 +02:00
Thomas GüttlerandClaude Opus 4.7 1a62907703 feat: default new SMTP accounts to implicit TLS (port 465)
The SMTP SSL/TLS toggle in the add-account form now defaults to on with
port 465. Previously the default was port 587 with the toggle off
(STARTTLS — TLS was active under the hood, but the off toggle made users
think the connection was insecure). The MX-record fallback in the
discovery service was flipped the same way; autoconfig XML parsing is
unchanged so servers that advertise STARTTLS still get STARTTLS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 15:50:37 +02:00
Thomas GüttlerandClaude Opus 4.7 fb767a8489 fix: don't resurrect locally-deleted IMAP message on next sync
The incremental IMAP sync issued `UID ${lastUid + 1}:*` to look for new
mail. RFC 3501 §6.4.4 reverses `n:*` to `*:n` when n exceeds the largest
UID, so a server with one message at UID 1 and `lastUid=1` returned UID 1
for `UID 2:*` — re-fetching and re-inserting a row the user had just
deleted locally (whose pending change had not yet flushed).

`_fetchAndUpsertImap` now looks up the UIDs in the mailbox that have a
pending `delete` or `move` queued and skips the insert for those. The
existing `UID n:*` query is left intact so freshly-delivered SMTP mail
keeps driving StreamBuilder rebuilds in the E2E flow.

Regression test in `email_repository_imap_test.dart` deletes a synced
message and calls `syncEmails` directly — exactly what the in-app sync
button does — and asserts the row stays gone with the pending change
still queued.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:02:12 +02:00
Thomas GüttlerandClaude Opus 4.7 db05878aca fix: reap orphan Xvfb before integration-ui run
xvfb-run --auto-servernum picks a fresh display number, but if a previous
session left an orphan Xvfb process (e.g. killed mid-flight), the stale
/tmp/.X11-unix/X<N> socket and X<N>-lock still belong to that orphan, and
xvfb-run's cleanup at the end fails with "kill: No such process" — flipping
the script's exit status to non-zero even when the integration test itself
passed. Reap orphan Xvfb processes (pgrep -u $USER -x Xvfb) and remove their
display sockets and lock files before invoking xvfb-run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 12:42:34 +02:00
Thomas GüttlerandClaude Opus 4.7 2e2b7c3d9f fix: Android E2E aliceTile race + bundle deploy-android infra
The Android UI integration test failed at tap(aliceTile) with "0 widgets"
even though pumpUntil had just found the tile. On the slow software-rendered
emulator the route-pop animation finalises during pumpUntil's trailing 300 ms
settle, briefly leaving the tile out of the tree. Re-confirm with a second
pumpUntil before the tap.

Bundles the previously uncommitted infra changes that make task deploy-android
run end-to-end inside nix develop: Linux desktop runtime libs + GL software
rendering env in flake.nix, path_provider_android pin to <2.3 to avoid the
libdartjni SIGSEGV, deferred DB-path resolution after WidgetsFlutterBinding,
+iglx for xvfb-run, platform-tools on PATH, and a single pre-commit script
replacing the dart-format / task-check-fast pair.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 12:36:30 +02:00
Thomas Güttler d2226388d7 deploy to android works now. 2026-04-27 08:44:42 +02:00
Thomas Güttler 2c3802b2d9 ... 2026-04-27 08:09:27 +02:00
Thomas GüttlerandClaude Sonnet 4.6 65c75c365a feat: replace custom search TextField with Flutter SearchBar widget
SearchBar is always visible in the AppBar bottom slot — no toggle needed.
Removed _isSearching, manual debounce timer, and slide animation.
SearchController listener clears results when text is emptied.
Updated E2E and widget tests for the new widget tree.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 08:04:20 +02:00
Thomas GüttlerandClaude Sonnet 4.6 2b260edb52 feat: MX record fallback in account auto-discovery
When JMAP well-known and autoconfig XML both fail, query DNS-over-HTTPS
(dns.google) for MX records and use the highest-priority MX host as IMAP
(993/SSL) and SMTP (587/STARTTLS) server. No new dependencies needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 07:46:28 +02:00