Repository navigation
fix(mobile): show a destructive confirm when discarding a draft on Android - #6512
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge The cross-platform in-app discard confirm is wired correctly: the intercepted leave is captured in a ref before the confirm closes, the draft clear is awaited before the captured action is replayed, a failed clear stays and toasts, and no listeners, timers, subscriptions, or effects are added that could leak. The iOS cutover from the native alert is deliberate and is held to the same one-implementation contract by the new node source-parity test. Files Reviewed (8 files)
Previous Review Summary (commit 0b7b7b1)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 0b7b7b1)Status: No Issues Found | Recommendation: Merge The Android-only in-app destructive confirm is wired correctly: the intercepted leave is captured before the dialog closes, the draft clear is awaited before the action is replayed, a failed clear toasts and stays, and no listeners, timers, or subscriptions are added that could leak. Files Reviewed (6 files)
Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0 Review guidance: REVIEW.md from base branch |
|
bot: Cross-platform fix. Pushed 98eab15 (kwf What changed:
|
98eab15 to
a32ee0c
Compare
…-defects-on-android-the-destructive-is-d-61f3b-0604 # Conflicts: # apps/mobile/plugins/branded-splash.test.ts # apps/mobile/src/components/destructive-confirm-dialog.mounted.test.tsx # apps/mobile/src/components/destructive-confirm-dialog.tsx
…merge The merged main removed the in-app dialog's sign-out caller (#6397 reverted that surface to the themed native alert), so the dialog and guard comments now describe the one remaining caller instead of a stale sign-out reference.
…r has main added two source-parity guards that hold use-new-session-discard-guard.ts to one shared Alert.alert call site: that call site is gone, because the guard now mounts the in-app DestructiveConfirmDialog so Android shows the destructive red fill. Delete those two clauses (and the now-unused source reads) and keep every assertion about the plugins themselves, whose other Alert.alert callers remain.
…onfirm The button case now applies to the alerts still rendered natively.
Changelog for users
Changelog for maintainers
draft-discard-dialog-ur— accepted. Android's nativeAlertDialogpaints every button with the theme accent —#6397themed it to--primary— soAlert.alert'sstyle: 'destructive'never reaches the screen. Both platforms now mountDestructiveConfirmDialog(one cross-platform implementation); the hook no longer callsAlert.alert.home-ur-portrait/home-ur-night— rejected. The home CTA already inheritstext-primary-foreground, and a disabled primary takes the mutedbg-primary-disabledfill. Nothing in this diff touches the CTA.model-search-deepseek,new-session-draft,repo-picker-ur— rejected. The composer shows its draft verbatim once with noundefinednodes, including behind the repository sheet; no product change was made.useNewSessionDiscardGuardnow returnsdiscardConfirm, and the new-session body mounts it once. A caller that ignores the returned node loses the confirm on both platforms.discardFailed.DestructiveConfirmDialoggained an optionalcancelLabel. The new-session confirm passescommon.keepEditing; no caller supplies one, so the default stayscommon.cancel.navigation.dispatchfirst: that is where a double leave or a dropped action would surface. The mounted suite forksPlatform.OSwith a mutable mock and keeps both platforms in one file;use-new-session-discard-guard.platform.test.tsfails in node if the hook regains a platform branch or anAlert.alertcall.mainfix(mobile): show branch control under label on new-session form #6447 landed the same change with its own rationale) and the theme-token opacity revert inpermission-card,question-card,attachment-preview-strip,pr-review-overview-partsand thecheck-classesrule (that reverted fix(mobile): stop theme-token opacity modifiers from silently dropping #6344, whichmainkeeps).mainalso added two node source-parity tests that pin this guard to one sharedAlert.alertcall site (src/lib/alert-dialog-button-case.test.ts,src/lib/android-alert-title.test.ts). The cutover removes that call site, so those two clauses and their source reads are deleted; every assertion about the prebuild plugins stays, and their otherAlert.alertcallers remain.maindeletedDestructiveConfirmDialogand its sign-out caller in fix(mobile): theme Android alert dialogs with the app's surface colors #6397 (the Android alert is themed throughwithAndroidAlertDialogThemeinstead); this PR reintroduces the dialog for the discard confirm only.E2E proof
[e5] repo-sheet-composer-behind: with the repository sheet open, the prompt field behind the sheet still shows the typed sentence once — 'undefinedAdd' is absent — The scripted scene MISSed its first anchor (cold launch unpainted at 5 s, then e5's script-call cap was hit), so it was driven via the sim tools: the digest shows the composer EditText behind the open repository sheet holding 'Add a CONTRIBUTING.md section on running the local dev stack' exactly once with no 'undefined' node (e5-repo-sheet-open2.txt, screenshot e5-repo-sheet-open2.png).
[e1] platform:android discard-dialog-destructive-affordance: a dirty new-session leave opens the in-app confirm with a red destructive 'ضائع کریں' beside a neutral 'ترمیم جاری رکھیں' — the capture shows… — Android dirty-leave opened the in-app confirm, not the native alert: e1-dialog-digest.log carries
android.view.View Discard draft?,android.widget.TextView Your prompt will be lost.,android.widget.Button Keep editingandandroid.widget.Button Discard; the destructive-vs-neutral colour is the visual reviewer's call (e1-discard-confirm.png), Discard then navigated home and cleared the draft (e1-discard-accepted.log:android.widget.EditText What would you like to work on?), and with the clear forced to fail the screen stayed onNew sessionwith the draft (e1-discard-failed.log).[e1] draft-restores-verbatim: a typed draft survives a forward tab leave and restores exactly once on return — no 'undefined' prefix, no duplicated truncated fragment — [android] A typed draft survives the leave/return and restores verbatim exactly once with no 'undefined': after Go back -> in-app 'Discard draft?' confirm -> 'Keep editing' the composer shows text="Add a CONTRIBUTING.md section on running the local dev stack" with showing-hint="false" and 0 occurrences of "undefined" (e1-restored.xml), the drive log records tapped "Keep editing" (jev-drive-1790033157272.log), and the scripted replay that also asserts a second Go back -> "/Discard/" cleanup reports "SCENE e1 OK" (e1-scene.log); replay saved at e1.replay.json; no behavioral UX-DEFECT observed.
[e4] draft-restores-verbatim: a typed draft survives a forward tab leave and restores exactly once on return — no 'undefined' prefix, no duplicated truncated fragment — android; a typed draft restores verbatim exactly once and never with an 'undefined' prefix: e4-restore-after-restart.txt has exactly one node text="Add a CONTRIBUTING.md section on running the local dev stack" (grep -c = 1) and 0 nodes containing 'undefined' after a cold app restart, corroborated by jev-drive-1790031074188.log ('tap e6 -> tapped "New coding task"', verified) and, after a forward leave to the repository picker and the intercepted Back -> Android confirm -> 'Keep editing', by e4-draft-restored.txt (jev-drive-1790030668115.log, jev-drive-1790030659952.log). The parked…
[e6] ux-check: android dark/Urdu dirty new-session — Back opens the discard confirm, Destructive vs Keep editing — android emulator-5606, app language Urdu (RTL) with Appearance Dark (
content-desc="تاریک" ... checked="true", e6-appearance.txt); fromsigned-in-homea typed new-session draft plus Back produced the in-app Modal confirm — e6-scene.log digest showsandroid.view.ViewGroup مسودہ حذف کریں؟, آپ کا پرامپٹ ضائع ہو جائے گا۔together withandroid.widget.Button ضائع کریںandandroid.widget.Button ترمیم جاری رکھیں(thecancelLabel=common.keepEditingprop only the new Android branch passes, per files/change.diff); capture e6.png for the visual reviewer — the red-fill vs neutral-outline glance…[e7] ux-check: keep-editing keeps the draft — After tapping Keep editing the digest shows
android.view.View New sessionwithandroid.widget.EditText Add a CONTRIBUTING.md section on running the land no confirm node — the dialog closed, the composer kept the draft, and no navigation occurred (e7-keep-editing.png).E2E proof — log excerpts
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-5-visual-defects-on-android-the-destructive-is-d-61f3b-0604/e2e-mobile-app/e1-scene.log/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-5-visual-defects-on-android-the-destructive-is-d-61f3b-0604/e2e-mobile-app/jev-drive-1790033157272.log/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-5-visual-defects-on-android-the-destructive-is-d-61f3b-0604/e2e-mobile-app/e3-scene.log/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-5-visual-defects-on-android-the-destructive-is-d-61f3b-0604/e2e-mobile-app/e2-scene.log/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-5-visual-defects-on-android-the-destructive-is-d-61f3b-0604/e2e-mobile-app/e2-live.logOwner request
[e12] ux-check: light mode — session composer and new-session composer (incl. — Light mode (
content-desc="Light" ... checked="true", e12-appearance.txt); e12-scene.log OK with 0 occurrences ofundefinedand final digestandroid.widget.EditText Add a CONTRIBUTING.md section on running the local dev stackonce after a cold relaunch and a model-search round trip (replay banks the launch step); e12-repo-sheet.txt shows the same sentence verbatim once behind the open repository sheet (text="Select repository") with 0undefined; e12-session-composer.txt shows the agent-chat composertext="Message" hint="Message" showing-hint="true"with 0undefined— findings 3-5…[e8] ux-check (android) — In-app Android confirm (no AlertController markers) shows 'Discard draft?' / 'Your prompt will be lost.' / 'Discard' / 'Keep editing'; tapping 'Discard' left the composer (e8-after-discard.txt shows 'Nothing running right now', 0 draft matches) and re-entry shows the placeholder 'What would you like to work on?' with 0 draft matches (e8-reentry.txt); no UX-DEFECT observed.
[e11] ux-check: Dark-mode home CTA label — With Appearance set to Dark (RadioButton 'Dark' [checked]) the Home digest shows the enabled Button 'New coding task' with its label once and no disabled state; the pill/label contrast is the visual reviewer's call on e11-dark-home.png (digest e11-dark-home.txt).
[e9] ux-check: failing draft clear — android: e9-toast-tap.log line 7 shows the composer still mounted with 'android.widget.EditText e9 draft text' and line 38 shows 'android.widget.TextView Could not discard the draft. Please try again.' after tapping Discard, so the confirm closed, the screen stayed and the toast rendered; the failing clear was created with a temporary staged edit in new-session-screen-body.tsx (reverted, worktree clean), and out/e9-toast.png is the capture for the visual reviewer. No UX-DEFECT on the visited composer/confirm/model-picker screens.
[e2] home-cta-legible (android) — Re-ran the edited parked e2 list after its screen MISS: 'SCENE e2 OK'; digest shows the enabled home primary CTA Button/TextView 'New coding task' with 'Nothing running right now' (English-locale device, so not 'کوڈنگ کا نیا کام'); fill/label contrast is the visual reviewer's call on e2.png, not claimed here.
[e3] ux-check: light mode — session composer and new-session composer (incl. — [android] Light mode (device-state night mode wanted no); no literal 'undefined' appears and the restored draft renders verbatim once — the new-session composer shows text="Add a CONTRIBUTING.md section on running the local dev stack" with 0 occurrences of "undefined" (e3-composer.xml), the same draft is present behind the open repository sheet ("Select repository", "Search repositories...") with 0 occurrences of "undefined" (e3-repo-sheet.xml), and the full replay (composer -> repo sheet -> launch -> draft restored -> model picker -> discard) reports "SCENE e3 OK" (e3-scene.log); the parked…
Follow-ups (not changed here)
Open findings (not fixed here)
E2E proof — log excerpts
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-platform-64de/e2e-mobile-app/e1-scene.log/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-platform-64de/e2e-mobile-app/e1b-scene.log/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-platform-64de/e2e-mobile-app/e1c-scene.log