feat: add reusable AnimationCanvas component
Standalone Skia canvas for wallpaper thumbnail previews with configurable FPS cap for battery efficiency.
This commit is contained in:
82
src/components/animation/AnimationCanvas.tsx
Normal file
82
src/components/animation/AnimationCanvas.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { StyleSheet, ViewStyle } from "react-native";
|
||||
import {
|
||||
Canvas,
|
||||
Image as SkImage,
|
||||
Shader,
|
||||
Fill,
|
||||
useImage,
|
||||
} from "@shopify/react-native-skia";
|
||||
import { useSharedValue, useFrameCallback } from "react-native-reanimated";
|
||||
import { shaders } from "@/shaders";
|
||||
import type { AnimationType, AnimationUniforms } from "@/types/wallpaper";
|
||||
|
||||
interface AnimationCanvasProps {
|
||||
sourceUri: string;
|
||||
animation: AnimationType;
|
||||
uniforms: AnimationUniforms;
|
||||
width: number;
|
||||
height: number;
|
||||
fps?: number;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standalone animated preview canvas.
|
||||
* Used in wallpaper cards on the home screen (mini previews at reduced FPS).
|
||||
*/
|
||||
export function AnimationCanvas({
|
||||
sourceUri,
|
||||
animation,
|
||||
uniforms,
|
||||
width,
|
||||
height,
|
||||
fps = 15,
|
||||
style,
|
||||
}: AnimationCanvasProps) {
|
||||
const image = useImage(sourceUri);
|
||||
const shader = useMemo(() => shaders[animation], [animation]);
|
||||
const time = useSharedValue(0);
|
||||
|
||||
const frameInterval = 1000 / fps;
|
||||
let lastFrame = 0;
|
||||
|
||||
useFrameCallback((info) => {
|
||||
const now = info.timeSinceFirstFrame ?? 0;
|
||||
if (now - lastFrame >= frameInterval) {
|
||||
time.value = now / 1000;
|
||||
lastFrame = now;
|
||||
}
|
||||
});
|
||||
|
||||
if (!image || !shader) return null;
|
||||
|
||||
return (
|
||||
<Canvas style={[{ width, height }, style]}>
|
||||
<Fill>
|
||||
<Shader
|
||||
source={shader}
|
||||
uniforms={{
|
||||
resolution: [width, height],
|
||||
time: time.value,
|
||||
intensity: uniforms.intensity,
|
||||
speed: uniforms.speed,
|
||||
direction: uniforms.direction ?? 0,
|
||||
particleType: 0,
|
||||
gyroX: 0,
|
||||
gyroY: 0,
|
||||
}}
|
||||
>
|
||||
<SkImage
|
||||
image={image}
|
||||
x={0}
|
||||
y={0}
|
||||
width={width}
|
||||
height={height}
|
||||
fit="cover"
|
||||
/>
|
||||
</Shader>
|
||||
</Fill>
|
||||
</Canvas>
|
||||
);
|
||||
}
|
||||
1
src/components/animation/index.ts
Normal file
1
src/components/animation/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { AnimationCanvas } from "./AnimationCanvas";
|
||||
Reference in New Issue
Block a user