import { invoke } from "@tauri-apps/api/core"; export type WallpaperState = { imageCount: number; enabled: boolean; intervalMinutes: number; shuffle: boolean; lockScreenOnly: boolean; allowMobileData: boolean; prefetchImmich: boolean; currentIndex: number; currentId: string | null; imageIds: string[]; imageUrls: string[]; }; export type GalleryImage = { id: string; url: string; selected: boolean; cropMode: "cover" | "contain"; cropZoom: number; cropPositionX: number; cropPositionY: number; cropRotation: number; }; export type GalleryPage = { total: number; items: GalleryImage[]; }; export type ImmichConnection = { configured: boolean; serverUrl: string; userName: string; }; export type ImmichAlbum = { id: string; name: string; assetCount: number; thumbnailUrl: string; }; export type ImmichAsset = { id: string; fileName: string; thumbnailUrl: string; takenAt: string; }; export type ImmichAssetsPage = { items: ImmichAsset[]; page: number; hasMore: boolean; }; export type ImmichImportProgress = { active: boolean; completed: number; total: number; bytesDownloaded: number; bytesTotal: number; }; const demoState: WallpaperState = { imageCount: 3, enabled: true, intervalMinutes: 30, shuffle: true, lockScreenOnly: true, allowMobileData: false, prefetchImmich: true, currentIndex: 0, currentId: "demo-0", imageIds: ["demo-0", "demo-1", "demo-2"], imageUrls: ["/wallpapers/alpine.png", "/wallpapers/waterfall.png", "/wallpapers/coast.png"], }; const inTauri = () => "__TAURI_INTERNALS__" in window; const demoCrops = new Map>(); const defaultCrop = { cropMode: "cover" as const, cropZoom: 1, cropPositionX: 0.5, cropPositionY: 0.5, cropRotation: 0 }; let demoImmichConnection: ImmichConnection = { configured: false, serverUrl: "", userName: "" }; export async function getState(): Promise { return inTauri() ? invoke("plugin:wallpaper|get_state") : demoState; } export async function getGallery(offset = 0, limit = 48): Promise { if (inTauri()) return invoke("plugin:wallpaper|get_gallery", { offset, limit }); return { total: demoState.imageUrls.length, items: demoState.imageUrls.slice(offset, offset + limit).map((url, index) => { const id = `demo-${offset + index}`; return { id, url, selected: offset + index === demoState.currentIndex, ...(demoCrops.get(id) ?? defaultCrop) }; }), }; } export async function selectImages(): Promise { if (!inTauri()) return demoState; return invoke("plugin:wallpaper|select_images"); } export async function deleteImage(id: string): Promise { if (inTauri()) return invoke("plugin:wallpaper|delete_image", { id }); const index = Number(id.replace("demo-", "")); if (Number.isInteger(index) && index >= 0 && index < demoState.imageUrls.length) { demoState.imageUrls.splice(index, 1); demoState.imageCount = demoState.imageUrls.length; demoState.currentIndex = Math.min(demoState.currentIndex, Math.max(0, demoState.imageCount - 1)); demoState.imageIds = demoState.imageUrls.map((_, itemIndex) => `demo-${itemIndex}`); demoState.currentId = demoState.imageIds[demoState.currentIndex] ?? null; } return { ...demoState, imageUrls: [...demoState.imageUrls] }; } export async function getImageIds(): Promise { if (inTauri()) return invoke("plugin:wallpaper|get_image_ids"); return demoState.imageUrls.map((_, index) => `demo-${index}`); } export async function deleteImages(ids: string[]): Promise { if (inTauri()) return invoke("plugin:wallpaper|delete_images", { ids }); const indexes = new Set(ids.map(id => Number(id.replace("demo-", ""))).filter(Number.isInteger)); demoState.imageUrls = demoState.imageUrls.filter((_, index) => !indexes.has(index)); demoState.imageCount = demoState.imageUrls.length; demoState.currentIndex = Math.min(demoState.currentIndex, Math.max(0, demoState.imageCount - 1)); demoState.imageIds = demoState.imageUrls.map((_, index) => `demo-${index}`); demoState.currentId = demoState.imageIds[demoState.currentIndex] ?? null; return { ...demoState, imageUrls: [...demoState.imageUrls] }; } export async function setImageCrop(image: GalleryImage): Promise { const payload = { id: image.id, mode: image.cropMode, zoom: image.cropZoom, positionX: image.cropPositionX, positionY: image.cropPositionY, rotation: image.cropRotation, }; if (inTauri()) return invoke("plugin:wallpaper|set_image_crop", payload); demoCrops.set(image.id, { cropMode: image.cropMode, cropZoom: image.cropZoom, cropPositionX: image.cropPositionX, cropPositionY: image.cropPositionY, cropRotation: image.cropRotation, }); return { ...image }; } export async function setSetting(name: "shuffle" | "lockScreenOnly" | "allowMobileData" | "prefetchImmich", value: boolean) { if (!inTauri()) return { ...demoState, [name]: value }; return invoke("plugin:wallpaper|set_setting", { name, value }); } export async function setIntervalMinutes(value: number) { if (!inTauri()) { demoState.intervalMinutes = value; demoState.enabled = value > 0; return { ...demoState }; } return invoke("plugin:wallpaper|set_interval", { minutes: value }); } export async function nextWallpaper(): Promise { if (!inTauri()) { if (demoState.imageUrls.length) demoState.currentIndex = (demoState.currentIndex + 1) % demoState.imageUrls.length; demoState.currentId = demoState.imageIds[demoState.currentIndex] ?? null; return { ...demoState }; } return invoke("plugin:wallpaper|next_wallpaper"); } export async function applyWallpaper(id: string): Promise { if (!inTauri()) { const index = demoState.imageIds.indexOf(id); if (index < 0) throw new Error("Image not found"); demoState.currentIndex = index; demoState.currentId = id; return { ...demoState }; } return invoke("plugin:wallpaper|apply_wallpaper", { id }); } export async function getImmichConnection(): Promise { return inTauri() ? invoke("plugin:wallpaper|get_immich_connection") : demoImmichConnection; } export async function connectImmich(serverUrl: string, apiKey: string): Promise { if (inTauri()) return invoke("plugin:wallpaper|connect_immich", { serverUrl, apiKey }); if (!serverUrl.trim() || !apiKey.trim()) throw new Error("Missing Immich credentials"); demoImmichConnection = { configured: true, serverUrl: serverUrl.trim(), userName: "Demo User" }; return demoImmichConnection; } export async function disconnectImmich(): Promise { if (inTauri()) return invoke("plugin:wallpaper|disconnect_immich"); demoImmichConnection = { configured: false, serverUrl: "", userName: "" }; return demoImmichConnection; } export async function getImmichAlbums(): Promise { if (inTauri()) return (await invoke<{ albums: ImmichAlbum[] }>("plugin:wallpaper|get_immich_albums")).albums; return [{ id: "demo-album", name: "Nature", assetCount: 3, thumbnailUrl: "/wallpapers/alpine.png" }]; } export async function getImmichAssets(albumId: string | null, page = 1, size = 30): Promise { if (inTauri()) return invoke("plugin:wallpaper|get_immich_assets", { albumId, page, size }); return { items: demoState.imageUrls.map((thumbnailUrl, index) => ({ id: `00000000-0000-4000-8000-00000000000${index}`, fileName: `wallpaper-${index + 1}.jpg`, thumbnailUrl, takenAt: "2026-08-21T12:00:00Z", })), page, hasMore: false, }; } export async function importImmichAssets(ids: string[]): Promise { if (inTauri()) return invoke("plugin:wallpaper|import_immich_assets", { ids }); return { ...demoState, imageUrls: [...demoState.imageUrls] }; } export async function getImmichImportProgress(): Promise { if (inTauri()) return invoke("plugin:wallpaper|get_immich_import_progress"); return { active: false, completed: 0, total: 0, bytesDownloaded: 0, bytesTotal: 0 }; }