feat: timeline-manager improvement to use AssetResponseDto efficiently (#24421)
parent
cbdf5011f9
commit
161147af51
|
|
@ -188,7 +188,7 @@
|
||||||
// the performance benefits of deferred layouts while still supporting deep linking
|
// the performance benefits of deferred layouts while still supporting deep linking
|
||||||
// to assets at the end of the timeline.
|
// to assets at the end of the timeline.
|
||||||
timelineManager.isScrollingOnLoad = true;
|
timelineManager.isScrollingOnLoad = true;
|
||||||
const monthGroup = await timelineManager.findMonthGroupForAsset(assetId);
|
const monthGroup = await timelineManager.findMonthGroupForAsset({ id: assetId });
|
||||||
if (!monthGroup) {
|
if (!monthGroup) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timeline-util';
|
import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timeline-util';
|
||||||
import { AssetOrder } from '@immich/sdk';
|
import { AssetOrder, type AssetResponseDto } from '@immich/sdk';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import type { MonthGroup } from '../month-group.svelte';
|
import type { MonthGroup } from '../month-group.svelte';
|
||||||
import { TimelineManager } from '../timeline-manager.svelte';
|
import { TimelineManager } from '../timeline-manager.svelte';
|
||||||
|
|
@ -7,12 +7,16 @@ import type { AssetDescriptor, Direction, TimelineAsset } from '../types';
|
||||||
|
|
||||||
export async function getAssetWithOffset(
|
export async function getAssetWithOffset(
|
||||||
timelineManager: TimelineManager,
|
timelineManager: TimelineManager,
|
||||||
assetDescriptor: AssetDescriptor,
|
assetDescriptor: AssetDescriptor | AssetResponseDto,
|
||||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
): Promise<TimelineAsset | undefined> {
|
): Promise<TimelineAsset | undefined> {
|
||||||
const { asset, monthGroup } = findMonthGroupForAsset(timelineManager, assetDescriptor.id) ?? {};
|
const monthGroup = await timelineManager.findMonthGroupForAsset(assetDescriptor);
|
||||||
if (!monthGroup || !asset) {
|
if (!monthGroup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const asset = monthGroup.findAssetById(assetDescriptor);
|
||||||
|
if (!asset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -524,6 +524,7 @@ describe('TimelineManager', () => {
|
||||||
{ count: 3, timeBucket: '2024-01-01T00:00:00.000Z' },
|
{ count: 3, timeBucket: '2024-01-01T00:00:00.000Z' },
|
||||||
]);
|
]);
|
||||||
sdkMock.getTimeBucket.mockImplementation(({ timeBucket }) => Promise.resolve(bucketAssetsResponse[timeBucket]));
|
sdkMock.getTimeBucket.mockImplementation(({ timeBucket }) => Promise.resolve(bucketAssetsResponse[timeBucket]));
|
||||||
|
sdkMock.getAssetInfo.mockRejectedValue(new Error('Asset not found'));
|
||||||
await timelineManager.updateViewport({ width: 1588, height: 1000 });
|
await timelineManager.updateViewport({ width: 1588, height: 1000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@ import { WebsocketSupport } from '$lib/managers/timeline-manager/internal/websoc
|
||||||
import { CancellableTask } from '$lib/utils/cancellable-task';
|
import { CancellableTask } from '$lib/utils/cancellable-task';
|
||||||
import { PersistedLocalStorage } from '$lib/utils/persisted';
|
import { PersistedLocalStorage } from '$lib/utils/persisted';
|
||||||
import {
|
import {
|
||||||
|
isAssetResponseDto,
|
||||||
setDifference,
|
setDifference,
|
||||||
toTimelineAsset,
|
toTimelineAsset,
|
||||||
type TimelineDateTime,
|
type TimelineDateTime,
|
||||||
type TimelineYearMonth,
|
type TimelineYearMonth,
|
||||||
} from '$lib/utils/timeline-util';
|
} from '$lib/utils/timeline-util';
|
||||||
import { AssetOrder, getAssetInfo, getTimeBuckets } from '@immich/sdk';
|
import { AssetOrder, getAssetInfo, getTimeBuckets, type AssetResponseDto } from '@immich/sdk';
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
import { clamp, isEqual } from 'lodash-es';
|
||||||
import { SvelteDate, SvelteSet } from 'svelte/reactivity';
|
import { SvelteDate, SvelteSet } from 'svelte/reactivity';
|
||||||
import { DayGroup } from './day-group.svelte';
|
import { DayGroup } from './day-group.svelte';
|
||||||
|
|
@ -343,27 +344,30 @@ export class TimelineManager extends VirtualScrollManager {
|
||||||
this.addAssetsUpsertSegments([...notExcluded]);
|
this.addAssetsUpsertSegments([...notExcluded]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findMonthGroupForAsset(id: string) {
|
async findMonthGroupForAsset(asset: AssetDescriptor | AssetResponseDto) {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
await this.initTask.waitUntilCompletion();
|
await this.initTask.waitUntilCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { id } = asset;
|
||||||
let { monthGroup } = findMonthGroupForAssetUtil(this, id) ?? {};
|
let { monthGroup } = findMonthGroupForAssetUtil(this, id) ?? {};
|
||||||
if (monthGroup) {
|
if (monthGroup) {
|
||||||
return monthGroup;
|
return monthGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await getAssetInfo({ ...authManager.params, id }).catch(() => null);
|
const response = isAssetResponseDto(asset)
|
||||||
|
? asset
|
||||||
|
: await getAssetInfo({ ...authManager.params, id }).catch(() => null);
|
||||||
if (!response) {
|
if (!response) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const asset = toTimelineAsset(response);
|
const timelineAsset = toTimelineAsset(response);
|
||||||
if (!asset || this.isExcluded(asset)) {
|
if (this.isExcluded(timelineAsset)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
monthGroup = await this.#loadMonthGroupAtTime(asset.localDateTime, { cancelable: false });
|
monthGroup = await this.#loadMonthGroupAtTime(timelineAsset.localDateTime, { cancelable: false });
|
||||||
if (monthGroup?.findAssetById({ id })) {
|
if (monthGroup?.findAssetById({ id })) {
|
||||||
return monthGroup;
|
return monthGroup;
|
||||||
}
|
}
|
||||||
|
|
@ -532,14 +536,14 @@ export class TimelineManager extends VirtualScrollManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLaterAsset(
|
async getLaterAsset(
|
||||||
assetDescriptor: AssetDescriptor,
|
assetDescriptor: AssetDescriptor | AssetResponseDto,
|
||||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
): Promise<TimelineAsset | undefined> {
|
): Promise<TimelineAsset | undefined> {
|
||||||
return await getAssetWithOffset(this, assetDescriptor, interval, 'later');
|
return await getAssetWithOffset(this, assetDescriptor, interval, 'later');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEarlierAsset(
|
async getEarlierAsset(
|
||||||
assetDescriptor: AssetDescriptor,
|
assetDescriptor: AssetDescriptor | AssetResponseDto,
|
||||||
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
): Promise<TimelineAsset | undefined> {
|
): Promise<TimelineAsset | undefined> {
|
||||||
return await getAssetWithOffset(this, assetDescriptor, interval, 'earlier');
|
return await getAssetWithOffset(this, assetDescriptor, interval, 'earlier');
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { TimelineAsset, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
|
import type { AssetDescriptor, TimelineAsset, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { getAssetRatio } from '$lib/utils/asset-utils';
|
import { getAssetRatio } from '$lib/utils/asset-utils';
|
||||||
import { AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
|
import { AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
|
||||||
|
|
@ -192,8 +192,13 @@ export const toTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset):
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset): unknownAsset is TimelineAsset =>
|
export const isTimelineAsset = (
|
||||||
(unknownAsset as TimelineAsset).ratio !== undefined;
|
unknownAsset: AssetDescriptor | AssetResponseDto | TimelineAsset,
|
||||||
|
): unknownAsset is TimelineAsset => (unknownAsset as TimelineAsset).ratio !== undefined;
|
||||||
|
|
||||||
|
export const isAssetResponseDto = (
|
||||||
|
unknownAsset: AssetDescriptor | AssetResponseDto | TimelineAsset,
|
||||||
|
): unknownAsset is AssetResponseDto => (unknownAsset as AssetResponseDto).type !== undefined;
|
||||||
|
|
||||||
export const isTimelineAssets = (assets: AssetResponseDto[] | TimelineAsset[]): assets is TimelineAsset[] =>
|
export const isTimelineAssets = (assets: AssetResponseDto[] | TimelineAsset[]): assets is TimelineAsset[] =>
|
||||||
assets.length === 0 || 'ratio' in assets[0];
|
assets.length === 0 || 'ratio' in assets[0];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue