mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix: correctly cancel select all assets (#26067)
This commit is contained in:
parent
e6e56d75e2
commit
a9e0fa43fa
6 changed files with 18 additions and 31 deletions
|
|
@ -1,7 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
|
||||||
import { IconButton } from '@immich/ui';
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiClose } from '@mdi/js';
|
import { mdiClose } from '@mdi/js';
|
||||||
import { onDestroy, onMount, type Snippet } from 'svelte';
|
import { onDestroy, onMount, type Snippet } from 'svelte';
|
||||||
|
|
@ -46,11 +44,6 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
$isSelectingAllAssets = false;
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (browser) {
|
if (browser) {
|
||||||
document.addEventListener('scroll', onScroll, { passive: true });
|
document.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
|
@ -82,7 +75,7 @@
|
||||||
{#if showBackButton}
|
{#if showBackButton}
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label={$t('close')}
|
aria-label={$t('close')}
|
||||||
onclick={handleClose}
|
onclick={onClose}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
shape="round"
|
shape="round"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
|
||||||
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
|
import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte';
|
||||||
import { isAssetViewerRoute, navigate } from '$lib/utils/navigation';
|
import { isAssetViewerRoute, navigate } from '$lib/utils/navigation';
|
||||||
import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util';
|
import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util';
|
||||||
|
|
@ -411,11 +410,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timelineManager.assetCount == assetInteraction.selectedAssets.length) {
|
assetInteraction.selectAll = timelineManager.assetCount === assetInteraction.selectedAssets.length;
|
||||||
isSelectingAllAssets.set(true);
|
|
||||||
} else {
|
|
||||||
isSelectingAllAssets.set(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelectAssets = async (asset: TimelineAsset) => {
|
const onSelectAssets = async (asset: TimelineAsset) => {
|
||||||
|
|
@ -559,7 +554,7 @@
|
||||||
assetInteraction.removeGroupFromMultiselectGroup(groupTitle);
|
assetInteraction.removeGroupFromMultiselectGroup(groupTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
isSelectingAllAssets.set(timelineManager.assetCount === assetInteraction.selectedAssets.length);
|
assetInteraction.selectAll = timelineManager.assetCount === assetInteraction.selectedAssets.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onClick = (
|
const _onClick = (
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
|
||||||
import { cancelMultiselect, selectAllAssets } from '$lib/utils/asset-utils';
|
import { cancelMultiselect, selectAllAssets } from '$lib/utils/asset-utils';
|
||||||
import { Button, IconButton } from '@immich/ui';
|
import { Button, IconButton } from '@immich/ui';
|
||||||
import { mdiSelectAll, mdiSelectRemove } from '@mdi/js';
|
import { mdiSelectAll, mdiSelectRemove } from '@mdi/js';
|
||||||
|
|
@ -14,6 +13,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let { timelineManager, assetInteraction, withText = false }: Props = $props();
|
let { timelineManager, assetInteraction, withText = false }: Props = $props();
|
||||||
|
const allAssetsSelected = $derived(assetInteraction.selectAll);
|
||||||
|
|
||||||
const handleSelectAll = async () => {
|
const handleSelectAll = async () => {
|
||||||
await selectAllAssets(timelineManager, assetInteraction);
|
await selectAllAssets(timelineManager, assetInteraction);
|
||||||
|
|
@ -26,21 +26,21 @@
|
||||||
|
|
||||||
{#if withText}
|
{#if withText}
|
||||||
<Button
|
<Button
|
||||||
leadingIcon={$isSelectingAllAssets ? mdiSelectRemove : mdiSelectAll}
|
leadingIcon={allAssetsSelected ? mdiSelectRemove : mdiSelectAll}
|
||||||
size="medium"
|
size="medium"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onclick={$isSelectingAllAssets ? handleCancel : handleSelectAll}
|
onclick={allAssetsSelected ? handleCancel : handleSelectAll}
|
||||||
>
|
>
|
||||||
{$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
{allAssetsSelected ? $t('unselect_all') : $t('select_all')}
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<IconButton
|
<IconButton
|
||||||
shape="round"
|
shape="round"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
aria-label={$isSelectingAllAssets ? $t('unselect_all') : $t('select_all')}
|
aria-label={allAssetsSelected ? $t('unselect_all') : $t('select_all')}
|
||||||
icon={$isSelectingAllAssets ? mdiSelectRemove : mdiSelectAll}
|
icon={allAssetsSelected ? mdiSelectRemove : mdiSelectAll}
|
||||||
onclick={$isSelectingAllAssets ? handleCancel : handleSelectAll}
|
onclick={allAssetsSelected ? handleCancel : handleSelectAll}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { fromStore } from 'svelte/store';
|
||||||
|
|
||||||
export class AssetInteraction {
|
export class AssetInteraction {
|
||||||
selectedAssets = $state<TimelineAsset[]>([]);
|
selectedAssets = $state<TimelineAsset[]>([]);
|
||||||
|
selectAll = $state(false);
|
||||||
hasSelectedAsset(assetId: string) {
|
hasSelectedAsset(assetId: string) {
|
||||||
return this.selectedAssets.some((asset) => asset.id === assetId);
|
return this.selectedAssets.some((asset) => asset.id === assetId);
|
||||||
}
|
}
|
||||||
|
|
@ -65,6 +66,8 @@ export class AssetInteraction {
|
||||||
}
|
}
|
||||||
|
|
||||||
clearMultiselect() {
|
clearMultiselect() {
|
||||||
|
this.selectAll = false;
|
||||||
|
|
||||||
// Multi-selection
|
// Multi-selection
|
||||||
this.selectedAssets = [];
|
this.selectedAssets = [];
|
||||||
this.selectedGroup.clear();
|
this.selectedGroup.clear();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
|
|
||||||
export const isSelectingAllAssets = writable(false);
|
|
||||||
|
|
@ -7,7 +7,6 @@ import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { downloadRequest, withError } from '$lib/utils';
|
import { downloadRequest, withError } from '$lib/utils';
|
||||||
import { getByteUnitString } from '$lib/utils/byte-units';
|
import { getByteUnitString } from '$lib/utils/byte-units';
|
||||||
|
|
@ -427,17 +426,17 @@ export const keepThisDeleteOthers = async (keepAsset: AssetResponseDto, stack: S
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectAllAssets = async (timelineManager: TimelineManager, assetInteraction: AssetInteraction) => {
|
export const selectAllAssets = async (timelineManager: TimelineManager, assetInteraction: AssetInteraction) => {
|
||||||
if (get(isSelectingAllAssets)) {
|
if (assetInteraction.selectAll) {
|
||||||
// Selection is already ongoing
|
// Selection is already ongoing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isSelectingAllAssets.set(true);
|
assetInteraction.selectAll = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const monthGroup of timelineManager.months) {
|
for (const monthGroup of timelineManager.months) {
|
||||||
await timelineManager.loadMonthGroup(monthGroup.yearMonth);
|
await timelineManager.loadMonthGroup(monthGroup.yearMonth);
|
||||||
|
|
||||||
if (!get(isSelectingAllAssets)) {
|
if (!assetInteraction.selectAll) {
|
||||||
assetInteraction.clearMultiselect();
|
assetInteraction.clearMultiselect();
|
||||||
break; // Cancelled
|
break; // Cancelled
|
||||||
}
|
}
|
||||||
|
|
@ -450,12 +449,12 @@ export const selectAllAssets = async (timelineManager: TimelineManager, assetInt
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const $t = get(t);
|
const $t = get(t);
|
||||||
handleError(error, $t('errors.error_selecting_all_assets'));
|
handleError(error, $t('errors.error_selecting_all_assets'));
|
||||||
isSelectingAllAssets.set(false);
|
assetInteraction.selectAll = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cancelMultiselect = (assetInteraction: AssetInteraction) => {
|
export const cancelMultiselect = (assetInteraction: AssetInteraction) => {
|
||||||
isSelectingAllAssets.set(false);
|
assetInteraction.selectAll = false;
|
||||||
assetInteraction.clearMultiselect();
|
assetInteraction.clearMultiselect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue