Files
lively/src/hooks/useWallpaperExport.ts
Mathis Pruvot 1a2fa0ffb5 feat: add animation, gyroscope, and wallpaper export hooks
useAnimation drives shader uniforms via Reanimated frame
callbacks. useGyroscope accumulates device rotation with
spring damping. useWallpaperExport bridges to native modules
with platform detection and Expo Go fallback.
2026-05-28 11:49:29 +00:00

148 lines
4.2 KiB
TypeScript

import { useState, useCallback } from "react";
import { Platform, Alert } from "react-native";
import type { WallpaperConfig } from "@/types/wallpaper";
type ExportStatus = "idle" | "preparing" | "exporting" | "success" | "error";
interface ExportResult {
status: ExportStatus;
progress: number;
error: string | null;
exportAsWallpaper: (config: WallpaperConfig) => Promise<void>;
}
export function useWallpaperExport(): ExportResult {
const [status, setStatus] = useState<ExportStatus>("idle");
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const exportAsWallpaper = useCallback(async (config: WallpaperConfig) => {
try {
setStatus("preparing");
setProgress(0);
setError(null);
if (Platform.OS === "android") {
await exportAndroid(config, setProgress, setStatus);
} else if (Platform.OS === "ios") {
await exportIOS(config, setProgress, setStatus);
} else {
throw new Error("Platform non supportée. Utilisez Android ou iOS.");
}
setStatus("success");
setProgress(1);
} catch (err) {
const message = err instanceof Error ? err.message : "Échec de l'export";
setError(message);
setStatus("error");
Alert.alert("Erreur d'export", message);
}
}, []);
return { status, progress, error, exportAsWallpaper };
}
async function exportAndroid(
config: WallpaperConfig,
onProgress: (p: number) => void,
onStatus: (s: ExportStatus) => void
) {
// Lazy-load native module (only available on Android device builds)
let WallpaperAndroid: typeof import("../../modules/wallpaper-android/src/WallpaperAndroidModule").WallpaperAndroid;
try {
WallpaperAndroid =
require("../../modules/wallpaper-android/src/WallpaperAndroidModule").WallpaperAndroid;
} catch {
Alert.alert(
"Module non disponible",
"Le module natif Android n'est pas disponible dans Expo Go. Créez un development build avec `npx expo run:android`.",
);
return;
}
// Check support
const supported = WallpaperAndroid.isLiveWallpaperSupported();
if (!supported) {
throw new Error("Les live wallpapers ne sont pas supportés sur cet appareil.");
}
onProgress(0.2);
onStatus("exporting");
// Save config to SharedPreferences (read by LiveWallpaperService)
const configJson = JSON.stringify({
sourceUri: config.sourceUri,
depthMapUri: config.depthMapUri ?? "",
animation: config.animation,
uniforms: config.uniforms,
fps: config.fps,
});
await WallpaperAndroid.saveConfig(configJson);
onProgress(0.6);
// Launch system wallpaper picker
await WallpaperAndroid.setLiveWallpaper();
onProgress(1.0);
}
async function exportIOS(
config: WallpaperConfig,
onProgress: (p: number) => void,
onStatus: (s: ExportStatus) => void
) {
let LivePhoto: typeof import("../../modules/livephoto-ios/src/LivePhotoModule").LivePhoto;
try {
LivePhoto =
require("../../modules/livephoto-ios/src/LivePhotoModule").LivePhoto;
} catch {
Alert.alert(
"Module non disponible",
"Le module natif iOS n'est pas disponible dans Expo Go. Créez un development build avec `npx expo run:ios`.",
);
return;
}
// Check/request photo library permission
let permission = await LivePhoto.checkPermission();
if (permission === "undetermined") {
permission = await LivePhoto.requestPermission();
}
if (permission !== "granted") {
throw new Error(
"Accès à la photothèque refusé. Activez-le dans Réglages > Lively > Photos."
);
}
onProgress(0.1);
onStatus("exporting");
const configJson = JSON.stringify({
sourceUri: config.sourceUri,
depthMapUri: config.depthMapUri ?? "",
animation: config.animation,
uniforms: config.uniforms,
fps: config.fps,
});
onProgress(0.3);
// Generate Live Photo (HEIC + MOV) and save to photo library
await LivePhoto.exportLivePhoto(configJson);
onProgress(0.9);
// Guide user to apply the wallpaper
Alert.alert(
"Live Photo sauvegardée",
"Pour l'appliquer comme fond d'écran :\n\n" +
"Réglages > Fond d'écran > Ajouter\n" +
"> Photos > Sélectionnez votre Live Photo\n" +
"> Activez « Live Photo »",
[{ text: "OK" }]
);
onProgress(1.0);
}