mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 08:31:59 +00:00
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 <alex.tran1502@gmail.com>
This commit is contained in:
parent
814030be77
commit
37edef834e
3 changed files with 71 additions and 20 deletions
|
@ -46,6 +46,11 @@ export class AssetGridState {
|
||||||
*/
|
*/
|
||||||
assets: AssetResponseDto[] = [];
|
assets: AssetResponseDto[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total assets that have been loaded along with additional data
|
||||||
|
*/
|
||||||
|
loadedAssets: Record<string, number> = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User that owns assets
|
* User that owns assets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -66,30 +66,62 @@ function createAssetInteractionStore() {
|
||||||
isViewingAssetStoreState.set(isViewing);
|
isViewingAssetStoreState.set(isViewing);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getNextAsset = async (currentBucketIndex: number, assetId: string): Promise<AssetResponseDto | null> => {
|
||||||
|
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<AssetResponseDto | null> => {
|
||||||
|
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') => {
|
const navigateAsset = async (direction: 'next' | 'previous') => {
|
||||||
let index = _assetGridState.assets.findIndex(({ id }) => id === _viewingAssetStoreState.id);
|
const currentAssetId = _viewingAssetStoreState.id;
|
||||||
|
const currentBucketIndex = _assetGridState.loadedAssets[currentAssetId];
|
||||||
index = direction === 'next' ? index + 1 : index - 1;
|
if (currentBucketIndex < 0 || currentBucketIndex >= _assetGridState.buckets.length) {
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const asset = _assetGridState.assets[index];
|
const asset =
|
||||||
|
direction === 'next'
|
||||||
|
? await getNextAsset(currentBucketIndex, currentAssetId)
|
||||||
|
: await getPrevAsset(currentBucketIndex, currentAssetId);
|
||||||
|
|
||||||
if (asset) {
|
if (asset) {
|
||||||
setViewingAsset(asset);
|
setViewingAsset(asset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,15 @@ function createAssetStore() {
|
||||||
return height;
|
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
|
* Set initial state
|
||||||
* @param viewportHeight
|
* @param viewportHeight
|
||||||
|
@ -54,6 +63,7 @@ function createAssetStore() {
|
||||||
position: BucketPosition.Unknown,
|
position: BucketPosition.Unknown,
|
||||||
})),
|
})),
|
||||||
assets: [],
|
assets: [],
|
||||||
|
loadedAssets: {},
|
||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,6 +111,7 @@ function createAssetStore() {
|
||||||
state.buckets[bucketIndex].assets = assets;
|
state.buckets[bucketIndex].assets = assets;
|
||||||
state.buckets[bucketIndex].position = position;
|
state.buckets[bucketIndex].position = position;
|
||||||
state.assets = state.buckets.flatMap((b) => b.assets);
|
state.assets = state.buckets.flatMap((b) => b.assets);
|
||||||
|
refreshLoadedAssets(state);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -123,6 +134,7 @@ function createAssetStore() {
|
||||||
_removeBucket(state.buckets[bucketIndex].bucketDate);
|
_removeBucket(state.buckets[bucketIndex].bucketDate);
|
||||||
}
|
}
|
||||||
state.assets = state.buckets.flatMap((b) => b.assets);
|
state.assets = state.buckets.flatMap((b) => b.assets);
|
||||||
|
refreshLoadedAssets(state);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -132,6 +144,7 @@ function createAssetStore() {
|
||||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
||||||
state.buckets.splice(bucketIndex, 1);
|
state.buckets.splice(bucketIndex, 1);
|
||||||
state.assets = state.buckets.flatMap((b) => b.assets);
|
state.assets = state.buckets.flatMap((b) => b.assets);
|
||||||
|
refreshLoadedAssets(state);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -180,6 +193,7 @@ function createAssetStore() {
|
||||||
state.buckets[bucketIndex].assets[assetIndex].isFavorite = isFavorite;
|
state.buckets[bucketIndex].assets[assetIndex].isFavorite = isFavorite;
|
||||||
|
|
||||||
state.assets = state.buckets.flatMap((b) => b.assets);
|
state.assets = state.buckets.flatMap((b) => b.assets);
|
||||||
|
refreshLoadedAssets(state);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue