Remove generics from AssetInteraction

This commit is contained in:
Min Idzelis 2025-04-20 03:47:51 +00:00
parent 9b7e9bc7b8
commit f3fe043c22
15 changed files with 43 additions and 45 deletions

View File

@ -4,7 +4,7 @@
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect, downloadAlbum } from '$lib/utils/asset-utils';
@ -36,7 +36,7 @@
$effect(() => void assetStore.updateOptions({ albumId: album.id, order: album.order }));
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
dragAndDropFilesStore.subscribe((value) => {
if (value.isDragging && value.files.length > 0) {

View File

@ -3,8 +3,7 @@
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { getKey } from '$lib/utils';
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
import { isTimelineAsset } from '$lib/utils/timeline-util';
import { getAssetInfo, type AssetResponseDto } from '@immich/sdk';
import { getAssetInfo } from '@immich/sdk';
import { mdiCloudDownloadOutline, mdiFileDownloadOutline, mdiFolderDownloadOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
@ -23,10 +22,7 @@
const assets = [...getAssets()];
if (assets.length === 1) {
clearSelect();
let asset: AssetResponseDto = assets[0] as AssetResponseDto;
if (isTimelineAsset(assets[0])) {
asset = await getAssetInfo({ id: assets[0].id, key: getKey() });
}
let asset = await getAssetInfo({ id: assets[0].id, key: getKey() });
await downloadFile(asset);
return;
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import type { AssetInteraction, BaseInteractionAsset } from '$lib/stores/asset-interaction.svelte';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { type AssetStore, isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
import { cancelMultiselect, selectAllAssets } from '$lib/utils/asset-utils';
import { mdiSelectAll, mdiSelectRemove } from '@mdi/js';
@ -8,7 +8,7 @@
interface Props {
assetStore: AssetStore;
assetInteraction: AssetInteraction<BaseInteractionAsset>;
assetInteraction: AssetInteraction;
}
let { assetStore, assetInteraction }: Props = $props();

View File

@ -11,7 +11,7 @@
import { navigate } from '$lib/utils/navigation';
import { getDateLocaleString } from '$lib/utils/timeline-util';
import type { AssetInteraction, BaseInteractionAsset } from '$lib/stores/asset-interaction.svelte';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js';
import { fly, scale } from 'svelte/transition';
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
@ -29,7 +29,7 @@
showArchiveIcon: boolean;
bucket: AssetBucket;
assetStore: AssetStore;
assetInteraction: AssetInteraction<BaseInteractionAsset>;
assetInteraction: AssetInteraction;
onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void;
onSelectAssets: (asset: TimelineAsset) => void;

View File

@ -41,7 +41,7 @@
additionally, update the page location/url with the asset as the asset-grid is scrolled */
enableRouting: boolean;
assetStore: AssetStore;
assetInteraction: AssetInteraction<TimelineAsset>;
assetInteraction: AssetInteraction;
removeAction?: AssetAction.UNARCHIVE | AssetAction.ARCHIVE | AssetAction.FAVORITE | AssetAction.UNFAVORITE | null;
withStacked?: boolean;
showArchiveIcon?: boolean;

View File

@ -4,8 +4,8 @@
export interface AssetControlContext {
// Wrap assets in a function, because context isn't reactive.
getAssets: () => BaseInteractionAsset[]; // All assets includes partners' assets
getOwnedAssets: () => BaseInteractionAsset[]; // Only assets owned by the user
getAssets: () => TimelineAsset[]; // All assets includes partners' assets
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
clearSelect: () => void;
}
@ -14,13 +14,13 @@
</script>
<script lang="ts">
import type { BaseInteractionAsset } from '$lib/stores/asset-interaction.svelte';
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
import { mdiClose } from '@mdi/js';
import type { Snippet } from 'svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
interface Props {
assets: BaseInteractionAsset[];
assets: TimelineAsset[];
clearSelect: () => void;
ownerId?: string | undefined;
children?: Snippet;

View File

@ -1,18 +1,18 @@
import { AssetInteraction, type BaseInteractionAsset } from '$lib/stores/asset-interaction.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { resetSavedUser, user } from '$lib/stores/user.store';
import { assetFactory } from '@test-data/factories/asset-factory';
import { timelineAssetFactory } from '@test-data/factories/asset-factory';
import { userAdminFactory } from '@test-data/factories/user-factory';
describe('AssetInteraction', () => {
let assetInteraction: AssetInteraction<BaseInteractionAsset>;
let assetInteraction: AssetInteraction;
beforeEach(() => {
assetInteraction = new AssetInteraction();
});
it('calculates derived values from selection', () => {
assetInteraction.selectAsset(assetFactory.build({ isFavorite: true, isArchived: true, isTrashed: true }));
assetInteraction.selectAsset(assetFactory.build({ isFavorite: true, isArchived: false, isTrashed: false }));
assetInteraction.selectAsset(timelineAssetFactory.build({ isFavorite: true, isArchived: true, isTrashed: true }));
assetInteraction.selectAsset(timelineAssetFactory.build({ isFavorite: true, isArchived: false, isTrashed: false }));
expect(assetInteraction.selectionActive).toBe(true);
expect(assetInteraction.isAllTrashed).toBe(false);
@ -22,7 +22,7 @@ describe('AssetInteraction', () => {
it('updates isAllUserOwned when the active user changes', () => {
const [user1, user2] = userAdminFactory.buildList(2);
assetInteraction.selectAsset(assetFactory.build({ ownerId: user1.id }));
assetInteraction.selectAsset(timelineAssetFactory.build({ ownerId: user1.id }));
const cleanup = $effect.root(() => {
expect(assetInteraction.isAllUserOwned).toBe(false);

View File

@ -3,8 +3,13 @@ import FormatBoldMessage from '$lib/components/i18n/format-bold-message.svelte';
import type { InterpolationValues } from '$lib/components/i18n/format-message';
import { NotificationType, notificationController } from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import type { AssetInteraction, BaseInteractionAsset } from '$lib/stores/asset-interaction.svelte';
import { assetsSnapshot, isSelectingAllAssets, type AssetStore } from '$lib/stores/assets-store.svelte';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import {
assetsSnapshot,
isSelectingAllAssets,
type AssetStore,
type TimelineAsset,
} from '$lib/stores/assets-store.svelte';
import { downloadManager } from '$lib/stores/download-store.svelte';
import { preferences } from '$lib/stores/user.store';
import { downloadRequest, getKey, withError } from '$lib/utils';
@ -364,7 +369,7 @@ export const getAssetType = (type: AssetTypeEnum) => {
}
};
export const getSelectedAssets = (assets: BaseInteractionAsset[], user: UserResponseDto | null): string[] => {
export const getSelectedAssets = (assets: TimelineAsset[], 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;
@ -467,10 +472,7 @@ export const keepThisDeleteOthers = async (keepAsset: AssetResponseDto, stack: S
}
};
export const selectAllAssets = async (
assetStore: AssetStore,
assetInteraction: AssetInteraction<BaseInteractionAsset>,
) => {
export const selectAllAssets = async (assetStore: AssetStore, assetInteraction: AssetInteraction) => {
if (get(isSelectingAllAssets)) {
// Selection is already ongoing
return;
@ -498,7 +500,7 @@ export const selectAllAssets = async (
}
};
export const cancelMultiselect = (assetInteraction: AssetInteraction<BaseInteractionAsset>) => {
export const cancelMultiselect = (assetInteraction: AssetInteraction) => {
isSelectingAllAssets.set(false);
assetInteraction.clearMultiselect();
};

View File

@ -38,7 +38,7 @@
import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
import { preferences, user } from '$lib/stores/user.store';
import { handlePromiseError } from '$lib/utils';
@ -107,8 +107,8 @@
let reactions: ActivityResponseDto[] = $state([]);
let albumOrder: AssetOrder | undefined = $state(data.album.order);
const assetInteraction = new AssetInteraction<TimelineAsset>();
const timelineInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const timelineInteraction = new AssetInteraction();
afterNavigate(({ from }) => {
let url: string | undefined = from?.url?.pathname;

View File

@ -14,7 +14,7 @@
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
@ -29,7 +29,7 @@
void assetStore.updateOptions({ isArchived: true });
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const handleEscape = () => {
if (assetInteraction.selectionActive) {

View File

@ -16,7 +16,7 @@
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { AssetAction } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { preferences } from '$lib/stores/user.store';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
import { onDestroy } from 'svelte';
@ -33,7 +33,7 @@
void assetStore.updateOptions({ isFavorite: true, withStacked: true });
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const handleEscape = () => {
if (assetInteraction.selectionActive) {

View File

@ -9,7 +9,7 @@
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import { AppRoute } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { mdiArrowLeft, mdiPlus } from '@mdi/js';
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
@ -24,7 +24,7 @@
const assetStore = new AssetStore();
$effect(() => void assetStore.updateOptions({ userId: data.partner.id, isArchived: false, withStacked: true }));
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const handleEscape = () => {
if (assetInteraction.selectionActive) {

View File

@ -71,7 +71,7 @@
$effect(() => void assetStore.updateOptions({ isArchived: false, personId: data.person.id }));
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
let viewMode: PersonPageViewMode = $state(PersonPageViewMode.VIEW_ASSETS);
let isEditingName = $state(false);

View File

@ -17,7 +17,7 @@
import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte';
import { AppRoute, AssetAction, QueryParameter, SettingInputFieldType } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
import { deleteTag, getAllTags, updateTag, upsertTags, type TagResponseDto } from '@immich/sdk';
import { Button, HStack, Text } from '@immich/ui';
@ -35,7 +35,7 @@
let pathSegments = $derived(data.path ? data.path.split('/') : []);
let currentPath = $derived($page.url.searchParams.get(QueryParameter.PATH) || '');
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const buildMap = (tags: TagResponseDto[]) => {
return Object.fromEntries(tags.map((tag) => [tag.value, tag]));

View File

@ -15,7 +15,7 @@
} from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore, type TimelineAsset } from '$lib/stores/assets-store.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
import { handlePromiseError } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
@ -40,7 +40,7 @@
void assetStore.updateOptions({ isTrashed: true });
onDestroy(() => assetStore.destroy());
const assetInteraction = new AssetInteraction<TimelineAsset>();
const assetInteraction = new AssetInteraction();
const handleEmptyTrash = async () => {
const isConfirmed = await dialogController.show({