chore(ui): migrate LocalClipboardManager to LocalClipboard #286

Merged
JMR-dev merged 2 commits from chore-237-localclipboard-migration into main 2026-07-04 05:37:57 +00:00
JMR-dev commented 2026-07-04 05:16:55 +00:00 (Migrated from github.com)

Closes #237

Call sites migrated

Only one usage existed in app/src/main: ReportReviewScreen.kt's "Copy report" action.

  • LocalClipboardManager.current → LocalClipboard.current (returns androidx.compose.ui.platform.Clipboard).
  • The synchronous clipboard.setText(AnnotatedString(viewModel.payload())) → the suspend clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(label, payload))), run inside the screen's existing rememberCoroutineScope() (same scope.launch that already showed the "copied" snackbar, now sequenced: copy first, then snackbar — same order/behavior as before).
  • The clipboard write is pulled into a small internal suspend fun copyReportPayloadToClipboard(clipboard: Clipboard, payload: String) so it can be unit-tested directly against a mocked Clipboard, without a Compose UI test or emulator.

Tests

  • Unit (new): ReportReviewClipboardTest — mocks Clipboard and statically mocks ClipData's newPlainText factory (same pattern ContactsPermissionManagerTest already uses for Uri), and asserts the exact payload text reaches ClipData.newPlainText and that the resulting ClipData is wrapped unmodified in the ClipEntry passed to setClipEntry.
  • Instrumented (new, added to the existing ReportReviewScreenTest): tappingCopy_putsThePayloadOnTheSystemClipboard_andShowsAConfirmation — taps "Copy report", waits for the "copied" snackbar, then reads the real Android ClipboardManager system service and asserts its content equals the report's toSubmissionPayload(). This is the end-to-end verification the ticket called out given the async copy changes the runtime surface.

Validation

A peer agent is using the only local emulator tonight, so per this ticket's instructions no emulator was booted locally. Validated locally instead with the compile/unit gate:

:app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt

All green (BUILD SUCCESSFUL), including the new unit test passing and the new instrumented test compiling cleanly. CI's full matrix (including the E2E jobs) will run the new instrumented test.

🤖 Generated with Claude Code

Closes #237 ## Call sites migrated Only one usage existed in `app/src/main`: `ReportReviewScreen.kt`'s "Copy report" action. - `LocalClipboardManager.current` → `LocalClipboard.current` (returns `androidx.compose.ui.platform.Clipboard`). - The synchronous `clipboard.setText(AnnotatedString(viewModel.payload()))` → the suspend `clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(label, payload)))`, run inside the screen's existing `rememberCoroutineScope()` (same `scope.launch` that already showed the "copied" snackbar, now sequenced: copy first, then snackbar — same order/behavior as before). - The clipboard write is pulled into a small `internal suspend fun copyReportPayloadToClipboard(clipboard: Clipboard, payload: String)` so it can be unit-tested directly against a mocked `Clipboard`, without a Compose UI test or emulator. ## Tests - **Unit** (new): `ReportReviewClipboardTest` — mocks `Clipboard` and statically mocks `ClipData`'s `newPlainText` factory (same pattern `ContactsPermissionManagerTest` already uses for `Uri`), and asserts the exact payload text reaches `ClipData.newPlainText` and that the resulting `ClipData` is wrapped unmodified in the `ClipEntry` passed to `setClipEntry`. - **Instrumented** (new, added to the existing `ReportReviewScreenTest`): `tappingCopy_putsThePayloadOnTheSystemClipboard_andShowsAConfirmation` — taps "Copy report", waits for the "copied" snackbar, then reads the **real** Android `ClipboardManager` system service and asserts its content equals the report's `toSubmissionPayload()`. This is the end-to-end verification the ticket called out given the async copy changes the runtime surface. ## Validation A peer agent is using the only local emulator tonight, so per this ticket's instructions no emulator was booted locally. Validated locally instead with the compile/unit gate: ``` :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt ``` All green (`BUILD SUCCESSFUL`), including the new unit test passing and the new instrumented test compiling cleanly. CI's full matrix (including the E2E jobs) will run the new instrumented test. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.