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.
## 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)
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.
Summary
ReportReviewScreen.kt), gated by basic local-part@domain.tld format validation; the address rides along onDebugReport.userEmailso it round-trips throughtoStorageJson()/fromStorageJson()and appears in the exacttoSubmissionPayload()shown for review, Copy, Save, and POST.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."supportingText) that, along with the field's outline, turns red viaisErroruntil the threshold is met. The email field gets the same red/isError+ inline-message treatment when malformed.state.submit != SubmitUiState.SUBMITTINGgate. TheReportReviewViewModel.submit()function itself is also guarded by the sameReportSubmissionRuleschecks (not just the Composeenabledflag), so an invalid submission can't proceed even if triggered outside the button's normal click path.AlertDialog: that dialog only reacts tostate.submit == SubmitUiState.SUCCEEDED, and the new guard sits entirely before that state is ever reached, so invalid attempts never touchSUBMITTING/SUCCEEDEDand the confirmation flow is untouched.Tests
ReportReviewViewModelTest: new/updated coverage for the pureisCommentLongEnough/isEmailValid/canSubmitgating (ReportReviewState), a matrix of valid/invalid email shapes, andsubmit()being a no-op (nostore.save, nosubmitter.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 newuserEmailfield.Closes #159
Test plan
assembleDebug+testDebugUnitTest+lintDebug+ktlintCheck+detekt+compileDebugAndroidTestKotlinall green locally (JDK 21)🤖 Generated with Claude Code