diff --git a/web/src/lib/components/album-page/album-map.svelte b/web/src/lib/components/album-page/album-map.svelte index c161bac552..455a99f755 100644 --- a/web/src/lib/components/album-page/album-map.svelte +++ b/web/src/lib/components/album-page/album-map.svelte @@ -1,7 +1,7 @@ diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index 19634d5aa4..13ac213b1b 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -5,12 +5,12 @@ import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte'; import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import Timeline from '$lib/components/timeline/Timeline.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { handleDownloadAlbum } from '$lib/services/album.service'; import { getGlobalActions } from '$lib/services/app.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; @@ -34,7 +34,6 @@ const album = sharedLink.album as AlbumResponseDto; - let { isViewing: showAssetViewer, setAssetId } = assetViewingStore; let { slideshowState, slideshowNavigation } = slideshowStore; const options = $derived({ albumId: album.id, order: album.order }); @@ -55,7 +54,9 @@ ? await timelineManager.getRandomAsset() : timelineManager.months[0]?.dayGroups[0]?.viewerAssets[0]?.asset; if (asset) { - handlePromiseError(setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow))); + handlePromiseError( + assetViewerManager.setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow)), + ); } }; @@ -66,7 +67,7 @@ use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: () => { - if (!$showAssetViewer && assetInteraction.selectionActive) { + if (!assetViewerManager.isViewing && assetInteraction.selectionActive) { cancelMultiselect(assetInteraction); } }, diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index c6e0de2955..e2981e2e55 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -14,7 +14,6 @@ import { editManager, EditToolType } from '$lib/managers/edit/edit-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; import { getAssetActions } from '$lib/services/asset.service'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; import { ocrManager } from '$lib/stores/ocr.svelte'; import { alwaysLoadOriginalVideo } from '$lib/stores/preferences.store'; @@ -91,7 +90,6 @@ onRandom, }: Props = $props(); - const { setAssetId } = assetViewingStore; const { restartProgress: restartSlideshowProgress, stopProgress: stopSlideshowProgress, @@ -190,7 +188,7 @@ if (editManager.hasAppliedEdits) { const refreshedAsset = await getAssetInfo({ id: asset.id }); onAssetChange?.(refreshedAsset); - assetViewingStore.setAsset(refreshedAsset); + assetViewerManager.setAsset(refreshedAsset); } assetViewerManager.closeEditor(); }; @@ -241,7 +239,7 @@ } if ($slideshowRepeat && slideshowStartAssetId) { - await setAssetId(slideshowStartAssetId); + await assetViewerManager.setAssetId(slideshowStartAssetId); $restartSlideshowProgress = true; return; } @@ -257,7 +255,7 @@ let assetViewerHtmlElement = $state(); const slideshowHistory = new SlideshowHistory((asset) => { - handlePromiseError(setAssetId(asset.id).then(() => ($restartSlideshowProgress = true))); + handlePromiseError(assetViewerManager.setAssetId(asset.id).then(() => ($restartSlideshowProgress = true))); }); const handleVideoStarted = () => { diff --git a/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte b/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte index 8dd7adaa5f..c5b4ab5ce7 100644 --- a/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte +++ b/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte @@ -1,12 +1,12 @@ handleNextAsset() }, diff --git a/web/src/lib/components/pages/SharedLinkPage.svelte b/web/src/lib/components/pages/SharedLinkPage.svelte index c6270d2de3..01a97fffe7 100644 --- a/web/src/lib/components/pages/SharedLinkPage.svelte +++ b/web/src/lib/components/pages/SharedLinkPage.svelte @@ -3,7 +3,7 @@ import IndividualSharedViewer from '$lib/components/share-page/individual-shared-viewer.svelte'; import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; import ThemeButton from '$lib/components/shared-components/theme-button.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { user } from '$lib/stores/user.store'; import { setSharedLink } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; @@ -31,7 +31,6 @@ const { data }: Props = $props(); - let { gridScrollTarget } = assetViewingStore; let { sharedLink, passwordRequired, key, slug, meta } = $state(data); let { title, description } = $state(meta); let isOwned = $derived($user ? $user.id === sharedLink?.userId : false); @@ -48,7 +47,7 @@ $t('shared_photos_and_videos_count', { values: { assetCount: sharedLink.assets.length } }); await tick(); await navigate( - { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: $gridScrollTarget }, + { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: assetViewerManager.gridScrollTarget }, { forceNavigate: true, replaceState: true }, ); } catch (error) { diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index 5d1254f8d9..9e14f8a074 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -2,16 +2,17 @@ import { goto } from '$app/navigation'; import { shortcuts, type ShortcutOptions } from '$lib/actions/shortcut'; import type { Action } from '$lib/components/asset-viewer/actions/action'; + import type { AssetCursor } from '$lib/components/asset-viewer/asset-viewer.svelte'; import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { AssetAction } from '$lib/constants'; import Portal from '$lib/elements/Portal.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types'; import AssetDeleteConfirmModal from '$lib/modals/AssetDeleteConfirmModal.svelte'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { handlePromiseError } from '$lib/utils'; import { deleteAssets } from '$lib/utils/actions'; @@ -64,7 +65,6 @@ allowDeletion = true, }: Props = $props(); - let { isViewing: isViewerOpen, asset: viewingAsset } = assetViewingStore; const navigationAssets = $derived(viewerAssets ?? assets); const geometry = $derived( @@ -256,7 +256,7 @@ const shortcutList = $derived( (() => { - if ($isViewerOpen) { + if (assetViewerManager.isViewing) { return []; } @@ -351,10 +351,10 @@ } }); - const assetCursor = $derived({ - current: $viewingAsset, - nextAsset: getNextAsset(navigationAssets, $viewingAsset), - previousAsset: getPreviousAsset(navigationAssets, $viewingAsset), + const assetCursor = $derived({ + current: assetViewerManager.asset!, + nextAsset: getNextAsset(navigationAssets, assetViewerManager.asset), + previousAsset: getPreviousAsset(navigationAssets, assetViewerManager.asset), }); @@ -408,7 +408,7 @@ {/if} -{#if $isViewerOpen} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} /> diff --git a/web/src/lib/components/timeline/Timeline.svelte b/web/src/lib/components/timeline/Timeline.svelte index d6ce722c96..0ebc4800ea 100644 --- a/web/src/lib/components/timeline/Timeline.svelte +++ b/web/src/lib/components/timeline/Timeline.svelte @@ -11,6 +11,7 @@ import HotModuleReload from '$lib/elements/HotModuleReload.svelte'; import Portal from '$lib/elements/Portal.svelte'; import Skeleton from '$lib/elements/Skeleton.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte'; import { isIntersecting } from '$lib/managers/timeline-manager/internal/intersection-support.svelte'; import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte'; @@ -18,7 +19,6 @@ import type { TimelineAsset, TimelineManagerOptions, ViewportTopMonth } from '$lib/managers/timeline-manager/types'; import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; import { isAssetViewerRoute, navigate } from '$lib/utils/navigation'; import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util'; @@ -88,10 +88,7 @@ onDestroy(() => timelineManager.destroy()); $effect(() => options && void timelineManager.updateOptions(options)); - let { isViewing: showAssetViewer, asset: viewingAsset, gridScrollTarget } = assetViewingStore; - let scrollableElement: HTMLElement | undefined = $state(); - let timelineElement: HTMLElement | undefined = $state(); let invisible = $state(true); // The percentage of scroll through the month that is currently intersecting the top boundary of the viewport. @@ -209,7 +206,7 @@ timelineManager.viewportWidth = rect.width; } } - const scrollTarget = $gridScrollTarget?.at; + const scrollTarget = assetViewerManager.gridScrollTarget?.at; let scrolled = false; if (scrollTarget) { scrolled = await scrollAndLoadAsset(scrollTarget); @@ -518,8 +515,8 @@ }); $effect(() => { - if ($showAssetViewer) { - const { localDateTime } = getTimes($viewingAsset.fileCreatedAt, DateTime.local().offset / 60); + if (assetViewerManager.asset && assetViewerManager.isViewing) { + const { localDateTime } = getTimes(assetViewerManager.asset.fileCreatedAt, DateTime.local().offset / 60); void timelineManager.loadMonthGroup({ year: localDateTime.year, month: localDateTime.month }); } }); @@ -565,7 +562,7 @@ onAfterUpdate={() => { const asset = page.url.searchParams.get('at'); if (asset) { - $gridScrollTarget = { at: asset }; + assetViewerManager.gridScrollTarget = { at: asset }; } void scrollAfterNavigate(); }} @@ -722,7 +719,7 @@ - {#if $showAssetViewer} + {#if assetViewerManager.isViewing} {/if} diff --git a/web/src/lib/components/timeline/TimelineAssetViewer.svelte b/web/src/lib/components/timeline/TimelineAssetViewer.svelte index cc0289e92b..47144dcca9 100644 --- a/web/src/lib/components/timeline/TimelineAssetViewer.svelte +++ b/web/src/lib/components/timeline/TimelineAssetViewer.svelte @@ -2,11 +2,11 @@ import type { Action } from '$lib/components/asset-viewer/actions/action'; import type { AssetCursor } from '$lib/components/asset-viewer/asset-viewer.svelte'; import { AssetAction } from '$lib/constants'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { assetCacheManager } from '$lib/managers/AssetCacheManager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { websocketEvents } from '$lib/stores/websocket'; import { handlePromiseError } from '$lib/utils'; import { updateStackedAssetInTimeline, updateUnstackedAssetInTimeline } from '$lib/utils/actions'; @@ -18,8 +18,6 @@ import { onDestroy, onMount, untrack } from 'svelte'; import { t } from 'svelte-i18n'; - let { asset: viewingAsset, gridScrollTarget } = assetViewingStore; - interface Props { timelineManager: TimelineManager; invisible: boolean; @@ -65,7 +63,7 @@ }; let assetCursor = $state({ - current: $viewingAsset, + current: assetViewerManager.asset!, previousAsset: undefined, nextAsset: undefined, }); @@ -82,9 +80,10 @@ //TODO: replace this with async derived in svelte 6 $effect(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - $viewingAsset; - untrack(() => handlePromiseError(loadCloseAssets($viewingAsset))); + const asset = assetViewerManager.asset; + if (asset) { + untrack(() => handlePromiseError(loadCloseAssets(asset))); + } }); const handleRandom = async () => { @@ -99,8 +98,12 @@ const handleClose = async (asset: { id: string }) => { invisible = true; - $gridScrollTarget = { at: asset.id }; - await navigate({ targetRoute: 'current', assetId: null, assetGridRouteSearchParams: $gridScrollTarget }); + assetViewerManager.gridScrollTarget = { at: asset.id }; + await navigate({ + targetRoute: 'current', + assetId: null, + assetGridRouteSearchParams: assetViewerManager.gridScrollTarget, + }); }; const handleRemoveFromAlbum = async (assetIds: string[]) => { @@ -202,7 +205,7 @@ const restoredAsset = assets[0]; const asset = await getAssetInfo({ ...authManager.params, id: restoredAsset.id }); - assetViewingStore.setAsset(asset); + assetViewerManager.setAsset(asset); await navigate({ targetRoute: 'current', assetId: restoredAsset.id }); }; diff --git a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte index a5fa34289b..612e7e22a3 100644 --- a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte +++ b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte @@ -5,6 +5,7 @@ setFocusToAsset as setFocusAssetInit, setFocusTo as setFocusToInit, } from '$lib/components/timeline/actions/focus-actions'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; @@ -14,7 +15,6 @@ import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { searchStore } from '$lib/stores/search.svelte'; import { handlePromiseError } from '$lib/utils'; @@ -32,8 +32,6 @@ let { timelineManager = $bindable(), assetInteraction, onEscape, scrollToAsset }: Props = $props(); - const { isViewing: showAssetViewer } = assetViewingStore; - const trashOrDelete = async (forceRequested?: boolean) => { const force = forceRequested || !featureFlagsManager.value.trash; const selectedAssets = assetInteraction.selectedAssets; @@ -142,7 +140,7 @@ }; const shortcutList = $derived.by(() => { - if (searchStore.isSearchEnabled || $showAssetViewer || isModalOpen()) { + if (searchStore.isSearchEnabled || assetViewerManager.isViewing || isModalOpen()) { return []; } diff --git a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte index aba2dc01f4..ab19f12079 100644 --- a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte +++ b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte @@ -2,8 +2,8 @@ import { shortcuts } from '$lib/actions/shortcut'; import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte'; import Portal from '$lib/elements/Portal.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { handlePromiseError } from '$lib/utils'; import { getNextAsset, getPreviousAsset } from '$lib/utils/asset-utils'; import { suggestDuplicate } from '$lib/utils/duplicate-utils'; @@ -22,8 +22,6 @@ } let { assets, onResolve, onStack }: Props = $props(); - const { isViewing: showAssetViewer, asset: viewingAsset, setAsset } = assetViewingStore; - // eslint-disable-next-line svelte/no-unnecessary-state-wrap let selectedAssetIds = $state(new SvelteSet()); let trashCount = $derived(assets.length - selectedAssetIds.size); @@ -40,7 +38,7 @@ }); onDestroy(() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); }); const onRandom = async () => { @@ -71,7 +69,7 @@ const onViewAsset = async ({ id }: AssetResponseDto) => { const asset = await getAssetInfo({ ...authManager.params, id }); - setAsset(asset); + assetViewerManager.setAsset(asset); await navigate({ targetRoute: 'current', assetId: asset.id }); }; @@ -86,9 +84,9 @@ }; const assetCursor = $derived({ - current: $viewingAsset, - nextAsset: getNextAsset(assets, $viewingAsset), - previousAsset: getPreviousAsset(assets, $viewingAsset), + current: assetViewerManager.asset!, + nextAsset: getNextAsset(assets, assetViewerManager.asset), + previousAsset: getPreviousAsset(assets, assetViewerManager.asset), }); @@ -166,7 +164,7 @@ -{#if $showAssetViewer} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} 1} {onRandom} onClose={() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} /> diff --git a/web/src/lib/managers/asset-viewer-manager.svelte.ts b/web/src/lib/managers/asset-viewer-manager.svelte.ts index 0bab3aff80..f46be6b698 100644 --- a/web/src/lib/managers/asset-viewer-manager.svelte.ts +++ b/web/src/lib/managers/asset-viewer-manager.svelte.ts @@ -1,7 +1,10 @@ +import { authManager } from '$lib/managers/auth-manager.svelte'; import type { ImageLoaderStatus } from '$lib/utils/adaptive-image-loader.svelte'; import { canCopyImageToClipboard } from '$lib/utils/asset-utils'; import { BaseEventManager } from '$lib/utils/base-event-manager.svelte'; +import type { AssetGridRouteSearchParams } from '$lib/utils/navigation'; import { PersistedLocalStorage } from '$lib/utils/persisted'; +import { getAssetInfo, type AssetResponseDto } from '@immich/sdk'; import type { ZoomImageWheelState } from '@zoom-image/core'; import { cubicOut } from 'svelte/easing'; @@ -21,7 +24,7 @@ export type Events = { Copy: []; }; -export class AssetViewerManager extends BaseEventManager { +class AssetViewerManager extends BaseEventManager { #zoomState = $state(createDefaultZoomState()); #animationFrameId: number | null = null; @@ -40,6 +43,18 @@ export class AssetViewerManager extends BaseEventManager { isPlayingMotionPhoto = $state(false); isShowEditor = $state(false); + #viewingAssetStoreState = $state(); + #viewState = $state(false); + gridScrollTarget = $state(); + + get asset() { + return this.#viewingAssetStoreState; + } + + get isViewing() { + return this.#viewState; + } + get isImageLoading() { return this.#isImageLoading; } @@ -145,6 +160,21 @@ export class AssetViewerManager extends BaseEventManager { closeEditor() { this.isShowEditor = false; } + + setAsset(asset: AssetResponseDto) { + this.#viewingAssetStoreState = asset; + this.#viewState = true; + } + + async setAssetId(id: string): Promise { + const asset = await getAssetInfo({ ...authManager.params, id }); + this.setAsset(asset); + return asset; + } + + showAssetViewer(show: boolean) { + this.#viewState = show; + } } export const assetViewerManager = new AssetViewerManager(); diff --git a/web/src/lib/stores/asset-viewing.store.ts b/web/src/lib/stores/asset-viewing.store.ts deleted file mode 100644 index 3cd2cd9579..0000000000 --- a/web/src/lib/stores/asset-viewing.store.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { authManager } from '$lib/managers/auth-manager.svelte'; -import { type AssetGridRouteSearchParams } from '$lib/utils/navigation'; -import { getAssetInfo, type AssetResponseDto } from '@immich/sdk'; -import { readonly, writable } from 'svelte/store'; - -function createAssetViewingStore() { - const viewingAssetStoreState = writable(); - const viewState = writable(false); - const gridScrollTarget = writable(); - - const setAsset = (asset: AssetResponseDto) => { - viewingAssetStoreState.set(asset); - viewState.set(true); - }; - - const setAssetId = async (id: string): Promise => { - const asset = await getAssetInfo({ ...authManager.params, id }); - setAsset(asset); - return asset; - }; - - const showAssetViewer = (show: boolean) => { - viewState.set(show); - }; - - return { - asset: readonly(viewingAssetStoreState), - isViewing: viewState, - gridScrollTarget, - setAsset, - setAssetId, - showAssetViewer, - }; -} - -export const assetViewingStore = createAssetViewingStore(); diff --git a/web/src/routes/(user)/+layout.svelte b/web/src/routes/(user)/+layout.svelte index e6e349fe91..983d25eced 100644 --- a/web/src/routes/(user)/+layout.svelte +++ b/web/src/routes/(user)/+layout.svelte @@ -1,30 +1,28 @@ -
+
{@render children?.()}
diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 9a2d36ed95..9010efe535 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -46,7 +46,6 @@ import { getGlobalActions } from '$lib/services/app.service'; import { getAssetBulkActions } from '$lib/services/asset.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; import { preferences, user } from '$lib/stores/user.store'; import { handlePromiseError } from '$lib/utils'; @@ -86,14 +85,9 @@ } let { data = $bindable() }: Props = $props(); - - let { isViewing: showAssetViewer, setAssetId, gridScrollTarget } = assetViewingStore; let { slideshowState, slideshowNavigation } = slideshowStore; - let oldAt: AssetGridRouteSearchParams | null | undefined = $state(); - let viewMode: AlbumPageViewMode = $state(AlbumPageViewMode.VIEW); - let timelineManager = $state() as TimelineManager; let showAlbumUsers = $derived(timelineManager?.showAssetOwners ?? false); @@ -114,7 +108,9 @@ ? await timelineManager.getRandomAsset() : timelineManager.months[0]?.dayGroups[0]?.viewerAssets[0]?.asset; if (asset) { - handlePromiseError(setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow))); + handlePromiseError( + assetViewerManager.setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow)), + ); } }; @@ -128,7 +124,7 @@ await handleCloseSelectAssets(); return; } - if ($showAssetViewer) { + if (assetViewerManager.isViewing) { return; } if (assetInteraction.selectionActive) { @@ -240,7 +236,7 @@ const isShared = $derived(viewMode === AlbumPageViewMode.SELECT_ASSETS ? false : album.albumUsers.length > 0); $effect(() => { - if ($showAssetViewer || !isShared) { + if (assetViewerManager.isViewing || !isShared) { return; } @@ -252,7 +248,9 @@ let isOwned = $derived($user.id == album.ownerId); let showActivityStatus = $derived( - album.albumUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || activityManager.commentCount > 0), + album.albumUsers.length > 0 && + !assetViewerManager.isViewing && + (album.isActivityEnabled || activityManager.commentCount > 0), ); let isEditor = $derived( album.albumUsers.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor || @@ -322,7 +320,7 @@ type: $t('command'), icon: mdiArrowLeft, onAction: handleEscape, - $if: () => !$showAssetViewer, + $if: () => !assetViewerManager.isViewing, shortcuts: { key: 'Escape' }, }); @@ -518,7 +516,7 @@ onclick={async () => { timelineManager.suspendTransitions = true; viewMode = AlbumPageViewMode.SELECT_ASSETS; - oldAt = { at: $gridScrollTarget?.at }; + oldAt = { at: assetViewerManager.gridScrollTarget?.at }; await navigate( { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: { at: null } }, { replaceState: true }, @@ -621,7 +619,7 @@ {/if} {/if}
- {#if album.albumUsers.length > 0 && album && assetViewerManager.isShowActivityPanel && $user && !$showAssetViewer} + {#if album.albumUsers.length > 0 && album && assetViewerManager.isShowActivityPanel && $user && !assetViewerManager.isViewing}
()); let selectedClusterBBox = $state.raw(); let isTimelinePanelVisible = $state(false); @@ -34,7 +31,7 @@ } onDestroy(() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); }); if (!featureFlagsManager.value.map) { @@ -42,7 +39,7 @@ } async function onViewAssets(assetIds: string[]) { - await setAssetId(assetIds[0]); + await assetViewerManager.setAssetId(assetIds[0]); closeTimelinePanel(); } @@ -50,7 +47,7 @@ selectedClusterIds = new Set(assetIds); selectedClusterBBox = bbox; isTimelinePanelVisible = true; - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); } @@ -89,13 +86,13 @@
- {#if $showAssetViewer} + {#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} isShared={false} diff --git a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte index 31a991fa8f..4d1775d7dc 100644 --- a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte @@ -20,11 +20,11 @@ import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import Timeline from '$lib/components/timeline/Timeline.svelte'; import { AssetAction } from '$lib/constants'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { Route } from '$lib/route'; import { getAssetBulkActions } from '$lib/services/asset.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; import { memoryStore } from '$lib/stores/memory.store.svelte'; import { preferences, user } from '$lib/stores/user.store'; @@ -43,7 +43,6 @@ import { mdiDotsVertical } from '@mdi/js'; import { t } from 'svelte-i18n'; - let { isViewing: showAssetViewer } = assetViewingStore; let timelineManager = $state() as TimelineManager; const options = { visibility: AssetVisibility.Timeline, withStacked: true, withPartners: true }; @@ -62,7 +61,7 @@ }); const handleEscape = () => { - if ($showAssetViewer) { + if (assetViewerManager.isViewing) { return; } if (assetInteraction.selectionActive) { diff --git a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte index c7c0c146ad..c7d30febc7 100644 --- a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -4,11 +4,11 @@ import { shortcuts } from '$lib/actions/shortcut'; import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; import DuplicatesCompareControl from '$lib/components/utilities-page/duplicates/duplicates-compare-control.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import DuplicatesInformationModal from '$lib/modals/DuplicatesInformationModal.svelte'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { locale } from '$lib/stores/preferences.store'; import { stackAssets } from '$lib/utils/asset-utils'; import { suggestDuplicate } from '$lib/utils/duplicate-utils'; @@ -57,7 +57,6 @@ }; let duplicates = $state(data.duplicates); - const { isViewing: showAssetViewer } = assetViewingStore; const correctDuplicatesIndex = (index: number) => { return Math.max(0, Math.min(index, duplicates.length - 1)); @@ -186,7 +185,7 @@ { if (asset) { - setAsset(asset); + assetViewerManager.setAsset(asset); } }); @@ -39,7 +39,7 @@ const onAction = (payload: Action) => { if (payload.type == 'trash') { assets = assets.filter((a) => a.id != payload.asset.id); - $showAssetViewer = false; + assetViewerManager.showAssetViewer(false); } }; @@ -48,9 +48,9 @@ }; const assetCursor = $derived({ - current: $viewingAsset, - nextAsset: getNextAsset(assets, $viewingAsset), - previousAsset: getPreviousAsset(assets, $viewingAsset), + current: assetViewerManager.asset!, + nextAsset: getNextAsset(assets, assetViewerManager.asset), + previousAsset: getPreviousAsset(assets, assetViewerManager.asset), }); @@ -68,7 +68,7 @@
-{#if $showAssetViewer} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} />