mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
feat: add shortcuts to asset-grid
This commit is contained in:
parent
b4d1470586
commit
e6e7f78f9f
@ -1,57 +1,32 @@
|
||||
<script lang="ts">
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import {
|
||||
NotificationType,
|
||||
notificationController,
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { api } from '@api';
|
||||
|
||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||
import { mdiArchiveArrowUpOutline, mdiArchiveArrowDownOutline, mdiTimerSand } from '@mdi/js';
|
||||
import type { OnArchive } from '$lib/utils/actions';
|
||||
import { archiveAssets, type OnArchive } from '$lib/utils/actions';
|
||||
import { isAllArchived } from '$lib/stores/asset-interaction.store';
|
||||
|
||||
export let onArchive: OnArchive | undefined = undefined;
|
||||
|
||||
export let menuItem = false;
|
||||
export let unarchive = false;
|
||||
|
||||
$: text = unarchive ? 'Unarchive' : 'Archive';
|
||||
$: icon = unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline;
|
||||
$: text = $isAllArchived ? 'Unarchive' : 'Archive';
|
||||
$: icon = $isAllArchived ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline;
|
||||
|
||||
let loading = false;
|
||||
|
||||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const isArchived = !unarchive;
|
||||
const isArchived = !$isAllArchived;
|
||||
loading = true;
|
||||
|
||||
try {
|
||||
const assets = Array.from(getOwnedAssets()).filter((asset) => asset.isArchived !== isArchived);
|
||||
const ids = assets.map(({ id }) => id);
|
||||
|
||||
if (ids.length > 0) {
|
||||
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isArchived } });
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
asset.isArchived = isArchived;
|
||||
}
|
||||
|
||||
onArchive?.(ids, isArchived);
|
||||
|
||||
notificationController.show({
|
||||
message: `${isArchived ? 'Archived' : 'Unarchived'} ${ids.length}`,
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
|
||||
const assets = Array.from(getOwnedAssets()).filter((asset) => asset.isArchived !== isArchived);
|
||||
if (await archiveAssets(isArchived, onArchive, assets)) {
|
||||
clearSelect();
|
||||
} catch (error) {
|
||||
handleError(error, `Unable to ${isArchived ? 'archive' : 'unarchive'}`);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
loading = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -1,58 +1,33 @@
|
||||
<script lang="ts">
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import {
|
||||
NotificationType,
|
||||
notificationController,
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { api } from '@api';
|
||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
|
||||
import type { OnFavorite } from '$lib/utils/actions';
|
||||
import { favoriteAssets, type OnFavorite } from '$lib/utils/actions';
|
||||
import { isAllFavorite } from '$lib/stores/asset-interaction.store';
|
||||
|
||||
export let onFavorite: OnFavorite | undefined = undefined;
|
||||
|
||||
export let menuItem = false;
|
||||
export let removeFavorite: boolean;
|
||||
|
||||
$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite';
|
||||
$: icon = removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline;
|
||||
$: text = $isAllFavorite ? 'Remove from Favorites' : 'Favorite';
|
||||
$: icon = $isAllFavorite ? mdiHeartMinusOutline : mdiHeartOutline;
|
||||
|
||||
let loading = false;
|
||||
|
||||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||
|
||||
const handleFavorite = async () => {
|
||||
const isFavorite = !removeFavorite;
|
||||
const isFavorite = !$isAllFavorite;
|
||||
loading = true;
|
||||
|
||||
try {
|
||||
const assets = Array.from(getOwnedAssets()).filter((asset) => asset.isFavorite !== isFavorite);
|
||||
|
||||
const ids = assets.map(({ id }) => id);
|
||||
|
||||
if (ids.length > 0) {
|
||||
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isFavorite } });
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
asset.isFavorite = isFavorite;
|
||||
}
|
||||
|
||||
onFavorite?.(ids, isFavorite);
|
||||
|
||||
notificationController.show({
|
||||
message: isFavorite ? `Added ${ids.length} to favorites` : `Removed ${ids.length} from favorites`,
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
const assets = Array.from(getOwnedAssets()).filter((asset) => asset.isFavorite !== isFavorite);
|
||||
|
||||
if (await favoriteAssets(isFavorite, onFavorite, assets)) {
|
||||
clearSelect();
|
||||
} catch (error) {
|
||||
handleError(error, `Unable to ${isFavorite ? 'add to' : 'remove from'} favorites`);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
|
||||
loading = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
import { BucketPosition, type AssetStore, isSelectAllCancelled } from '$lib/stores/assets.store';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
|
||||
import { get } from 'svelte/store';
|
||||
import { mdiTimerSand, mdiSelectAll } from '@mdi/js';
|
||||
import { selectAll } from '$lib/utils/actions';
|
||||
import type { AssetStore } from '$lib/stores/assets.store';
|
||||
|
||||
export let assetStore: AssetStore;
|
||||
export let assetInteractionStore: AssetInteractionStore;
|
||||
@ -12,25 +13,11 @@
|
||||
let selecting = false;
|
||||
|
||||
const handleSelectAll = async () => {
|
||||
try {
|
||||
$isSelectAllCancelled = false;
|
||||
selecting = true;
|
||||
selecting = true;
|
||||
|
||||
const assetGridState = get(assetStore);
|
||||
for (const bucket of assetGridState.buckets) {
|
||||
if ($isSelectAllCancelled) {
|
||||
break;
|
||||
}
|
||||
await assetStore.loadBucket(bucket.bucketDate, BucketPosition.Unknown);
|
||||
for (const asset of bucket.assets) {
|
||||
assetInteractionStore.selectAsset(asset);
|
||||
}
|
||||
}
|
||||
selectAll(get(assetStore), assetStore, assetInteractionStore);
|
||||
|
||||
selecting = false;
|
||||
} catch (e) {
|
||||
handleError(e, 'Error selecting all assets');
|
||||
}
|
||||
selecting = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -2,7 +2,12 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { AppRoute, AssetAction } from '$lib/constants';
|
||||
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
import {
|
||||
isAllUserOwned,
|
||||
type AssetInteractionStore,
|
||||
isAllFavorite,
|
||||
isAllArchived,
|
||||
} from '$lib/stores/asset-interaction.store';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { BucketPosition, type AssetStore, type Viewport } from '$lib/stores/assets.store';
|
||||
import { locale, showDeleteModal } from '$lib/stores/preferences.store';
|
||||
@ -19,8 +24,11 @@
|
||||
import AssetDateGroup from './asset-date-group.svelte';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||
import { deleteAssets } from '$lib/utils/actions';
|
||||
import { archiveAssets, deleteAssets, favoriteAssets, selectAll } from '$lib/utils/actions';
|
||||
import DeleteAssetDialog from './delete-asset-dialog.svelte';
|
||||
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
export let isSelectionMode = false;
|
||||
export let singleSelect = false;
|
||||
@ -47,6 +55,9 @@
|
||||
$: idsSelectedAssets = Array.from($selectedAssets)
|
||||
.filter((a) => !a.isExternal)
|
||||
.map((a) => a.id);
|
||||
$: $isAllUserOwned = Array.from($selectedAssets).every((asset) => asset.ownerId === $user.id);
|
||||
$: $isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
|
||||
$: $isAllArchived = Array.from($selectedAssets).every((asset) => asset.isArchived);
|
||||
|
||||
const onKeyboardPress = (event: KeyboardEvent) => handleKeyboardPress(event);
|
||||
const dispatch = createEventDispatcher<{ select: AssetResponseDto; escape: void }>();
|
||||
@ -70,24 +81,30 @@
|
||||
assetStore.disconnect();
|
||||
});
|
||||
|
||||
const trashOrDelete = (force: boolean = false) => {
|
||||
const trashOrDelete = async (force: boolean = false) => {
|
||||
isShowDeleteConfirmation = false;
|
||||
deleteAssets(!(isTrashEnabled && !force), (assetId) => assetStore.removeAsset(assetId), idsSelectedAssets);
|
||||
assetInteractionStore.clearMultiselect();
|
||||
if (
|
||||
await deleteAssets(!(isTrashEnabled && !force), (assetId) => assetStore.removeAsset(assetId), idsSelectedAssets)
|
||||
) {
|
||||
assetInteractionStore.clearMultiselect();
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyboardPress = (event: KeyboardEvent) => {
|
||||
const handleKeyboardPress = async (event: KeyboardEvent) => {
|
||||
if ($isSearchEnabled || shouldIgnoreShortcut(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = event.key;
|
||||
const shiftKey = event.shiftKey;
|
||||
const ctrlKey = event.ctrlKey;
|
||||
const assets = Array.from($selectedAssets);
|
||||
|
||||
if (!$showAssetViewer) {
|
||||
switch (key) {
|
||||
case 'Escape':
|
||||
dispatch('escape');
|
||||
case '/':
|
||||
event.preventDefault();
|
||||
goto(AppRoute.EXPLORE);
|
||||
return;
|
||||
case '?':
|
||||
if (event.shiftKey) {
|
||||
@ -95,9 +112,43 @@
|
||||
showShortcuts = !showShortcuts;
|
||||
}
|
||||
return;
|
||||
case '/':
|
||||
event.preventDefault();
|
||||
goto(AppRoute.EXPLORE);
|
||||
case 'a':
|
||||
case 'A':
|
||||
if ($isMultiSelectState) {
|
||||
if (ctrlKey) {
|
||||
event.preventDefault();
|
||||
selectAll(get(assetStore), assetStore, assetInteractionStore);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($isAllUserOwned) {
|
||||
if (
|
||||
await archiveAssets(
|
||||
!$isAllArchived,
|
||||
(assetIds) => {
|
||||
for (const assetId of assetIds) {
|
||||
assetStore.removeAsset(assetId);
|
||||
}
|
||||
},
|
||||
assets,
|
||||
)
|
||||
) {
|
||||
assetInteractionStore.clearMultiselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if ($isMultiSelectState) {
|
||||
assetInteractionStore.clearMultiselect();
|
||||
if (assets.length === 1) {
|
||||
await downloadFile(assets[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
await downloadArchive('immich.zip', { assetIds: assets.map((asset) => asset.id) });
|
||||
}
|
||||
return;
|
||||
case 'Delete':
|
||||
if ($isMultiSelectState) {
|
||||
@ -113,6 +164,16 @@
|
||||
trashOrDelete(force);
|
||||
}
|
||||
return;
|
||||
case 'Escape':
|
||||
dispatch('escape');
|
||||
return;
|
||||
case 'f':
|
||||
if ($isMultiSelectState && $isAllUserOwned) {
|
||||
if (await favoriteAssets(!$isAllFavorite, undefined, assets)) {
|
||||
assetInteractionStore.clearMultiselect();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -147,3 +147,7 @@ export function createAssetInteractionStore(): AssetInteractionStore {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const isAllUserOwned = writable<boolean>();
|
||||
export const isAllFavorite = writable<boolean>();
|
||||
export const isAllArchived = writable<boolean>();
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification';
|
||||
import { api } from '@api';
|
||||
import { api, AssetResponseDto } from '@api';
|
||||
import { handleError } from './handle-error';
|
||||
import { isSelectAllCancelled, type AssetStore, BucketPosition } from '$lib/stores/assets.store';
|
||||
import { get } from 'svelte/store';
|
||||
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
|
||||
export type OnDelete = (assetId: string) => void;
|
||||
export type OnRestore = (ids: string[]) => void;
|
||||
@ -8,7 +11,7 @@ export type OnArchive = (ids: string[], isArchived: boolean) => void;
|
||||
export type OnFavorite = (ids: string[], favorite: boolean) => void;
|
||||
export type OnStack = (ids: string[]) => void;
|
||||
|
||||
export const deleteAssets = async (force: boolean, onAssetDelete: OnDelete, ids: string[]) => {
|
||||
export const deleteAssets = async (force: boolean, onAssetDelete: OnDelete, ids: string[]): Promise<boolean> => {
|
||||
try {
|
||||
await api.assetApi.deleteAssets({ assetBulkDeleteDto: { ids, force } });
|
||||
for (const id of ids) {
|
||||
@ -19,7 +22,92 @@ export const deleteAssets = async (force: boolean, onAssetDelete: OnDelete, ids:
|
||||
message: `${force ? 'Permanently deleted' : 'Trashed'} ${ids.length} assets`,
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
handleError(e, 'Error deleting assets');
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const favoriteAssets = async (
|
||||
isFavorite: boolean,
|
||||
onFavorite: OnFavorite | undefined,
|
||||
assets: AssetResponseDto[],
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const ids = assets.map(({ id }) => id);
|
||||
|
||||
if (ids.length > 0) {
|
||||
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isFavorite } });
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
asset.isFavorite = isFavorite;
|
||||
}
|
||||
|
||||
onFavorite?.(ids, isFavorite);
|
||||
|
||||
notificationController.show({
|
||||
message: isFavorite ? `Added ${ids.length} to favorites` : `Removed ${ids.length} from favorites`,
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
handleError(error, `Unable to ${isFavorite ? 'add to' : 'remove from'} favorites`);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const archiveAssets = async (
|
||||
isArchived: boolean,
|
||||
onArchive: OnArchive | undefined,
|
||||
assets: AssetResponseDto[],
|
||||
) => {
|
||||
try {
|
||||
const ids = assets.map(({ id }) => id);
|
||||
|
||||
if (ids.length > 0) {
|
||||
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids, isArchived } });
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
asset.isArchived = isArchived;
|
||||
}
|
||||
|
||||
onArchive?.(ids, isArchived);
|
||||
|
||||
notificationController.show({
|
||||
message: `${isArchived ? 'Archived' : 'Unarchived'} ${ids.length}`,
|
||||
type: NotificationType.Info,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
handleError(error, `Unable to ${isArchived ? 'archive' : 'unarchive'}`);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const selectAll = async (
|
||||
assetGridState: AssetStore,
|
||||
assetStore: AssetStore,
|
||||
assetInteractionStore: AssetInteractionStore,
|
||||
): Promise<boolean> => {
|
||||
isSelectAllCancelled.set(false);
|
||||
try {
|
||||
for (const bucket of assetGridState.buckets) {
|
||||
if (get(isSelectAllCancelled)) {
|
||||
break;
|
||||
}
|
||||
await assetStore.loadBucket(bucket.bucketDate, BucketPosition.Unknown);
|
||||
for (const asset of bucket.assets) {
|
||||
assetInteractionStore.selectAsset(asset);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
handleError(e, 'Error selecting all assets');
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
@ -29,7 +29,7 @@
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||
import { AppRoute, dateFormats } from '$lib/constants';
|
||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
import { createAssetInteractionStore, isAllUserOwned } from '$lib/stores/asset-interaction.store';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||
import { AssetStore } from '$lib/stores/assets.store';
|
||||
@ -110,8 +110,6 @@
|
||||
const { selectedAssets: timelineSelected } = timelineInteractionStore;
|
||||
|
||||
$: isOwned = $user.id == album.ownerId;
|
||||
$: isAllUserOwned = Array.from($selectedAssets).every((asset) => asset.ownerId === $user.id);
|
||||
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
|
||||
$: {
|
||||
if (isShowActivity) {
|
||||
assetGridWidth = globalWidth - (globalWidth < 768 ? 360 : 460);
|
||||
@ -440,15 +438,15 @@
|
||||
<AddToAlbum shared />
|
||||
</AssetSelectContextMenu>
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||
{#if isAllUserOwned}
|
||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||
{#if $isAllUserOwned}
|
||||
<FavoriteAction menuItem />
|
||||
<ArchiveAction menuItem />
|
||||
{/if}
|
||||
<ArchiveAction menuItem />
|
||||
<DownloadAction menuItem filename="{album.albumName}.zip" />
|
||||
{#if isOwned || isAllUserOwned}
|
||||
{#if isOwned || $isAllUserOwned}
|
||||
<RemoveFromAlbum menuItem bind:album onRemove={(assetIds) => handleRemoveAssets(assetIds)} />
|
||||
{/if}
|
||||
{#if isAllUserOwned}
|
||||
{#if $isAllUserOwned}
|
||||
<DeleteAssets menuItem onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
||||
<ChangeDate menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
|
@ -23,13 +23,11 @@
|
||||
const assetStore = new AssetStore({ isArchived: true });
|
||||
const assetInteractionStore = createAssetInteractionStore();
|
||||
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
||||
|
||||
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
|
||||
</script>
|
||||
|
||||
{#if $isMultiSelectState}
|
||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
||||
<ArchiveAction unarchive onArchive={(ids) => assetStore.removeAssets(ids)} />
|
||||
<ArchiveAction onArchive={(ids) => assetStore.removeAssets(ids)} />
|
||||
<CreateSharedLink />
|
||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||
@ -39,7 +37,7 @@
|
||||
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||
<DownloadAction menuItem />
|
||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||
<FavoriteAction menuItem />
|
||||
</AssetSelectContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
{/if}
|
||||
|
@ -25,14 +25,12 @@
|
||||
const assetStore = new AssetStore({ isFavorite: true });
|
||||
const assetInteractionStore = createAssetInteractionStore();
|
||||
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
||||
|
||||
$: isAllArchive = Array.from($selectedAssets).every((asset) => asset.isArchived);
|
||||
</script>
|
||||
|
||||
<!-- Multiselection mode app bar -->
|
||||
{#if $isMultiSelectState}
|
||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}>
|
||||
<FavoriteAction removeFavorite onFavorite={(ids) => assetStore.removeAssets(ids)} />
|
||||
<FavoriteAction onFavorite={(ids) => assetStore.removeAssets(ids)} />
|
||||
<CreateSharedLink />
|
||||
<SelectAllAssets {assetStore} {assetInteractionStore} />
|
||||
<AssetSelectContextMenu icon={mdiPlus} title="Add">
|
||||
@ -42,7 +40,7 @@
|
||||
<DeleteAssets onAssetDelete={(assetId) => assetStore.removeAsset(assetId)} />
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||
<DownloadAction menuItem />
|
||||
<ArchiveAction menuItem unarchive={isAllArchive} />
|
||||
<ArchiveAction menuItem />
|
||||
<ChangeDate menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
</AssetSelectContextMenu>
|
||||
|
@ -108,8 +108,6 @@
|
||||
isSearchingPeople = false;
|
||||
};
|
||||
|
||||
$: isAllArchive = Array.from($selectedAssets).every((asset) => asset.isArchived);
|
||||
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
|
||||
$: $onPersonThumbnail === data.person.id &&
|
||||
(thumbnailData = api.getPeopleThumbnailUrl(data.person.id) + `?now=${Date.now()}`);
|
||||
|
||||
@ -394,8 +392,8 @@
|
||||
<DeleteAssets onAssetDelete={(assetId) => $assetStore.removeAsset(assetId)} />
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||
<DownloadAction menuItem filename="{data.person.name || 'immich'}.zip" />
|
||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||
<ArchiveAction menuItem unarchive={isAllArchive} onArchive={(ids) => $assetStore.removeAssets(ids)} />
|
||||
<FavoriteAction menuItem />
|
||||
<ArchiveAction menuItem onArchive={(ids) => $assetStore.removeAssets(ids)} />
|
||||
<MenuOption text="Fix incorrect match" on:click={handleReassignAssets} />
|
||||
<ChangeDate menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
|
@ -31,8 +31,6 @@
|
||||
const assetInteractionStore = createAssetInteractionStore();
|
||||
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
||||
|
||||
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
|
||||
|
||||
const handleEscape = () => {
|
||||
if ($showAssetViewer) {
|
||||
return;
|
||||
@ -65,7 +63,7 @@
|
||||
onAssetDelete={(assetId) => assetStore.removeAsset(assetId)}
|
||||
/>
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||
<FavoriteAction menuItem />
|
||||
<DownloadAction menuItem />
|
||||
<ArchiveAction menuItem onArchive={(ids) => assetStore.removeAssets(ids)} />
|
||||
{#if $selectedAssets.size > 1}
|
||||
|
@ -96,8 +96,6 @@
|
||||
|
||||
let selectedAssets: Set<AssetResponseDto> = new Set();
|
||||
$: isMultiSelectionMode = selectedAssets.size > 0;
|
||||
$: isAllArchived = Array.from(selectedAssets).every((asset) => asset.isArchived);
|
||||
$: isAllFavorite = Array.from(selectedAssets).every((asset) => asset.isFavorite);
|
||||
$: searchResultAssets = data.results?.assets.items;
|
||||
|
||||
const onAssetDelete = (assetId: string) => {
|
||||
@ -122,8 +120,8 @@
|
||||
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Add">
|
||||
<DownloadAction menuItem />
|
||||
<FavoriteAction menuItem removeFavorite={isAllFavorite} />
|
||||
<ArchiveAction menuItem unarchive={isAllArchived} />
|
||||
<FavoriteAction menuItem />
|
||||
<ArchiveAction menuItem />
|
||||
<ChangeDate menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
</AssetSelectContextMenu>
|
||||
|
Loading…
x
Reference in New Issue
Block a user