From 37edef834e5ed7c74851cb0818c9238be415c7db Mon Sep 17 00:00:00 2001 From: Sergey Kondrikov Date: Wed, 5 Jul 2023 23:24:23 +0300 Subject: [PATCH] fix(web): previous/next asset navigation (#3107) * fix(web): previous/next asset navigation * Apply suggestions from code review Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> * Call setViewingAsset once * Make code more readable * Avoid recursive call * Simplify return statement * Set position of the bucket to Unknown --------- Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> Co-authored-by: Alex Tran --- web/src/lib/models/asset-grid-state.ts | 5 ++ web/src/lib/stores/asset-interaction.store.ts | 72 +++++++++++++------ web/src/lib/stores/assets.store.ts | 14 ++++ 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/web/src/lib/models/asset-grid-state.ts b/web/src/lib/models/asset-grid-state.ts index fcf5da767e..35a3b2a5ad 100644 --- a/web/src/lib/models/asset-grid-state.ts +++ b/web/src/lib/models/asset-grid-state.ts @@ -46,6 +46,11 @@ export class AssetGridState { */ assets: AssetResponseDto[] = []; + /** + * Total assets that have been loaded along with additional data + */ + loadedAssets: Record = {}; + /** * User that owns assets */ diff --git a/web/src/lib/stores/asset-interaction.store.ts b/web/src/lib/stores/asset-interaction.store.ts index 494b023955..0c8738c25a 100644 --- a/web/src/lib/stores/asset-interaction.store.ts +++ b/web/src/lib/stores/asset-interaction.store.ts @@ -66,30 +66,62 @@ function createAssetInteractionStore() { isViewingAssetStoreState.set(isViewing); }; + const getNextAsset = async (currentBucketIndex: number, assetId: string): Promise => { + const currentBucket = _assetGridState.buckets[currentBucketIndex]; + const assetIndex = currentBucket.assets.findIndex(({ id }) => id == assetId); + if (assetIndex === -1) { + return null; + } + + if (assetIndex + 1 < currentBucket.assets.length) { + return currentBucket.assets[assetIndex + 1]; + } + + const nextBucketIndex = currentBucketIndex + 1; + if (nextBucketIndex >= _assetGridState.buckets.length) { + return null; + } + + const nextBucket = _assetGridState.buckets[nextBucketIndex]; + await assetStore.getAssetsByBucket(nextBucket.bucketDate, BucketPosition.Unknown); + + return nextBucket.assets[0] ?? null; + }; + + const getPrevAsset = async (currentBucketIndex: number, assetId: string): Promise => { + const currentBucket = _assetGridState.buckets[currentBucketIndex]; + const assetIndex = currentBucket.assets.findIndex(({ id }) => id == assetId); + if (assetIndex === -1) { + return null; + } + + if (assetIndex > 0) { + return currentBucket.assets[assetIndex - 1]; + } + + const prevBucketIndex = currentBucketIndex - 1; + if (prevBucketIndex < 0) { + return null; + } + + const prevBucket = _assetGridState.buckets[prevBucketIndex]; + await assetStore.getAssetsByBucket(prevBucket.bucketDate, BucketPosition.Unknown); + + return prevBucket.assets[prevBucket.assets.length - 1] ?? null; + }; + const navigateAsset = async (direction: 'next' | 'previous') => { - let index = _assetGridState.assets.findIndex(({ id }) => id === _viewingAssetStoreState.id); - - index = direction === 'next' ? index + 1 : index - 1; - - const needMoreAbove = index < 0; - const needMoreBelow = index >= _assetGridState.assets.length; - - // Try to load more assets if we're at the end. - if (needMoreAbove || needMoreBelow) { - for (const bucket of _assetGridState.buckets) { - if (bucket.assets.length === 0) { - await assetStore.getAssetsByBucket( - bucket.bucketDate, - needMoreAbove ? BucketPosition.Above : BucketPosition.Below, - ); - navigateAsset(direction); - break; - } - } + const currentAssetId = _viewingAssetStoreState.id; + const currentBucketIndex = _assetGridState.loadedAssets[currentAssetId]; + if (currentBucketIndex < 0 || currentBucketIndex >= _assetGridState.buckets.length) { return; } - const asset = _assetGridState.assets[index]; + const asset = + direction === 'next' + ? await getNextAsset(currentBucketIndex, currentAssetId) + : await getPrevAsset(currentBucketIndex, currentAssetId); + if (asset) { setViewingAsset(asset); } diff --git a/web/src/lib/stores/assets.store.ts b/web/src/lib/stores/assets.store.ts index f3d142eddf..4772753014 100644 --- a/web/src/lib/stores/assets.store.ts +++ b/web/src/lib/stores/assets.store.ts @@ -30,6 +30,15 @@ function createAssetStore() { return height; }; + const refreshLoadedAssets = (state: AssetGridState): void => { + state.loadedAssets = {}; + state.buckets.forEach((bucket, bucketIndex) => + bucket.assets.map((asset) => { + state.loadedAssets[asset.id] = bucketIndex; + }), + ); + }; + /** * Set initial state * @param viewportHeight @@ -54,6 +63,7 @@ function createAssetStore() { position: BucketPosition.Unknown, })), assets: [], + loadedAssets: {}, userId, }); @@ -101,6 +111,7 @@ function createAssetStore() { state.buckets[bucketIndex].assets = assets; state.buckets[bucketIndex].position = position; state.assets = state.buckets.flatMap((b) => b.assets); + refreshLoadedAssets(state); return state; }); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -123,6 +134,7 @@ function createAssetStore() { _removeBucket(state.buckets[bucketIndex].bucketDate); } state.assets = state.buckets.flatMap((b) => b.assets); + refreshLoadedAssets(state); return state; }); }; @@ -132,6 +144,7 @@ function createAssetStore() { const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate); state.buckets.splice(bucketIndex, 1); state.assets = state.buckets.flatMap((b) => b.assets); + refreshLoadedAssets(state); return state; }); }; @@ -180,6 +193,7 @@ function createAssetStore() { state.buckets[bucketIndex].assets[assetIndex].isFavorite = isFavorite; state.assets = state.buckets.flatMap((b) => b.assets); + refreshLoadedAssets(state); return state; }); };