Replace the remaining ~155 untyped invoke() calls across stores, services, components, and routes with the generated commands.* wrappers from $lib/api/bindings, so every IPC call is compile-time-checked against the command signatures. - Register repository_get_subtitle_url and repository_get_video_download_url in specta_builder() and the invoke_handler; regenerate bindings.ts. - Source duplicated wire types (AutoplaySettings, CacheConfig, Session, ConnectivityStatus, audio/video settings, etc.) from bindings. - Fix two bugs surfaced by the typed wrappers: - VideoDownloadButton passed an un-awaited Promise as the stream URL. - setAutoplaySettings omitted the required userId argument. - Update unit tests asserting the old invoke(name, args) shape. - Remove the five param-naming guard tests; the compiler and codegen now enforce what they checked. svelte-check: 0 errors. vitest: green. cargo test --lib: green.
91 lines
2.2 KiB
Svelte
91 lines
2.2 KiB
Svelte
<script lang="ts">
|
|
import { commands } from "$lib/api/bindings";
|
|
import { auth } from "$lib/stores/auth";
|
|
import { get } from "svelte/store";
|
|
|
|
interface Props {
|
|
itemId: string;
|
|
imageType?: string;
|
|
tag?: string | null;
|
|
maxWidth?: number;
|
|
maxHeight?: number;
|
|
class?: string;
|
|
alt?: string;
|
|
}
|
|
|
|
let {
|
|
itemId,
|
|
imageType = "Primary",
|
|
tag,
|
|
maxWidth,
|
|
maxHeight,
|
|
class: className = "",
|
|
alt = "",
|
|
}: Props = $props();
|
|
|
|
let imageUrl = $state<string | null>(null);
|
|
let loading = $state(true);
|
|
let error = $state(false);
|
|
let lastLoadKey = "";
|
|
|
|
async function loadImage() {
|
|
if (!itemId) {
|
|
loading = false;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
loading = true;
|
|
error = false;
|
|
|
|
// Get repository handle from auth store
|
|
const authState = get(auth);
|
|
if (!authState.isAuthenticated) {
|
|
throw new Error("Not authenticated");
|
|
}
|
|
const repository = auth.getRepository();
|
|
const repositoryHandle = repository.getHandle();
|
|
|
|
// Call Rust to get image as base64 data URL
|
|
const dataUrl = await commands.imageGetUrl(repositoryHandle, {
|
|
itemId,
|
|
imageType,
|
|
maxWidth,
|
|
maxHeight,
|
|
tag,
|
|
});
|
|
|
|
// Use data URL directly
|
|
imageUrl = dataUrl;
|
|
error = false;
|
|
} catch (e) {
|
|
error = true;
|
|
imageUrl = null;
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
|
|
// Only reload when the image identity changes (not on parent re-renders)
|
|
$effect(() => {
|
|
const loadKey = `${itemId}|${imageType}|${tag || ""}`;
|
|
if (loadKey !== lastLoadKey) {
|
|
lastLoadKey = loadKey;
|
|
imageUrl = null;
|
|
loadImage();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
{#if loading}
|
|
<div class="{className} bg-gray-700 animate-pulse" aria-busy="true" aria-label="Loading image"></div>
|
|
{:else if error || !imageUrl}
|
|
<div class="{className} bg-gray-800 flex items-center justify-center">
|
|
<svg class="w-8 h-8 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
|
|
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
|
|
</svg>
|
|
</div>
|
|
{:else}
|
|
<img src={imageUrl} {alt} class={className} />
|
|
{/if}
|