diff --git a/mobile/src/components/MobilePrComposeSheet.tsx b/mobile/src/components/MobilePrComposeSheet.tsx deleted file mode 100644 index 124f91922..000000000 --- a/mobile/src/components/MobilePrComposeSheet.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Linking } from 'react-native' -import { BottomDrawer } from './BottomDrawer' -import { MobilePrComposeForm, type PrComposePrefill } from './pr-sidebar/MobilePrComposeForm' -import type { RpcClient } from '../transport/rpc-client' - -type Props = { - visible: boolean - client: RpcClient | null - worktreeId: string - prefill: PrComposePrefill - // Head branch — enables the base≠head guard and the "from " hint. - head?: string | null - onClose: () => void - onCreated: (url: string, warning?: string) => void -} - -// BottomDrawer wrapper around the inline compose form, for full-screen roots -// (source-control modals). The PR sidebar empty-state renders MobilePrComposeForm -// inline instead, since a BottomDrawer overlay nested in a ScrollView clips it. -export function MobilePrComposeSheet({ - visible, - client, - worktreeId, - prefill, - head, - onClose, - onCreated -}: Props) { - return ( - - {/* Why: key on visible + prefill fields so reopening (or a new prefill) - remounts the form with fresh initial values; the previous sheet reset - its fields via an effect on the same signals. */} - - - ) -} - -export function openMobilePrUrl(url: string): void { - // Why: Linking.openURL rejects when iOS/Android can't open the URL (no app, - // bad scheme, etc.). Without a catch that surfaces as LogBox "Uncaught - // (in promise) Error: Unable to open URL…" over the PR screen. - void Linking.openURL(url).catch(() => {}) -} diff --git a/mobile/src/components/mobile-pr-url.ts b/mobile/src/components/mobile-pr-url.ts new file mode 100644 index 000000000..3f642d5cc --- /dev/null +++ b/mobile/src/components/mobile-pr-url.ts @@ -0,0 +1,6 @@ +import { Linking } from 'react-native' + +export function openMobilePrUrl(url: string): void { + // Prevent unhandled rejections when no app accepts the URL. + void Linking.openURL(url).catch(() => {}) +} diff --git a/mobile/src/components/pr-sidebar/MobilePrComposeForm.tsx b/mobile/src/components/pr-sidebar/MobilePrComposeForm.tsx index 618e399d1..d832d38c8 100644 --- a/mobile/src/components/pr-sidebar/MobilePrComposeForm.tsx +++ b/mobile/src/components/pr-sidebar/MobilePrComposeForm.tsx @@ -38,11 +38,7 @@ type Props = { onCreated: (url: string, warning?: string) => void } -// PR compose form body: title/body/base/draft with AI prefill (git.generate -// PullRequestFields), submitting via createMobilePr. Renders a plain View so it -// can sit inline inside the PR sidebar's existing ScrollView (a BottomDrawer -// overlay trapped in a ScrollView clips the form). The BottomDrawer wrapper -// MobilePrComposeSheet reuses this body at full-screen roots. +// A plain View keeps the compose form usable inside the PR sidebar ScrollView. export function MobilePrComposeForm({ client, worktreeId, diff --git a/mobile/src/components/pr-sidebar/PRSidebarHeader.tsx b/mobile/src/components/pr-sidebar/PRSidebarHeader.tsx index 8a399babe..335108e07 100644 --- a/mobile/src/components/pr-sidebar/PRSidebarHeader.tsx +++ b/mobile/src/components/pr-sidebar/PRSidebarHeader.tsx @@ -7,7 +7,7 @@ import type { MobilePrTitleAction } from '../../session/use-mobile-pr-title-acti import { prStateBadge } from './pr-checks-presentation' import { statusColor } from './pr-sidebar-status-color' import { canEditPRTitle } from '../../session/pr-title-edit' -import { openMobilePrUrl } from '../MobilePrComposeSheet' +import { openMobilePrUrl } from '../mobile-pr-url' import { mobilePrSidebarStyles as styles } from './mobile-pr-sidebar-styles' import { prCommentComposerStyles as composerStyles } from './pr-comment-composer-styles' diff --git a/mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx b/mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx index ebc724d94..cffde86ea 100644 --- a/mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx +++ b/mobile/src/components/pr-sidebar/PrSidebarCreateEmptyState.tsx @@ -18,7 +18,7 @@ import { runMobileHostedReviewCreateIntent } from '../../source-control/mobile-hosted-review-create-intent-runner' import { fetchWorktreeLinkedPR } from '../../source-control/mobile-pr-link' -import { openMobilePrUrl } from '../MobilePrComposeSheet' +import { openMobilePrUrl } from '../mobile-pr-url' import { MobileLinkPrForm } from './MobileLinkPrForm' import { prCreateEmptyStateStyles as styles } from './pr-create-empty-state-styles' diff --git a/mobile/src/session/mobile-diff-review-state.ts b/mobile/src/session/mobile-diff-review-state.ts index a9bab2347..a9680a66d 100644 --- a/mobile/src/session/mobile-diff-review-state.ts +++ b/mobile/src/session/mobile-diff-review-state.ts @@ -104,31 +104,6 @@ export function mergeMobileDiffReviewState( } } -export function markMobileDiffReviewFileOpened( - state: MobileDiffReviewState, - descriptor: MobileDiffReviewFileDescriptor, - now: number -): MobileDiffReviewState { - const previous = state.files[descriptor.key] - return { - ...state, - updatedAt: now, - files: { - ...state.files, - [descriptor.key]: { - key: descriptor.key, - filePath: descriptor.filePath, - oldPath: descriptor.oldPath, - scope: descriptor.scope, - reviewedAt: previous?.reviewedAt, - reviewDiffIdentity: previous?.reviewDiffIdentity, - lastOpenedAt: now, - lastSeenDiffIdentity: descriptor.diffIdentity - } - } - } -} - export function markMobileDiffReviewFileReviewed( state: MobileDiffReviewState, descriptor: MobileDiffReviewFileDescriptor, diff --git a/mobile/src/session/use-native-chat-action-outcomes.ts b/mobile/src/session/use-native-chat-action-outcomes.ts index 51a6f831b..a81d08dfd 100644 --- a/mobile/src/session/use-native-chat-action-outcomes.ts +++ b/mobile/src/session/use-native-chat-action-outcomes.ts @@ -1,5 +1,4 @@ import { useCallback } from 'react' -import type { MobileNativeChatSendOutcome } from './mobile-native-chat-send' /** Wraps a chat card action so an accepted write also retires the route's held * failure banner. @@ -23,15 +22,3 @@ export function useNativeChatAcceptedAction( [action, onAccepted] ) } - -/** Boolean surface for callers with no pre-pasted input: 'unknown' stays true - * (the send usually landed; the optimistic echo is already held unconfirmed). */ -export function useNativeChatSentFlag( - send: (text: string, images?: string[]) => Promise -): (text: string, images?: string[]) => Promise { - return useCallback( - async (text: string, images?: string[]): Promise => - (await send(text, images)) !== 'rejected', - [send] - ) -} diff --git a/mobile/src/source-control/MobileSourceControlModals.tsx b/mobile/src/source-control/MobileSourceControlModals.tsx index b58d25207..f9659240e 100644 --- a/mobile/src/source-control/MobileSourceControlModals.tsx +++ b/mobile/src/source-control/MobileSourceControlModals.tsx @@ -1,7 +1,7 @@ import { ActionSheetModal, type ActionSheetAction } from '../components/ActionSheetModal' import { ConfirmModal } from '../components/ConfirmModal' import { PickerModal } from '../components/PickerModal' -import { openMobilePrUrl } from '../components/MobilePrComposeSheet' +import { openMobilePrUrl } from '../components/mobile-pr-url' import { MobileBranchDiffPreviewDrawer } from './MobileBranchDiffPreviewDrawer' import type { MobileSourceControlState } from './use-mobile-source-control-state' diff --git a/mobile/src/source-control/MobileSourceControlPanel.tsx b/mobile/src/source-control/MobileSourceControlPanel.tsx index 9c3ebb270..3244d440b 100644 --- a/mobile/src/source-control/MobileSourceControlPanel.tsx +++ b/mobile/src/source-control/MobileSourceControlPanel.tsx @@ -18,7 +18,7 @@ import { isMobileConflictAborting } from './mobile-source-control-conflict-abort import { useMobilePrSidebarController } from '../session/use-mobile-pr-sidebar-controller' import { prSidebarDetailsNeedFetch } from '../session/mobile-pr-sidebar-state' import { MobilePrViewPanelBody } from '../components/pr-sidebar/MobilePrViewPanel' -import { openMobilePrUrl } from '../components/MobilePrComposeSheet' +import { openMobilePrUrl } from '../components/mobile-pr-url' export type MobileSourceControlPanelProps = { hostId: string diff --git a/mobile/src/source-control/mobile-base-ref-search.ts b/mobile/src/source-control/mobile-base-ref-search.ts index 8e51fe0d5..84a962a41 100644 --- a/mobile/src/source-control/mobile-base-ref-search.ts +++ b/mobile/src/source-control/mobile-base-ref-search.ts @@ -2,13 +2,6 @@ import type { RpcClient } from '../transport/rpc-client' import type { RpcSuccess } from '../transport/types' import { mobileRepoSelectorFromWorktreeId } from './mobile-pr-create' -// Base-branch selection for the create-PR composer, mirroring the desktop -// useCreatePullRequestDialogFields flow: a default ref from repo.baseRefDefault and -// a debounced search via repo.searchRefs (both allowlisted for mobile). Result -// mapping is pure + unit-tested; the wrappers are thin sendRequest calls. - -// Defensively normalize the repo.searchRefs payload (`{ refs: string[] }`) to a -// clean string[] — drops non-string / malformed entries instead of throwing. export function mapBaseRefResults(raw: unknown): string[] { if (raw === null || typeof raw !== 'object') { return [] @@ -20,20 +13,6 @@ export function mapBaseRefResults(raw: unknown): string[] { return refs.filter((r): r is string => typeof r === 'string' && r.length > 0) } -export async function fetchDefaultBaseRef( - client: Pick, - worktreeId: string -): Promise { - const response = await client.sendRequest('repo.baseRefDefault', { - repo: mobileRepoSelectorFromWorktreeId(worktreeId) - }) - if (!response.ok) { - return null - } - const result = (response as RpcSuccess).result as { defaultBaseRef?: string | null } - return typeof result?.defaultBaseRef === 'string' ? result.defaultBaseRef : null -} - export async function searchBaseRefs( client: Pick, worktreeId: string, diff --git a/mobile/src/source-control/mobile-open-pr-prefill.ts b/mobile/src/source-control/mobile-open-pr-prefill.ts index 705b4dc68..2369095f3 100644 --- a/mobile/src/source-control/mobile-open-pr-prefill.ts +++ b/mobile/src/source-control/mobile-open-pr-prefill.ts @@ -1,14 +1,7 @@ -import type { RpcClient } from '../transport/rpc-client' import { readMobileGitStatusResult } from '../session/mobile-diff-review-rpc' import type { MobileGitStatusResult } from './mobile-git-status' -import { resolveMobilePrPrefill, type MobilePrPrefill } from './mobile-pr-create' -// Resolves the create-PR prefill from a git status snapshot. Split from the -// runners hook to keep that file under the line limit. - -// Reads a fresh git.status after a push so the prefill reflects the just-pushed -// branch's upstream/ahead data instead of the pre-push captured status. Best-effort: -// returns the captured status on any read failure. +// Refresh after a push when possible so readiness reflects the new upstream state. export async function readFreshGitStatus( worktreeId: string, fallback: MobileGitStatusResult | null, @@ -22,23 +15,6 @@ export async function readFreshGitStatus( } } -export async function buildOpenPrPrefill( - client: Pick | null, - worktreeId: string, - status: MobileGitStatusResult | null, - branchLabel: string -): Promise { - if (!client) { - return { provider: 'github', base: 'main', title: branchLabel, body: '' } - } - const gitReadiness = getMobilePrEligibilityReadiness(status) - return resolveMobilePrPrefill(client, worktreeId, { - branch: status?.branch, - title: branchLabel, - ...gitReadiness - }) -} - export function getMobilePrEligibilityReadiness(status: MobileGitStatusResult | null): { hasUncommittedChanges?: boolean hasUpstream?: boolean