refactor: load support
This commit is contained in:
Generated
+15
-5
@@ -26,6 +26,7 @@
|
|||||||
"intl-messageformat": "^10.7.11",
|
"intl-messageformat": "^10.7.11",
|
||||||
"justified-layout": "^4.1.0",
|
"justified-layout": "^4.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lru-cache": "^11.1.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"maplibre-gl": "^5.3.0",
|
"maplibre-gl": "^5.3.0",
|
||||||
"pmtiles": "^4.3.0",
|
"pmtiles": "^4.3.0",
|
||||||
@@ -6592,11 +6593,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "10.4.3",
|
"version": "11.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
"integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
|
||||||
"dev": true,
|
"license": "ISC",
|
||||||
"license": "ISC"
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lru-queue": {
|
"node_modules/lru-queue": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -7335,6 +7338,13 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/path-scurry/node_modules/lru-cache": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/pathe": {
|
"node_modules/pathe": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
"intl-messageformat": "^10.7.11",
|
"intl-messageformat": "^10.7.11",
|
||||||
"justified-layout": "^4.1.0",
|
"justified-layout": "^4.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lru-cache": "^11.1.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"maplibre-gl": "^5.3.0",
|
"maplibre-gl": "^5.3.0",
|
||||||
"pmtiles": "^4.3.0",
|
"pmtiles": "^4.3.0",
|
||||||
|
|||||||
@@ -105,7 +105,6 @@
|
|||||||
let fullscreenElement = $state<Element>();
|
let fullscreenElement = $state<Element>();
|
||||||
let unsubscribes: (() => void)[] = [];
|
let unsubscribes: (() => void)[] = [];
|
||||||
let selectedEditType: string = $state('');
|
let selectedEditType: string = $state('');
|
||||||
let stack: StackResponseDto | null = $state(null);
|
|
||||||
|
|
||||||
let zoomToggle = $state(() => void 0);
|
let zoomToggle = $state(() => void 0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import type { AssetPackage } from '$lib/managers/asset-manager/asset-package.svelte';
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import { loadFromAssetPackage } from '$lib/managers/asset-manager/internal/load-support.svelte';
|
||||||
import { CancellableTask } from '$lib/utils/cancellable-task';
|
import { CancellableTask } from '$lib/utils/cancellable-task';
|
||||||
import type { AssetGridRouteSearchParams } from '$lib/utils/navigation';
|
import type { AssetGridRouteSearchParams } from '$lib/utils/navigation';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
|
||||||
import {
|
|
||||||
getAllAlbums,
|
|
||||||
getAssetInfo,
|
|
||||||
getAssetOriginalPath,
|
|
||||||
getAssetPlaybackPath,
|
|
||||||
getAssetThumbnailPath,
|
|
||||||
getBaseUrl,
|
|
||||||
type AlbumResponseDto,
|
|
||||||
type AssetResponseDto,
|
|
||||||
} from '@immich/sdk';
|
|
||||||
import { type ZoomImageWheelState } from '@zoom-image/core';
|
import { type ZoomImageWheelState } from '@zoom-image/core';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
import { LRUCache } from 'lru-cache';
|
||||||
|
|
||||||
export enum AssetMediaSize {
|
export enum AssetMediaSize {
|
||||||
Original = 'original',
|
Original = 'original',
|
||||||
@@ -24,28 +14,38 @@ export enum AssetMediaSize {
|
|||||||
Playback = 'playback',
|
Playback = 'playback',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AssetManagerOptions = {
|
export type LoadAssetOptions = {
|
||||||
assetId?: string;
|
|
||||||
preloadAssetIds?: string[];
|
|
||||||
loadAlbums?: boolean;
|
loadAlbums?: boolean;
|
||||||
size?: AssetMediaSize;
|
loadStack?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AssetManagerOptions = {};
|
||||||
|
|
||||||
export class AssetManager {
|
export class AssetManager {
|
||||||
isInitialized = $state(false);
|
isInitialized = $state(false);
|
||||||
isLoaded = $state(false);
|
isLoaded = $state(false);
|
||||||
loadError = $state(false);
|
loadError = $state(false);
|
||||||
asset: AssetResponseDto | undefined = $state();
|
// The queue waited for load. The first is the currect and the next is preload.
|
||||||
preloadAssets: TimelineAsset[] = $state([]);
|
// The preload asset is not need to loading immediately.
|
||||||
albums: AlbumResponseDto[] = $state([]);
|
assetLoadingQueue: AssetPackage[] = $state([]);
|
||||||
|
|
||||||
cacheKey: string | null = $derived(this.asset?.thumbhash ?? null);
|
// url: string | undefined = $derived.by(() => {
|
||||||
|
// if (this.asset) {
|
||||||
|
// return this.#getAssetUrl(toTimelineAsset(this.asset!));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
url: string | undefined = $derived.by(() => {
|
#maximumLRUCache: number = $state(10);
|
||||||
if (this.asset) {
|
|
||||||
return this.#getAssetUrl(toTimelineAsset(this.asset!));
|
// TODO: This function is used to test.
|
||||||
|
dispose(value: AssetPackage, key: string) {
|
||||||
|
console.log(key);
|
||||||
|
console.log(value);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
assetCache: LRUCache<string, AssetPackage> = $state(
|
||||||
|
new LRUCache({ max: this.#maximumLRUCache, dispose: this.dispose }),
|
||||||
|
);
|
||||||
|
|
||||||
showAssetViewer: boolean = $state(false);
|
showAssetViewer: boolean = $state(false);
|
||||||
gridScrollTarget: AssetGridRouteSearchParams | undefined = $state();
|
gridScrollTarget: AssetGridRouteSearchParams | undefined = $state();
|
||||||
@@ -54,9 +54,8 @@ export class AssetManager {
|
|||||||
initTask = new CancellableTask(
|
initTask = new CancellableTask(
|
||||||
() => (this.isInitialized = true),
|
() => (this.isInitialized = true),
|
||||||
() => {
|
() => {
|
||||||
this.asset = undefined;
|
this.assetLoadingQueue = [];
|
||||||
this.preloadAssets = [];
|
this.assetCache.clear();
|
||||||
this.albums = [];
|
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
},
|
},
|
||||||
() => void 0,
|
() => void 0,
|
||||||
@@ -65,28 +64,33 @@ export class AssetManager {
|
|||||||
static #INIT_OPTIONS = {};
|
static #INIT_OPTIONS = {};
|
||||||
#options: AssetManagerOptions = AssetManager.#INIT_OPTIONS;
|
#options: AssetManagerOptions = AssetManager.#INIT_OPTIONS;
|
||||||
|
|
||||||
|
static #DEFAULT_LOAD_ASSET_OPTIONS: LoadAssetOptions = {
|
||||||
|
loadAlbums: false,
|
||||||
|
loadStack: false,
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
async loadAssetPackage(options?: LoadAssetOptions, cancelable?: boolean): Promise<void> {
|
||||||
|
cancelable = cancelable ?? true;
|
||||||
|
options = options ?? AssetManager.#DEFAULT_LOAD_ASSET_OPTIONS;
|
||||||
|
|
||||||
|
const assetPackage = this.assetLoadingQueue[0];
|
||||||
|
if (!assetPackage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetPackage.loader?.executed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await assetPackage.loader?.execute(async (signal: AbortSignal) => {
|
||||||
|
await loadFromAssetPackage(this, assetPackage, options, signal);
|
||||||
|
}, cancelable);
|
||||||
|
}
|
||||||
|
|
||||||
async #initializeAsset() {
|
async #initializeAsset() {
|
||||||
if (this.#options.assetId) {
|
|
||||||
const assetResponse = await getAssetInfo({ id: this.#options.assetId, key: authManager.key });
|
|
||||||
if (!assetResponse) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.asset = assetResponse;
|
|
||||||
} else {
|
|
||||||
throw new Error('The assetId in required in options.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Preload assets.
|
// TODO: Preload assets.
|
||||||
|
|
||||||
if (this.#options.loadAlbums ?? true) {
|
|
||||||
const albumsResponse = await getAllAlbums({ assetId: this.#options.assetId });
|
|
||||||
if (!albumsResponse) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.albums = albumsResponse;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOptions(options: AssetManagerOptions) {
|
async updateOptions(options: AssetManagerOptions) {
|
||||||
@@ -97,27 +101,13 @@ export class AssetManager {
|
|||||||
await this.#init(options);
|
await this.#init(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
#checkOptions() {
|
|
||||||
this.#options.size = AssetMediaSize.Original;
|
|
||||||
|
|
||||||
if (!this.asset || !this.zoomImageState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.asset.originalMimeType === 'image/gif' || this.zoomImageState.currentZoom > 1) {
|
|
||||||
// TODO: use original image forcely and according to the setting.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async #init(options: AssetManagerOptions) {
|
async #init(options: AssetManagerOptions) {
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.asset = undefined;
|
this.assetLoadingQueue = [];
|
||||||
this.preloadAssets = [];
|
this.assetCache.clear();
|
||||||
this.albums = [];
|
|
||||||
await this.initTask.execute(async () => {
|
await this.initTask.execute(async () => {
|
||||||
this.#options = options;
|
this.#options = options;
|
||||||
await this.#initializeAsset();
|
await this.#initializeAsset();
|
||||||
this.#checkOptions();
|
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,63 +115,71 @@ export class AssetManager {
|
|||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshAlbums() {}
|
// #checkOptions() {
|
||||||
|
// this.#options.size = AssetMediaSize.Original;
|
||||||
|
|
||||||
async refreshAsset() {}
|
// if (!this.asset || !this.zoomImageState) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
#preload() {
|
// if (this.asset.originalMimeType === 'image/gif' || this.zoomImageState.currentZoom > 1) {
|
||||||
for (const preloadAsset of this.preloadAssets) {
|
// // TODO: use original image forcely and according to the setting.
|
||||||
if (preloadAsset.isImage) {
|
// }
|
||||||
let img = new Image();
|
// }
|
||||||
const preloadUrl = this.#getAssetUrl(preloadAsset);
|
|
||||||
if (preloadUrl) {
|
|
||||||
img.src = preloadUrl;
|
|
||||||
} else {
|
|
||||||
throw new Error('AssetManager is not initialized.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#getAssetUrl(asset: TimelineAsset) {
|
// #preload() {
|
||||||
if (!this.asset) {
|
// for (const preloadAsset of this.preloadAssets) {
|
||||||
return;
|
// if (preloadAsset.isImage) {
|
||||||
}
|
// let img = new Image();
|
||||||
|
// const preloadUrl = this.#getAssetUrl(preloadAsset);
|
||||||
|
// if (preloadUrl) {
|
||||||
|
// img.src = preloadUrl;
|
||||||
|
// } else {
|
||||||
|
// throw new Error('AssetManager is not initialized.');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let path = undefined;
|
// #getAssetUrl(asset: TimelineAsset) {
|
||||||
const searchParameters = new URLSearchParams();
|
// if (!this.asset) {
|
||||||
if (authManager.key) {
|
// return;
|
||||||
searchParameters.set('key', authManager.key);
|
// }
|
||||||
}
|
|
||||||
if (this.cacheKey) {
|
|
||||||
searchParameters.set('c', this.cacheKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (this.#options.size) {
|
// let path = undefined;
|
||||||
case AssetMediaSize.Original: {
|
// const searchParameters = new URLSearchParams();
|
||||||
path = getAssetOriginalPath(this.asset.id);
|
// if (authManager.key) {
|
||||||
break;
|
// searchParameters.set('key', authManager.key);
|
||||||
}
|
// }
|
||||||
case AssetMediaSize.Fullsize:
|
// if (this.cacheKey) {
|
||||||
case AssetMediaSize.Thumbnail:
|
// searchParameters.set('c', this.cacheKey);
|
||||||
case AssetMediaSize.Preview: {
|
// }
|
||||||
path = getAssetThumbnailPath(this.asset.id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetMediaSize.Playback: {
|
|
||||||
path = getAssetPlaybackPath(this.asset.id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// TODO: default AssetMediaSize
|
|
||||||
}
|
|
||||||
|
|
||||||
return getBaseUrl() + path + '?' + searchParameters.toString();
|
// switch (this.#options.size) {
|
||||||
}
|
// case AssetMediaSize.Original: {
|
||||||
|
// path = getAssetOriginalPath(this.asset.id);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case AssetMediaSize.Fullsize:
|
||||||
|
// case AssetMediaSize.Thumbnail:
|
||||||
|
// case AssetMediaSize.Preview: {
|
||||||
|
// path = getAssetThumbnailPath(this.asset.id);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case AssetMediaSize.Playback: {
|
||||||
|
// path = getAssetPlaybackPath(this.asset.id);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default:
|
||||||
|
// // TODO: default AssetMediaSize
|
||||||
|
// }
|
||||||
|
|
||||||
get isOriginalImage() {
|
// return getBaseUrl() + path + '?' + searchParameters.toString();
|
||||||
return this.#options.size === AssetMediaSize.Original || this.#options.size === AssetMediaSize.Fullsize;
|
// }
|
||||||
}
|
|
||||||
|
// get isOriginalImage() {
|
||||||
|
// return this.#options.size === AssetMediaSize.Original || this.#options.size === AssetMediaSize.Fullsize;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// const getAssetUrl = (id: string, targetSize: AssetMediaSize | 'original', cacheKey: string | null) => {
|
// const getAssetUrl = (id: string, targetSize: AssetMediaSize | 'original', cacheKey: string | null) => {
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { CancellableTask } from '$lib/utils/cancellable-task';
|
||||||
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
import type { AlbumResponseDto, AssetResponseDto, StackResponseDto } from '@immich/sdk';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
import type { AssetManager, AssetManagerOptions } from './asset-manager.svelte';
|
||||||
|
|
||||||
|
export class AssetPackage {
|
||||||
|
isLoaded: boolean = $state(false);
|
||||||
|
asset: AssetResponseDto | undefined = $state();
|
||||||
|
albums: AlbumResponseDto[] = $state([]);
|
||||||
|
stack: StackResponseDto | undefined = $state();
|
||||||
|
readonly assetId: string;
|
||||||
|
readonly assetManager: AssetManager;
|
||||||
|
|
||||||
|
// To ensure albums and stack is need to reloading.
|
||||||
|
options: AssetManagerOptions | undefined = $state();
|
||||||
|
|
||||||
|
loader: CancellableTask | undefined;
|
||||||
|
|
||||||
|
constructor(store: AssetManager, assetId: string) {
|
||||||
|
this.assetManager = store;
|
||||||
|
this.assetId = assetId;
|
||||||
|
|
||||||
|
this.loader = new CancellableTask(
|
||||||
|
() => {
|
||||||
|
this.isLoaded = true;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.asset = undefined;
|
||||||
|
this.albums = [];
|
||||||
|
this.stack = undefined;
|
||||||
|
this.isLoaded = false;
|
||||||
|
},
|
||||||
|
this.#handleLoadError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add error message to translation.
|
||||||
|
#handleLoadError(error: unknown) {
|
||||||
|
const _$t = get(t);
|
||||||
|
handleError(error, _$t('errors.failed_to_load_asset'));
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.loader?.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,69 @@
|
|||||||
import type { AssetManager } from '$lib/managers/asset-manager/asset-manager.svelte';
|
import type { AssetManager, LoadAssetOptions } from '$lib/managers/asset-manager/asset-manager.svelte';
|
||||||
import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
import { AssetPackage } from '$lib/managers/asset-manager/asset-package.svelte';
|
||||||
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
|
// import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
||||||
|
import { getAllAlbums, getAssetInfo, getStack } from '@immich/sdk';
|
||||||
|
|
||||||
|
export async function loadFromAssetPackage(
|
||||||
|
assetManager: AssetManager,
|
||||||
|
assetPackage: AssetPackage,
|
||||||
|
options: LoadAssetOptions,
|
||||||
|
signal: AbortSignal,
|
||||||
|
): Promise<void> {
|
||||||
|
const assetId = assetPackage.assetId;
|
||||||
|
const assetCache = assetManager.assetCache.get(assetId);
|
||||||
|
if (assetCache && assetCache.options === options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Compare between assetCache and assetCache.options to ensure whether we need update or not.
|
||||||
|
|
||||||
|
// If there is assetCache, then asset info is not need to update.
|
||||||
|
if (!assetCache) {
|
||||||
|
const key = authManager.key;
|
||||||
|
const assetResponse = await getAssetInfo(
|
||||||
|
{
|
||||||
|
id: assetId,
|
||||||
|
key,
|
||||||
|
},
|
||||||
|
{ signal },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!assetResponse) {
|
||||||
|
throw new Error('get AssetInfo error');
|
||||||
|
}
|
||||||
|
assetPackage.asset = assetResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: need to update albums
|
||||||
|
if (options.loadAlbums) {
|
||||||
|
const albumsResponse = await getAllAlbums(
|
||||||
|
{
|
||||||
|
assetId,
|
||||||
|
},
|
||||||
|
{ signal },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!albumsResponse) {
|
||||||
|
throw new Error('get AllAlbums error');
|
||||||
|
}
|
||||||
|
assetPackage.albums = albumsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.loadStack) {
|
||||||
|
const stackResponse = await getStack(
|
||||||
|
{
|
||||||
|
id: assetId,
|
||||||
|
},
|
||||||
|
{ signal },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!stackResponse) {
|
||||||
|
throw new Error('get Stack error');
|
||||||
|
}
|
||||||
|
assetPackage.stack = stackResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function mediaLoaded(assetManager: AssetManager) {
|
export function mediaLoaded(assetManager: AssetManager) {
|
||||||
assetManager.isLoaded = true;
|
assetManager.isLoaded = true;
|
||||||
@@ -9,9 +73,9 @@ export function mediaLoadError(assetManager: AssetManager) {
|
|||||||
assetManager.isLoaded = assetManager.loadError = true;
|
assetManager.isLoaded = assetManager.loadError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cancelImageLoad(assetManager: AssetManager) {
|
// export function cancelImageLoad(assetManager: AssetManager) {
|
||||||
if (assetManager.url) {
|
// if (assetManager.url) {
|
||||||
cancelImageUrl(assetManager.url);
|
// cancelImageUrl(assetManager.url);
|
||||||
}
|
// }
|
||||||
assetManager.isLoaded = assetManager.loadError = false;
|
// assetManager.isLoaded = assetManager.loadError = false;
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import type { AssetPackage } from '$lib/managers/asset-manager/asset-package.svelte';
|
||||||
|
|
||||||
|
export const assetPackage = (assetPackage: AssetPackage): AssetPackage => $state.snapshot(assetPackage);
|
||||||
Reference in New Issue
Block a user