mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor: favorite action (#25121)
This commit is contained in:
@@ -9,6 +9,6 @@
|
||||
const { title, icon, color = 'secondary', onAction } = $derived(action);
|
||||
</script>
|
||||
|
||||
{#if action.$if?.() ?? true}
|
||||
{#if icon && (action.$if?.() ?? true)}
|
||||
<IconButton variant="ghost" shape="round" {color} {icon} aria-label={title} onclick={() => onAction(action)} />
|
||||
{/if}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
const { title, icon, onAction } = $derived(action);
|
||||
</script>
|
||||
|
||||
{#if action.$if?.() ?? true}
|
||||
{#if icon && (action.$if?.() ?? true)}
|
||||
<IconButton {size} shape="round" color="primary" {icon} aria-label={title} onclick={() => onAction(action)} />
|
||||
{/if}
|
||||
|
||||
@@ -5,8 +5,6 @@ import type { AlbumResponseDto, AssetResponseDto, PersonResponseDto, StackRespon
|
||||
type ActionMap = {
|
||||
[AssetAction.ARCHIVE]: { asset: TimelineAsset };
|
||||
[AssetAction.UNARCHIVE]: { asset: TimelineAsset };
|
||||
[AssetAction.FAVORITE]: { asset: TimelineAsset };
|
||||
[AssetAction.UNFAVORITE]: { asset: TimelineAsset };
|
||||
[AssetAction.TRASH]: { asset: TimelineAsset };
|
||||
[AssetAction.DELETE]: { asset: TimelineAsset };
|
||||
[AssetAction.RESTORE]: { asset: TimelineAsset };
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { shortcut } from '$lib/actions/shortcut';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { updateAsset, type AssetResponseDto } from '@immich/sdk';
|
||||
import { IconButton, toastManager } from '@immich/ui';
|
||||
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { OnAction } from './action';
|
||||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
onAction: OnAction;
|
||||
}
|
||||
|
||||
let { asset, onAction }: Props = $props();
|
||||
|
||||
const toggleFavorite = async () => {
|
||||
try {
|
||||
const data = await updateAsset({
|
||||
id: asset.id,
|
||||
updateAssetDto: {
|
||||
isFavorite: !asset.isFavorite,
|
||||
},
|
||||
});
|
||||
|
||||
asset = { ...asset, isFavorite: data.isFavorite };
|
||||
|
||||
onAction({
|
||||
type: asset.isFavorite ? AssetAction.FAVORITE : AssetAction.UNFAVORITE,
|
||||
asset: toTimelineAsset(asset),
|
||||
});
|
||||
|
||||
toastManager.success(asset.isFavorite ? $t('added_to_favorites') : $t('removed_from_favorites'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_add_remove_favorites', { values: { favorite: asset.isFavorite } }));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:document use:shortcut={{ shortcut: { key: 'f' }, onShortcut: toggleFavorite }} />
|
||||
|
||||
<IconButton
|
||||
color="secondary"
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
|
||||
aria-label={asset.isFavorite ? $t('unfavorite') : $t('to_favorite')}
|
||||
onclick={toggleFavorite}
|
||||
/>
|
||||
@@ -8,7 +8,6 @@
|
||||
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
|
||||
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
|
||||
import DownloadAction from '$lib/components/asset-viewer/actions/download-action.svelte';
|
||||
import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte';
|
||||
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
|
||||
import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
|
||||
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
|
||||
@@ -28,7 +27,7 @@
|
||||
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||
import { getAssetJobName, getSharedLink } from '$lib/utils';
|
||||
import { getAssetJobName, getSharedLink, withoutIcons } from '$lib/utils';
|
||||
import type { OnUndoDelete } from '$lib/utils/actions';
|
||||
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
@@ -105,6 +104,7 @@
|
||||
|
||||
const Close: ActionItem = {
|
||||
title: $t('go_back'),
|
||||
type: $t('assets'),
|
||||
icon: mdiArrowLeft,
|
||||
$if: () => !!onClose,
|
||||
onAction: () => onClose?.(),
|
||||
@@ -113,7 +113,9 @@
|
||||
|
||||
const { Cast } = $derived(getGlobalActions($t));
|
||||
|
||||
const { Share, Offline, PlayMotionPhoto, StopMotionPhoto, Info } = $derived(getAssetActions($t, asset));
|
||||
const { Share, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } = $derived(
|
||||
getAssetActions($t, asset),
|
||||
);
|
||||
|
||||
// $: showEditorButton =
|
||||
// isOwner &&
|
||||
@@ -128,7 +130,7 @@
|
||||
|
||||
<CommandPaletteDefaultProvider
|
||||
name={$t('assets')}
|
||||
actions={[Close, Share, Offline, PlayMotionPhoto, StopMotionPhoto, Info]}
|
||||
actions={withoutIcons([Close, Share, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info])}
|
||||
/>
|
||||
|
||||
<div
|
||||
@@ -172,9 +174,10 @@
|
||||
{/if}
|
||||
|
||||
<ActionButton action={Info} />
|
||||
<ActionButton action={Favorite} />
|
||||
<ActionButton action={Unfavorite} />
|
||||
|
||||
{#if isOwner}
|
||||
<FavoriteAction {asset} {onAction} />
|
||||
<RatingAction {asset} {onAction} />
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -350,15 +350,6 @@
|
||||
selectedEditType = type;
|
||||
};
|
||||
|
||||
const handleAssetReplace = async ({ oldAssetId, newAssetId }: { oldAssetId: string; newAssetId: string }) => {
|
||||
if (oldAssetId !== asset.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
await new Promise((promise) => setTimeout(promise, 500));
|
||||
await goto(`${AppRoute.PHOTOS}/${newAssetId}`);
|
||||
};
|
||||
|
||||
let isFullScreen = $derived(fullscreenElement !== null);
|
||||
|
||||
$effect(() => {
|
||||
@@ -391,9 +382,24 @@
|
||||
preloadManager.preload(cursor.nextAsset);
|
||||
preloadManager.preload(cursor.previousAsset);
|
||||
});
|
||||
|
||||
const onAssetReplace = async ({ oldAssetId, newAssetId }: { oldAssetId: string; newAssetId: string }) => {
|
||||
if (oldAssetId !== asset.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
await new Promise((promise) => setTimeout(promise, 500));
|
||||
await goto(`${AppRoute.PHOTOS}/${newAssetId}`);
|
||||
};
|
||||
|
||||
const onAssetUpdate = (update: AssetResponseDto) => {
|
||||
if (asset.id === update.id) {
|
||||
asset = update;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<OnEvents onAssetReplace={handleAssetReplace} />
|
||||
<OnEvents {onAssetReplace} {onAssetUpdate} />
|
||||
|
||||
<svelte:document bind:fullscreenElement />
|
||||
|
||||
|
||||
@@ -39,13 +39,7 @@
|
||||
timelineManager?: TimelineManager;
|
||||
options?: TimelineManagerOptions;
|
||||
assetInteraction: AssetInteraction;
|
||||
removeAction?:
|
||||
| AssetAction.UNARCHIVE
|
||||
| AssetAction.ARCHIVE
|
||||
| AssetAction.FAVORITE
|
||||
| AssetAction.UNFAVORITE
|
||||
| AssetAction.SET_VISIBILITY_TIMELINE
|
||||
| null;
|
||||
removeAction?: AssetAction.UNARCHIVE | AssetAction.ARCHIVE | AssetAction.SET_VISIBILITY_TIMELINE | null;
|
||||
withStacked?: boolean;
|
||||
showArchiveIcon?: boolean;
|
||||
isShared?: boolean;
|
||||
|
||||
@@ -25,13 +25,7 @@
|
||||
album?: AlbumResponseDto;
|
||||
person?: PersonResponseDto;
|
||||
|
||||
removeAction?:
|
||||
| AssetAction.UNARCHIVE
|
||||
| AssetAction.ARCHIVE
|
||||
| AssetAction.FAVORITE
|
||||
| AssetAction.UNFAVORITE
|
||||
| AssetAction.SET_VISIBILITY_TIMELINE
|
||||
| null;
|
||||
removeAction?: AssetAction.UNARCHIVE | AssetAction.ARCHIVE | AssetAction.SET_VISIBILITY_TIMELINE | null;
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -141,8 +135,6 @@
|
||||
switch (action.type) {
|
||||
case AssetAction.ARCHIVE:
|
||||
case AssetAction.UNARCHIVE:
|
||||
case AssetAction.FAVORITE:
|
||||
case AssetAction.UNFAVORITE:
|
||||
case AssetAction.ADD: {
|
||||
timelineManager.upsertAssets([action.asset]);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user