Extract asset viewer navigation logic into separate components
• Move navigation handlers (next, previous, random, close) from asset-grid to dedicated asset-viewer-actions component • Extract asset action handlers (archive, stack, favorite) into reusable module • Create asset-viewer-and-actions wrapper to compose viewer with navigation actions
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
<script lang="ts">
|
||||
import type { Action } from '$lib/components/asset-viewer/actions/action';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { updateStackedAssetInTimeline, updateUnstackedAssetInTimeline } from '$lib/utils/actions';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { getAssetInfo, type AssetResponseDto } from '@immich/sdk';
|
||||
|
||||
let { asset: viewingAsset, gridScrollTarget, mutex } = assetViewingStore;
|
||||
|
||||
interface Props {
|
||||
timelineManager: TimelineManager;
|
||||
showSkeleton: boolean;
|
||||
removeAction?:
|
||||
| AssetAction.UNARCHIVE
|
||||
| AssetAction.ARCHIVE
|
||||
| AssetAction.FAVORITE
|
||||
| AssetAction.UNFAVORITE
|
||||
| AssetAction.SET_VISIBILITY_TIMELINE;
|
||||
handlePreAction?: (action: Action) => Promise<void>;
|
||||
handleAction?: (action: Action) => void;
|
||||
handleNext?: () => Promise<boolean>;
|
||||
handlePrevious?: () => Promise<boolean>;
|
||||
handleRandom?: () => Promise<AssetResponseDto | undefined>;
|
||||
handleClose?: (asset: { id: string }) => Promise<void>;
|
||||
}
|
||||
|
||||
let {
|
||||
timelineManager = $bindable(),
|
||||
showSkeleton = $bindable(false),
|
||||
removeAction,
|
||||
handlePreAction = $bindable(),
|
||||
handleAction = $bindable(),
|
||||
handleNext = $bindable(),
|
||||
handlePrevious = $bindable(),
|
||||
handleRandom = $bindable(),
|
||||
handleClose = $bindable(),
|
||||
}: Props = $props();
|
||||
|
||||
handlePrevious = async () => {
|
||||
const release = await mutex.acquire();
|
||||
const laterAsset = await timelineManager.getLaterAsset($viewingAsset);
|
||||
|
||||
if (laterAsset) {
|
||||
const preloadAsset = await timelineManager.getLaterAsset(laterAsset);
|
||||
const asset = await getAssetInfo({ ...authManager.params, id: laterAsset.id });
|
||||
assetViewingStore.setAsset(asset, preloadAsset ? [preloadAsset] : []);
|
||||
await navigate({ targetRoute: 'current', assetId: laterAsset.id });
|
||||
}
|
||||
|
||||
release();
|
||||
return !!laterAsset;
|
||||
};
|
||||
|
||||
handleNext = async () => {
|
||||
const release = await mutex.acquire();
|
||||
const earlierAsset = await timelineManager.getEarlierAsset($viewingAsset);
|
||||
|
||||
if (earlierAsset) {
|
||||
const preloadAsset = await timelineManager.getEarlierAsset(earlierAsset);
|
||||
const asset = await getAssetInfo({ ...authManager.params, id: earlierAsset.id });
|
||||
assetViewingStore.setAsset(asset, preloadAsset ? [preloadAsset] : []);
|
||||
await navigate({ targetRoute: 'current', assetId: earlierAsset.id });
|
||||
}
|
||||
|
||||
release();
|
||||
return !!earlierAsset;
|
||||
};
|
||||
|
||||
handleRandom = async () => {
|
||||
const randomAsset = await timelineManager.getRandomAsset();
|
||||
|
||||
if (randomAsset) {
|
||||
const asset = await getAssetInfo({ ...authManager.params, id: randomAsset.id });
|
||||
assetViewingStore.setAsset(asset);
|
||||
await navigate({ targetRoute: 'current', assetId: randomAsset.id });
|
||||
return asset;
|
||||
}
|
||||
};
|
||||
|
||||
handleClose = async (asset: { id: string }) => {
|
||||
assetViewingStore.showAssetViewer(false);
|
||||
showSkeleton = true;
|
||||
$gridScrollTarget = { at: asset.id };
|
||||
await navigate({ targetRoute: 'current', assetId: null, assetGridRouteSearchParams: $gridScrollTarget });
|
||||
};
|
||||
|
||||
handlePreAction = async (action: Action) => {
|
||||
switch (action.type) {
|
||||
case removeAction:
|
||||
case AssetAction.TRASH:
|
||||
case AssetAction.RESTORE:
|
||||
case AssetAction.DELETE:
|
||||
case AssetAction.ARCHIVE:
|
||||
case AssetAction.SET_VISIBILITY_LOCKED:
|
||||
case AssetAction.SET_VISIBILITY_TIMELINE: {
|
||||
// find the next asset to show or close the viewer
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
(await handleNext()) || (await handlePrevious()) || (await handleClose(action.asset));
|
||||
|
||||
// delete after find the next one
|
||||
timelineManager.removeAssets([action.asset.id]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
handleAction = (action: Action) => {
|
||||
switch (action.type) {
|
||||
case AssetAction.ARCHIVE:
|
||||
case AssetAction.UNARCHIVE:
|
||||
case AssetAction.FAVORITE:
|
||||
case AssetAction.UNFAVORITE: {
|
||||
timelineManager.updateAssets([action.asset]);
|
||||
break;
|
||||
}
|
||||
|
||||
case AssetAction.ADD: {
|
||||
timelineManager.addAssets([action.asset]);
|
||||
break;
|
||||
}
|
||||
|
||||
case AssetAction.UNSTACK: {
|
||||
updateUnstackedAssetInTimeline(timelineManager, action.assets);
|
||||
break;
|
||||
}
|
||||
case AssetAction.REMOVE_ASSET_FROM_STACK: {
|
||||
timelineManager.addAssets([toTimelineAsset(action.asset)]);
|
||||
if (action.stack) {
|
||||
//Have to unstack then restack assets in timeline in order to update the stack count in the timeline.
|
||||
updateUnstackedAssetInTimeline(
|
||||
timelineManager,
|
||||
action.stack.assets.map((asset) => toTimelineAsset(asset)),
|
||||
);
|
||||
updateStackedAssetInTimeline(timelineManager, {
|
||||
stack: action.stack,
|
||||
toDeleteIds: action.stack.assets
|
||||
.filter((asset) => asset.id !== action.stack?.primaryAssetId)
|
||||
.map((asset) => asset.id),
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AssetAction.SET_STACK_PRIMARY_ASSET: {
|
||||
//Have to unstack then restack assets in timeline in order for the currently removed new primary asset to be made visible.
|
||||
updateUnstackedAssetInTimeline(
|
||||
timelineManager,
|
||||
action.stack.assets.map((asset) => toTimelineAsset(asset)),
|
||||
);
|
||||
updateStackedAssetInTimeline(timelineManager, {
|
||||
stack: action.stack,
|
||||
toDeleteIds: action.stack.assets
|
||||
.filter((asset) => asset.id !== action.stack.primaryAssetId)
|
||||
.map((asset) => asset.id),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user