import { useCallback, useMemo } from "react";
import {
ActivityIndicator,
Dimensions,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useRouter, useLocalSearchParams } from "expo-router";
import {
Canvas,
Image as SkImage,
Shader,
Fill,
useImage,
} from "@shopify/react-native-skia";
import Animated, { FadeIn, FadeInUp } from "react-native-reanimated";
import { ArrowLeft, Check, Export } from "phosphor-react-native";
import { GlassBottomSheet, GlassButton, GlassCard, GlassPill, GlassSlider } from "@/components/glass";
import { useWallpaperStore } from "@/stores/wallpaper.store";
import { useAnimation } from "@/hooks/useAnimation";
import { useGyroscope } from "@/hooks/useGyroscope";
import { useWallpaperExport } from "@/hooks/useWallpaperExport";
import { shaders } from "@/shaders";
import {
ANIMATION_META,
type AnimationType,
} from "@/types/wallpaper";
import { colors, typography, spacing, layout } from "@/theme";
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("window");
const AVAILABLE_ANIMATIONS: AnimationType[] = [
"ken-burns",
"color-shift",
"particles",
"vignette-pulse",
"glitch",
];
export default function EditorScreen() {
const insets = useSafeAreaInsets();
const router = useRouter();
const { id } = useLocalSearchParams<{ id: string }>();
const {
sourceUri,
animation,
uniforms,
particlePreset,
setAnimation,
setUniform,
setParticlePreset,
saveWallpaper,
} = useWallpaperStore();
const { time } = useAnimation(animation, uniforms);
const gyro = useGyroscope(animation === "depth-parallax");
const { status, exportAsWallpaper } = useWallpaperExport();
const image = useImage(sourceUri);
const shader = useMemo(() => shaders[animation], [animation]);
const handleApply = useCallback(async () => {
const config = saveWallpaper();
if (config) {
await exportAsWallpaper(config);
}
}, [saveWallpaper, exportAsWallpaper]);
const handleSaveOnly = useCallback(() => {
saveWallpaper();
router.back();
}, [saveWallpaper, router]);
// No image selected — redirect back
if (!sourceUri) {
return (
Aucune image sélectionnée
Retournez à la galerie pour choisir une photo
router.back()}
variant="primary"
size="md"
/>
);
}
// Image loading
if (!image) {
return (
Chargement de l'image...
);
}
return (
{/* Full-screen animated preview */}
{/* Top bar overlay */}
router.back()} style={styles.iconButton}>
{/* Bottom sheet with controls */}
{/* Animation selector */}
Animation
{AVAILABLE_ANIMATIONS.map((type) => (
setAnimation(type)}
/>
))}
{/* Particle preset selector (only for particles animation) */}
{animation === "particles" && (
<>
Style
{(["snow", "rain", "bokeh"] as const).map((preset) => (
setParticlePreset(preset)}
/>
))}
>
)}
{/* Uniform controls */}
setUniform("intensity", v)}
/>
setUniform("speed", v)}
/>
{(animation === "ken-burns" || animation === "glitch") && (
setUniform("direction", v)}
formatValue={(v) => `${Math.round((v * 180) / Math.PI)}°`}
/>
)}
{/* Export button */}
) : undefined
}
/>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
},
centered: {
justifyContent: "center",
alignItems: "center",
paddingHorizontal: layout.screenPadding,
},
canvas: {
position: "absolute",
top: 0,
left: 0,
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
},
topBar: {
position: "absolute",
left: 16,
right: 16,
flexDirection: "row",
justifyContent: "space-between",
zIndex: 10,
},
iconButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "rgba(0, 0, 0, 0.4)",
borderWidth: 1,
borderColor: colors.glass.border,
alignItems: "center",
justifyContent: "center",
},
animationScroll: {
marginBottom: spacing.lg,
},
controls: {
marginBottom: spacing.lg,
},
ctaContainer: {
marginTop: spacing.sm,
},
});