refactor(web): asset grid stores (#3464)

* Refactor asset grid stores

* Iterate over buckets with for..of loop

* Rebase on top of main branch changes
This commit is contained in:
Sergey Kondrikov 2023-08-01 04:27:56 +03:00 committed by GitHub
parent 13051c1e5a
commit 5f9dfa9493
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 330 additions and 265 deletions

View file

@ -1,28 +1,30 @@
<script lang="ts">
import { get } from 'svelte/store';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import SelectAll from 'svelte-material-icons/SelectAll.svelte';
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
import { assetInteractionStore } from '$lib/stores/asset-interaction.store';
import { assetGridState, assetStore } from '$lib/stores/assets.store';
import { handleError } from '../../../utils/handle-error';
import { AssetGridState, BucketPosition } from '$lib/models/asset-grid-state';
import { BucketPosition } from '$lib/models/asset-grid-state';
import type { AssetStore } from '$lib/stores/assets.store';
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
export let assetStore: AssetStore;
export let assetInteractionStore: AssetInteractionStore;
let selecting = false;
const handleSelectAll = async () => {
try {
selecting = true;
let _assetGridState = new AssetGridState();
assetGridState.subscribe((state) => {
_assetGridState = state;
});
for (let i = 0; i < _assetGridState.buckets.length; i++) {
await assetStore.getAssetsByBucket(_assetGridState.buckets[i].bucketDate, BucketPosition.Unknown);
for (const asset of _assetGridState.buckets[i].assets) {
const assetGridState = get(assetStore);
for (const bucket of assetGridState.buckets) {
await assetStore.getAssetsByBucket(bucket.bucketDate, BucketPosition.Unknown);
for (const asset of bucket.assets) {
assetInteractionStore.addAssetToMultiselectGroup(asset);
}
}
selecting = false;
} catch (e) {
handleError(e, 'Error selecting all assets');

View file

@ -1,13 +1,4 @@
<script lang="ts">
import {
assetInteractionStore,
assetSelectionCandidates,
assetsInAlbumStoreState,
isMultiSelectStoreState,
selectedAssets,
selectedGroup,
} from '$lib/stores/asset-interaction.store';
import { assetStore } from '$lib/stores/assets.store';
import { locale } from '$lib/stores/preferences.store';
import { getAssetRatio } from '$lib/utils/asset-utils';
import { formatGroupTitle, splitBucketIntoDateGroups } from '$lib/utils/timeline-util';
@ -19,6 +10,9 @@
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
import { fly } from 'svelte/transition';
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import type { AssetStore } from '$lib/stores/assets.store';
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
export let assets: AssetResponseDto[];
export let bucketDate: string;
@ -26,6 +20,12 @@
export let isAlbumSelectionMode = false;
export let viewportWidth: number;
export let assetStore: AssetStore;
export let assetInteractionStore: AssetInteractionStore;
const { selectedGroup, selectedAssets, assetsInAlbumState, assetSelectionCandidates, isMultiSelectState } =
assetInteractionStore;
const dispatch = createEventDispatcher();
let isMouseOverGroup = false;
@ -94,10 +94,10 @@
return;
}
if ($isMultiSelectStoreState) {
if ($isMultiSelectState) {
assetSelectHandler(asset, assetsInDateGroup, dateGroupTitle);
} else {
assetInteractionStore.setViewingAsset(asset);
assetViewingStore.setAssetId(asset.id);
}
};
@ -137,7 +137,7 @@
// Show multi select icon on hover on date group
hoveredDateGroup = dateGroupTitle;
if ($isMultiSelectStoreState) {
if ($isMultiSelectState) {
dispatch('selectAssetCandidates', { asset });
}
};
@ -207,9 +207,9 @@
on:click={() => assetClickHandler(asset, assetsInDateGroup, dateGroupTitle)}
on:select={() => assetSelectHandler(asset, assetsInDateGroup, dateGroupTitle)}
on:mouse-event={() => assetMouseEventHandler(dateGroupTitle, asset)}
selected={$selectedAssets.has(asset) || $assetsInAlbumStoreState.some(({ id }) => id === asset.id)}
selected={$selectedAssets.has(asset) || $assetsInAlbumState.some(({ id }) => id === asset.id)}
selectionCandidate={$assetSelectionCandidates.has(asset)}
disabled={$assetsInAlbumStoreState.some(({ id }) => id === asset.id)}
disabled={$assetsInAlbumState.some(({ id }) => id === asset.id)}
thumbnailWidth={box.width}
thumbnailHeight={box.height}
/>

View file

@ -1,15 +1,6 @@
<script lang="ts">
import { BucketPosition } from '$lib/models/asset-grid-state';
import {
assetInteractionStore,
assetSelectionCandidates,
assetSelectionStart,
isMultiSelectStoreState,
isViewingAssetStoreState,
selectedAssets,
viewingAssetStoreState,
} from '$lib/stores/asset-interaction.store';
import { assetGridState, assetStore, loadingBucketState } from '$lib/stores/assets.store';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { locale } from '$lib/stores/preferences.store';
import { formatGroupTitle, splitBucketIntoDateGroups } from '$lib/utils/timeline-util';
import type { UserResponseDto } from '@api';
@ -31,11 +22,20 @@
import { browser } from '$app/environment';
import { isSearchEnabled } from '$lib/stores/search.store';
import ShowShortcuts from '../shared-components/show-shortcuts.svelte';
import type { AssetStore } from '$lib/stores/assets.store';
import type { AssetInteractionStore } from '$lib/stores/asset-interaction.store';
export let user: UserResponseDto | undefined = undefined;
export let isAlbumSelectionMode = false;
export let showMemoryLane = false;
export let assetStore: AssetStore;
export let assetInteractionStore: AssetInteractionStore;
const { assetSelectionCandidates, assetSelectionStart, selectedAssets, isMultiSelectState } = assetInteractionStore;
let { isViewing: showAssetViewer, asset: viewingAsset } = assetViewingStore;
let viewportHeight = 0;
let viewportWidth = 0;
let assetGridElement: HTMLElement;
@ -61,7 +61,7 @@
// Get asset bucket if bucket height is smaller than viewport height
let bucketsToFetchInitially: string[] = [];
let initialBucketsHeight = 0;
$assetGridState.buckets.every((bucket) => {
$assetStore.buckets.every((bucket) => {
if (initialBucketsHeight < viewportHeight) {
initialBucketsHeight += bucket.bucketHeight;
bucketsToFetchInitially.push(bucket.bucketDate);
@ -89,7 +89,7 @@
return;
}
if (!$isViewingAssetStoreState) {
if (!$showAssetViewer) {
switch (event.key) {
case 'Escape':
assetInteractionStore.clearMultiselect();
@ -121,12 +121,18 @@
assetGridElement.scrollBy(0, event.detail.heightDelta);
}
const navigateToPreviousAsset = () => {
assetInteractionStore.navigateAsset('previous');
const navigateToPreviousAsset = async () => {
const prevAsset = await assetStore.getAdjacentAsset($viewingAsset.id, 'previous');
if (prevAsset) {
assetViewingStore.setAssetId(prevAsset);
}
};
const navigateToNextAsset = () => {
assetInteractionStore.navigateAsset('next');
const navigateToNextAsset = async () => {
const nextAsset = await assetStore.getAdjacentAsset($viewingAsset.id, 'next');
if (nextAsset) {
assetViewingStore.setAssetId(nextAsset);
}
};
let lastScrollPosition = 0;
@ -228,8 +234,8 @@
assetInteractionStore.clearAssetSelectionCandidates();
if ($assetSelectionStart && rangeSelection) {
let startBucketIndex = $assetGridState.loadedAssets[$assetSelectionStart.id];
let endBucketIndex = $assetGridState.loadedAssets[asset.id];
let startBucketIndex = $assetStore.loadedAssets[$assetSelectionStart.id];
let endBucketIndex = $assetStore.loadedAssets[asset.id];
if (endBucketIndex < startBucketIndex) {
[startBucketIndex, endBucketIndex] = [endBucketIndex, startBucketIndex];
@ -237,7 +243,7 @@
// Select/deselect assets in all intermediate buckets
for (let bucketIndex = startBucketIndex + 1; bucketIndex < endBucketIndex; bucketIndex++) {
const bucket = $assetGridState.buckets[bucketIndex];
const bucket = $assetStore.buckets[bucketIndex];
await assetStore.getAssetsByBucket(bucket.bucketDate, BucketPosition.Unknown);
for (const asset of bucket.assets) {
if (deselect) {
@ -250,7 +256,7 @@
// Update date group selection
for (let bucketIndex = startBucketIndex; bucketIndex <= endBucketIndex; bucketIndex++) {
const bucket = $assetGridState.buckets[bucketIndex];
const bucket = $assetStore.buckets[bucketIndex];
// Split bucket into date groups and check each group
const assetsGroupByDate = splitBucketIntoDateGroups(bucket.assets, $locale);
@ -279,18 +285,18 @@
return;
}
let start = $assetGridState.assets.indexOf(rangeStart);
let end = $assetGridState.assets.indexOf(asset);
let start = $assetStore.assets.indexOf(rangeStart);
let end = $assetStore.assets.indexOf(asset);
if (start > end) {
[start, end] = [end, start];
}
assetInteractionStore.setAssetSelectionCandidates($assetGridState.assets.slice(start, end + 1));
assetInteractionStore.setAssetSelectionCandidates($assetStore.assets.slice(start, end + 1));
};
const onSelectStart = (e: Event) => {
if ($isMultiSelectStoreState && shiftKeyIsDown) {
if ($isMultiSelectState && shiftKeyIsDown) {
e.preventDefault();
}
};
@ -302,8 +308,9 @@
<ShowShortcuts on:close={() => (showShortcuts = !showShortcuts)} />
{/if}
{#if bucketInfo && viewportHeight && $assetGridState.timelineHeight > viewportHeight}
{#if bucketInfo && viewportHeight && $assetStore.timelineHeight > viewportHeight}
<Scrollbar
{assetStore}
scrollbarHeight={viewportHeight}
scrollTop={lastScrollPosition}
on:onscrollbarclick={(e) => handleScrollbarClick(e.detail)}
@ -324,15 +331,12 @@
{#if showMemoryLane}
<MemoryLane />
{/if}
<section id="virtual-timeline" style:height={$assetGridState.timelineHeight + 'px'}>
{#each $assetGridState.buckets as bucket, bucketIndex (bucketIndex)}
<section id="virtual-timeline" style:height={$assetStore.timelineHeight + 'px'}>
{#each $assetStore.buckets as bucket, bucketIndex (bucketIndex)}
<IntersectionObserver
on:intersected={intersectedHandler}
on:hidden={async () => {
// If bucket is hidden and in loading state, cancel the request
if ($loadingBucketState[bucket.bucketDate]) {
await assetStore.cancelBucketRequest(bucket.cancelToken, bucket.bucketDate);
}
await assetStore.cancelBucketRequest(bucket.cancelToken, bucket.bucketDate);
}}
let:intersecting
top={750}
@ -342,6 +346,8 @@
<div id={'bucket_' + bucket.bucketDate} style:height={bucket.bucketHeight + 'px'}>
{#if intersecting}
<AssetDateGroup
{assetStore}
{assetInteractionStore}
{isAlbumSelectionMode}
on:shift={handleScrollTimeline}
on:selectAssetCandidates={handleSelectAssetCandidates}
@ -360,13 +366,14 @@
</section>
<Portal target="body">
{#if $isViewingAssetStoreState}
{#if $showAssetViewer}
<AssetViewer
asset={$viewingAssetStoreState}
{assetStore}
asset={$viewingAsset}
on:navigate-previous={navigateToPreviousAsset}
on:navigate-next={navigateToNextAsset}
on:close={() => {
assetInteractionStore.setIsViewingAsset(false);
assetViewingStore.showAssetViewer(false);
}}
on:archived={handleArchiveSuccess}
/>