import * as Haptics from "expo-haptics"; import { GlassView } from "expo-glass-effect"; import { SymbolView } from "../../components/AppSymbol"; import { useCallback, useEffect, useRef } from "react"; import { ActivityIndicator, Pressable, StyleSheet, useColorScheme, View } from "react-native"; import Animated, { FadeIn, FadeOut, LinearTransition } from "react-native-reanimated"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { AppText as Text } from "../../components/AppText"; import { APP_BAR_HEIGHT } from "../../lib/layoutMetrics"; import { themeColorWithAlpha } from "../../lib/mobileTheme"; import { tryOpenExternalUrl } from "../../lib/openExternalUrl"; import { useUniwindTheme } from "../../lib/useUniwindTheme"; import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import type { GitActionProgress } from "../../state/use-vcs-action-state"; const OVERLAY_LAYOUT_TRANSITION = LinearTransition.duration(220); const OVERLAY_TOP_GAP = 8; const AnimatedGlassView = Animated.createAnimatedComponent(GlassView); export function GitActionProgressOverlay(props: { readonly progress: GitActionProgress; readonly onDismiss: () => void; }) { const { progress, onDismiss } = props; const insets = useSafeAreaInsets(); const prevPhaseRef = useRef(progress.phase); useEffect(() => { const prev = prevPhaseRef.current; prevPhaseRef.current = progress.phase; if (prev === "running" && progress.phase === "success") { Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); } else if (prev === "running" && progress.phase === "error") { Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); } }, [progress.phase]); const handlePress = useCallback(() => { if (progress.prUrl) { void tryOpenExternalUrl(progress.prUrl, "pull-request"); return; } if (progress.phase === "success" || progress.phase === "error") { onDismiss(); } }, [onDismiss, progress.phase, progress.prUrl]); if (progress.phase === "idle") { return null; } return ( ); } function OverlayContent(props: { readonly progress: GitActionProgress }) { const { progress } = props; const colors = useUniwindTheme(); const glassSurface = colors["--color-glass-surface"]; const foreground = colors["--color-foreground"]; const shadowColor = colors["--color-primary-shadow"]; const isDarkMode = useColorScheme() === "dark"; const glassTint = themeColorWithAlpha(String(glassSurface), isDarkMode ? 0.48 : 0.38); const glassBorder = themeColorWithAlpha(String(foreground), isDarkMode ? 0.18 : 0.12); const content = ( <> {progress.label ? ( {progress.label} ) : null} {progress.description ? ( {progress.description} ) : null} {progress.prUrl ? ( ) : null} ); if (NATIVE_LIQUID_GLASS_SUPPORTED) { return ( {content} ); } const bgClass = progress.phase === "error" ? "border-danger-border bg-danger" : "bg-card border-border"; return ( {content} ); } function OverlayIcon(props: { readonly phase: GitActionProgress["phase"] }) { switch (props.phase) { case "running": return ; case "success": return ( ); case "error": return ( ); default: return null; } }