Commit Graph
6 Commits
Author SHA1 Message Date
JMR-devandClaude Opus 4.8 8e29aebc2e fix: render reader emails readably in dark mode
The reader rendered HTML emails as black-on-black in dark mode: the WebView
background was transparent (so the near-black app surface showed through) and the
injected CSS set no text or background color, so the WebView fell back to its
default black text.

Wrap each email with explicit, theme-derived background, text, and link colors
(surface / onSurface / primary) plus a matching color-scheme, set the WebView
background to the surface color, and allow WebView algorithmic darkening where
supported as a backstop for emails that hardcode their own foreground colors.

Add JVM contrast guards: HtmlBodyTest pins the wrapper's readability contract
(explicit colors meeting WCAG AA), and ColorSchemeContrastTest audits the
fallback light/dark Material schemes' role pairs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:17:06 -05:00
JMR-devandClaude Opus 4.8 13a32df873 Add IMAP folder navigation drawer + per-API E2E CI matrix
Folder view: a left navigation drawer lists each account's IMAP folders;
tapping one browses and caches that folder's mail. IMAP UIDs are unique only
within a folder, so message identity, the fetch/read/flag/delete paths, sync,
and the Room cache all became folder-aware (id = "accountId:folder:uid"; new
`folder` column; schema v7->v8). Standard folders (Inbox/Sent/Drafts/Spam/Trash/
Archive) surface with friendly names + icons via RFC 6154 SPECIAL-USE attributes
with a case-insensitive name fallback; the multi-account drawer adds an account
switcher and a unified "All Inboxes". INBOX stays the only auto-synced,
IDLE-watched, notifying folder; other folders sync on demand.

Lower minSdk 33 -> 29 for a rolling ~7-year Android support window; guard the
API-33 POST_NOTIFICATIONS runtime request accordingly.

Tests and CI:
- Bump espresso-core 3.6.1 -> 3.7.0 so Compose UI tests run on API 37
  (3.6.1's InputManagerEventInjectionStrategy reflects a removed hidden method).
- New coverage across layers: FolderRoleTest, ImapClientTest folder cases,
  MailboxViewModelTest, MailRepositoryImplTest folder routing, a FolderDrawer
  Compose UI test, and LibreMailDatabaseTest folder DAO/reconcile tests.
- Gradle Managed Devices + a CI E2E matrix over every API 29-36; a single
  "CI passed" gate job fans in all jobs and is required by branch protection.
- Non-blocking, custom-provisioned API 37 (preview) E2E job with image caching.
- Build + unit-test jobs run on arm64 (ubuntu-24.04-arm); emulators stay x86_64.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:23:00 -05:00
JMR-devandClaude Opus 4.8 96c9f71a26 Harden transport security and add opt-in encrypted local cache
From a whole-repo security review (no critical/high issues; TLS cert and
hostname validation were already intact):

- Don't offer the plaintext "None" transport in manual account setup; it
  would send credentials in the clear. The enum value stays only for local
  test servers.
- Relabel the advanced toggle "Allow insecure STARTTLS fallback" with a
  warning subtitle: it relaxes (does not enable) STARTTLS and permits a
  plaintext downgrade when on. Default stays off/secure.
- Set mail.<proto>.ssl.checkserveridentity=true explicitly on IMAP/SMTP as
  insurance over the (already-true) Angus default.
- Add a Content-Security-Policy meta to the reader WebView (JavaScript is
  already disabled).
- Strip Log.d/Log.v in release builds and drop the account address from the
  IDLE log; mark new-mail notifications VISIBILITY_PRIVATE.

Add opt-in at-rest encryption of the Room cache (Settings -> "Encrypt local
cache", off by default) using SQLCipher. The DB passphrase is a random key
sealed by the existing Keystore crypto and kept in a separate DataStore.
DatabaseEncryption performs a self-healing, atomic plaintext<->encrypted
migration at startup that preserves PRAGMA user_version, so toggling applies
on next launch without data loss.

Verified end-to-end on an API 37 emulator (DatabaseEncryptionTest round-trip,
7 instrumented tests) plus 12 unit tests and a release R8 build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 19:50:27 -05:00
JMR-devandClaude Opus 4.8 5386ae76d3 Add IMAP receive: background sync of inbox into Room
Increment 3 — receive.

- ImapClient.fetchRecentInbox pulls recent INBOX headers (ENVELOPE/FLAGS/UID)
  over IMAP (password or XOAUTH2) into FetchedMessage.
- MailSyncer orchestrates per-account fetch -> Room (replace-per-account),
  refreshing and re-persisting the Gmail OAuth token when needed.
- WorkManager background sync via a @HiltWorker (periodic 15-min + an expedited
  one-shot after adding an account); Application supplies the HiltWorkerFactory
  and the default WorkManager initializer is removed.
- Mailbox renders real cached mail with pull-to-refresh and proper empty states
  (welcome/add-account vs no-messages); the sample-data crutch is removed.
- Shared entity mappers; MessageDao.replaceAccountMessages transaction.
- Tests: GreenMail-backed fetchRecentInbox unit test (deliver via SMTP, read via
  IMAP, newest-first). Instrumented Keystore + Angus-provider tests stay green on
  the Android 17 emulator, where the SyncWorker also runs to SUCCESS.
- Add error_prone_annotations to the compile classpath (Hilt/Dagger codegen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 18:25:54 -05:00
JMR-devandClaude Opus 4.8 9c74510832 Add account setup: Gmail OAuth + IMAP/SMTP with encrypted credentials
Increment 2 — authentication and account management.

- Gmail OAuth 2.0 via AppAuth (Authorization Code + PKCE, restricted
  https://mail.google.com/ scope); redirect scheme derived from the client id.
- Generic IMAP/SMTP manual setup (host/port/security) with an Advanced section.
- Angus/Jakarta Mail IMAP client (password + XOAUTH2); "test connection" logs in
  and lists folders before an account is saved.
- Android Keystore-backed AES-256-GCM credential store (encrypts the OAuth
  AuthState / IMAP password); accounts + secrets persisted in Room (schema v2).
- AccountRepository + Hilt wiring; Settings accounts list (add / remove).
- Tests: GreenMail-backed IMAP client unit test; instrumented Keystore round-trip
  and Angus Mail provider-resolution tests (green on the Android 17 emulator).
- Remove the placeholder Compose smoke test (the API 37 Compose-UI-test library
  hits InputManager.getInstance); on-device rendering verified via screenshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:26:57 -05:00
JMR-devandClaude Opus 4.8 c931c73745 Scaffold LibreMail: Material You email app foundation
Initial scaffold for LibreMail, a free and open-source (GPL-3.0) Android email
client. This increment delivers a buildable, runnable, themed app shell on top
of the full architecture skeleton; account sign-in, IMAP/SMTP sync and sending
arrive in later increments.

- Gradle 9.6 + AGP 9.2 + Kotlin 2.4.0 (AGP built-in Kotlin via the buildscript
  classpath; KSP, no KAPT); version catalog; minSdk 33, target/compile SDK 37
- Jetpack Compose + Material 3 with Material You dynamic color, light/dark and
  edge-to-edge; adaptive, themed launcher icon
- Navigation across Inbox, Reader, Compose, Settings (with an Advanced Settings
  group) and Account Setup
- Hilt DI, Room cache (entities/DAOs/database), domain models, and a
  MailRepository as single source of truth with a sample-data fallback
- Unit tests (repository + sample data) and a Compose smoke test
- GPL-3.0 LICENSE, SPDX headers, README with build and Gmail OAuth setup steps

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 00:17:59 -05:00