import { ActivityIndicator, Platform, Pressable, ScrollView, SectionList, Text, TextInput, View } from 'react-native' import { Minus, MoreHorizontal, Plus, Sparkles } from 'lucide-react-native' import { imeGuardedSubmitProps } from '../ime/ime-submit-carry' import { colors, spacing } from '../theme/mobile-theme' import { MobileSourceControlCreatePrEntry } from './MobileSourceControlCreatePrEntry' import { MobileCommitFailurePanel } from './MobileCommitFailurePanel' import { KEYBOARD_COMMIT_BAR_CLEARANCE } from './mobile-source-control-screen-state' import { makeRenderFileRow, BranchCompareFooter } from './MobileSourceControlFileRows' import type { MobileSourceControlState } from './use-mobile-source-control-state' import { styles } from './mobile-source-control-styles' import { hubStyles } from './mobile-source-control-hub-styles' type Props = { state: MobileSourceControlState } // Changes tab: local file changes only — uncommitted (staged/unstaged) plus // committed-on-branch vs base. PR conflicts and push status live elsewhere. export function MobileSourceControlContent({ state }: Props) { const { insets, connState, busyAction, commitMessage, setCommitMessage, generatingMessage, setShowActionSheet, setDiscardTarget, actionError, commitFailureRecovery, commitFailureRecoveryAction, keyboardLift, openingPath, openingBranchPath, sections, hasVisibleChanges, stageablePaths, unstageablePaths, stagedCount, primaryAction, createPrAction, stageAll, unstageAll, generateCommitMessage, cancelGenerateCommitMessage, openFile, openBranchDiff, runGitAction } = state const ioBusy = busyAction !== null || openingPath !== null || openingBranchPath !== null const shouldShowGenerateButton = stagedCount > 0 || generatingMessage const createPrHeroActive = createPrAction.visible && !createPrAction.disabled && !createPrAction.pushFirst const branchCompareFooter = ( ) return ( <> {connState !== 'connected' ? ( // Why: once data has loaded the screen looks alive even when the // desktop link is down, so taps appear to do nothing (STA-1511). // Surface the reconnect state where the user is looking. Reconnecting to desktop... ) : null} {commitFailureRecovery ? ( ) : actionError ? ( {actionError} ) : null} [ styles.bulkButton, (stageablePaths.length === 0 || ioBusy) && styles.bulkButtonDisabled, pressed && styles.bulkButtonPressed ]} onPress={() => void stageAll()} disabled={ioBusy || stageablePaths.length === 0} > {busyAction === 'stage-all' ? ( ) : ( )} Stage All [ styles.bulkButton, (unstageablePaths.length === 0 || ioBusy) && styles.bulkButtonDisabled, pressed && styles.bulkButtonPressed ]} onPress={() => void unstageAll()} disabled={ioBusy || unstageablePaths.length === 0} > {busyAction === 'unstage-all' ? ( ) : ( )} Unstage All [ styles.bulkMenuButton, pressed && styles.bulkButtonPressed, ioBusy && styles.bulkButtonDisabled ]} onPress={() => setShowActionSheet(true)} disabled={ioBusy} hitSlop={8} accessibilityLabel="Open source control actions" > {!hasVisibleChanges ? ( No local changes Working tree is clean. ) : sections.length === 0 ? ( // Why: RN SectionList with empty `sections` often skips ListFooterComponent, // which hid "Committed on Branch" when only branch files remain. {branchCompareFooter} ) : ( `${item.area}:${item.path}:${item.oldPath ?? ''}`} renderSectionHeader={({ section }) => ( {section.title} {section.data.length} )} ListFooterComponent={branchCompareFooter} stickySectionHeadersEnabled={false} contentContainerStyle={styles.listContent} /> )} 0 ? keyboardLift + KEYBOARD_COMMIT_BAR_CLEARANCE : keyboardLift, paddingBottom: keyboardLift > 0 ? spacing.md : spacing.md + insets.bottom } ]} > {stagedCount === 0 ? ( No staged files ) : ( )} {shouldShowGenerateButton ? ( [ styles.generateButton, busyAction !== null && styles.commitButtonDisabled, pressed && styles.commitButtonPressed ]} // Why: commit-message AI belongs to the commit path; hiding it // during Stage All keeps the quick action visually unambiguous. disabled={busyAction !== null} onPress={() => generatingMessage ? cancelGenerateCommitMessage() : void generateCommitMessage() } accessibilityLabel={ generatingMessage ? 'Cancel commit message generation' : 'Generate commit message with AI' } > {generatingMessage ? ( ) : ( )} ) : null} [ styles.commitButton, createPrHeroActive && styles.commitButtonSecondary, primaryAction.disabled && styles.commitButtonDisabled, pressed && styles.commitButtonPressed ]} onPress={primaryAction.onPress} disabled={primaryAction.disabled} accessibilityLabel={primaryAction.accessibilityLabel} accessibilityHint={primaryAction.accessibilityHint} > {primaryAction.loading ? ( ) : ( {primaryAction.label} )} ) }