Files
immich/web/src/lib/stores/asset-interaction.store.ts
Alex 552340add7 Feature - Implemented virtual scroll on web (#573)
This PR implemented a virtual scroll on the web, as seen in this article.

[Building the Google Photos Web UI](https://medium.com/google-design/google-photos-45b714dfbed1)
2022-09-04 08:34:39 -05:00

151 lines
4.1 KiB
TypeScript

import { AssetGridState } from '$lib/models/asset-grid-state';
import { api, AssetResponseDto } from '@api';
import { derived, writable } from 'svelte/store';
import { assetGridState, assetStore } from './assets.store';
import _ from 'lodash-es';
// Asset Viewer
export const viewingAssetStoreState = writable<AssetResponseDto>();
export const isViewingAssetStoreState = writable<boolean>(false);
// Multi-Selection mode
export const assetsInAlbumStoreState = writable<AssetResponseDto[]>([]);
export const selectedAssets = writable<Set<AssetResponseDto>>(new Set());
export const selectedGroup = writable<Set<string>>(new Set());
export const isMultiSelectStoreState = derived(
selectedAssets,
($selectedAssets) => $selectedAssets.size > 0
);
function createAssetInteractionStore() {
let _assetGridState = new AssetGridState();
let _viewingAssetStoreState: AssetResponseDto;
let _selectedAssets: Set<AssetResponseDto>;
let _selectedGroup: Set<string>;
let _assetsInAblums: AssetResponseDto[];
let savedAssetLength = 0;
let assetSortedByDate: AssetResponseDto[] = [];
// Subscriber
assetGridState.subscribe((state) => {
_assetGridState = state;
});
viewingAssetStoreState.subscribe((asset) => {
_viewingAssetStoreState = asset;
});
selectedAssets.subscribe((assets) => {
_selectedAssets = assets;
});
selectedGroup.subscribe((group) => {
_selectedGroup = group;
});
assetsInAlbumStoreState.subscribe((assets) => {
_assetsInAblums = assets;
});
// Methods
/**
* Asset Viewer
*/
const setViewingAsset = async (asset: AssetResponseDto) => {
const { data } = await api.assetApi.getAssetById(asset.id);
viewingAssetStoreState.set(data);
isViewingAssetStoreState.set(true);
};
const setIsViewingAsset = (isViewing: boolean) => {
isViewingAssetStoreState.set(isViewing);
};
const navigateAsset = async (direction: 'next' | 'previous') => {
// Flatten and sort the asset by date if there are new assets
if (assetSortedByDate.length === 0 || savedAssetLength !== _assetGridState.assets.length) {
assetSortedByDate = _.sortBy(_assetGridState.assets, (a) => a.createdAt);
savedAssetLength = _assetGridState.assets.length;
}
// Find the index of the current asset
const currentIndex = assetSortedByDate.findIndex((a) => a.id === _viewingAssetStoreState.id);
// Get the next or previous asset
const nextIndex = direction === 'previous' ? currentIndex + 1 : currentIndex - 1;
// Run out of asset, this might be because there is no asset in the next bucket.
if (nextIndex == -1) {
let nextBucket = '';
// Find next bucket that doesn't have all assets loaded
for (const bucket of _assetGridState.buckets) {
if (bucket.assets.length === 0) {
nextBucket = bucket.bucketDate;
break;
}
}
if (nextBucket !== '') {
await assetStore.getAssetsByBucket(nextBucket);
navigateAsset(direction);
}
return;
}
const nextAsset = assetSortedByDate[nextIndex];
setViewingAsset(nextAsset);
};
/**
* Multiselect
*/
const addAssetToMultiselectGroup = (asset: AssetResponseDto) => {
// Not select if in album alreaady
if (_assetsInAblums.find((a) => a.id === asset.id)) {
return;
}
_selectedAssets.add(asset);
selectedAssets.set(_selectedAssets);
};
const removeAssetFromMultiselectGroup = (asset: AssetResponseDto) => {
_selectedAssets.delete(asset);
selectedAssets.set(_selectedAssets);
};
const addGroupToMultiselectGroup = (group: string) => {
_selectedGroup.add(group);
selectedGroup.set(_selectedGroup);
};
const removeGroupFromMultiselectGroup = (group: string) => {
_selectedGroup.delete(group);
selectedGroup.set(_selectedGroup);
};
const clearMultiselect = () => {
_selectedAssets.clear();
_selectedGroup.clear();
_assetsInAblums = [];
selectedAssets.set(_selectedAssets);
selectedGroup.set(_selectedGroup);
assetsInAlbumStoreState.set(_assetsInAblums);
};
return {
setViewingAsset,
setIsViewingAsset,
navigateAsset,
addAssetToMultiselectGroup,
removeAssetFromMultiselectGroup,
addGroupToMultiselectGroup,
removeGroupFromMultiselectGroup,
clearMultiselect
};
}
export const assetInteractionStore = createAssetInteractionStore();