feat(reporting): require a reply-to email and a 200-char minimum on problem reports #183

Merged
JMR-dev merged 2 commits from feat-159-report-required-email into main 2026-07-03 00:20:15 +00:00
JMR-dev commented 2026-07-02 23:52:52 +00:00 (Migrated from github.com)

Summary

  • Adds a required email field to the "Report a Problem" review screen (ReportReviewScreen.kt), gated by basic local-part@domain.tld format validation; the address rides along on DebugReport.userEmail so it round-trips through toStorageJson()/fromStorageJson() and appears in the exact toSubmissionPayload() shown for review, Copy, Save, and POST.
  • Adds the required consent copy verbatim as R.string.report_email_consent, shown directly below the email field (and above the payload/submit area): "By submitting this report and supplying your email, you agree that the maintainers of LibreMail may contact you at the supplied email. Supplying an email and submitting a report does not guarantee reply or resolution to your concern."
  • Adds a 200-character minimum on the comment field with a live "x/200" counter (supportingText) that, along with the field's outline, turns red via isError until the threshold is met. The email field gets the same red/isError + inline-message treatment when malformed.
  • Submit is enabled only when the comment is ≥200 characters and the email is valid, mirroring and extending the existing state.submit != SubmitUiState.SUBMITTING gate. The ReportReviewViewModel.submit() function itself is also guarded by the same ReportSubmissionRules checks (not just the Compose enabled flag), so an invalid submission can't proceed even if triggered outside the button's normal click path.
  • Integrates cleanly with #161's post-submit confirmation AlertDialog: that dialog only reacts to state.submit == SubmitUiState.SUCCEEDED, and the new guard sits entirely before that state is ever reached, so invalid attempts never touch SUBMITTING/SUCCEEDED and the confirmation flow is untouched.

Tests

  • ReportReviewViewModelTest: new/updated coverage for the pure isCommentLongEnough/isEmailValid/canSubmit gating (ReportReviewState), a matrix of valid/invalid email shapes, and submit() being a no-op (no store.save, no submitter.submit) when the comment is short, the email is blank, or the email is malformed — plus updated happy-path tests that now supply a valid email and a ≥200-char comment.
  • DebugReportTest: round-trip and payload-inclusion coverage for the new userEmail field.

Closes #159

Test plan

  • assembleDebug + testDebugUnitTest + lintDebug + ktlintCheck + detekt + compileDebugAndroidTestKotlin all green locally (JDK 21)
  • CI (including the E2E matrix)

🤖 Generated with Claude Code

## Summary - Adds a **required email field** to the "Report a Problem" review screen (`ReportReviewScreen.kt`), gated by basic local-part@domain.tld format validation; the address rides along on `DebugReport.userEmail` so it round-trips through `toStorageJson()`/`fromStorageJson()` and appears in the exact `toSubmissionPayload()` shown for review, Copy, Save, and POST. - Adds the required **consent copy** verbatim as `R.string.report_email_consent`, shown directly below the email field (and above the payload/submit area): "By submitting this report and supplying your email, you agree that the maintainers of LibreMail may contact you at the supplied email. Supplying an email and submitting a report does not guarantee reply or resolution to your concern." - Adds a **200-character minimum** on the comment field with a live "x/200" counter (`supportingText`) that, along with the field's outline, turns red via `isError` until the threshold is met. The email field gets the same red/`isError` + inline-message treatment when malformed. - **Submit is enabled only when** the comment is ≥200 characters *and* the email is valid, mirroring and extending the existing `state.submit != SubmitUiState.SUBMITTING` gate. The `ReportReviewViewModel.submit()` function itself is also guarded by the same `ReportSubmissionRules` checks (not just the Compose `enabled` flag), so an invalid submission can't proceed even if triggered outside the button's normal click path. - Integrates cleanly with #161's post-submit confirmation `AlertDialog`: that dialog only reacts to `state.submit == SubmitUiState.SUCCEEDED`, and the new guard sits entirely before that state is ever reached, so invalid attempts never touch `SUBMITTING`/`SUCCEEDED` and the confirmation flow is untouched. ## Tests - `ReportReviewViewModelTest`: new/updated coverage for the pure `isCommentLongEnough`/`isEmailValid`/`canSubmit` gating (`ReportReviewState`), a matrix of valid/invalid email shapes, and `submit()` being a no-op (no `store.save`, no `submitter.submit`) when the comment is short, the email is blank, or the email is malformed — plus updated happy-path tests that now supply a valid email and a ≥200-char comment. - `DebugReportTest`: round-trip and payload-inclusion coverage for the new `userEmail` field. Closes #159 ## Test plan - [x] `assembleDebug` + `testDebugUnitTest` + `lintDebug` + `ktlintCheck` + `detekt` + `compileDebugAndroidTestKotlin` all green locally (JDK 21) - [ ] CI (including the E2E matrix) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.