import { useCallback, useMemo, useRef } from "react"; import { Pressable, Text, View, type PressableStateCallbackType } from "react-native"; import { useQueryClient } from "@tanstack/react-query"; import { ChevronDown, GitBranch } from "lucide-react-native"; import { StyleSheet, withUnistyles } from "react-native-unistyles"; import { useTranslation } from "react-i18next"; import type { Theme } from "@/styles/theme"; import { Combobox, ComboboxItem, type ComboboxProps } from "@/components/ui/combobox"; import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useToast } from "@/contexts/toast-context"; import { useBranchSwitcher } from "@/hooks/use-branch-switcher"; interface BranchSwitcherProps { currentBranchName: string | null; serverId: string; workspaceId: string; workspaceDirectory: string | null; isGitCheckout: boolean; testID?: string; } const foregroundMutedIconColorMapping = (theme: Theme) => ({ color: theme.colors.foregroundMuted, }); const ThemedGitBranch = withUnistyles(GitBranch); const ThemedChevronDown = withUnistyles(ChevronDown); export function BranchSwitcher({ currentBranchName, serverId, workspaceId, workspaceDirectory, isGitCheckout, testID = "workspace-header-branch-switcher", }: BranchSwitcherProps) { const { t } = useTranslation(); const anchorRef = useRef(null); const client = useHostRuntimeClient(serverId); const isConnected = useHostRuntimeIsConnected(serverId); const toast = useToast(); const queryClient = useQueryClient(); const { branchOptions, isOpen, setIsOpen, handleBranchSelect } = useBranchSwitcher({ client, normalizedServerId: serverId, normalizedWorkspaceId: workspaceId, workspaceDirectory, currentBranchName, isGitCheckout, isConnected, toast, queryClient, }); const handleOpen = useCallback(() => setIsOpen(true), [setIsOpen]); const triggerStyle = useCallback( ({ hovered = false, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [ styles.trigger, (Boolean(hovered) || pressed) && styles.triggerHovered, ], [], ); const branchLeadingSlot = useMemo( () => , [], ); const renderBranchOption = useCallback>( ({ option, selected, active, onPress }) => ( ), [branchLeadingSlot], ); if (!currentBranchName) { return null; } return ( {currentBranchName} ); } const styles = StyleSheet.create((theme) => ({ anchor: { flexShrink: 1, minWidth: 0, }, trigger: { flexDirection: "row", alignItems: "center", gap: theme.spacing[1], minWidth: 0, paddingVertical: theme.spacing[1], paddingHorizontal: theme.spacing[2], marginLeft: -theme.spacing[2], borderRadius: theme.borderRadius.md, flexShrink: 1, }, triggerHovered: { backgroundColor: theme.colors.surface1, }, branchLabel: { fontSize: theme.fontSize.sm, color: theme.colors.foreground, fontWeight: theme.fontWeight.medium, flexShrink: 1, }, }));