feat(wallpaper): add apply_wallpaper workflow and rotation worker

Adds a new apply_wallpaper command and its plumbing across
desktop, mobile, and Android. A WorkManager-based rotation
worker handles applying wallpapers in the background. Wallpaper
state now tracks currentId and imageIds for precise control.

- Introduced apply_wallpaper command across desktop, mobile and Android
- Added WorkManager-based rotation worker to apply wallpapers in the
  background
- Extended wallpaper state with currentId and imageIds and updated schemas/permissions
This commit is contained in:
2026-08-21 23:15:00 +02:00
parent e494b17117
commit 73f8599c7f
25 changed files with 266 additions and 49 deletions
+21 -1
View File
@@ -7,6 +7,8 @@ export type WallpaperState = {
shuffle: boolean;
lockScreenOnly: boolean;
currentIndex: number;
currentId: string | null;
imageIds: string[];
imageUrls: string[];
};
@@ -67,6 +69,8 @@ const demoState: WallpaperState = {
shuffle: true,
lockScreenOnly: true,
currentIndex: 0,
currentId: "demo-0",
imageIds: ["demo-0", "demo-1", "demo-2"],
imageUrls: ["/wallpapers/alpine.png", "/wallpapers/waterfall.png", "/wallpapers/coast.png"],
};
@@ -102,6 +106,8 @@ export async function deleteImage(id: string): Promise<WallpaperState> {
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] };
}
@@ -117,6 +123,8 @@ export async function deleteImages(ids: string[]): Promise<WallpaperState> {
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] };
}
@@ -156,12 +164,24 @@ export async function setIntervalMinutes(value: number) {
export async function nextWallpaper(): Promise<WallpaperState> {
if (!inTauri()) {
demoState.currentIndex = (demoState.currentIndex + 1) % demoState.imageUrls.length;
if (demoState.imageUrls.length) demoState.currentIndex = (demoState.currentIndex + 1) % demoState.imageUrls.length;
demoState.currentId = demoState.imageIds[demoState.currentIndex] ?? null;
return { ...demoState };
}
return invoke<WallpaperState>("plugin:wallpaper|next_wallpaper");
}
export async function applyWallpaper(id: string): Promise<WallpaperState> {
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<WallpaperState>("plugin:wallpaper|apply_wallpaper", { id });
}
export async function getImmichConnection(): Promise<ImmichConnection> {
return inTauri() ? invoke<ImmichConnection>("plugin:wallpaper|get_immich_connection") : demoImmichConnection;
}