From 8f8cee08b4b1a0f3b4eebc0c185a188dbfb0bae1 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Mon, 11 May 2026 21:45:46 -0400 Subject: [PATCH] Use app modals for markdown discard Co-authored-by: Orca --- .../app/h/[hostId]/session/[worktreeId].tsx | 88 +++++++++++++------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/mobile/app/h/[hostId]/session/[worktreeId].tsx b/mobile/app/h/[hostId]/session/[worktreeId].tsx index 7cbed1d31b7..54870356126 100644 --- a/mobile/app/h/[hostId]/session/[worktreeId].tsx +++ b/mobile/app/h/[hostId]/session/[worktreeId].tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useRef, useCallback } from 'react' -import { Alert, Animated, AppState, type AppStateStatus } from 'react-native' +import { Animated, AppState, type AppStateStatus } from 'react-native' import * as Clipboard from 'expo-clipboard' import { BackHandler, @@ -47,6 +47,7 @@ import { import { StatusDot } from '../../../../src/components/StatusDot' import { ActionSheetModal } from '../../../../src/components/ActionSheetModal' import { TextInputModal } from '../../../../src/components/TextInputModal' +import { ConfirmModal } from '../../../../src/components/ConfirmModal' import { CustomKeyModal, loadCustomKeys, @@ -103,6 +104,12 @@ type MarkdownDocState = } | { status: 'error'; message: string } +type DirtyMarkdownDraft = { + tabId: string + title: string + content: string +} + type TerminalCreateResult = { terminal: { handle: string @@ -345,6 +352,11 @@ export default function SessionScreen() { MobileSessionTab, { type: 'markdown' } > | null>(null) + const [discardMarkdownTarget, setDiscardMarkdownTarget] = useState | null>(null) + const [leaveDrafts, setLeaveDrafts] = useState(null) const [renameTarget, setRenameTarget] = useState(null) const [customKeys, setCustomKeys] = useState([]) const [showCustomKeyModal, setShowCustomKeyModal] = useState(false) @@ -957,7 +969,7 @@ export default function SessionScreen() { ) const getDirtyMarkdownDrafts = useCallback(() => { - const drafts: Array<{ tabId: string; title: string; content: string }> = [] + const drafts: DirtyMarkdownDraft[] = [] for (const [tabId, doc] of markdownDocs) { if (doc.status === 'ready' && doc.isDirty) { const tab = sessionTabs.find((candidate) => candidate.id === tabId) @@ -973,23 +985,7 @@ export default function SessionScreen() { router.back() return } - Alert.alert('Unsaved markdown changes', 'Copy or discard phone drafts before leaving.', [ - { text: 'Cancel', style: 'cancel' }, - { - text: 'Copy All & Leave', - onPress: () => { - const combined = dirtyDrafts - .map((draft) => `# ${draft.title}\n\n${draft.content}`) - .join('\n\n---\n\n') - void Clipboard.setStringAsync(combined).finally(() => router.back()) - } - }, - { - text: 'Discard', - style: 'destructive', - onPress: () => router.back() - } - ]) + setLeaveDrafts(dirtyDrafts) }, [getDirtyMarkdownDrafts, router]) useEffect(() => { @@ -1011,18 +1007,19 @@ export default function SessionScreen() { void readMarkdownTab(tab) return } - Alert.alert('Discard changes?', 'This will replace the phone draft with the desktop file.', [ - { text: 'Cancel', style: 'cancel' }, - { - text: 'Discard', - style: 'destructive', - onPress: () => void readMarkdownTab(tab) - } - ]) + setDiscardMarkdownTarget(tab) }, [markdownDocs, readMarkdownTab] ) + const confirmDiscardMarkdown = useCallback(() => { + const target = discardMarkdownTarget + setDiscardMarkdownTarget(null) + if (target) { + void readMarkdownTab(target) + } + }, [discardMarkdownTarget, readMarkdownTab]) + const saveMarkdownTab = useCallback( async (tab: Extract) => { if (!client) return @@ -2283,6 +2280,43 @@ export default function SessionScreen() { ]} onClose={() => setMarkdownActionTarget(null)} /> + { + const drafts = leaveDrafts ?? [] + const combined = drafts + .map((draft) => `# ${draft.title}\n\n${draft.content}`) + .join('\n\n---\n\n') + setLeaveDrafts(null) + void Clipboard.setStringAsync(combined).finally(() => router.back()) + } + }, + { + label: 'Discard & Leave', + destructive: true, + onPress: () => { + setLeaveDrafts(null) + router.back() + } + } + ]} + onClose={() => setLeaveDrafts(null)} + /> + setDiscardMarkdownTarget(null)} + />