mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor: asset select manager (#27329)
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||||
import { handlePromiseError } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import type { AlbumResponseDto, SharedLinkResponseDto, UserResponseDto } from '@immich/sdk';
|
import type { AlbumResponseDto, SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { ActionButton, IconButton, Logo } from '@immich/ui';
|
import { ActionButton, IconButton, Logo } from '@immich/ui';
|
||||||
import { mdiDownload, mdiFileImagePlusOutline, mdiPresentationPlay } from '@mdi/js';
|
import { mdiDownload, mdiFileImagePlusOutline, mdiPresentationPlay } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@@ -26,10 +26,9 @@
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sharedLink: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
user?: UserResponseDto | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let { sharedLink, user = undefined }: Props = $props();
|
let { sharedLink }: Props = $props();
|
||||||
|
|
||||||
const album = sharedLink.album as AlbumResponseDto;
|
const album = sharedLink.album as AlbumResponseDto;
|
||||||
|
|
||||||
@@ -97,11 +96,7 @@
|
|||||||
|
|
||||||
<header>
|
<header>
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
ownerId={user?.id}
|
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
||||||
{#if sharedLink.allowDownload}
|
{#if sharedLink.allowDownload}
|
||||||
<DownloadAction filename="{album.albumName}.zip" />
|
<DownloadAction filename="{album.albumName}.zip" />
|
||||||
|
|||||||
@@ -336,11 +336,7 @@
|
|||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<div class="sticky top-0 z-1 dark">
|
<div class="sticky top-0 z-1 dark">
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar forceDark>
|
||||||
forceDark
|
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|||||||
@@ -80,10 +80,7 @@
|
|||||||
|
|
||||||
<header class="fixed top-0 inset-s-0 w-full">
|
<header class="fixed top-0 inset-s-0 w-full">
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
shape="round"
|
shape="round"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import { getAssetBulkActions } from '$lib/services/asset.service';
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { mapSettings } from '$lib/stores/preferences.store';
|
import { mapSettings } from '$lib/stores/preferences.store';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import {
|
import {
|
||||||
updateStackedAssetInTimeline,
|
updateStackedAssetInTimeline,
|
||||||
updateUnstackedAssetInTimeline,
|
updateUnstackedAssetInTimeline,
|
||||||
@@ -122,11 +122,7 @@
|
|||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
|
|
||||||
<Portal target="body">
|
<Portal target="body">
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
ownerId={$user.id}
|
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
||||||
<ActionButton action={Actions.AddToAlbum} />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
|
|||||||
@@ -1,32 +1,26 @@
|
|||||||
<script lang="ts" module>
|
|
||||||
import { setAssetControlContext } from '$lib/utils/context';
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
|
import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte';
|
||||||
|
import { setAssetControlContext } from '$lib/utils/context';
|
||||||
import { mdiClose } from '@mdi/js';
|
import { mdiClose } from '@mdi/js';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
assets: TimelineAsset[];
|
|
||||||
clearSelect: () => void;
|
|
||||||
ownerId?: string | undefined;
|
|
||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
forceDark?: boolean;
|
forceDark?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { assets, clearSelect, ownerId = undefined, children, forceDark }: Props = $props();
|
let { children, forceDark }: Props = $props();
|
||||||
|
|
||||||
setAssetControlContext({
|
setAssetControlContext(assetMultiSelectManager.asControlContext());
|
||||||
getAssets: () => assets,
|
|
||||||
getOwnedAssets: () => (ownerId === undefined ? assets : assets.filter((asset) => asset.ownerId === ownerId)),
|
const onClose = () => assetMultiSelectManager.clear();
|
||||||
clearSelect: () => clearSelect(),
|
|
||||||
});
|
const assets = $derived(assetMultiSelectManager.assets);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ControlAppBar onClose={clearSelect} {forceDark} backIcon={mdiClose} tailwindClasses="bg-white shadow-md">
|
<ControlAppBar {onClose} {forceDark} backIcon={mdiClose} tailwindClasses="bg-white shadow-md">
|
||||||
{#snippet leading()}
|
{#snippet leading()}
|
||||||
<div class="font-medium {forceDark ? 'text-immich-dark-primary' : 'text-primary'}">
|
<div class="font-medium {forceDark ? 'text-immich-dark-primary' : 'text-primary'}">
|
||||||
<p class="block sm:hidden">{assets.length}</p>
|
<p class="block sm:hidden">{assets.length}</p>
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ export class AssetMultiSelectManager {
|
|||||||
|
|
||||||
asControlContext(): AssetControlContext {
|
asControlContext(): AssetControlContext {
|
||||||
return {
|
return {
|
||||||
getOwnedAssets: () => this.assets.filter((asset) => asset.ownerId === this.#userId),
|
getOwnedAssets: () =>
|
||||||
|
this.#userId ? this.assets.filter((asset) => asset.ownerId === this.#userId) : this.assets,
|
||||||
getAssets: () => this.assets,
|
getAssets: () => this.assets,
|
||||||
clearSelect: () => this.clear(),
|
clearSelect: () => this.clear(),
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-4
@@ -451,10 +451,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
</UserPageLayout>
|
</UserPageLayout>
|
||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<ArchiveAction
|
<ArchiveAction
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<!-- Multiselection mode app bar -->
|
<!-- Multiselection mode app bar -->
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<div class="fixed top-0 start-0 w-full">
|
<div class="fixed top-0 start-0 w-full">
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
<!-- Multi-selection mode app bar -->
|
<!-- Multi-selection mode app bar -->
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
<SelectAllAssets withText {timelineManager} assetInteraction={assetMultiSelectManager} />
|
<SelectAllAssets withText {timelineManager} assetInteraction={assetMultiSelectManager} />
|
||||||
<SetVisibilityAction unlock onVisibilitySet={handleMoveOffLockedFolder} />
|
<SetVisibilityAction unlock onVisibilitySet={handleMoveOffLockedFolder} />
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
|
|||||||
+1
-1
@@ -458,7 +458,7 @@
|
|||||||
|
|
||||||
<header>
|
<header>
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
import { getAssetBulkActions } from '$lib/services/asset.service';
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { getAssetMediaUrl, memoryLaneTitle } from '$lib/utils';
|
import { getAssetMediaUrl, memoryLaneTitle } from '$lib/utils';
|
||||||
import {
|
import {
|
||||||
updateStackedAssetInTimeline,
|
updateStackedAssetInTimeline,
|
||||||
@@ -112,11 +112,7 @@
|
|||||||
</UserPageLayout>
|
</UserPageLayout>
|
||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
ownerId={$user.id}
|
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
|
|
||||||
|
|||||||
@@ -318,10 +318,7 @@
|
|||||||
<section>
|
<section>
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<div class="fixed top-0 start-0 w-full z-2">
|
<div class="fixed top-0 start-0 w-full z-2">
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
import { getAssetBulkActions } from '$lib/services/asset.service';
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { getTagActions } from '$lib/services/tag.service';
|
import { getTagActions } from '$lib/services/tag.service';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { joinPaths, TreeNode } from '$lib/utils/tree-utils';
|
import { joinPaths, TreeNode } from '$lib/utils/tree-utils';
|
||||||
import { getAllTags, type TagResponseDto } from '@immich/sdk';
|
import { getAllTags, type TagResponseDto } from '@immich/sdk';
|
||||||
import { ActionButton, CommandPaletteDefaultProvider, Text } from '@immich/ui';
|
import { ActionButton, CommandPaletteDefaultProvider, Text } from '@immich/ui';
|
||||||
@@ -113,11 +113,7 @@
|
|||||||
<section>
|
<section>
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<div class="fixed top-0 start-0 w-full">
|
<div class="fixed top-0 start-0 w-full">
|
||||||
<AssetSelectControlBar
|
<AssetSelectControlBar>
|
||||||
ownerId={$user.id}
|
|
||||||
assets={assetMultiSelectManager.assets}
|
|
||||||
clearSelect={() => assetMultiSelectManager.clear()}
|
|
||||||
>
|
|
||||||
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())}
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if assetMultiSelectManager.selectionActive}
|
{#if assetMultiSelectManager.selectionActive}
|
||||||
<AssetSelectControlBar assets={assetMultiSelectManager.assets} clearSelect={() => assetMultiSelectManager.clear()}>
|
<AssetSelectControlBar>
|
||||||
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
<SelectAllAssets {timelineManager} assetInteraction={assetMultiSelectManager} />
|
||||||
<DeleteAssets force onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
<DeleteAssets force onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||||
<RestoreAssets onRestore={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
<RestoreAssets onRestore={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||||
|
|||||||
Reference in New Issue
Block a user