import * as Haptics from "expo-haptics";
import { isLiquidGlassSupported, LiquidGlassView } from "@callstack/liquid-glass";
import { SymbolView } from "../../components/AppSymbol";
import { useCallback, useEffect, useRef } from "react";
import { ActivityIndicator, Pressable, StyleSheet, 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 { tryOpenExternalUrl } from "../../lib/openExternalUrl";
import { useThemeColor } from "../../lib/useThemeColor";
import type { GitActionProgress } from "../../state/use-vcs-action-state";
import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider";
const OVERLAY_LAYOUT_TRANSITION = LinearTransition.duration(220);
const OVERLAY_TOP_GAP = 8;
const AnimatedLiquidGlassView = Animated.createAnimatedComponent(LiquidGlassView);
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 iconColor = useThemeColor("--color-icon");
const glassBorder = useThemeColor("--color-header-border");
const glassTint = useThemeColor("--color-glass-tint");
const { themeAppearance } = useAppearancePreferences();
const isDarkMode = themeAppearance === "dark";
const content = (
<>
{progress.label ? (
{progress.label}
) : null}
{progress.description ? (
{progress.description}
) : null}
{progress.prUrl ? (
) : null}
>
);
if (isLiquidGlassSupported) {
return (
{content}
);
}
const bgClass =
progress.phase === "error"
? "bg-red-50 dark:bg-red-950/80 border-red-200 dark:border-red-800"
: "bg-card border-border";
return (
{content}
);
}
function OverlayIcon(props: {
readonly phase: GitActionProgress["phase"];
readonly iconColor: ReturnType;
}) {
switch (props.phase) {
case "running":
return ;
case "success":
return (
);
case "error":
return (
);
default:
return null;
}
}