mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
Merge c6e1170e6d into efa21af6f9
This commit is contained in:
commit
57e7bf2264
57 changed files with 259 additions and 280 deletions
|
|
@ -1,24 +1,24 @@
|
|||
import type { AssetAction } from '$lib/constants';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import type { AlbumResponseDto, AssetResponseDto, PersonResponseDto, StackResponseDto } from '@immich/sdk';
|
||||
|
||||
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 };
|
||||
[AssetAction.ADD]: { asset: TimelineAsset };
|
||||
[AssetAction.ADD_TO_ALBUM]: { asset: TimelineAsset; album: AlbumResponseDto };
|
||||
[AssetAction.ARCHIVE]: { asset: Asset };
|
||||
[AssetAction.UNARCHIVE]: { asset: Asset };
|
||||
[AssetAction.FAVORITE]: { asset: Asset };
|
||||
[AssetAction.UNFAVORITE]: { asset: Asset };
|
||||
[AssetAction.TRASH]: { asset: Asset };
|
||||
[AssetAction.DELETE]: { asset: Asset };
|
||||
[AssetAction.RESTORE]: { asset: Asset };
|
||||
[AssetAction.ADD]: { asset: Asset };
|
||||
[AssetAction.ADD_TO_ALBUM]: { asset: Asset; album: AlbumResponseDto };
|
||||
[AssetAction.STACK]: { stack: StackResponseDto };
|
||||
[AssetAction.UNSTACK]: { assets: TimelineAsset[] };
|
||||
[AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: TimelineAsset };
|
||||
[AssetAction.UNSTACK]: { assets: Asset[] };
|
||||
[AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: Asset };
|
||||
[AssetAction.SET_STACK_PRIMARY_ASSET]: { stack: StackResponseDto };
|
||||
[AssetAction.REMOVE_ASSET_FROM_STACK]: { stack: StackResponseDto | null; asset: AssetResponseDto };
|
||||
[AssetAction.SET_VISIBILITY_LOCKED]: { asset: TimelineAsset };
|
||||
[AssetAction.SET_VISIBILITY_TIMELINE]: { asset: TimelineAsset };
|
||||
[AssetAction.SET_VISIBILITY_LOCKED]: { asset: Asset };
|
||||
[AssetAction.SET_VISIBILITY_TIMELINE]: { asset: Asset };
|
||||
[AssetAction.SET_PERSON_FEATURED_PHOTO]: { asset: AssetResponseDto; person: PersonResponseDto };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import { AssetAction } from '$lib/constants';
|
||||
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
|
||||
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { modalManager } from '@immich/ui';
|
||||
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
|
||||
|
|
@ -29,13 +29,13 @@
|
|||
if (albums.length === 1) {
|
||||
const album = albums[0];
|
||||
await addAssetsToAlbum(album.id, [asset.id]);
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album });
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toAsset(asset), album });
|
||||
} else {
|
||||
await addAssetsToAlbums(
|
||||
albums.map((a) => a.id),
|
||||
[asset.id],
|
||||
);
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album: albums[0] });
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toAsset(asset), album: albums[0] });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { toggleArchive } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
const onArchive = async () => {
|
||||
if (!asset.isArchived) {
|
||||
preAction({ type: AssetAction.ARCHIVE, asset: toTimelineAsset(asset) });
|
||||
preAction({ type: AssetAction.ARCHIVE, asset: toAsset(asset) });
|
||||
}
|
||||
const updatedAsset = await toggleArchive(asset);
|
||||
if (updatedAsset) {
|
||||
onAction({ type: asset.isArchived ? AssetAction.ARCHIVE : AssetAction.UNARCHIVE, asset: toTimelineAsset(asset) });
|
||||
onAction({ type: asset.isArchived ? AssetAction.ARCHIVE : AssetAction.UNARCHIVE, asset: toAsset(asset) });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
import { showDeleteModal } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { deleteAssets, type AssetResponseDto } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import { mdiDeleteForeverOutline, mdiDeleteOutline } from '@mdi/js';
|
||||
|
|
@ -43,9 +43,9 @@
|
|||
|
||||
const trashAsset = async () => {
|
||||
try {
|
||||
preAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
preAction({ type: AssetAction.TRASH, asset: toAsset(asset) });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id] } });
|
||||
onAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
onAction({ type: AssetAction.TRASH, asset: toAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
message: $t('moved_to_trash'),
|
||||
|
|
@ -58,9 +58,9 @@
|
|||
|
||||
const deleteAsset = async () => {
|
||||
try {
|
||||
preAction({ type: AssetAction.DELETE, asset: toTimelineAsset(asset) });
|
||||
preAction({ type: AssetAction.DELETE, asset: toAsset(asset) });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
|
||||
onAction({ type: AssetAction.DELETE, asset: toTimelineAsset(asset) });
|
||||
onAction({ type: AssetAction.DELETE, asset: toAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
message: $t('permanently_deleted_asset'),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { shortcut } from '$lib/actions/shortcut';
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { downloadFile } from '$lib/utils/asset-utils';
|
||||
import { getAssetInfo } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
menuItem?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { updateAsset, type AssetResponseDto } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { OnAction } from './action';
|
||||
import { IconButton } from '@immich/ui';
|
||||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
onAction({
|
||||
type: asset.isFavorite ? AssetAction.FAVORITE : AssetAction.UNFAVORITE,
|
||||
asset: toTimelineAsset(asset),
|
||||
asset: toAsset(asset),
|
||||
});
|
||||
|
||||
notificationController.show({
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { keepThisDeleteOthers } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto, StackResponseDto } from '@immich/sdk';
|
||||
import { modalManager } from '@immich/ui';
|
||||
import { mdiPinOutline } from '@mdi/js';
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
const keptAsset = await keepThisDeleteOthers(asset, stack);
|
||||
if (keptAsset) {
|
||||
onAction({ type: AssetAction.UNSTACK, assets: [toTimelineAsset(keptAsset)] });
|
||||
onAction({ type: AssetAction.UNSTACK, assets: [toAsset(keptAsset)] });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { restoreAssets, type AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiHistory } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
await restoreAssets({ bulkIdsDto: { ids: [asset.id] } });
|
||||
asset.isTrashed = false;
|
||||
|
||||
onAction({ type: AssetAction.RESTORE, asset: toTimelineAsset(asset) });
|
||||
onAction({ type: AssetAction.RESTORE, asset: toAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { AssetVisibility, updateAssets } from '@immich/sdk';
|
||||
import { modalManager } from '@immich/ui';
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
import type { OnAction, PreAction } from './action';
|
||||
|
||||
interface Props {
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
onAction: OnAction;
|
||||
preAction: PreAction;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { deleteStack } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import type { StackResponseDto } from '@immich/sdk';
|
||||
import { mdiImageOffOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
const handleUnstack = async () => {
|
||||
const unstackedAssets = await deleteStack([stack.id]);
|
||||
if (unstackedAssets) {
|
||||
onAction({ type: AssetAction.UNSTACK, assets: unstackedAssets.map((asset) => toTimelineAsset(asset)) });
|
||||
onAction({ type: AssetAction.UNSTACK, assets: unstackedAssets.map((asset) => toAsset(asset)) });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
import { getAssetJobName, getSharedLink } from '$lib/utils';
|
||||
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import {
|
||||
AssetJobName,
|
||||
AssetTypeEnum,
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
{/if}
|
||||
|
||||
{#if !isOwner && showDownloadButton}
|
||||
<DownloadAction asset={toTimelineAsset(asset)} />
|
||||
<DownloadAction asset={toAsset(asset)} />
|
||||
{/if}
|
||||
|
||||
{#if showDetailButton}
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
||||
{/if}
|
||||
{#if showDownloadButton}
|
||||
<DownloadAction asset={toTimelineAsset(asset)} menuItem />
|
||||
<DownloadAction asset={toAsset(asset)} menuItem />
|
||||
{/if}
|
||||
|
||||
{#if !isLocked}
|
||||
|
|
@ -243,7 +243,7 @@
|
|||
{/if}
|
||||
|
||||
{#if !asset.isTrashed}
|
||||
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
|
||||
<SetVisibilityAction asset={toAsset(asset)} {onAction} {preAction} />
|
||||
{/if}
|
||||
<hr />
|
||||
<MenuOption
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import { AssetAction, ProjectionType } from '$lib/constants';
|
||||
import { activityManager } from '$lib/managers/activity-manager.svelte';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { closeEditorCofirm } from '$lib/stores/asset-editor.store';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { isShowDetail } from '$lib/stores/preferences.store';
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
import { getAssetJobMessage, getSharedLink, handlePromiseError } from '$lib/utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { SlideshowHistory } from '$lib/utils/slideshow-history';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import {
|
||||
AssetJobName,
|
||||
AssetTypeEnum,
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
preloadAssets?: TimelineAsset[];
|
||||
preloadAssets?: Asset[];
|
||||
showNavigation?: boolean;
|
||||
withStacked?: boolean;
|
||||
isShared?: boolean;
|
||||
|
|
@ -126,7 +126,7 @@
|
|||
|
||||
untrack(() => {
|
||||
if (stack && stack?.assets.length > 1) {
|
||||
preloadAssets.push(toTimelineAsset(stack.assets[1]));
|
||||
preloadAssets.push(toAsset(stack.assets[1]));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
slideshowStateUnsubscribe = slideshowState.subscribe((value) => {
|
||||
if (value === SlideshowState.PlaySlideshow) {
|
||||
slideshowHistory.reset();
|
||||
slideshowHistory.queue(toTimelineAsset(asset));
|
||||
slideshowHistory.queue(toAsset(asset));
|
||||
handlePromiseError(handlePlaySlideshow());
|
||||
} else if (value === SlideshowState.StopSlideshow) {
|
||||
handlePromiseError(handleStopSlideshow());
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
shuffleSlideshowUnsubscribe = slideshowNavigation.subscribe((value) => {
|
||||
if (value === SlideshowNavigation.Shuffle) {
|
||||
slideshowHistory.reset();
|
||||
slideshowHistory.queue(toTimelineAsset(asset));
|
||||
slideshowHistory.queue(toAsset(asset));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -569,7 +569,7 @@
|
|||
imageClass={{ 'border-2 border-white': stackedAsset.id === asset.id }}
|
||||
brokenAssetClass="text-xs"
|
||||
dimmed={stackedAsset.id !== asset.id}
|
||||
asset={toTimelineAsset(stackedAsset)}
|
||||
asset={toAsset(stackedAsset)}
|
||||
onClick={() => {
|
||||
asset = stackedAsset;
|
||||
previewStackedAsset = undefined;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
resetGlobalCropStore,
|
||||
rotateDegrees,
|
||||
} from '$lib/stores/asset-editor.store';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { animateCropChange, recalculateCrop } from './crop-settings';
|
||||
import { cropAreaEl, cropFrame, imgElement, isResizingOrDragging, overlayEl, resetCropStore } from './crop-store';
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
aria-label="Crop area"
|
||||
type="button"
|
||||
>
|
||||
<img draggable="false" src={img?.src} alt={$getAltText(toTimelineAsset(asset))} />
|
||||
<img draggable="false" src={img?.src} alt={$getAltText(toAsset(asset))} />
|
||||
<div class={`${$isResizingOrDragging ? 'resizing' : ''} crop-frame`} bind:this={$cropFrame}>
|
||||
<div class="grid"></div>
|
||||
<div class="corner top-left"></div>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import BrokenAsset from '$lib/components/assets/broken-asset.svelte';
|
||||
import { assetViewerFadeDuration } from '$lib/constants';
|
||||
import { castManager } from '$lib/managers/cast-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
||||
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
|
||||
import { boundingBoxesArray } from '$lib/stores/people.store';
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
import { getBoundingBox } from '$lib/utils/people-utils';
|
||||
import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { AssetMediaSize, type AssetResponseDto, type SharedLinkResponseDto } from '@immich/sdk';
|
||||
import { LoadingSpinner } from '@immich/ui';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
preloadAssets?: TimelineAsset[] | undefined;
|
||||
preloadAssets?: Asset[] | undefined;
|
||||
element?: HTMLDivElement | undefined;
|
||||
haveFadeTransition?: boolean;
|
||||
sharedLink?: SharedLinkResponseDto | undefined;
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
$boundingBoxesArray = [];
|
||||
});
|
||||
|
||||
const preload = (targetSize: AssetMediaSize | 'original', preloadAssets?: TimelineAsset[]) => {
|
||||
const preload = (targetSize: AssetMediaSize | 'original', preloadAssets?: Asset[]) => {
|
||||
for (const preloadAsset of preloadAssets || []) {
|
||||
if (preloadAsset.isImage) {
|
||||
let img = new Image();
|
||||
|
|
@ -249,7 +249,7 @@
|
|||
<img
|
||||
bind:this={$photoViewerImgElement}
|
||||
src={assetFileUrl}
|
||||
alt={$getAltText(toTimelineAsset(asset))}
|
||||
alt={$getAltText(toAsset(asset))}
|
||||
class="h-full w-full {$slideshowState === SlideshowState.None
|
||||
? 'object-contain'
|
||||
: slideshowLookCssMapping[$slideshowLook]}"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { thumbhash } from '$lib/actions/thumbhash';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
|
||||
import { moveFocus } from '$lib/utils/focus-util';
|
||||
import { currentUrlReplaceAssetId } from '$lib/utils/navigation';
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
import VideoThumbnail from './video-thumbnail.svelte';
|
||||
|
||||
interface Props {
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
groupIndex?: number;
|
||||
thumbnailSize?: number;
|
||||
thumbnailWidth?: number;
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
imageClass?: ClassValue;
|
||||
brokenAssetClass?: ClassValue;
|
||||
dimmed?: boolean;
|
||||
onClick?: (asset: TimelineAsset) => void;
|
||||
onSelect?: (asset: TimelineAsset) => void;
|
||||
onClick?: (asset: Asset) => void;
|
||||
onSelect?: (asset: Asset) => void;
|
||||
onMouseEvent?: (event: { isMouseOver: boolean; selectedGroupIndex: number }) => void;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { assetViewerFadeDuration } from '$lib/constants';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||
import { AssetMediaSize } from '@immich/sdk';
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
import { fade } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
onImageLoad: () => void;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { assetViewerFadeDuration } from '$lib/constants';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { AssetMediaSize } from '@immich/sdk';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
videoPlayer: HTMLVideoElement | undefined;
|
||||
videoViewerMuted?: boolean;
|
||||
videoViewerVolume?: number;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { type MemoryAsset, memoryStore } from '$lib/stores/memory.store.svelte';
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
import { preferences } from '$lib/stores/user.store';
|
||||
import { getAssetThumbnailUrl, handlePromiseError, memoryLaneTitle } from '$lib/utils';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
import { fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { fromISODateTimeUTC, toAsset } from '$lib/utils/timeline-util';
|
||||
import { AssetMediaSize, getAssetInfo } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import {
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
let currentMemoryAssetFull = $derived.by(async () =>
|
||||
current?.asset ? await getAssetInfo({ ...authManager.params, id: current.asset.id }) : undefined,
|
||||
);
|
||||
let currentTimelineAssets = $derived(current?.memory.assets.map((asset) => toTimelineAsset(asset)) || []);
|
||||
let currentAssets = $derived(current?.memory.assets.map((asset) => toAsset(asset)) || []);
|
||||
|
||||
let isSaved = $derived(current?.memory.isSaved);
|
||||
let viewerHeight = $state(0);
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
await goto(asHref(asset));
|
||||
};
|
||||
|
||||
const setProgressDuration = (asset: TimelineAsset) => {
|
||||
const setProgressDuration = (asset: Asset) => {
|
||||
if (asset.isVideo) {
|
||||
const timeParts = asset.duration!.split(':').map(Number);
|
||||
const durationInMilliseconds = (timeParts[0] * 3600 + timeParts[1] * 60 + timeParts[2]) * 1000;
|
||||
|
|
@ -116,8 +116,7 @@
|
|||
const handleNextMemory = () => handleNavigate(current?.nextMemory?.assets[0]);
|
||||
const handlePreviousMemory = () => handleNavigate(current?.previousMemory?.assets[0]);
|
||||
const handleEscape = async () => goto(AppRoute.PHOTOS);
|
||||
const handleSelectAll = () =>
|
||||
assetInteraction.selectAssets(current?.memory.assets.map((a) => toTimelineAsset(a)) || []);
|
||||
const handleSelectAll = () => assetInteraction.selectAssets(current?.memory.assets.map((a) => toAsset(a)) || []);
|
||||
|
||||
const handleAction = async (callingContext: string, action: 'reset' | 'pause' | 'play') => {
|
||||
// leaving these log statements here as comments. Very useful to figure out what's going on during dev!
|
||||
|
|
@ -658,7 +657,7 @@
|
|||
<GalleryViewer
|
||||
onNext={handleNextAsset}
|
||||
onPrevious={handlePreviousAsset}
|
||||
assets={currentTimelineAssets}
|
||||
assets={currentAssets}
|
||||
viewport={galleryViewport}
|
||||
{assetInteraction}
|
||||
slidingWindowOffset={viewerHeight}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import { memoryStore } from '$lib/stores/memory.store.svelte';
|
||||
import { getAssetThumbnailUrl, memoryLaneTitle } from '$lib/utils';
|
||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { Icon } from '@immich/ui';
|
||||
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
<img
|
||||
class="h-full w-full rounded-xl object-cover"
|
||||
src={getAssetThumbnailUrl(memory.assets[0].id)}
|
||||
alt={$t('memory_lane_title', { values: { title: $getAltText(toTimelineAsset(memory.assets[0])) } })}
|
||||
alt={$t('memory_lane_title', { values: { title: $getAltText(toAsset(memory.assets[0])) } })}
|
||||
draggable="false"
|
||||
/>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
import { cancelMultiselect, downloadArchive } from '$lib/utils/asset-utils';
|
||||
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { addSharedLinkAssets, getAssetInfo, type SharedLinkResponseDto } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import { mdiArrowLeft, mdiDownload, mdiFileImagePlusOutline, mdiSelectAll } from '@mdi/js';
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
const viewport: Viewport = $state({ width: 0, height: 0 });
|
||||
const assetInteraction = new AssetInteraction();
|
||||
|
||||
let assets = $derived(sharedLink.assets.map((a) => toTimelineAsset(a)));
|
||||
let assets = $derived(sharedLink.assets.map((a) => toAsset(a)));
|
||||
|
||||
dragAndDropFilesStore.subscribe((value) => {
|
||||
if (value.isDragging && value.files.length > 0) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
|
||||
import { AppRoute, AssetAction } from '$lib/constants';
|
||||
import Portal from '$lib/elements/Portal.svelte';
|
||||
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
|
||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getJustifiedLayoutFromAssets, type CommonJustifiedLayout } from '$lib/utils/layout-utils';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
import { isTimelineAsset, toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { isAsset, toAsset } from '$lib/utils/timeline-util';
|
||||
import { AssetVisibility, type AssetResponseDto } from '@immich/sdk';
|
||||
import { modalManager } from '@immich/ui';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
interface Props {
|
||||
initialAssetId?: string;
|
||||
assets: (TimelineAsset | AssetResponseDto)[];
|
||||
assets: (Asset | AssetResponseDto)[];
|
||||
assetInteraction: AssetInteraction;
|
||||
disableAssetSelect?: boolean;
|
||||
showArchiveIcon?: boolean;
|
||||
|
|
@ -130,7 +130,7 @@
|
|||
}
|
||||
|
||||
let shiftKeyIsDown = $state(false);
|
||||
let lastAssetMouseEvent: TimelineAsset | null = $state(null);
|
||||
let lastAssetMouseEvent: Asset | null = $state(null);
|
||||
let slidingWindow = $state({ top: 0, bottom: 0 });
|
||||
|
||||
const updateSlidingWindow = () => {
|
||||
|
|
@ -157,14 +157,14 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
const viewAssetHandler = async (asset: TimelineAsset) => {
|
||||
const viewAssetHandler = async (asset: Asset) => {
|
||||
currentIndex = assets.findIndex((a) => a.id == asset.id);
|
||||
await setAssetId(assets[currentIndex].id);
|
||||
await navigate({ targetRoute: 'current', assetId: $viewingAsset.id });
|
||||
};
|
||||
|
||||
const selectAllAssets = () => {
|
||||
assetInteraction.selectAssets(assets.map((a) => toTimelineAsset(a)));
|
||||
assetInteraction.selectAssets(assets.map((a) => toAsset(a)));
|
||||
};
|
||||
|
||||
const deselectAllAssets = () => {
|
||||
|
|
@ -186,7 +186,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleSelectAssets = (asset: TimelineAsset) => {
|
||||
const handleSelectAssets = (asset: Asset) => {
|
||||
if (!asset) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -209,14 +209,14 @@
|
|||
assetInteraction.setAssetSelectionStart(deselect ? null : asset);
|
||||
};
|
||||
|
||||
const handleSelectAssetCandidates = (asset: TimelineAsset | null) => {
|
||||
const handleSelectAssetCandidates = (asset: Asset | null) => {
|
||||
if (asset) {
|
||||
selectAssetCandidates(asset);
|
||||
}
|
||||
lastAssetMouseEvent = asset;
|
||||
};
|
||||
|
||||
const selectAssetCandidates = (endAsset: TimelineAsset) => {
|
||||
const selectAssetCandidates = (endAsset: Asset) => {
|
||||
if (!shiftKeyIsDown) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@
|
|||
[start, end] = [end, start];
|
||||
}
|
||||
|
||||
assetInteraction.setAssetSelectionCandidates(assets.slice(start, end + 1).map((a) => toTimelineAsset(a)));
|
||||
assetInteraction.setAssetSelectionCandidates(assets.slice(start, end + 1).map((a) => toAsset(a)));
|
||||
};
|
||||
|
||||
const onSelectStart = (event: Event) => {
|
||||
|
|
@ -434,7 +434,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const assetMouseEventHandler = (asset: TimelineAsset | null) => {
|
||||
const assetMouseEventHandler = (asset: Asset | null) => {
|
||||
if (assetInteraction.selectionActive) {
|
||||
handleSelectAssetCandidates(asset);
|
||||
}
|
||||
|
|
@ -496,21 +496,21 @@
|
|||
readonly={disableAssetSelect}
|
||||
onClick={() => {
|
||||
if (assetInteraction.selectionActive) {
|
||||
handleSelectAssets(toTimelineAsset(currentAsset));
|
||||
handleSelectAssets(toAsset(currentAsset));
|
||||
return;
|
||||
}
|
||||
void viewAssetHandler(toTimelineAsset(currentAsset));
|
||||
void viewAssetHandler(toAsset(currentAsset));
|
||||
}}
|
||||
onSelect={() => handleSelectAssets(toTimelineAsset(currentAsset))}
|
||||
onMouseEvent={() => assetMouseEventHandler(toTimelineAsset(currentAsset))}
|
||||
onSelect={() => handleSelectAssets(toAsset(currentAsset))}
|
||||
onMouseEvent={() => assetMouseEventHandler(toAsset(currentAsset))}
|
||||
{showArchiveIcon}
|
||||
asset={toTimelineAsset(currentAsset)}
|
||||
asset={toAsset(currentAsset)}
|
||||
selected={assetInteraction.hasSelectedAsset(currentAsset.id)}
|
||||
selectionCandidate={assetInteraction.hasSelectionCandidate(currentAsset.id)}
|
||||
thumbnailWidth={layout.width}
|
||||
thumbnailHeight={layout.height}
|
||||
/>
|
||||
{#if showAssetName && !isTimelineAsset(currentAsset)}
|
||||
{#if showAssetName && !isAsset(currentAsset)}
|
||||
<div
|
||||
class="absolute text-center p-1 text-xs font-mono font-semibold w-full bottom-0 bg-linear-to-t bg-slate-50/75 dark:bg-slate-800/75 overflow-clip text-ellipsis whitespace-pre-wrap"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
export interface AssetControlContext {
|
||||
// Wrap assets in a function, because context isn't reactive.
|
||||
getAssets: () => TimelineAsset[]; // All assets includes partners' assets
|
||||
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
|
||||
getAssets: () => Asset[]; // All assets includes partners' assets
|
||||
getOwnedAssets: () => Asset[]; // Only assets owned by the user
|
||||
clearSelect: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -14,13 +14,13 @@
|
|||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { mdiClose } from '@mdi/js';
|
||||
import type { Snippet } from 'svelte';
|
||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||
|
||||
interface Props {
|
||||
assets: TimelineAsset[];
|
||||
assets: Asset[];
|
||||
clearSelect: () => void;
|
||||
ownerId?: string | undefined;
|
||||
children?: Snippet;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { resizeObserver, type OnResizeCallback } from '$lib/actions/resize-observer';
|
||||
import Scrubber from '$lib/components/timeline/Scrubber.svelte';
|
||||
import TimelineAssetViewer from '$lib/components/timeline/TimelineAssetViewer.svelte';
|
||||
import AssetViewer from '$lib/components/timeline/TimelineAssetViewer.svelte';
|
||||
import TimelineKeyboardActions from '$lib/components/timeline/actions/TimelineKeyboardActions.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import HotModuleReload from '$lib/elements/HotModuleReload.svelte';
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
|
||||
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } 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 { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
|
|
@ -48,21 +48,16 @@
|
|||
album?: AlbumResponseDto | null;
|
||||
person?: PersonResponseDto | null;
|
||||
isShowDeleteConfirmation?: boolean;
|
||||
onSelect?: (asset: TimelineAsset) => void;
|
||||
onSelect?: (asset: Asset) => void;
|
||||
onEscape?: () => void;
|
||||
children?: Snippet;
|
||||
empty?: Snippet;
|
||||
customLayout?: Snippet<[TimelineAsset]>;
|
||||
customLayout?: Snippet<[Asset]>;
|
||||
onThumbnailClick?: (
|
||||
asset: TimelineAsset,
|
||||
asset: Asset,
|
||||
timelineManager: TimelineManager,
|
||||
dayGroup: DayGroup,
|
||||
onClick: (
|
||||
timelineManager: TimelineManager,
|
||||
assets: TimelineAsset[],
|
||||
groupTitle: string,
|
||||
asset: TimelineAsset,
|
||||
) => void,
|
||||
onClick: (timelineManager: TimelineManager, assets: Asset[], groupTitle: string, asset: Asset) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +177,7 @@
|
|||
return true;
|
||||
};
|
||||
|
||||
const scrollToAsset = (asset: TimelineAsset) => {
|
||||
const scrollToAsset = (asset: Asset) => {
|
||||
const monthGroup = timelineManager.getMonthGroupByAssetId(asset.id);
|
||||
if (!monthGroup) {
|
||||
return false;
|
||||
|
|
@ -384,13 +379,13 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleSelectAsset = (asset: TimelineAsset) => {
|
||||
const handleSelectAsset = (asset: Asset) => {
|
||||
if (!timelineManager.albumAssets.has(asset.id)) {
|
||||
assetInteraction.selectAsset(asset);
|
||||
}
|
||||
};
|
||||
|
||||
let lastAssetMouseEvent: TimelineAsset | null = $state(null);
|
||||
let lastAssetMouseEvent: Asset | null = $state(null);
|
||||
|
||||
let shiftKeyIsDown = $state(false);
|
||||
|
||||
|
|
@ -407,14 +402,14 @@
|
|||
shiftKeyIsDown = false;
|
||||
}
|
||||
};
|
||||
const handleSelectAssetCandidates = (asset: TimelineAsset | null) => {
|
||||
const handleSelectAssetCandidates = (asset: Asset | null) => {
|
||||
if (asset) {
|
||||
void selectAssetCandidates(asset);
|
||||
}
|
||||
lastAssetMouseEvent = asset;
|
||||
};
|
||||
|
||||
const handleGroupSelect = (timelineManager: TimelineManager, group: string, assets: TimelineAsset[]) => {
|
||||
const handleGroupSelect = (timelineManager: TimelineManager, group: string, assets: Asset[]) => {
|
||||
if (assetInteraction.selectedGroup.has(group)) {
|
||||
assetInteraction.removeGroupFromMultiselectGroup(group);
|
||||
for (const asset of assets) {
|
||||
|
|
@ -434,7 +429,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleSelectAssets = async (asset: TimelineAsset) => {
|
||||
const handleSelectAssets = async (asset: Asset) => {
|
||||
if (!asset) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -518,7 +513,7 @@
|
|||
assetInteraction.setAssetSelectionStart(deselect ? null : asset);
|
||||
};
|
||||
|
||||
const selectAssetCandidates = async (endAsset: TimelineAsset) => {
|
||||
const selectAssetCandidates = async (endAsset: Asset) => {
|
||||
if (!shiftKeyIsDown) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -686,7 +681,7 @@
|
|||
|
||||
<Portal target="body">
|
||||
{#if $showAssetViewer}
|
||||
<TimelineAssetViewer bind:showSkeleton {timelineManager} {removeAction} {withStacked} {isShared} {album} {person} />
|
||||
<AssetViewer bind:showSkeleton {timelineManager} {removeAction} {withStacked} {isShared} {album} {person} />
|
||||
{/if}
|
||||
</Portal>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { updateStackedAssetInTimeline, updateUnstackedAssetInTimeline } from '$lib/utils/actions';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { getAssetInfo, type AlbumResponseDto, type PersonResponseDto } from '@immich/sdk';
|
||||
|
||||
let { asset: viewingAsset, gridScrollTarget, mutex, preloadAssets } = assetViewingStore;
|
||||
|
|
@ -135,12 +135,12 @@
|
|||
break;
|
||||
}
|
||||
case AssetAction.REMOVE_ASSET_FROM_STACK: {
|
||||
timelineManager.addAssets([toTimelineAsset(action.asset)]);
|
||||
timelineManager.addAssets([toAsset(action.asset)]);
|
||||
if (action.stack) {
|
||||
//Have to unstack then restack assets in timeline in order to update the stack count in the timeline.
|
||||
updateUnstackedAssetInTimeline(
|
||||
timelineManager,
|
||||
action.stack.assets.map((asset) => toTimelineAsset(asset)),
|
||||
action.stack.assets.map((asset) => toAsset(asset)),
|
||||
);
|
||||
updateStackedAssetInTimeline(timelineManager, {
|
||||
stack: action.stack,
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
//Have to unstack then restack assets in timeline in order for the currently removed new primary asset to be made visible.
|
||||
updateUnstackedAssetInTimeline(
|
||||
timelineManager,
|
||||
action.stack.assets.map((asset) => toTimelineAsset(asset)),
|
||||
action.stack.assets.map((asset) => toAsset(asset)),
|
||||
);
|
||||
updateStackedAssetInTimeline(timelineManager, {
|
||||
stack: action.stack,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
|
||||
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
|
||||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } 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 { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||
|
|
@ -28,22 +28,17 @@
|
|||
monthGroup: MonthGroup;
|
||||
timelineManager: TimelineManager;
|
||||
assetInteraction: AssetInteraction;
|
||||
customLayout?: Snippet<[TimelineAsset]>;
|
||||
customLayout?: Snippet<[Asset]>;
|
||||
|
||||
onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void;
|
||||
onSelectAssets: (asset: TimelineAsset) => void;
|
||||
onSelectAssetCandidates: (asset: TimelineAsset | null) => void;
|
||||
onSelect: ({ title, assets }: { title: string; assets: Asset[] }) => void;
|
||||
onSelectAssets: (asset: Asset) => void;
|
||||
onSelectAssetCandidates: (asset: Asset | null) => void;
|
||||
onScrollCompensation: (compensation: { heightDelta?: number; scrollTop?: number }) => void;
|
||||
onThumbnailClick?: (
|
||||
asset: TimelineAsset,
|
||||
asset: Asset,
|
||||
timelineManager: TimelineManager,
|
||||
dayGroup: DayGroup,
|
||||
onClick: (
|
||||
timelineManager: TimelineManager,
|
||||
assets: TimelineAsset[],
|
||||
groupTitle: string,
|
||||
asset: TimelineAsset,
|
||||
) => void,
|
||||
onClick: (timelineManager: TimelineManager, assets: Asset[], groupTitle: string, asset: Asset) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
|
@ -70,12 +65,7 @@
|
|||
monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150,
|
||||
);
|
||||
const scaleDuration = $derived(transitionDuration === 0 ? 0 : transitionDuration + 100);
|
||||
const _onClick = (
|
||||
timelineManager: TimelineManager,
|
||||
assets: TimelineAsset[],
|
||||
groupTitle: string,
|
||||
asset: TimelineAsset,
|
||||
) => {
|
||||
const _onClick = (timelineManager: TimelineManager, assets: Asset[], groupTitle: string, asset: Asset) => {
|
||||
if (isSelectionMode || assetInteraction.selectionActive) {
|
||||
assetSelectHandler(timelineManager, asset, assets, groupTitle);
|
||||
return;
|
||||
|
|
@ -83,12 +73,12 @@
|
|||
void navigate({ targetRoute: 'current', assetId: asset.id });
|
||||
};
|
||||
|
||||
const handleSelectGroup = (title: string, assets: TimelineAsset[]) => onSelect({ title, assets });
|
||||
const handleSelectGroup = (title: string, assets: Asset[]) => onSelect({ title, assets });
|
||||
|
||||
const assetSelectHandler = (
|
||||
timelineManager: TimelineManager,
|
||||
asset: TimelineAsset,
|
||||
assetsInDayGroup: TimelineAsset[],
|
||||
asset: Asset,
|
||||
assetsInDayGroup: Asset[],
|
||||
groupTitle: string,
|
||||
) => {
|
||||
onSelectAssets(asset);
|
||||
|
|
@ -112,7 +102,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const assetMouseEventHandler = (groupTitle: string, asset: TimelineAsset | null) => {
|
||||
const assetMouseEventHandler = (groupTitle: string, asset: Asset | null) => {
|
||||
// Show multi select icon on hover on date group
|
||||
hoveredDayGroup = groupTitle;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import type { OnLink, OnUnlink } from '$lib/utils/actions';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { getAssetInfo, updateAsset } from '@immich/sdk';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import { mdiLinkOff, mdiMotionPlayOutline, mdiTimerSand } from '@mdi/js';
|
||||
|
|
@ -31,14 +31,14 @@
|
|||
|
||||
const handleLink = async () => {
|
||||
let [still, motion] = [...getOwnedAssets()];
|
||||
if ((still as TimelineAsset).isVideo) {
|
||||
if ((still as Asset).isVideo) {
|
||||
[still, motion] = [motion, still];
|
||||
}
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
const stillResponse = await updateAsset({ id: still.id, updateAssetDto: { livePhotoVideoId: motion.id } });
|
||||
onLink({ still: toTimelineAsset(stillResponse), motion: motion as TimelineAsset });
|
||||
onLink({ still: toAsset(stillResponse), motion: motion as Asset });
|
||||
clearSelect();
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_link_motion_video'));
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
loading = true;
|
||||
const stillResponse = await updateAsset({ id: still.id, updateAssetDto: { livePhotoVideoId: null } });
|
||||
const motionResponse = await getAssetInfo({ ...authManager.params, id: motionId });
|
||||
onUnlink({ still: toTimelineAsset(stillResponse), motion: toTimelineAsset(motionResponse) });
|
||||
onUnlink({ still: toAsset(stillResponse), motion: toAsset(motionResponse) });
|
||||
clearSelect();
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_unlink_motion_video'));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import type { OnStack, OnUnstack } from '$lib/utils/actions';
|
||||
import { deleteStack, stackAssets } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { mdiImageMultipleOutline, mdiImageOffOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
const unstackedAssets = await deleteStack([stack.id]);
|
||||
if (unstackedAssets) {
|
||||
onUnstack?.(unstackedAssets.map((a) => toTimelineAsset(a)));
|
||||
onUnstack?.(unstackedAssets.map((a) => toAsset(a)));
|
||||
}
|
||||
clearSelect();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
} from '$lib/components/timeline/actions/focus-actions';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
|
||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
assetInteraction: AssetInteraction;
|
||||
isShowDeleteConfirmation: boolean;
|
||||
onEscape?: () => void;
|
||||
scrollToAsset: (asset: TimelineAsset) => boolean;
|
||||
scrollToAsset: (asset: Asset) => boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { moveFocus } from '$lib/utils/focus-util';
|
||||
import { InvocationTracker } from '$lib/utils/invocationTracker';
|
||||
import { tick } from 'svelte';
|
||||
|
|
@ -21,7 +21,7 @@ export const focusPreviousAsset = () =>
|
|||
|
||||
const queryHTMLElement = (query: string) => document.querySelector(query) as HTMLElement;
|
||||
|
||||
export const setFocusToAsset = (scrollToAsset: (asset: TimelineAsset) => boolean, asset: TimelineAsset) => {
|
||||
export const setFocusToAsset = (scrollToAsset: (asset: Asset) => boolean, asset: Asset) => {
|
||||
const scrolled = scrollToAsset(asset);
|
||||
if (scrolled) {
|
||||
const element = queryHTMLElement(`[data-thumbnail-focus-container][data-asset="${asset.id}"]`);
|
||||
|
|
@ -30,7 +30,7 @@ export const setFocusToAsset = (scrollToAsset: (asset: TimelineAsset) => boolean
|
|||
};
|
||||
|
||||
export const setFocusTo = async (
|
||||
scrollToAsset: (asset: TimelineAsset) => boolean,
|
||||
scrollToAsset: (asset: Asset) => boolean,
|
||||
store: TimelineManager,
|
||||
direction: 'earlier' | 'later',
|
||||
interval: 'day' | 'month' | 'year' | 'asset',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { getAssetThumbnailUrl } from '$lib/utils';
|
||||
import { getAssetResolution, getFileSize } from '$lib/utils/asset-utils';
|
||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { type AssetResponseDto, getAllAlbums } from '@immich/sdk';
|
||||
import { Icon } from '@immich/ui';
|
||||
import { mdiHeart, mdiImageMultipleOutline, mdiMagnifyPlus } from '@mdi/js';
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<!-- THUMBNAIL-->
|
||||
<img
|
||||
src={getAssetThumbnailUrl(asset.id)}
|
||||
alt={$getAltText(toTimelineAsset(asset))}
|
||||
alt={$getAltText(toAsset(asset))}
|
||||
title={assetData}
|
||||
class="h-60 object-cover rounded-t-xl w-full"
|
||||
draggable="false"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
|
||||
import { getFileSize } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { type AssetResponseDto } from '@immich/sdk';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
title={assetData}
|
||||
>
|
||||
<div class="relative w-full h-full overflow-hidden rounded-lg">
|
||||
<Thumbnail asset={toTimelineAsset(asset)} readonly onClick={() => onViewAsset(asset)} thumbnailSize={boxWidth} />
|
||||
<Thumbnail asset={toAsset(asset)} readonly onClick={() => onViewAsset(asset)} thumbnailSize={boxWidth} />
|
||||
|
||||
{#if !!asset.libraryId}
|
||||
<div class="absolute bottom-1 end-3 px-4 py-1 rounded-xl text-xs transition-colors bg-red-500">External</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { plainDateTimeCompare } from '$lib/utils/timeline-util';
|
|||
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
import type { MonthGroup } from './month-group.svelte';
|
||||
import type { AssetOperation, Direction, MoveAsset, TimelineAsset } from './types';
|
||||
import type { Asset, AssetOperation, Direction, MoveAsset } from './types';
|
||||
import { ViewerAsset } from './viewer-asset.svelte';
|
||||
|
||||
export class DayGroup {
|
||||
|
|
@ -82,7 +82,7 @@ export class DayGroup {
|
|||
return this.viewerAssets[0]?.asset;
|
||||
}
|
||||
|
||||
*assetsIterator(options: { startAsset?: TimelineAsset; direction?: Direction } = {}) {
|
||||
*assetsIterator(options: { startAsset?: Asset; direction?: Direction } = {}) {
|
||||
const isEarlier = (options?.direction ?? 'earlier') === 'earlier';
|
||||
let assetIndex = options?.startAsset
|
||||
? this.viewerAssets.findIndex((viewerAsset) => viewerAsset.asset.id === options.startAsset!.id)
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import { AssetOrder } from '@immich/sdk';
|
|||
import { SvelteSet } from 'svelte/reactivity';
|
||||
import type { DayGroup } from './day-group.svelte';
|
||||
import type { MonthGroup } from './month-group.svelte';
|
||||
import type { TimelineAsset } from './types';
|
||||
import type { Asset } from './types';
|
||||
|
||||
export class GroupInsertionCache {
|
||||
#lookupCache: {
|
||||
[year: number]: { [month: number]: { [day: number]: DayGroup } };
|
||||
} = {};
|
||||
unprocessedAssets: TimelineAsset[] = [];
|
||||
unprocessedAssets: Asset[] = [];
|
||||
changedDayGroups = new SvelteSet<DayGroup>();
|
||||
newDayGroups = new SvelteSet<DayGroup>();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import { SvelteSet } from 'svelte/reactivity';
|
|||
import { GroupInsertionCache } from '../group-insertion-cache.svelte';
|
||||
import { MonthGroup } from '../month-group.svelte';
|
||||
import type { TimelineManager } from '../timeline-manager.svelte';
|
||||
import type { AssetOperation, TimelineAsset } from '../types';
|
||||
import type { Asset, AssetOperation } from '../types';
|
||||
import { updateGeometry } from './layout-support.svelte';
|
||||
import { getMonthGroupByDate } from './search-support.svelte';
|
||||
|
||||
export function addAssetsToMonthGroups(
|
||||
timelineManager: TimelineManager,
|
||||
assets: TimelineAsset[],
|
||||
assets: Asset[],
|
||||
options: { order: AssetOrder },
|
||||
) {
|
||||
if (assets.length === 0) {
|
||||
|
|
@ -30,7 +30,7 @@ export function addAssetsToMonthGroups(
|
|||
timelineManager.months.push(month);
|
||||
}
|
||||
|
||||
month.addTimelineAsset(asset, addContext);
|
||||
month.addAsset(asset, addContext);
|
||||
updatedMonthGroups.add(month);
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ export function runAssetOperation(
|
|||
const changedMonthGroups = new SvelteSet<MonthGroup>();
|
||||
let idsToProcess = new SvelteSet(ids);
|
||||
const idsProcessed = new SvelteSet<string>();
|
||||
const combinedMoveAssets: { asset: TimelineAsset; date: TimelineDate }[][] = [];
|
||||
const combinedMoveAssets: { asset: Asset; date: TimelineDate }[][] = [];
|
||||
for (const month of timelineManager.months) {
|
||||
if (idsToProcess.size > 0) {
|
||||
const { moveAssets, processedIds, changedGeometry } = month.runAssetOperation(idsToProcess, operation);
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timelin
|
|||
import { AssetOrder } from '@immich/sdk';
|
||||
import type { MonthGroup } from '../month-group.svelte';
|
||||
import type { TimelineManager } from '../timeline-manager.svelte';
|
||||
import type { AssetDescriptor, Direction, TimelineAsset } from '../types';
|
||||
import type { Asset, AssetDescriptor, Direction } from '../types';
|
||||
|
||||
export async function getAssetWithOffset(
|
||||
timelineManager: TimelineManager,
|
||||
assetDescriptor: AssetDescriptor,
|
||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||
direction: Direction,
|
||||
): Promise<TimelineAsset | undefined> {
|
||||
): Promise<Asset | undefined> {
|
||||
const { asset, monthGroup } = findMonthGroupForAsset(timelineManager, assetDescriptor.id) ?? {};
|
||||
if (!monthGroup || !asset) {
|
||||
return;
|
||||
|
|
@ -51,7 +51,7 @@ export function getMonthGroupByDate(
|
|||
|
||||
async function getAssetByAssetOffset(
|
||||
timelineManager: TimelineManager,
|
||||
asset: TimelineAsset,
|
||||
asset: Asset,
|
||||
monthGroup: MonthGroup,
|
||||
direction: Direction,
|
||||
) {
|
||||
|
|
@ -70,7 +70,7 @@ async function getAssetByAssetOffset(
|
|||
|
||||
async function getAssetByDayOffset(
|
||||
timelineManager: TimelineManager,
|
||||
asset: TimelineAsset,
|
||||
asset: Asset,
|
||||
monthGroup: MonthGroup,
|
||||
direction: Direction,
|
||||
) {
|
||||
|
|
@ -120,7 +120,7 @@ export async function retrieveRange(timelineManager: TimelineManager, start: Ass
|
|||
[startMonthGroup, endMonthGroup] = [endMonthGroup, startMonthGroup];
|
||||
}
|
||||
|
||||
const range: TimelineAsset[] = [];
|
||||
const range: Asset[] = [];
|
||||
const startDayGroup = startMonthGroup.findDayGroupForAsset(startAsset);
|
||||
for await (const targetAsset of timelineManager.assetsIterator({
|
||||
startMonthGroup,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { PendingChange, TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset, PendingChange } from '$lib/managers/timeline-manager/types';
|
||||
import { websocketEvents } from '$lib/stores/websocket';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { throttle } from 'lodash-es';
|
||||
import type { Unsubscriber } from 'svelte/store';
|
||||
|
||||
|
|
@ -31,11 +31,11 @@ export class WebsocketSupport {
|
|||
connectWebsocketEvents() {
|
||||
this.#unsubscribers.push(
|
||||
websocketEvents.on('on_upload_success', (asset) =>
|
||||
this.#addPendingChanges({ type: 'add', values: [toTimelineAsset(asset)] }),
|
||||
this.#addPendingChanges({ type: 'add', values: [toAsset(asset)] }),
|
||||
),
|
||||
websocketEvents.on('on_asset_trash', (ids) => this.#addPendingChanges({ type: 'trash', values: ids })),
|
||||
websocketEvents.on('on_asset_update', (asset) =>
|
||||
this.#addPendingChanges({ type: 'update', values: [toTimelineAsset(asset)] }),
|
||||
this.#addPendingChanges({ type: 'update', values: [toAsset(asset)] }),
|
||||
),
|
||||
websocketEvents.on('on_asset_delete', (id: string) => this.#addPendingChanges({ type: 'delete', values: [id] })),
|
||||
);
|
||||
|
|
@ -55,8 +55,8 @@ export class WebsocketSupport {
|
|||
|
||||
#getPendingChangeBatches() {
|
||||
const batch: {
|
||||
add: TimelineAsset[];
|
||||
update: TimelineAsset[];
|
||||
add: Asset[];
|
||||
update: Asset[];
|
||||
remove: string[];
|
||||
} = {
|
||||
add: [],
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { SvelteSet } from 'svelte/reactivity';
|
|||
import { DayGroup } from './day-group.svelte';
|
||||
import { GroupInsertionCache } from './group-insertion-cache.svelte';
|
||||
import type { TimelineManager } from './timeline-manager.svelte';
|
||||
import type { AssetDescriptor, AssetOperation, Direction, MoveAsset, TimelineAsset } from './types';
|
||||
import type { Asset, AssetDescriptor, AssetOperation, Direction, MoveAsset } from './types';
|
||||
import { ViewerAsset } from './viewer-asset.svelte';
|
||||
|
||||
export class MonthGroup {
|
||||
|
|
@ -101,7 +101,7 @@ export class MonthGroup {
|
|||
|
||||
getAssets() {
|
||||
// eslint-disable-next-line unicorn/no-array-reduce
|
||||
return this.dayGroups.reduce((accumulator: TimelineAsset[], g: DayGroup) => accumulator.concat(g.getAssets()), []);
|
||||
return this.dayGroups.reduce((accumulator: Asset[], g: DayGroup) => accumulator.concat(g.getAssets()), []);
|
||||
}
|
||||
|
||||
sortDayGroups() {
|
||||
|
|
@ -161,7 +161,7 @@ export class MonthGroup {
|
|||
bucketAssets.localOffsetHours[i],
|
||||
);
|
||||
|
||||
const timelineAsset: TimelineAsset = {
|
||||
const timelineAsset: Asset = {
|
||||
city: bucketAssets.city[i],
|
||||
country: bucketAssets.country[i],
|
||||
duration: bucketAssets.duration[i],
|
||||
|
|
@ -192,7 +192,7 @@ export class MonthGroup {
|
|||
timelineAsset.latitude = bucketAssets.latitude?.[i];
|
||||
timelineAsset.longitude = bucketAssets.longitude?.[i];
|
||||
}
|
||||
this.addTimelineAsset(timelineAsset, addContext);
|
||||
this.addAsset(timelineAsset, addContext);
|
||||
}
|
||||
|
||||
for (const group of addContext.existingDayGroups) {
|
||||
|
|
@ -208,7 +208,7 @@ export class MonthGroup {
|
|||
return addContext.unprocessedAssets;
|
||||
}
|
||||
|
||||
addTimelineAsset(timelineAsset: TimelineAsset, addContext: GroupInsertionCache) {
|
||||
addAsset(timelineAsset: Asset, addContext: GroupInsertionCache) {
|
||||
const { localDateTime } = timelineAsset;
|
||||
|
||||
const { year, month } = this.yearMonth;
|
||||
|
|
@ -294,7 +294,7 @@ export class MonthGroup {
|
|||
handleError(error, _$t('errors.failed_to_load_assets'));
|
||||
}
|
||||
|
||||
findDayGroupForAsset(asset: TimelineAsset) {
|
||||
findDayGroupForAsset(asset: Asset) {
|
||||
for (const group of this.dayGroups) {
|
||||
if (group.viewerAssets.some((viewerAsset) => viewerAsset.id === asset.id)) {
|
||||
return group;
|
||||
|
|
@ -321,7 +321,7 @@ export class MonthGroup {
|
|||
return -1;
|
||||
}
|
||||
|
||||
*assetsIterator(options?: { startDayGroup?: DayGroup; startAsset?: TimelineAsset; direction?: Direction }) {
|
||||
*assetsIterator(options?: { startDayGroup?: DayGroup; startAsset?: Asset; direction?: Direction }) {
|
||||
const direction = options?.direction ?? 'earlier';
|
||||
let { startAsset } = options ?? {};
|
||||
const isEarlier = direction === 'earlier';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { fromISODateTimeUTCToObject } from '$lib/utils/timeline-util';
|
|||
import { type AssetResponseDto, type TimeBucketAssetResponseDto } from '@immich/sdk';
|
||||
import { timelineAssetFactory, toResponseDto } from '@test-data/factories/asset-factory';
|
||||
import { TimelineManager } from './timeline-manager.svelte';
|
||||
import type { TimelineAsset } from './types';
|
||||
import type { Asset } from './types';
|
||||
|
||||
async function getAssets(timelineManager: TimelineManager) {
|
||||
const assets = [];
|
||||
|
|
@ -15,7 +15,7 @@ async function getAssets(timelineManager: TimelineManager) {
|
|||
return assets;
|
||||
}
|
||||
|
||||
function deriveLocalDateTimeFromFileCreatedAt(arg: TimelineAsset): TimelineAsset {
|
||||
function deriveLocalDateTimeFromFileCreatedAt(arg: Asset): Asset {
|
||||
return {
|
||||
...arg,
|
||||
localDateTime: arg.fileCreatedAt,
|
||||
|
|
@ -29,7 +29,7 @@ describe('TimelineManager', () => {
|
|||
|
||||
describe('init', () => {
|
||||
let timelineManager: TimelineManager;
|
||||
const bucketAssets: Record<string, TimelineAsset[]> = {
|
||||
const bucketAssets: Record<string, Asset[]> = {
|
||||
'2024-03-01T00:00:00.000Z': timelineAssetFactory.buildList(1).map((asset) =>
|
||||
deriveLocalDateTimeFromFileCreatedAt({
|
||||
...asset,
|
||||
|
|
@ -94,7 +94,7 @@ describe('TimelineManager', () => {
|
|||
|
||||
describe('loadMonthGroup', () => {
|
||||
let timelineManager: TimelineManager;
|
||||
const bucketAssets: Record<string, TimelineAsset[]> = {
|
||||
const bucketAssets: Record<string, Asset[]> = {
|
||||
'2024-01-03T00:00:00.000Z': timelineAssetFactory.buildList(1).map((asset) =>
|
||||
deriveLocalDateTimeFromFileCreatedAt({
|
||||
...asset,
|
||||
|
|
@ -436,7 +436,7 @@ describe('TimelineManager', () => {
|
|||
|
||||
describe('getLaterAsset', () => {
|
||||
let timelineManager: TimelineManager;
|
||||
const bucketAssets: Record<string, TimelineAsset[]> = {
|
||||
const bucketAssets: Record<string, Asset[]> = {
|
||||
'2024-03-01T00:00:00.000Z': timelineAssetFactory.buildList(1).map((asset) =>
|
||||
deriveLocalDateTimeFromFileCreatedAt({
|
||||
...asset,
|
||||
|
|
@ -583,7 +583,7 @@ describe('TimelineManager', () => {
|
|||
|
||||
describe('getRandomAsset', () => {
|
||||
let timelineManager: TimelineManager;
|
||||
const bucketAssets: Record<string, TimelineAsset[]> = {
|
||||
const bucketAssets: Record<string, Asset[]> = {
|
||||
'2024-03-01T00:00:00.000Z': timelineAssetFactory.buildList(1).map((asset) =>
|
||||
deriveLocalDateTimeFromFileCreatedAt({
|
||||
...asset,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { AssetOrder, getAssetInfo, getTimeBuckets } from '@immich/sdk';
|
|||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
|
||||
import { CancellableTask } from '$lib/utils/cancellable-task';
|
||||
import { toTimelineAsset, type TimelineDateTime, type TimelineYearMonth } from '$lib/utils/timeline-util';
|
||||
import { toAsset, type TimelineDateTime, type TimelineYearMonth } from '$lib/utils/timeline-util';
|
||||
|
||||
import { clamp, debounce, isEqual } from 'lodash-es';
|
||||
import { SvelteDate, SvelteMap, SvelteSet } from 'svelte/reactivity';
|
||||
|
|
@ -27,11 +27,11 @@ import { DayGroup } from './day-group.svelte';
|
|||
import { isMismatched, updateObject } from './internal/utils.svelte';
|
||||
import { MonthGroup } from './month-group.svelte';
|
||||
import type {
|
||||
Asset,
|
||||
AssetDescriptor,
|
||||
AssetOperation,
|
||||
Direction,
|
||||
ScrubberMonth,
|
||||
TimelineAsset,
|
||||
TimelineManagerLayoutOptions,
|
||||
TimelineManagerOptions,
|
||||
Viewport,
|
||||
|
|
@ -192,7 +192,7 @@ export class TimelineManager {
|
|||
async *assetsIterator(options?: {
|
||||
startMonthGroup?: MonthGroup;
|
||||
startDayGroup?: DayGroup;
|
||||
startAsset?: TimelineAsset;
|
||||
startAsset?: Asset;
|
||||
direction?: Direction;
|
||||
}) {
|
||||
const direction = options?.direction ?? 'earlier';
|
||||
|
|
@ -409,7 +409,7 @@ export class TimelineManager {
|
|||
}
|
||||
}
|
||||
|
||||
addAssets(assets: TimelineAsset[]) {
|
||||
addAssets(assets: Asset[]) {
|
||||
const assetsToUpdate = assets.filter((asset) => !this.isExcluded(asset));
|
||||
const notUpdated = this.updateAssets(assetsToUpdate);
|
||||
addAssetsToMonthGroups(this, [...notUpdated], { order: this.#options.order ?? AssetOrder.Desc });
|
||||
|
|
@ -430,7 +430,7 @@ export class TimelineManager {
|
|||
return;
|
||||
}
|
||||
|
||||
const asset = toTimelineAsset(response);
|
||||
const asset = toAsset(response);
|
||||
if (!asset || this.isExcluded(asset)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -454,7 +454,7 @@ export class TimelineManager {
|
|||
// note: the `index` input is expected to be in the range [0, assetCount). This
|
||||
// value can be passed to make the method deterministic, which is mainly useful
|
||||
// for testing.
|
||||
async getRandomAsset(index?: number): Promise<TimelineAsset | undefined> {
|
||||
async getRandomAsset(index?: number): Promise<Asset | undefined> {
|
||||
const randomAssetIndex = index ?? Math.floor(Math.random() * this.assetCount);
|
||||
|
||||
let accumulatedCount = 0;
|
||||
|
|
@ -493,8 +493,8 @@ export class TimelineManager {
|
|||
runAssetOperation(this, new SvelteSet(ids), operation, { order: this.#options.order ?? AssetOrder.Desc });
|
||||
}
|
||||
|
||||
updateAssets(assets: TimelineAsset[]) {
|
||||
const lookup = new SvelteMap<string, TimelineAsset>(assets.map((asset) => [asset.id, asset]));
|
||||
updateAssets(assets: Asset[]) {
|
||||
const lookup = new SvelteMap<string, Asset>(assets.map((asset) => [asset.id, asset]));
|
||||
const { unprocessedIds } = runAssetOperation(
|
||||
this,
|
||||
new SvelteSet(lookup.keys()),
|
||||
|
|
@ -504,7 +504,7 @@ export class TimelineManager {
|
|||
},
|
||||
{ order: this.#options.order ?? AssetOrder.Desc },
|
||||
);
|
||||
const result: TimelineAsset[] = [];
|
||||
const result: Asset[] = [];
|
||||
for (const id of unprocessedIds.values()) {
|
||||
result.push(lookup.get(id)!);
|
||||
}
|
||||
|
|
@ -530,21 +530,21 @@ export class TimelineManager {
|
|||
this.updateIntersections();
|
||||
}
|
||||
|
||||
getFirstAsset(): TimelineAsset | undefined {
|
||||
getFirstAsset(): Asset | undefined {
|
||||
return this.months[0]?.getFirstAsset();
|
||||
}
|
||||
|
||||
async getLaterAsset(
|
||||
assetDescriptor: AssetDescriptor,
|
||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||
): Promise<TimelineAsset | undefined> {
|
||||
): Promise<Asset | undefined> {
|
||||
return await getAssetWithOffset(this, assetDescriptor, interval, 'later');
|
||||
}
|
||||
|
||||
async getEarlierAsset(
|
||||
assetDescriptor: AssetDescriptor,
|
||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||
): Promise<TimelineAsset | undefined> {
|
||||
): Promise<Asset | undefined> {
|
||||
return await getAssetWithOffset(this, assetDescriptor, interval, 'earlier');
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +567,7 @@ export class TimelineManager {
|
|||
return retrieveRangeUtil(this, start, end);
|
||||
}
|
||||
|
||||
isExcluded(asset: TimelineAsset) {
|
||||
isExcluded(asset: Asset) {
|
||||
return (
|
||||
isMismatched(this.#options.visibility, asset.visibility) ||
|
||||
isMismatched(this.#options.isFavorite, asset.isFavorite) ||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export type AssetDescriptor = { id: string };
|
|||
|
||||
export type Direction = 'earlier' | 'later';
|
||||
|
||||
export type TimelineAsset = {
|
||||
export type Asset = {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
ratio: number;
|
||||
|
|
@ -35,9 +35,9 @@ export type TimelineAsset = {
|
|||
longitude?: number | null;
|
||||
};
|
||||
|
||||
export type AssetOperation = (asset: TimelineAsset) => { remove: boolean };
|
||||
export type AssetOperation = (asset: Asset) => { remove: boolean };
|
||||
|
||||
export type MoveAsset = { asset: TimelineAsset; date: TimelineDate };
|
||||
export type MoveAsset = { asset: Asset; date: TimelineDate };
|
||||
|
||||
export interface Viewport {
|
||||
width: number;
|
||||
|
|
@ -51,12 +51,12 @@ export type ViewportXY = Viewport & {
|
|||
|
||||
export interface AddAsset {
|
||||
type: 'add';
|
||||
values: TimelineAsset[];
|
||||
values: Asset[];
|
||||
}
|
||||
|
||||
export interface UpdateAsset {
|
||||
type: 'update';
|
||||
values: TimelineAsset[];
|
||||
values: Asset[];
|
||||
}
|
||||
|
||||
export interface DeleteAsset {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { TimelineAsset } from './types';
|
||||
import type { Asset } from './types';
|
||||
|
||||
export const assetSnapshot = (asset: TimelineAsset): TimelineAsset => $state.snapshot(asset);
|
||||
export const assetsSnapshot = (assets: TimelineAsset[]) => assets.map((asset) => $state.snapshot(asset));
|
||||
export const assetSnapshot = (asset: Asset): Asset => $state.snapshot(asset);
|
||||
export const assetsSnapshot = (assets: Asset[]) => assets.map((asset) => $state.snapshot(asset));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { CommonPosition } from '$lib/utils/layout-utils';
|
|||
|
||||
import type { DayGroup } from './day-group.svelte';
|
||||
import { calculateViewerAssetIntersecting } from './internal/intersection-support.svelte';
|
||||
import type { TimelineAsset } from './types';
|
||||
import type { Asset } from './types';
|
||||
|
||||
export class ViewerAsset {
|
||||
readonly #group: DayGroup;
|
||||
|
|
@ -19,10 +19,10 @@ export class ViewerAsset {
|
|||
});
|
||||
|
||||
position: CommonPosition | undefined = $state();
|
||||
asset: TimelineAsset = <TimelineAsset>$state();
|
||||
asset: Asset = <Asset>$state();
|
||||
id: string = $derived(this.asset.id);
|
||||
|
||||
constructor(group: DayGroup, asset: TimelineAsset) {
|
||||
constructor(group: DayGroup, asset: Asset) {
|
||||
this.#group = group;
|
||||
this.asset = asset;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { AssetVisibility, type UserAdminResponseDto } from '@immich/sdk';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
import { fromStore } from 'svelte/store';
|
||||
|
||||
export class AssetInteraction {
|
||||
selectedAssets = $state<TimelineAsset[]>([]);
|
||||
selectedAssets = $state<Asset[]>([]);
|
||||
hasSelectedAsset(assetId: string) {
|
||||
return this.selectedAssets.some((asset) => asset.id === assetId);
|
||||
}
|
||||
selectedGroup = new SvelteSet<string>();
|
||||
assetSelectionCandidates = $state<TimelineAsset[]>([]);
|
||||
assetSelectionCandidates = $state<Asset[]>([]);
|
||||
hasSelectionCandidate(assetId: string) {
|
||||
return this.assetSelectionCandidates.some((asset) => asset.id === assetId);
|
||||
}
|
||||
assetSelectionStart = $state<TimelineAsset | null>(null);
|
||||
assetSelectionStart = $state<Asset | null>(null);
|
||||
selectionActive = $derived(this.selectedAssets.length > 0);
|
||||
|
||||
private user = fromStore<UserAdminResponseDto | undefined>(user);
|
||||
|
|
@ -25,13 +25,13 @@ export class AssetInteraction {
|
|||
isAllFavorite = $derived(this.selectedAssets.every((asset) => asset.isFavorite));
|
||||
isAllUserOwned = $derived(this.selectedAssets.every((asset) => asset.ownerId === this.userId));
|
||||
|
||||
selectAsset(asset: TimelineAsset) {
|
||||
selectAsset(asset: Asset) {
|
||||
if (!this.hasSelectedAsset(asset.id)) {
|
||||
this.selectedAssets.push(asset);
|
||||
}
|
||||
}
|
||||
|
||||
selectAssets(assets: TimelineAsset[]) {
|
||||
selectAssets(assets: Asset[]) {
|
||||
for (const asset of assets) {
|
||||
this.selectAsset(asset);
|
||||
}
|
||||
|
|
@ -52,11 +52,11 @@ export class AssetInteraction {
|
|||
this.selectedGroup.delete(group);
|
||||
}
|
||||
|
||||
setAssetSelectionStart(asset: TimelineAsset | null) {
|
||||
setAssetSelectionStart(asset: Asset | null) {
|
||||
this.assetSelectionStart = asset;
|
||||
}
|
||||
|
||||
setAssetSelectionCandidates(assets: TimelineAsset[]) {
|
||||
setAssetSelectionCandidates(assets: Asset[]) {
|
||||
this.assetSelectionCandidates = assets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { type AssetGridRouteSearchParams } from '$lib/utils/navigation';
|
||||
import { getAssetInfo, type AssetResponseDto } from '@immich/sdk';
|
||||
import { Mutex } from 'async-mutex';
|
||||
|
|
@ -7,12 +7,12 @@ import { readonly, writable } from 'svelte/store';
|
|||
|
||||
function createAssetViewingStore() {
|
||||
const viewingAssetStoreState = writable<AssetResponseDto>();
|
||||
const preloadAssets = writable<TimelineAsset[]>([]);
|
||||
const preloadAssets = writable<Asset[]>([]);
|
||||
const viewState = writable<boolean>(false);
|
||||
const viewingAssetMutex = new Mutex();
|
||||
const gridScrollTarget = writable<AssetGridRouteSearchParams | null | undefined>();
|
||||
|
||||
const setAsset = (asset: AssetResponseDto, assetsToPreload: TimelineAsset[] = []) => {
|
||||
const setAsset = (asset: AssetResponseDto, assetsToPreload: Asset[] = []) => {
|
||||
preloadAssets.set(assetsToPreload);
|
||||
viewingAssetStoreState.set(asset);
|
||||
viewState.set(true);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { asLocalTimeISO } from '$lib/utils/date-time';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { deleteMemory, type MemoryResponseDto, removeMemoryAssets, searchMemories, updateMemory } from '@immich/sdk';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ type MemoryIndex = {
|
|||
|
||||
export type MemoryAsset = MemoryIndex & {
|
||||
memory: MemoryResponseDto;
|
||||
asset: TimelineAsset;
|
||||
asset: Asset;
|
||||
previousMemory?: MemoryResponseDto;
|
||||
previous?: MemoryAsset;
|
||||
next?: MemoryAsset;
|
||||
|
|
@ -36,7 +36,7 @@ class MemoryStoreSvelte {
|
|||
memoryIndex,
|
||||
previousMemory: this.memories[memoryIndex - 1],
|
||||
nextMemory: this.memories[memoryIndex + 1],
|
||||
asset: toTimelineAsset(asset),
|
||||
asset: toAsset(asset),
|
||||
assetIndex,
|
||||
previous,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import type { StackResponse } from '$lib/utils/asset-utils';
|
||||
import { AssetVisibility, deleteAssets as deleteBulk, restoreAssets } from '@immich/sdk';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
|
@ -8,21 +8,21 @@ import { get } from 'svelte/store';
|
|||
import { handleError } from './handle-error';
|
||||
|
||||
export type OnDelete = (assetIds: string[]) => void;
|
||||
export type OnUndoDelete = (assets: TimelineAsset[]) => void;
|
||||
export type OnUndoDelete = (assets: Asset[]) => void;
|
||||
export type OnRestore = (ids: string[]) => void;
|
||||
export type OnLink = (assets: { still: TimelineAsset; motion: TimelineAsset }) => void;
|
||||
export type OnUnlink = (assets: { still: TimelineAsset; motion: TimelineAsset }) => void;
|
||||
export type OnLink = (assets: { still: Asset; motion: Asset }) => void;
|
||||
export type OnUnlink = (assets: { still: Asset; motion: Asset }) => void;
|
||||
export type OnAddToAlbum = (ids: string[], albumId: string) => void;
|
||||
export type OnArchive = (ids: string[], visibility: AssetVisibility) => void;
|
||||
export type OnFavorite = (ids: string[], favorite: boolean) => void;
|
||||
export type OnStack = (result: StackResponse) => void;
|
||||
export type OnUnstack = (assets: TimelineAsset[]) => void;
|
||||
export type OnUnstack = (assets: Asset[]) => void;
|
||||
export type OnSetVisibility = (ids: string[]) => void;
|
||||
|
||||
export const deleteAssets = async (
|
||||
force: boolean,
|
||||
onAssetDelete: OnDelete,
|
||||
assets: TimelineAsset[],
|
||||
assets: Asset[],
|
||||
onUndoDelete: OnUndoDelete | undefined = undefined,
|
||||
) => {
|
||||
const $t = get(t);
|
||||
|
|
@ -47,7 +47,7 @@ export const deleteAssets = async (
|
|||
}
|
||||
};
|
||||
|
||||
const undoDeleteAssets = async (onUndoDelete: OnUndoDelete, assets: TimelineAsset[]) => {
|
||||
const undoDeleteAssets = async (onUndoDelete: OnUndoDelete, assets: Asset[]) => {
|
||||
const $t = get(t);
|
||||
try {
|
||||
const ids = assets.map((a) => a.id);
|
||||
|
|
@ -89,7 +89,7 @@ export function updateStackedAssetInTimeline(timelineManager: TimelineManager, {
|
|||
* @param timelineManager - The timeline manager to update.
|
||||
* @param assets - The array of asset response DTOs to update in the timeline manager.
|
||||
*/
|
||||
export function updateUnstackedAssetInTimeline(timelineManager: TimelineManager, assets: TimelineAsset[]) {
|
||||
export function updateUnstackedAssetInTimeline(timelineManager: TimelineManager, assets: Asset[]) {
|
||||
timelineManager.updateAssetOperation(
|
||||
assets.map((asset) => asset.id),
|
||||
(asset) => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { AppRoute } from '$lib/constants';
|
|||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { downloadManager } from '$lib/managers/download-manager.svelte';
|
||||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } 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';
|
||||
|
|
@ -405,7 +405,7 @@ export const getAssetType = (type: AssetTypeEnum) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getSelectedAssets = (assets: TimelineAsset[], user: UserResponseDto | null): string[] => {
|
||||
export const getSelectedAssets = (assets: Asset[], user: UserResponseDto | null): string[] => {
|
||||
const ids = [...assets].filter((a) => user && a.ownerId === user.id).map((a) => a.id);
|
||||
|
||||
const numberOfIssues = [...assets].filter((a) => user && a.ownerId !== user.id).length;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// note: it's important that this is not imported in more than one file due to https://github.com/sveltejs/kit/issues/7805
|
||||
// import { JustifiedLayout, type LayoutOptions } from '@immich/justified-layout-wasm';
|
||||
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { getAssetRatio } from '$lib/utils/asset-utils';
|
||||
import { isTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { isAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import createJustifiedLayout from 'justified-layout';
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export type CommonLayoutOptions = {
|
|||
};
|
||||
|
||||
export function getJustifiedLayoutFromAssets(
|
||||
assets: (TimelineAsset | AssetResponseDto)[],
|
||||
assets: (Asset | AssetResponseDto)[],
|
||||
options: CommonLayoutOptions,
|
||||
): CommonJustifiedLayout {
|
||||
// if (useWasm) {
|
||||
|
|
@ -90,7 +90,7 @@ class Adapter {
|
|||
}
|
||||
}
|
||||
|
||||
export function justifiedLayout(assets: (TimelineAsset | AssetResponseDto)[], options: CommonLayoutOptions) {
|
||||
export function justifiedLayout(assets: (Asset | AssetResponseDto)[], options: CommonLayoutOptions) {
|
||||
const adapter = {
|
||||
targetRowHeight: options.rowHeight,
|
||||
containerWidth: options.rowWidth,
|
||||
|
|
@ -100,7 +100,7 @@ export function justifiedLayout(assets: (TimelineAsset | AssetResponseDto)[], op
|
|||
};
|
||||
|
||||
const result = createJustifiedLayout(
|
||||
assets.map((asset) => (isTimelineAsset(asset) ? asset.ratio : getAssetRatio(asset))),
|
||||
assets.map((asset) => (isAsset(asset) ? asset.ratio : getAssetRatio(asset))),
|
||||
adapter,
|
||||
);
|
||||
return new Adapter(result);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||
import { AssetVisibility } from '@immich/sdk';
|
||||
import { init, register, waitLocale } from 'svelte-i18n';
|
||||
|
|
@ -57,7 +57,7 @@ describe('getAltText', () => {
|
|||
expected: string;
|
||||
}) => {
|
||||
const testDate = new Date('2024-01-01T12:00:00.000Z');
|
||||
const asset: TimelineAsset = {
|
||||
const asset: Asset = {
|
||||
id: 'test-id',
|
||||
ownerId: 'test-owner',
|
||||
ratio: 1,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { fromTimelinePlainDateTime } from '$lib/utils/timeline-util';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
|
@ -39,7 +39,7 @@ export function getThumbnailSize(assetCount: number, viewWidth: number): number
|
|||
}
|
||||
|
||||
export const getAltText = derived(t, ($t) => {
|
||||
return (asset: TimelineAsset) => {
|
||||
return (asset: Asset) => {
|
||||
const date = fromTimelinePlainDateTime(asset.localDateTime).toJSDate().toLocaleString(get(locale), {
|
||||
dateStyle: 'long',
|
||||
timeZone: 'UTC',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { getAssetRatio } from '$lib/utils/asset-utils';
|
||||
import { AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
|
||||
|
|
@ -160,8 +160,8 @@ export const getDateTimeOffsetLocaleString = (date: DateTime, opts?: LocaleOptio
|
|||
opts,
|
||||
);
|
||||
|
||||
export const toTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset): TimelineAsset => {
|
||||
if (isTimelineAsset(unknownAsset)) {
|
||||
export const toAsset = (unknownAsset: AssetResponseDto | Asset): Asset => {
|
||||
if (isAsset(unknownAsset)) {
|
||||
return unknownAsset;
|
||||
}
|
||||
const assetResponse = unknownAsset;
|
||||
|
|
@ -198,8 +198,8 @@ export const toTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset):
|
|||
};
|
||||
};
|
||||
|
||||
export const isTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset): unknownAsset is TimelineAsset =>
|
||||
(unknownAsset as TimelineAsset).ratio !== undefined;
|
||||
export const isAsset = (unknownAsset: AssetResponseDto | Asset): unknownAsset is Asset =>
|
||||
(unknownAsset as Asset).ratio !== undefined;
|
||||
|
||||
export const plainDateTimeCompare = (ascending: boolean, a: TimelineDateTime, b: TimelineDateTime) => {
|
||||
const [aDateTime, bDateTime] = ascending ? [a, b] : [b, a];
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
import { AlbumPageViewMode, AppRoute } from '$lib/constants';
|
||||
import { activityManager } from '$lib/managers/activity-manager.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
||||
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
||||
import AlbumUsersModal from '$lib/modals/AlbumUsersModal.svelte';
|
||||
|
|
@ -272,7 +272,7 @@
|
|||
await refreshAlbum();
|
||||
};
|
||||
|
||||
const handleUndoRemoveAssets = async (assets: TimelineAsset[]) => {
|
||||
const handleUndoRemoveAssets = async (assets: Asset[]) => {
|
||||
timelineManager.addAssets(assets);
|
||||
await refreshAlbum();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
import { foldersStore } from '$lib/stores/folders.svelte';
|
||||
import { preferences } from '$lib/stores/user.store';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { joinPaths } from '$lib/utils/tree-utils';
|
||||
import { IconButton } from '@immich/ui';
|
||||
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
assetInteraction.selectAssets(data.pathAssets.map((asset) => toTimelineAsset(asset)));
|
||||
assetInteraction.selectAssets(data.pathAssets.map((asset) => toAsset(asset)));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||
import { AppRoute, PersonPageViewMode, QueryParameter, SessionStorageKey } from '$lib/constants';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import PersonEditBirthDateModal from '$lib/modals/PersonEditBirthDateModal.svelte';
|
||||
import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
data = { ...data, person };
|
||||
};
|
||||
|
||||
const handleSelectFeaturePhoto = async (asset: TimelineAsset) => {
|
||||
const handleSelectFeaturePhoto = async (asset: Asset) => {
|
||||
if (viewMode !== PersonPageViewMode.SELECT_PERSON) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -354,7 +354,7 @@
|
|||
await updateAssetCount();
|
||||
};
|
||||
|
||||
const handleUndoDeleteAssets = async (assets: TimelineAsset[]) => {
|
||||
const handleUndoDeleteAssets = async (assets: Asset[]) => {
|
||||
timelineManager.addAssets(assets);
|
||||
await updateAssetCount();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { lang, locale } from '$lib/stores/preferences.store';
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
import { parseUtcDate } from '$lib/utils/date-time';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { isAlbumsRoute, isPeopleRoute } from '$lib/utils/navigation';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import {
|
||||
type AlbumResponseDto,
|
||||
getPerson,
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
|
||||
let nextPage = $state(1);
|
||||
let searchResultAlbums: AlbumResponseDto[] = $state([]);
|
||||
let searchResultAssets: TimelineAsset[] = $state([]);
|
||||
let searchResultAssets: Asset[] = $state([]);
|
||||
let isLoading = $state(true);
|
||||
let scrollY = $state(0);
|
||||
let scrollYHistory = 0;
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
|
||||
const onAssetDelete = (assetIds: string[]) => {
|
||||
const assetIdSet = new Set(assetIds);
|
||||
searchResultAssets = searchResultAssets.filter((asset: TimelineAsset) => !assetIdSet.has(asset.id));
|
||||
searchResultAssets = searchResultAssets.filter((asset: Asset) => !assetIdSet.has(asset.id));
|
||||
};
|
||||
|
||||
const handleSetVisibility = (assetIds: string[]) => {
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
: await searchAssets({ metadataSearchDto: searchDto });
|
||||
|
||||
searchResultAlbums.push(...albums.items);
|
||||
searchResultAssets.push(...assets.items.map((asset) => toTimelineAsset(asset)));
|
||||
searchResultAssets.push(...assets.items.map((asset) => toAsset(asset)));
|
||||
|
||||
nextPage = Number(assets.nextPage) || 0;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import GeolocationUpdateConfirmModal from '$lib/modals/GeolocationUpdateConfirmModal.svelte';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
import { setQueryValue } from '$lib/utils/navigation';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { toAsset } from '$lib/utils/timeline-util';
|
||||
import { AssetVisibility, getAssetInfo, updateAssets } from '@immich/sdk';
|
||||
import { Button, LoadingSpinner, modalManager, Text } from '@immich/ui';
|
||||
import { mdiMapMarkerMultipleOutline, mdiPencilOutline, mdiSelectRemove } from '@mdi/js';
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
const updatedAssets = await Promise.all(
|
||||
assetInteraction.selectedAssets.map(async (asset) => {
|
||||
const updatedAsset = await getAssetInfo({ ...authManager.params, id: asset.id });
|
||||
return toTimelineAsset(updatedAsset);
|
||||
return toAsset(updatedAsset);
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
@ -106,20 +106,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
const hasGps = (asset: TimelineAsset) => {
|
||||
const hasGps = (asset: Asset) => {
|
||||
return !!asset.latitude && !!asset.longitude;
|
||||
};
|
||||
|
||||
const handleThumbnailClick = (
|
||||
asset: TimelineAsset,
|
||||
asset: Asset,
|
||||
timelineManager: TimelineManager,
|
||||
dayGroup: DayGroup,
|
||||
onClick: (
|
||||
timelineManager: TimelineManager,
|
||||
assets: TimelineAsset[],
|
||||
groupTitle: string,
|
||||
asset: TimelineAsset,
|
||||
) => void,
|
||||
onClick: (timelineManager: TimelineManager, assets: Asset[], groupTitle: string, asset: Asset) => void,
|
||||
) => {
|
||||
if (hasGps(asset)) {
|
||||
locationUpdated = true;
|
||||
|
|
@ -195,7 +190,7 @@
|
|||
withStacked
|
||||
onThumbnailClick={handleThumbnailClick}
|
||||
>
|
||||
{#snippet customLayout(asset: TimelineAsset)}
|
||||
{#snippet customLayout(asset: Asset)}
|
||||
{#if hasGps(asset)}
|
||||
<div class="absolute bottom-1 end-3 px-4 py-1 rounded-xl text-xs transition-colors bg-success text-black">
|
||||
{asset.city || $t('gps')}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import type { Asset } from '$lib/managers/timeline-manager/types';
|
||||
import { fromISODateTimeUTCToObject, fromTimelinePlainDateTime } from '$lib/utils/timeline-util';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { AssetTypeEnum, AssetVisibility, type AssetResponseDto, type TimeBucketAssetResponseDto } from '@immich/sdk';
|
||||
|
|
@ -30,7 +30,7 @@ export const assetFactory = Sync.makeFactory<AssetResponseDto>({
|
|||
visibility: AssetVisibility.Timeline,
|
||||
});
|
||||
|
||||
export const timelineAssetFactory = Sync.makeFactory<TimelineAsset>({
|
||||
export const timelineAssetFactory = Sync.makeFactory<Asset>({
|
||||
id: Sync.each(() => faker.string.uuid()),
|
||||
ratio: Sync.each(() => faker.number.int()),
|
||||
ownerId: Sync.each(() => faker.string.uuid()),
|
||||
|
|
@ -51,7 +51,7 @@ export const timelineAssetFactory = Sync.makeFactory<TimelineAsset>({
|
|||
people: [faker.person.fullName()],
|
||||
});
|
||||
|
||||
export const toResponseDto = (...timelineAsset: TimelineAsset[]) => {
|
||||
export const toResponseDto = (...timelineAsset: Asset[]) => {
|
||||
const bucketAssets: TimeBucketAssetResponseDto = {
|
||||
city: [],
|
||||
country: [],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue