Replying from an open email now routes through MailRepository.buildReplyDraft (quotes the original into a <blockquote>, bakes the signature, prefixes Re:/Fwd: without double-prefixing) and opens compose on the built draft via a new ReaderEvent.OpenCompose — the same high-fidelity path the mailbox's multi-select reply uses — instead of navigating to Routes.compose(sender, "Re: …") with an empty body. Adds Reply-All and Forward via an app-bar overflow menu. The hardcoded, non-localized "Re: " is gone (subject prefixing is handled by ReplyBuilder).
#304 — one-shot buttons not guarded against double-tap
SignatureEditViewModel.save, ReportReviewViewModel.submit, AccountSettingsViewModel.removeAccount, and ProblemReportsViewModel.createManualReport now flip a busy/saving flag synchronously before the first suspension (mirroring account-setup's SetupStatus.CONNECTING) and gate their buttons, so a rapid double-tap can no longer create duplicate signatures/reports, enqueue two uploads, or over-pop the back stack past the mailbox.
Tests
Unit: each guard has a rapid double-invoke test asserting the underlying create/submit/collectManual/deleteAccount runs exactly once (run on a StandardTestDispatcher so the second tap lands before the first coroutine is dispatched). Reader reply path: buildReplyDraft invoked once and OpenCompose(draftId) emitted; Forward passes FORWARD; failure emits ComposeFailed.
E2E:ReaderScreenTest clicks Reply / Forward / Reply-All and asserts the correct ReplyMode draft is built and compose is opened.
Local gate green: testDebugUnitTest, compileDebugAndroidTestKotlin, lintDebug, ktlintCheck, detekt. Instrumented suite runs in CI.
## #303 — reader Reply produces a bare compose
Replying from an **open** email now routes through `MailRepository.buildReplyDraft` (quotes the original into a `<blockquote>`, bakes the signature, prefixes `Re:`/`Fwd:` without double-prefixing) and opens compose on the built draft via a new `ReaderEvent.OpenCompose` — the same high-fidelity path the mailbox's multi-select reply uses — instead of navigating to `Routes.compose(sender, "Re: …")` with an empty body. Adds **Reply-All** and **Forward** via an app-bar overflow menu. The hardcoded, non-localized `"Re: "` is gone (subject prefixing is handled by `ReplyBuilder`).
## #304 — one-shot buttons not guarded against double-tap
`SignatureEditViewModel.save`, `ReportReviewViewModel.submit`, `AccountSettingsViewModel.removeAccount`, and `ProblemReportsViewModel.createManualReport` now flip a `busy`/`saving` flag **synchronously before the first suspension** (mirroring account-setup's `SetupStatus.CONNECTING`) and gate their buttons, so a rapid double-tap can no longer create duplicate signatures/reports, enqueue two uploads, or over-pop the back stack past the mailbox.
## Tests
- **Unit:** each guard has a rapid double-invoke test asserting the underlying `create`/`submit`/`collectManual`/`deleteAccount` runs **exactly once** (run on a `StandardTestDispatcher` so the second tap lands before the first coroutine is dispatched). Reader reply path: `buildReplyDraft` invoked once and `OpenCompose(draftId)` emitted; Forward passes `FORWARD`; failure emits `ComposeFailed`.
- **E2E:** `ReaderScreenTest` clicks Reply / Forward / Reply-All and asserts the correct `ReplyMode` draft is built and compose is opened.
Local gate green: `testDebugUnitTest`, `compileDebugAndroidTestKotlin`, `lintDebug`, `ktlintCheck`, `detekt`. Instrumented suite runs in CI.
Closes #303
Closes #304
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#303 — reader Reply produces a bare compose
Replying from an open email now routes through
MailRepository.buildReplyDraft(quotes the original into a<blockquote>, bakes the signature, prefixesRe:/Fwd:without double-prefixing) and opens compose on the built draft via a newReaderEvent.OpenCompose— the same high-fidelity path the mailbox's multi-select reply uses — instead of navigating toRoutes.compose(sender, "Re: …")with an empty body. Adds Reply-All and Forward via an app-bar overflow menu. The hardcoded, non-localized"Re: "is gone (subject prefixing is handled byReplyBuilder).#304 — one-shot buttons not guarded against double-tap
SignatureEditViewModel.save,ReportReviewViewModel.submit,AccountSettingsViewModel.removeAccount, andProblemReportsViewModel.createManualReportnow flip abusy/savingflag synchronously before the first suspension (mirroring account-setup'sSetupStatus.CONNECTING) and gate their buttons, so a rapid double-tap can no longer create duplicate signatures/reports, enqueue two uploads, or over-pop the back stack past the mailbox.Tests
create/submit/collectManual/deleteAccountruns exactly once (run on aStandardTestDispatcherso the second tap lands before the first coroutine is dispatched). Reader reply path:buildReplyDraftinvoked once andOpenCompose(draftId)emitted; Forward passesFORWARD; failure emitsComposeFailed.ReaderScreenTestclicks Reply / Forward / Reply-All and asserts the correctReplyModedraft is built and compose is opened.Local gate green:
testDebugUnitTest,compileDebugAndroidTestKotlin,lintDebug,ktlintCheck,detekt. Instrumented suite runs in CI.Closes #303
Closes #304
🤖 Generated with Claude Code