mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
Refactor date group actions from Svelte component to TypeScript class
• Convert asset-date-group-actions.svelte to date-group-actions-lib.svelte.ts class • Remove complex prop binding between asset-grid-without-scrubber and asset-date-group • Use class instance in asset-date-group with direct method access
This commit is contained in:
parent
0beeea6985
commit
9a30198238
4 changed files with 220 additions and 245 deletions
|
|
@ -1,218 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } 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 { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||
import { searchStore } from '$lib/stores/search.svelte';
|
||||
|
||||
interface Props {
|
||||
timelineManager: TimelineManager;
|
||||
assetInteraction: AssetInteraction;
|
||||
singleSelect?: boolean;
|
||||
|
||||
handleScrollTop: (scrollTop: number) => void;
|
||||
onSelect?: (asset: TimelineAsset) => void;
|
||||
|
||||
onDateGroupSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void;
|
||||
onSelectAssets: (asset: TimelineAsset) => Promise<void>;
|
||||
onSelectAssetCandidates: (asset: TimelineAsset | null) => void;
|
||||
}
|
||||
|
||||
let {
|
||||
singleSelect = false,
|
||||
timelineManager,
|
||||
assetInteraction,
|
||||
handleScrollTop = () => {},
|
||||
onSelect = () => {},
|
||||
onDateGroupSelect = $bindable(),
|
||||
onSelectAssets = $bindable(),
|
||||
onSelectAssetCandidates = $bindable(),
|
||||
}: Props = $props();
|
||||
|
||||
const handleSelectAsset = (asset: TimelineAsset) => {
|
||||
if (!timelineManager.albumAssets.has(asset.id)) {
|
||||
assetInteraction.selectAsset(asset);
|
||||
}
|
||||
};
|
||||
|
||||
let lastAssetMouseEvent: TimelineAsset | null = $state(null);
|
||||
|
||||
let shiftKeyIsDown = $state(false);
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (searchStore.isSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'Shift') {
|
||||
event.preventDefault();
|
||||
shiftKeyIsDown = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyUp = (event: KeyboardEvent) => {
|
||||
if (searchStore.isSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'Shift') {
|
||||
event.preventDefault();
|
||||
shiftKeyIsDown = false;
|
||||
}
|
||||
};
|
||||
|
||||
onSelectAssetCandidates = (asset: TimelineAsset | null) => {
|
||||
if (asset) {
|
||||
void selectAssetCandidates(asset);
|
||||
}
|
||||
lastAssetMouseEvent = asset;
|
||||
};
|
||||
|
||||
onDateGroupSelect = ({ title: group, assets }: { title: string; assets: TimelineAsset[] }) => {
|
||||
if (assetInteraction.selectedGroup.has(group)) {
|
||||
assetInteraction.removeGroupFromMultiselectGroup(group);
|
||||
for (const asset of assets) {
|
||||
assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
}
|
||||
} else {
|
||||
assetInteraction.addGroupToMultiselectGroup(group);
|
||||
for (const asset of assets) {
|
||||
handleSelectAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
if (timelineManager.assetCount == assetInteraction.selectedAssets.length) {
|
||||
isSelectingAllAssets.set(true);
|
||||
} else {
|
||||
isSelectingAllAssets.set(false);
|
||||
}
|
||||
};
|
||||
|
||||
onSelectAssets = async (asset: TimelineAsset) => {
|
||||
if (!asset) {
|
||||
return;
|
||||
}
|
||||
onSelect(asset);
|
||||
|
||||
if (singleSelect) {
|
||||
handleScrollTop(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeSelection = assetInteraction.assetSelectionCandidates.length > 0;
|
||||
const deselect = assetInteraction.hasSelectedAsset(asset.id);
|
||||
|
||||
// Select/deselect already loaded assets
|
||||
if (deselect) {
|
||||
for (const candidate of assetInteraction.assetSelectionCandidates) {
|
||||
assetInteraction.removeAssetFromMultiselectGroup(candidate.id);
|
||||
}
|
||||
assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
} else {
|
||||
for (const candidate of assetInteraction.assetSelectionCandidates) {
|
||||
handleSelectAsset(candidate);
|
||||
}
|
||||
handleSelectAsset(asset);
|
||||
}
|
||||
|
||||
assetInteraction.clearAssetSelectionCandidates();
|
||||
|
||||
if (assetInteraction.assetSelectionStart && rangeSelection) {
|
||||
let startBucket = timelineManager.getMonthGroupByAssetId(assetInteraction.assetSelectionStart.id);
|
||||
let endBucket = timelineManager.getMonthGroupByAssetId(asset.id);
|
||||
|
||||
if (startBucket === null || endBucket === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Select/deselect assets in range (start,end)
|
||||
let started = false;
|
||||
for (const monthGroup of timelineManager.months) {
|
||||
if (monthGroup === endBucket) {
|
||||
break;
|
||||
}
|
||||
if (started) {
|
||||
await timelineManager.loadMonthGroup(monthGroup.yearMonth);
|
||||
for (const asset of monthGroup.assetsIterator()) {
|
||||
if (deselect) {
|
||||
assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
} else {
|
||||
handleSelectAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (monthGroup === startBucket) {
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update date group selection in range [start,end]
|
||||
started = false;
|
||||
for (const monthGroup of timelineManager.months) {
|
||||
if (monthGroup === startBucket) {
|
||||
started = true;
|
||||
}
|
||||
if (started) {
|
||||
// Split month group into day groups and check each group
|
||||
for (const dayGroup of monthGroup.dayGroups) {
|
||||
const dayGroupTitle = dayGroup.groupTitle;
|
||||
if (dayGroup.getAssets().every((a) => assetInteraction.hasSelectedAsset(a.id))) {
|
||||
assetInteraction.addGroupToMultiselectGroup(dayGroupTitle);
|
||||
} else {
|
||||
assetInteraction.removeGroupFromMultiselectGroup(dayGroupTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (monthGroup === endBucket) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assetInteraction.setAssetSelectionStart(deselect ? null : asset);
|
||||
};
|
||||
|
||||
const selectAssetCandidates = async (endAsset: TimelineAsset) => {
|
||||
if (!shiftKeyIsDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startAsset = assetInteraction.assetSelectionStart;
|
||||
if (!startAsset) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assets = assetsSnapshot(await timelineManager.retrieveRange(startAsset, endAsset));
|
||||
assetInteraction.setAssetSelectionCandidates(assets);
|
||||
};
|
||||
|
||||
let isEmpty = $derived(timelineManager.isInitialized && timelineManager.months.length === 0);
|
||||
|
||||
$effect(() => {
|
||||
if (isEmpty) {
|
||||
assetInteraction.clearMultiselect();
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (!lastAssetMouseEvent) {
|
||||
assetInteraction.clearAssetSelectionCandidates();
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (!shiftKeyIsDown) {
|
||||
assetInteraction.clearAssetSelectionCandidates();
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (shiftKeyIsDown && lastAssetMouseEvent) {
|
||||
void selectAssetCandidates(lastAssetMouseEvent);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:document onkeydown={onKeyDown} onkeyup={onKeyUp} />
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { assetSnapshot, assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
import { flip } from 'svelte/animate';
|
||||
import { fly, scale } from 'svelte/transition';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { DateGroupActionLib } from './date-group-actions-lib.svelte';
|
||||
|
||||
let { isUploading } = uploadAssetsStore;
|
||||
|
||||
interface Props {
|
||||
|
|
@ -29,11 +32,13 @@
|
|||
timelineManager: TimelineManager;
|
||||
assetInteraction: AssetInteraction;
|
||||
customLayout?: Snippet<[TimelineAsset]>;
|
||||
onSelect: (asset: TimelineAsset) => void;
|
||||
|
||||
onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void;
|
||||
onSelectAssets: (asset: TimelineAsset) => void;
|
||||
onSelectAssetCandidates: (asset: TimelineAsset | null) => void;
|
||||
// onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void;
|
||||
// onSelectAssets: (asset: TimelineAsset) => void;
|
||||
// onSelectAssetCandidates: (asset: TimelineAsset | null) => void;
|
||||
onScrollCompensation: (compensation: { heightDelta?: number; scrollTop?: number }) => void;
|
||||
scrollTop: (top: number) => void;
|
||||
onThumbnailClick?: (
|
||||
asset: TimelineAsset,
|
||||
timelineManager: TimelineManager,
|
||||
|
|
@ -57,12 +62,21 @@
|
|||
timelineManager,
|
||||
customLayout,
|
||||
onSelect,
|
||||
onSelectAssets,
|
||||
onSelectAssetCandidates,
|
||||
onScrollCompensation,
|
||||
scrollTop,
|
||||
onThumbnailClick,
|
||||
}: Props = $props();
|
||||
|
||||
const actionLib = new DateGroupActionLib();
|
||||
|
||||
onMount(() => {
|
||||
actionLib.assetInteraction = assetInteraction;
|
||||
actionLib.timelineManager = timelineManager;
|
||||
actionLib.singleSelect = singleSelect;
|
||||
actionLib.onSelect = onSelect;
|
||||
actionLib.scrollTop = scrollTop;
|
||||
});
|
||||
|
||||
let isMouseOverGroup = $state(false);
|
||||
let hoveredDayGroup = $state();
|
||||
|
||||
|
|
@ -83,15 +97,14 @@
|
|||
void navigate({ targetRoute: 'current', assetId: asset.id });
|
||||
};
|
||||
|
||||
const handleSelectGroup = (title: string, assets: TimelineAsset[]) => onSelect({ title, assets });
|
||||
|
||||
// called when clicking asset with shift key pressed or with mouse
|
||||
const assetSelectHandler = (
|
||||
timelineManager: TimelineManager,
|
||||
asset: TimelineAsset,
|
||||
assetsInDayGroup: TimelineAsset[],
|
||||
groupTitle: string,
|
||||
) => {
|
||||
onSelectAssets(asset);
|
||||
void actionLib.onSelectAssets(asset);
|
||||
|
||||
// Check if all assets are selected in a group to toggle the group selection's icon
|
||||
let selectedAssetsInGroupCount = assetsInDayGroup.filter((asset) =>
|
||||
|
|
@ -117,7 +130,7 @@
|
|||
hoveredDayGroup = groupTitle;
|
||||
|
||||
if (assetInteraction.selectionActive) {
|
||||
onSelectAssetCandidates(asset);
|
||||
actionLib.onSelectAssetCandidates(asset);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -143,6 +156,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<svelte:document onkeydown={actionLib.onKeyDown} onkeyup={actionLib.onKeyUp} />
|
||||
|
||||
{#each filterIntersecting(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)}
|
||||
{@const absoluteWidth = dayGroup.left}
|
||||
|
||||
|
|
@ -173,8 +188,10 @@
|
|||
<div
|
||||
transition:fly={{ x: -24, duration: 200, opacity: 0.5 }}
|
||||
class="inline-block pe-2 hover:cursor-pointer"
|
||||
onclick={() => handleSelectGroup(dayGroup.groupTitle, assetsSnapshot(dayGroup.getAssets()))}
|
||||
onkeydown={() => handleSelectGroup(dayGroup.groupTitle, assetsSnapshot(dayGroup.getAssets()))}
|
||||
onclick={() =>
|
||||
actionLib.onDateGroupSelect({ title: dayGroup.groupTitle, assets: assetsSnapshot(dayGroup.getAssets()) })}
|
||||
onkeydown={() =>
|
||||
actionLib.onDateGroupSelect({ title: dayGroup.groupTitle, assets: assetsSnapshot(dayGroup.getAssets()) })}
|
||||
>
|
||||
{#if assetInteraction.selectedGroup.has(dayGroup.groupTitle)}
|
||||
<Icon path={mdiCheckCircle} size="24" class="text-primary" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { resizeObserver, type OnResizeCallback } from '$lib/actions/resize-observer';
|
||||
import AssetDateGroupActions from '$lib/components/photos-page/asset-date-group-actions.svelte';
|
||||
import AssetGridActions from '$lib/components/photos-page/asset-grid-actions.svelte';
|
||||
import AssetViewerAndActions from '$lib/components/photos-page/asset-viewer-and-actions.svelte';
|
||||
import Skeleton from '$lib/components/photos-page/skeleton.svelte';
|
||||
|
|
@ -75,7 +74,7 @@
|
|||
album = null,
|
||||
person = null,
|
||||
isShowDeleteConfirmation = $bindable(false),
|
||||
onSelect = () => {},
|
||||
onSelect = (asset: TimelineAsset) => void 0,
|
||||
onEscape = () => {},
|
||||
children,
|
||||
empty,
|
||||
|
|
@ -278,16 +277,6 @@
|
|||
let onSelectAssetCandidates = <(asset: TimelineAsset | null) => void>$state();
|
||||
</script>
|
||||
|
||||
<AssetDateGroupActions
|
||||
{timelineManager}
|
||||
{assetInteraction}
|
||||
handleScrollTop={scrollTop}
|
||||
{onSelect}
|
||||
bind:onDateGroupSelect
|
||||
bind:onSelectAssets
|
||||
bind:onSelectAssetCandidates
|
||||
></AssetDateGroupActions>
|
||||
|
||||
<AssetGridActions {scrollToAsset} {timelineManager} {assetInteraction} bind:isShowDeleteConfirmation {onEscape}
|
||||
></AssetGridActions>
|
||||
|
||||
|
|
@ -356,9 +345,8 @@
|
|||
{isSelectionMode}
|
||||
{singleSelect}
|
||||
{monthGroup}
|
||||
onSelect={onDateGroupSelect}
|
||||
{onSelectAssetCandidates}
|
||||
{onSelectAssets}
|
||||
{onSelect}
|
||||
{scrollTop}
|
||||
onScrollCompensation={handleScrollCompensation}
|
||||
{customLayout}
|
||||
{onThumbnailClick}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,188 @@
|
|||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||
import { searchStore } from '$lib/stores/search.svelte';
|
||||
|
||||
/** Glue functions that update the assetInteraction (asset selection) in response to AssetDateGroup UI
|
||||
*
|
||||
*/
|
||||
export class DateGroupActionLib {
|
||||
onSelect: (asset: TimelineAsset) => void = () => void 0;
|
||||
scrollTop: (top: number) => void = () => void 0;
|
||||
assetInteraction: AssetInteraction = $state(new AssetInteraction());
|
||||
timelineManager: TimelineManager = $state(new TimelineManager());
|
||||
singleSelect: boolean = $state(false);
|
||||
lastAssetMouseEvent: TimelineAsset | null = $state(null);
|
||||
shiftKeyIsDown = $state(false);
|
||||
isEmpty = $derived(this.timelineManager.isInitialized && this.timelineManager.months.length === 0);
|
||||
|
||||
constructor() {
|
||||
$effect(() => {
|
||||
if (!this.lastAssetMouseEvent || !this.lastAssetMouseEvent) {
|
||||
this.assetInteraction.clearAssetSelectionCandidates();
|
||||
}
|
||||
if (this.shiftKeyIsDown && this.lastAssetMouseEvent) {
|
||||
void this.selectAssetCandidates(this.lastAssetMouseEvent);
|
||||
}
|
||||
if (this.isEmpty) {
|
||||
this.assetInteraction.clearMultiselect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleSelectAsset(asset: TimelineAsset) {
|
||||
if (!this.timelineManager.albumAssets.has(asset.id)) {
|
||||
this.assetInteraction.selectAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
onKeyDown = (event: KeyboardEvent) => {
|
||||
if (searchStore.isSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'Shift') {
|
||||
event.preventDefault();
|
||||
this.shiftKeyIsDown = true;
|
||||
}
|
||||
};
|
||||
|
||||
onKeyUp = (event: KeyboardEvent) => {
|
||||
if (searchStore.isSearchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'Shift') {
|
||||
event.preventDefault();
|
||||
this.shiftKeyIsDown = false;
|
||||
}
|
||||
};
|
||||
|
||||
onSelectAssetCandidates = (asset: TimelineAsset | null) => {
|
||||
if (asset) {
|
||||
void this.selectAssetCandidates(asset);
|
||||
}
|
||||
this.lastAssetMouseEvent = asset;
|
||||
};
|
||||
|
||||
onDateGroupSelect = ({ title: group, assets }: { title: string; assets: TimelineAsset[] }) => {
|
||||
if (this.assetInteraction.selectedGroup.has(group)) {
|
||||
this.assetInteraction.removeGroupFromMultiselectGroup(group);
|
||||
for (const asset of assets) {
|
||||
this.assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
}
|
||||
} else {
|
||||
this.assetInteraction.addGroupToMultiselectGroup(group);
|
||||
for (const asset of assets) {
|
||||
this.handleSelectAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.timelineManager.assetCount == this.assetInteraction.selectedAssets.length) {
|
||||
isSelectingAllAssets.set(true);
|
||||
} else {
|
||||
isSelectingAllAssets.set(false);
|
||||
}
|
||||
};
|
||||
|
||||
onSelectAssets = async (asset: TimelineAsset) => {
|
||||
if (!asset) {
|
||||
return;
|
||||
}
|
||||
this.onSelect(asset);
|
||||
|
||||
if (this.singleSelect) {
|
||||
this.scrollTop(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeSelection = this.assetInteraction.assetSelectionCandidates.length > 0;
|
||||
const deselect = this.assetInteraction.hasSelectedAsset(asset.id);
|
||||
|
||||
// Select/deselect already loaded assets
|
||||
if (deselect) {
|
||||
for (const candidate of this.assetInteraction.assetSelectionCandidates) {
|
||||
this.assetInteraction.removeAssetFromMultiselectGroup(candidate.id);
|
||||
}
|
||||
this.assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
} else {
|
||||
for (const candidate of this.assetInteraction.assetSelectionCandidates) {
|
||||
this.handleSelectAsset(candidate);
|
||||
}
|
||||
this.handleSelectAsset(asset);
|
||||
}
|
||||
|
||||
this.assetInteraction.clearAssetSelectionCandidates();
|
||||
|
||||
if (this.assetInteraction.assetSelectionStart && rangeSelection) {
|
||||
let startBucket = this.timelineManager.getMonthGroupByAssetId(this.assetInteraction.assetSelectionStart.id);
|
||||
let endBucket = this.timelineManager.getMonthGroupByAssetId(asset.id);
|
||||
|
||||
if (startBucket === null || endBucket === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Select/deselect assets in range (start,end)
|
||||
let started = false;
|
||||
for (const monthGroup of this.timelineManager.months) {
|
||||
if (monthGroup === endBucket) {
|
||||
break;
|
||||
}
|
||||
if (started) {
|
||||
await this.timelineManager.loadMonthGroup(monthGroup.yearMonth);
|
||||
for (const asset of monthGroup.assetsIterator()) {
|
||||
if (deselect) {
|
||||
this.assetInteraction.removeAssetFromMultiselectGroup(asset.id);
|
||||
} else {
|
||||
this.handleSelectAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (monthGroup === startBucket) {
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update date group selection in range [start,end]
|
||||
started = false;
|
||||
for (const monthGroup of this.timelineManager.months) {
|
||||
if (monthGroup === startBucket) {
|
||||
started = true;
|
||||
}
|
||||
if (started) {
|
||||
// Split month group into day groups and check each group
|
||||
for (const dayGroup of monthGroup.dayGroups) {
|
||||
const dayGroupTitle = dayGroup.groupTitle;
|
||||
if (dayGroup.getAssets().every((a) => this.assetInteraction.hasSelectedAsset(a.id))) {
|
||||
this.assetInteraction.addGroupToMultiselectGroup(dayGroupTitle);
|
||||
} else {
|
||||
this.assetInteraction.removeGroupFromMultiselectGroup(dayGroupTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (monthGroup === endBucket) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.assetInteraction.setAssetSelectionStart(deselect ? null : asset);
|
||||
};
|
||||
|
||||
selectAssetCandidates = async (endAsset: TimelineAsset) => {
|
||||
if (!this.shiftKeyIsDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startAsset = this.assetInteraction.assetSelectionStart;
|
||||
if (!startAsset) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assets = assetsSnapshot(await this.timelineManager.retrieveRange(startAsset, endAsset));
|
||||
this.assetInteraction.setAssetSelectionCandidates(assets);
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue