refactor: asset select manager (#27327)

This commit is contained in:
Jason Rasmussen
2026-03-27 13:48:51 -04:00
committed by GitHub
parent 9b80ffd9c6
commit 14cce0cba3
22 changed files with 148 additions and 212 deletions
@@ -16,13 +16,7 @@
import { showDeleteModal } from '$lib/stores/preferences.store';
import { handlePromiseError } from '$lib/utils';
import { deleteAssets } from '$lib/utils/actions';
import {
archiveAssets,
cancelMultiselect,
getNextAsset,
getPreviousAsset,
navigateToAsset,
} from '$lib/utils/asset-utils';
import { archiveAssets, getNextAsset, getPreviousAsset, navigateToAsset } from '$lib/utils/asset-utils';
import { moveFocus } from '$lib/utils/focus-util';
import { handleError } from '$lib/utils/handle-error';
import { getJustifiedLayoutFromAssets } from '$lib/utils/layout-utils';
@@ -126,10 +120,6 @@
assetInteraction.selectAssets(assets.map((a) => toTimelineAsset(a)));
};
const deselectAllAssets = () => {
cancelMultiselect(assetInteraction);
};
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Shift') {
event.preventDefault();
@@ -153,18 +143,18 @@
// Select/deselect already loaded assets
if (deselect) {
for (const candidate of assetInteraction.assetSelectionCandidates) {
for (const candidate of assetInteraction.candidates) {
assetInteraction.removeAssetFromMultiselectGroup(candidate.id);
}
assetInteraction.removeAssetFromMultiselectGroup(asset.id);
} else {
for (const candidate of assetInteraction.assetSelectionCandidates) {
for (const candidate of assetInteraction.candidates) {
assetInteraction.selectAsset(candidate);
}
assetInteraction.selectAsset(asset);
}
assetInteraction.clearAssetSelectionCandidates();
assetInteraction.clearCandidates();
assetInteraction.setAssetSelectionStart(deselect ? null : asset);
};
@@ -202,13 +192,13 @@
};
const onDelete = () => {
const hasTrashedAsset = assetInteraction.selectedAssets.some((asset) => asset.isTrashed);
const hasTrashedAsset = assetInteraction.assets.some((asset) => asset.isTrashed);
handlePromiseError(trashOrDelete(hasTrashedAsset));
};
const trashOrDelete = async (force: boolean = false) => {
const forceOrNoTrash = force || !featureFlagsManager.value.trash;
const selectedAssets = assetInteraction.selectedAssets;
const selectedAssets = assetInteraction.assets;
if ($showDeleteModal && forceOrNoTrash) {
const confirmed = await modalManager.show(AssetDeleteConfirmModal, { size: selectedAssets.length });
@@ -224,17 +214,17 @@
onReload,
);
assetInteraction.clearMultiselect();
assetInteraction.clear();
};
const toggleArchive = async () => {
const ids = await archiveAssets(
assetInteraction.selectedAssets,
assetInteraction.assets,
assetInteraction.isAllArchived ? AssetVisibility.Timeline : AssetVisibility.Archive,
);
if (ids) {
assets = assets.filter((asset) => !ids.includes(asset.id));
deselectAllAssets();
assetInteraction.clear();
}
};
@@ -274,8 +264,8 @@
if (assetInteraction.selectionActive) {
shortcuts.push(
{ shortcut: { key: 'Escape' }, onShortcut: deselectAllAssets },
{ shortcut: { key: 'D', ctrl: true }, onShortcut: deselectAllAssets },
{ shortcut: { key: 'Escape' }, onShortcut: () => assetInteraction.clear() },
{ shortcut: { key: 'D', ctrl: true }, onShortcut: () => assetInteraction.clear() },
);
if (allowDeletion) {
shortcuts.push(
@@ -335,13 +325,13 @@
$effect(() => {
if (!lastAssetMouseEvent) {
assetInteraction.clearAssetSelectionCandidates();
assetInteraction.clearCandidates();
}
});
$effect(() => {
if (!shiftKeyIsDown) {
assetInteraction.clearAssetSelectionCandidates();
assetInteraction.clearCandidates();
}
});
@@ -45,7 +45,7 @@
let { bbox, selectedClusterIds, assetCount, onClose }: Props = $props();
let timelineManager = $state<TimelineManager>() as TimelineManager;
let selectedAssets = $derived(assetMultiSelectManager.selectedAssets);
let selectedAssets = $derived(assetMultiSelectManager.assets);
let isAssetStackSelected = $derived(selectedAssets.length === 1 && !!selectedAssets[0].stack);
let isLinkActionAvailable = $derived.by(() => {
const isLivePhoto = selectedAssets.length === 1 && !!selectedAssets[0].livePhotoVideoId;
@@ -69,11 +69,11 @@
const handleSetVisibility = (assetIds: string[]) => {
timelineManager.removeAssets(assetIds);
assetMultiSelectManager.clearMultiselect();
assetMultiSelectManager.clear();
};
const handleEscape = () => {
assetMultiSelectManager.clearMultiselect();
assetMultiSelectManager.clear();
};
const timelineBoundingBox = $derived(
@@ -90,7 +90,7 @@
$effect.pre(() => {
void timelineOptions;
assetMultiSelectManager.clearMultiselect();
assetMultiSelectManager.clear();
});
</script>
@@ -124,8 +124,8 @@
<Portal target="body">
<AssetSelectControlBar
ownerId={$user.id}
assets={assetMultiSelectManager.selectedAssets}
clearSelect={() => assetMultiSelectManager.clearMultiselect()}
assets={assetMultiSelectManager.assets}
clearSelect={() => assetMultiSelectManager.clear()}
>
<CreateSharedLink />
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
@@ -139,7 +139,7 @@
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
<DownloadAction menuItem />
{#if assetMultiSelectManager.selectedAssets.length > 1 || isAssetStackSelected}
{#if assetMultiSelectManager.assets.length > 1 || isAssetStackSelected}
<StackAction
unstack={isAssetStackSelected}
onStack={(result) => updateStackedAssetInTimeline(timelineManager, result)}
@@ -149,7 +149,7 @@
{#if isLinkActionAvailable}
<LinkLivePhotoAction
menuItem
unlink={assetMultiSelectManager.selectedAssets.length === 1}
unlink={assetMultiSelectManager.assets.length === 1}
onLink={handleLink}
onUnlink={handleUnlink}
/>