feat: add Zustand stores with MMKV persistence
Wallpaper store (editor state, saved wallpapers, CRUD) and settings store (export quality, FPS, haptics, auto depth map).
This commit is contained in:
55
src/stores/settings.store.ts
Normal file
55
src/stores/settings.store.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { createMMKV } from "react-native-mmkv";
|
||||||
|
|
||||||
|
const storage = createMMKV({ id: "lively-settings" });
|
||||||
|
|
||||||
|
interface SettingsState {
|
||||||
|
exportQuality: "low" | "medium" | "high";
|
||||||
|
fps: 15 | 24 | 30;
|
||||||
|
hapticFeedback: boolean;
|
||||||
|
autoDepthMap: boolean;
|
||||||
|
|
||||||
|
setExportQuality: (quality: "low" | "medium" | "high") => void;
|
||||||
|
setFps: (fps: 15 | 24 | 30) => void;
|
||||||
|
setHapticFeedback: (enabled: boolean) => void;
|
||||||
|
setAutoDepthMap: (enabled: boolean) => void;
|
||||||
|
loadSettings: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSettingsStore = create<SettingsState>((set) => ({
|
||||||
|
exportQuality: "high",
|
||||||
|
fps: 24,
|
||||||
|
hapticFeedback: true,
|
||||||
|
autoDepthMap: false,
|
||||||
|
|
||||||
|
setExportQuality: (quality) => {
|
||||||
|
storage.set("exportQuality", quality);
|
||||||
|
set({ exportQuality: quality });
|
||||||
|
},
|
||||||
|
setFps: (fps) => {
|
||||||
|
storage.set("fps", fps);
|
||||||
|
set({ fps });
|
||||||
|
},
|
||||||
|
setHapticFeedback: (enabled) => {
|
||||||
|
storage.set("hapticFeedback", enabled);
|
||||||
|
set({ hapticFeedback: enabled });
|
||||||
|
},
|
||||||
|
setAutoDepthMap: (enabled) => {
|
||||||
|
storage.set("autoDepthMap", enabled);
|
||||||
|
set({ autoDepthMap: enabled });
|
||||||
|
},
|
||||||
|
|
||||||
|
loadSettings: () => {
|
||||||
|
const quality = storage.getString("exportQuality");
|
||||||
|
const fps = storage.getNumber("fps");
|
||||||
|
const haptic = storage.getBoolean("hapticFeedback");
|
||||||
|
const autoDepth = storage.getBoolean("autoDepthMap");
|
||||||
|
|
||||||
|
set({
|
||||||
|
...(quality && { exportQuality: quality as "low" | "medium" | "high" }),
|
||||||
|
...(fps && { fps: fps as 15 | 24 | 30 }),
|
||||||
|
...(haptic !== undefined && { hapticFeedback: haptic }),
|
||||||
|
...(autoDepth !== undefined && { autoDepthMap: autoDepth }),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}));
|
||||||
110
src/stores/wallpaper.store.ts
Normal file
110
src/stores/wallpaper.store.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { createMMKV } from "react-native-mmkv";
|
||||||
|
import type {
|
||||||
|
AnimationType,
|
||||||
|
AnimationUniforms,
|
||||||
|
WallpaperConfig,
|
||||||
|
ParticlePreset,
|
||||||
|
} from "@/types/wallpaper";
|
||||||
|
|
||||||
|
const storage = createMMKV({ id: "lively-wallpapers" });
|
||||||
|
|
||||||
|
interface WallpaperState {
|
||||||
|
// Current editing session
|
||||||
|
sourceUri: string | null;
|
||||||
|
depthMapUri: string | null;
|
||||||
|
animation: AnimationType;
|
||||||
|
uniforms: AnimationUniforms;
|
||||||
|
particlePreset: ParticlePreset;
|
||||||
|
|
||||||
|
// Saved wallpapers
|
||||||
|
savedWallpapers: WallpaperConfig[];
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
setSourceImage: (uri: string) => void;
|
||||||
|
setDepthMap: (uri: string | null) => void;
|
||||||
|
setAnimation: (type: AnimationType) => void;
|
||||||
|
setUniform: (key: string, value: number) => void;
|
||||||
|
setParticlePreset: (preset: ParticlePreset) => void;
|
||||||
|
resetEditor: () => void;
|
||||||
|
saveWallpaper: () => WallpaperConfig | null;
|
||||||
|
deleteWallpaper: (id: string) => void;
|
||||||
|
loadSavedWallpapers: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_UNIFORMS_VALUES: AnimationUniforms = {
|
||||||
|
intensity: 0.5,
|
||||||
|
speed: 0.3,
|
||||||
|
direction: 0,
|
||||||
|
scale: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useWallpaperStore = create<WallpaperState>((set, get) => ({
|
||||||
|
sourceUri: null,
|
||||||
|
depthMapUri: null,
|
||||||
|
animation: "ken-burns",
|
||||||
|
uniforms: { ...DEFAULT_UNIFORMS_VALUES },
|
||||||
|
particlePreset: "snow",
|
||||||
|
savedWallpapers: [],
|
||||||
|
|
||||||
|
setSourceImage: (uri) => set({ sourceUri: uri }),
|
||||||
|
setDepthMap: (uri) => set({ depthMapUri: uri }),
|
||||||
|
setAnimation: (type) => set({ animation: type }),
|
||||||
|
setUniform: (key, value) =>
|
||||||
|
set((state) => ({
|
||||||
|
uniforms: { ...state.uniforms, [key]: value },
|
||||||
|
})),
|
||||||
|
setParticlePreset: (preset) => set({ particlePreset: preset }),
|
||||||
|
|
||||||
|
resetEditor: () =>
|
||||||
|
set({
|
||||||
|
sourceUri: null,
|
||||||
|
depthMapUri: null,
|
||||||
|
animation: "ken-burns",
|
||||||
|
uniforms: { ...DEFAULT_UNIFORMS_VALUES },
|
||||||
|
particlePreset: "snow",
|
||||||
|
}),
|
||||||
|
|
||||||
|
saveWallpaper: () => {
|
||||||
|
const { sourceUri, depthMapUri, animation, uniforms, particlePreset } = get();
|
||||||
|
if (!sourceUri) return null;
|
||||||
|
|
||||||
|
const config: WallpaperConfig = {
|
||||||
|
id: `wp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
||||||
|
sourceUri,
|
||||||
|
depthMapUri: depthMapUri ?? undefined,
|
||||||
|
animation,
|
||||||
|
uniforms: { ...uniforms },
|
||||||
|
particlePreset: animation === "particles" ? particlePreset : undefined,
|
||||||
|
fps: 24,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
set((state) => {
|
||||||
|
const updated = [config, ...state.savedWallpapers];
|
||||||
|
storage.set("wallpapers", JSON.stringify(updated));
|
||||||
|
return { savedWallpapers: updated };
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteWallpaper: (id) =>
|
||||||
|
set((state) => {
|
||||||
|
const updated = state.savedWallpapers.filter((w) => w.id !== id);
|
||||||
|
storage.set("wallpapers", JSON.stringify(updated));
|
||||||
|
return { savedWallpapers: updated };
|
||||||
|
}),
|
||||||
|
|
||||||
|
loadSavedWallpapers: () => {
|
||||||
|
const raw = storage.getString("wallpapers");
|
||||||
|
if (raw) {
|
||||||
|
try {
|
||||||
|
set({ savedWallpapers: JSON.parse(raw) });
|
||||||
|
} catch {
|
||||||
|
storage.remove("wallpapers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
Reference in New Issue
Block a user