The mailbox list observed the entire `messages` table (observeSummaries, no
WHERE/LIMIT), mapped every cached row to a domain Message, and filtered down to
the visible account+folder in MailboxViewModel — so its cost scaled with the
whole cache and re-ran on every write to `messages` (IDLE delivery, a flag
toggle, a backfill page, any folder sync). On a 20k-row cache that is ~125 ms of
work per unrelated write.
Push the account/folder filter into SQL (observeFolderSummaries /
observeUnifiedFolderSummaries, exposed via observeFolderMessages /
observeUnifiedFolderMessages) and flatMapLatest the ViewModel over the selected
account+folder. The only remaining client-side pass separates the normal list
from an active search over the small folder-scoped set.
Validated on an emulator against 1k/5k/20k-row caches (docs/perf/issue-86-
profiling.md): the account-scoped query is ~1.5 ms flat (~80x faster at 20k) and
is already served by the existing (accountId, folder, uid) index — so NO
composite index and NO schema migration are added. The ticket's proposed
(accountId, folder, inInbox, timestampMillis) index changes timing only within
noise and isn't even preferred by SQLite's planner. The unified "All inboxes"
view stays an O(N) folder scan (still 5.6x better) and is a follow-up for paging;
IMAP latency on folder open is a separate, unmeasured concern.
Closes#86
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite the manual-dispatch release.yml into the issue-#19 pipeline:
v* tag push (or dispatch with dry-run/re-release inputs) runs the fast
CI gate, builds bundleRelease + assembleRelease signed from base64
keystore secrets (falling back to *-unsigned artifacts when unset),
generates a Conventional-Commit changelog and SHA-256 checksums, then
creates the GitHub release and fans out to secret-gated Google Play
publish (staged rollout supported), a documented Galaxy Store manual
stub, and an S3-compatible archive under releases/<tag>/. Every
credentialed stage skips with a clear notice while the store accounts
(#16/#17/#18) don't exist yet; no secret lives in the repo and
app/build.gradle.kts is unchanged. docs/release.md documents the
secrets, flows, and per-store manual fallbacks.
Part of #19
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Repo-actionable deliverables for the Google Play compliance work (issue #17),
every claim verified against the code and the built release artifacts:
- PRIVACY.md: user-facing privacy policy (device-local mail cache, optional
SQLCipher encryption, traffic only to the user's own mail provider,
on-device-only contacts autocomplete, strictly local opt-in debug reports,
no ads/analytics/tracking SDKs).
- docs/play-data-safety.md: Play Data safety questionnaire mapping -- answer
'no data collected/shared' with per-category code evidence, the policy
exemptions relied on, a dependency audit, and a conservative fallback.
- docs/play-permissions.md: merged-manifest permission audit (incl. the
WorkManager-injected WAKE_LOCK / RECEIVE_BOOT_COMPLETED) with paste-ready
Console justifications for READ_CONTACTS, POST_NOTIFICATIONS, and the
FOREGROUND_SERVICE_DATA_SYNC declaration + demo-video script.
- docs/play-compliance.md: verified targetSdk 37 (requirement: 35+), 16 KB
page-size compliance (all packaged .so PT_LOAD p_align=0x4000, incl.
sqlcipher-android 4.16.0), bundleRelease AAB check, the Gmail-app-password /
no-CASA OAuth note, the console-steps checklist with drafted content-rating
and listing answers, and repo findings (push-mail default vs docs, README
minSdk/app-lock drift, debug-key release fallback).
- README.md: link PRIVACY.md and note the no-Google-OAuth/no-CASA status
(fuller README pass stays issue #20).
Part of #17.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI runs ktlint/detekt and the E2E suites (not Android lintDebug), and the
KnownVuln rationale should not imply blanket TLS enforcement.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prepare for F-Droid publication (issue #16):
- docs/fdroid-compliance.md: full dependency license audit (release
runtime classpath + buildscript classpath — all FOSS, no Play
Services/Firebase, no non-free Gradle plugins), an anti-feature
review of actual app behavior (none to declare: debug reporting is
opt-in/local-only with no endpoint by default, Android Backup is
gated off by default, Outlook OAuth is optional per-account with a
public client id), a complete network-surface inventory, and the
clean-room build verification (assembleRelease succeeds with no
secrets.properties).
- app/build.gradle.kts: stop embedding AGP's dependency-info block (a
Google-Play-encrypted dependency list in the APK signing block) in
APKs/bundles — a known F-Droid inclusion/reproducibility blocker.
- fastlane/metadata/android/en-US/: store listing (title, short/full
description, changelog for versionCode 1) that F-Droid reads from
the repo; listing .txt files deliberately carry no license headers.
- docs/fdroid/org.libremail.app.yml: commented template + instructions
for the eventual fdroiddata build recipe (submission out of scope).
- README.md: F-Droid section pointing at the above.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>