import { ActivityIndicator, FlatList, Pressable, Text, View } from 'react-native' import { RefreshCw } from 'lucide-react-native' import type { RefObject } from 'react' import type { DiffComment } from '../../../src/shared/types' import { colors } from '../theme/mobile-theme' import { MobileDiffReviewLine } from './MobileDiffReviewLine' import type { ReviewDiffLine, ReviewDiffState, ReviewScreenState } from '../session/mobile-diff-review-screen-model' import type { MobileDiffReviewQueueItem } from '../session/mobile-diff-review-queue' import { mobileDiffReviewStyles as styles } from './mobile-diff-review-screen-styles' type Props = { activeHunkIndex: number | null commentsByLine: ReadonlyMap currentItem: MobileDiffReviewQueueItem | null diffState: ReviewDiffState filteredCount: number listRef: RefObject | null> screenState: ReviewScreenState staleCommentIds: ReadonlySet onAddNote: (lineNumber: number) => void onEditNote: (comment: DiffComment) => void onRetry: () => void } export function MobileDiffReviewBody({ activeHunkIndex, commentsByLine, currentItem, diffState, filteredCount, listRef, screenState, staleCommentIds, onAddNote, onEditNote, onRetry }: Props) { if (screenState.kind === 'loading') { return } if (screenState.kind === 'error' || screenState.kind === 'unavailable') { return ( ) } if (filteredCount === 0) { return } if (diffState.kind === 'loading') { return } if (diffState.kind !== 'ready') { return } return ( `${currentItem?.key ?? 'diff'}:${index}`} renderItem={({ item, index }) => { const lineNumber = item.newLineNumber ?? -1 const active = activeHunkIndex !== null && index >= (diffState.hunks[activeHunkIndex]?.startIndex ?? -1) && index <= (diffState.hunks[activeHunkIndex]?.endIndex ?? -1) return ( ) }} contentContainerStyle={styles.diffList} onScrollToIndexFailed={(info) => { listRef.current?.scrollToOffset({ offset: Math.max(0, info.averageItemLength * info.index), animated: true }) }} ListFooterComponent={ diffState.truncated ? ( Diff truncated for mobile preview. ) : null } /> ) } function DiffUnavailableState({ diffState, onRetry }: { diffState: ReviewDiffState onRetry: () => void }) { const title = diffState.kind === 'binary' ? 'Binary Diff' : diffState.kind === 'too-large' ? 'Diff Too Large' : diffState.kind === 'deleted' ? 'Deleted File' : 'Diff Unavailable' const text = diffState.kind === 'binary' ? 'This file cannot be rendered as text on mobile.' : diffState.kind === 'too-large' ? 'This diff is too large for the mobile preview.' : diffState.kind === 'deleted' ? 'This file was deleted. Add a file note or mark it reviewed.' : diffState.kind === 'error' ? diffState.message : 'Select a file to review.' return } function CenteredState({ busy, muted, title, text, onRetry }: { busy?: boolean muted?: boolean title?: string text: string onRetry?: () => void }) { return ( {busy ? ( ) : null} {title ? {title} : null} {text} {onRetry ? ( [styles.retryButton, pressed && styles.buttonPressed]} onPress={onRetry} accessibilityRole="button" accessibilityLabel="Retry loading review" > Retry ) : null} ) }