Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 16 additions & 57 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,18 @@
setExtendedColors,
setNativeColors,
setIconTheme,
setAdjustments,
setColor,
setExtendedColor,
setAppOverride,
setAppOverrides,
setAdditionalImages,
setLightMode,
setExtractionMode,
applyBackendState,
getThemeSnapshot,
getThemeSignature,
getLastAppliedSignature,
getIsApplying,
getIsAdjusting,
getIsExtracting,
setLastExtractedPath,
type BackendStatePayload,
} from '$lib/stores/theme.svelte';
import {debounce} from '$lib/utils/debounce';
import {STORAGE_KEYS} from '$lib/constants/storage';
Expand Down Expand Up @@ -156,10 +153,15 @@
.catch(() => {});
}, STATE_SYNC_DEBOUNCE_MS);

// Send only snapshots that differ from the last mirrored state, so a
// backend push of equal values does not cause another SyncState call.
let lastSyncedSignature = '';
$effect(() => {
syncStateToBackend(
getThemeSnapshot() as unknown as main.SyncStateRequest
);
const snapshot = getThemeSnapshot();
const signature = getThemeSignature(snapshot);
if (signature === lastSyncedSignature) return;
lastSyncedSignature = signature;
syncStateToBackend(snapshot as unknown as main.SyncStateRequest);
});

// Arming records the initial state without applying it. Queuing is not an
Expand Down Expand Up @@ -553,55 +555,12 @@
}
} catch {}

// Listen for IPC remote control state changes
EventsOn(
'ipc-state-changed',
(state: {
palette?: string[];
extendedColors?: Record<string, string>;
nativeColors?: Record<string, string>;
iconTheme?: {mode?: string; id?: string};
lightMode?: boolean;
mode?: string;
wallpaper?: string;
wallpaperBlur?: boolean;
adjustments?: import('$lib/types/theme').Adjustments;
appOverrides?: Record<string, Record<string, string>>;
additionalImages?: string[];
}) => {
if (state.palette && state.palette.length >= 16) {
setPalette(state.palette);
}
if (state.extendedColors) {
setExtendedColors(state.extendedColors);
}
if (state.nativeColors) {
setNativeColors(state.nativeColors);
}
if (state.iconTheme)
setIconTheme(state.iconTheme, true);
if (state.lightMode !== undefined) {
setLightMode(state.lightMode);
}
if (state.mode) {
setExtractionMode(state.mode);
}
if (state.wallpaper !== undefined) {
setWallpaperPath(state.wallpaper);
}
if (state.wallpaperBlur !== undefined)
setWallpaperBlur(state.wallpaperBlur, true);
if (state.adjustments) {
setAdjustments(state.adjustments);
}
if (state.appOverrides) {
setAppOverrides(state.appOverrides);
}
if (state.additionalImages) {
setAdditionalImages(state.additionalImages);
}
}
);
// Listen for IPC remote control state changes. The applier
// skips fields that already match, so an echo of our own
// SyncState cannot re-arm the sync effect above.
EventsOn('ipc-state-changed', (state: BackendStatePayload) => {
applyBackendState(state);
});
} catch {}
})();
});
Expand Down
19 changes: 17 additions & 2 deletions frontend/src/lib/actions/blueprintActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
setAdditionalImages,
setLastExtractedPath,
setLockedColor,
dedupeAdditionalImages,
} from '$lib/stores/theme.svelte';

export function loadBlueprintIntoEditor(bp: Blueprint): void {
Expand All @@ -36,11 +37,25 @@ export function loadBlueprintIntoEditor(bp: Blueprint): void {
setWallpaperPath(bp.palette.wallpaper ?? '');
setWallpaperBlur(!!bp.palette.wallpaperBlur, true);
setAppOverrides(bp.appOverrides ?? {});
setAdditionalImages(bp.palette.additionalImages ?? []);
// Blueprints can list the same wallpaper twice, or two wallpapers sharing a
// filename; the backend stages them into one flat directory and rejects
// such a set with a basename collision, so drop the unusable entries and
// tell the user instead of failing the later apply.
const requestedImages = bp.palette.additionalImages ?? [];
const uniqueImages = dedupeAdditionalImages(
requestedImages,
bp.palette.wallpaper ?? ''
);
setAdditionalImages(uniqueImages);
setLastExtractedPath(bp.palette.wallpaper ?? '');
for (let i = 0; i < 16; i++) {
setLockedColor(i, bp.palette.lockedColors?.includes(i) ?? false);
}
setActiveTab('editor');
showToast(`Loaded: ${bp.name}. Review, then apply when ready.`);
const skippedImages = requestedImages.length - uniqueImages.length;
showToast(
skippedImages > 0
? `Loaded: ${bp.name}. Skipped ${skippedImages} duplicate wallpaper${skippedImages === 1 ? '' : 's'}.`
: `Loaded: ${bp.name}. Review, then apply when ready.`
);
}
11 changes: 8 additions & 3 deletions frontend/src/lib/components/editor/AdditionalImages.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@
);
const path = await OpenFileDialog();
if (path) {
addAdditionalImage(path);
showToast('Image added');
showToast(
addAdditionalImage(path)
? 'Image added'
: 'Skipped: the theme already has a wallpaper with that filename'
);
}
} catch {}
}
Expand Down Expand Up @@ -73,7 +76,9 @@
</div>

<div class="grid grid-cols-2 gap-2 px-3.5 pb-3.5 pt-3">
{#each getAdditionalImages() as img (img)}
<!-- Unkeyed on purpose. A keyed each throws on a repeated path,
and that error stopped every later effect (issue #130). -->
{#each getAdditionalImages() as img}
<div
class="border-border group relative aspect-video overflow-hidden border bg-black"
>
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/lib/components/favorites/FavoritesView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,11 @@
showToast('Already in additional images');
return;
}
addAdditionalImage(localPath);
showToast('Added to additional images');
showToast(
addAdditionalImage(localPath)
? 'Added to additional images'
: 'Skipped: the theme already has a wallpaper with that filename'
);
}

async function resolvePreviewSrc(fav: Favorite): Promise<string> {
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/lib/components/github/GitHubCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@
showToast('Already in additional images');
return;
}
addAdditionalImage(path);
showToast('Added to additional images');
showToast(
addAdditionalImage(path)
? 'Added to additional images'
: 'Skipped: the theme already has a wallpaper with that filename'
);
} else {
setWallpaperPath(path);
setActiveTab('editor');
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/lib/components/local/LocalBrowser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,11 @@
showToast('Already in additional images');
return;
}
addAdditionalImage(path);
showToast('Added to additional images');
showToast(
addAdditionalImage(path)
? 'Added to additional images'
: 'Skipped: the theme already has a wallpaper with that filename'
);
}

async function handleFavorite(wp: Wallpaper) {
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/lib/components/wallhaven/WallpaperCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@
showToast('Already in additional images');
return;
}
addAdditionalImage(localPath);
showToast('Added to additional images');
showToast(
addAdditionalImage(localPath)
? 'Added to additional images'
: 'Skipped: the theme already has a wallpaper with that filename'
);
} catch {
showToast('Failed to download wallpaper');
}
Expand Down
Loading