mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): update right arrow gallery load more
- add hotkey support - add loading state - only show if there are more images to load
This commit is contained in:
committed by
Kent Keirsey
parent
2c956806d7
commit
3001e4c947
@ -57,6 +57,7 @@ const selector = createSelector(
|
|||||||
images,
|
images,
|
||||||
allImagesTotal,
|
allImagesTotal,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isFetching,
|
||||||
categories,
|
categories,
|
||||||
selectedBoardId,
|
selectedBoardId,
|
||||||
};
|
};
|
||||||
@ -82,8 +83,14 @@ const ImageGalleryGrid = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { images, isLoading, allImagesTotal, categories, selectedBoardId } =
|
const {
|
||||||
useAppSelector(selector);
|
images,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
allImagesTotal,
|
||||||
|
categories,
|
||||||
|
selectedBoardId,
|
||||||
|
} = useAppSelector(selector);
|
||||||
|
|
||||||
const { selectedBoard } = useListAllBoardsQuery(undefined, {
|
const { selectedBoard } = useListAllBoardsQuery(undefined, {
|
||||||
selectFromResult: ({ data }) => ({
|
selectFromResult: ({ data }) => ({
|
||||||
@ -176,7 +183,7 @@ const ImageGalleryGrid = () => {
|
|||||||
<IAIButton
|
<IAIButton
|
||||||
onClick={handleLoadMoreImages}
|
onClick={handleLoadMoreImages}
|
||||||
isDisabled={!areMoreAvailable}
|
isDisabled={!areMoreAvailable}
|
||||||
isLoading={isLoading}
|
isLoading={isFetching}
|
||||||
loadingText="Loading"
|
loadingText="Loading"
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
>
|
>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { ChakraProps, Flex, Grid, IconButton } from '@chakra-ui/react';
|
import { ChakraProps, Flex, Grid, IconButton, Spinner } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
|
||||||
import { useCallback, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaAngleLeft, FaAngleRight, FaRedo } from 'react-icons/fa';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
imageSelected,
|
imageSelected,
|
||||||
|
selectFilteredImages,
|
||||||
selectImagesById,
|
selectImagesById,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
|
import { clamp, isEqual } from 'lodash-es';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { selectFilteredImages } from 'features/gallery/store/gallerySlice';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaAngleDoubleRight, FaAngleLeft, FaAngleRight } from 'react-icons/fa';
|
||||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
|
|
||||||
const nextPrevButtonTriggerAreaStyles: ChakraProps['sx'] = {
|
const nextPrevButtonTriggerAreaStyles: ChakraProps['sx'] = {
|
||||||
@ -27,6 +27,7 @@ const nextPrevButtonStyles: ChakraProps['sx'] = {
|
|||||||
export const nextPrevImageButtonsSelector = createSelector(
|
export const nextPrevImageButtonsSelector = createSelector(
|
||||||
[stateSelector, selectFilteredImages],
|
[stateSelector, selectFilteredImages],
|
||||||
(state, filteredImages) => {
|
(state, filteredImages) => {
|
||||||
|
const { total, isFetching } = state.gallery;
|
||||||
const lastSelectedImage =
|
const lastSelectedImage =
|
||||||
state.gallery.selection[state.gallery.selection.length - 1];
|
state.gallery.selection[state.gallery.selection.length - 1];
|
||||||
|
|
||||||
@ -64,6 +65,8 @@ export const nextPrevImageButtonsSelector = createSelector(
|
|||||||
isOnFirstImage: currentImageIndex === 0,
|
isOnFirstImage: currentImageIndex === 0,
|
||||||
isOnLastImage:
|
isOnLastImage:
|
||||||
!isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1,
|
!isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1,
|
||||||
|
areMoreImagesAvailable: total > imagesLength,
|
||||||
|
isFetching,
|
||||||
nextImage,
|
nextImage,
|
||||||
prevImage,
|
prevImage,
|
||||||
nextImageId,
|
nextImageId,
|
||||||
@ -81,8 +84,14 @@ const NextPrevImageButtons = () => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { isOnFirstImage, isOnLastImage, nextImageId, prevImageId } =
|
const {
|
||||||
useAppSelector(nextPrevImageButtonsSelector);
|
isOnFirstImage,
|
||||||
|
isOnLastImage,
|
||||||
|
nextImageId,
|
||||||
|
prevImageId,
|
||||||
|
areMoreImagesAvailable,
|
||||||
|
isFetching,
|
||||||
|
} = useAppSelector(nextPrevImageButtonsSelector);
|
||||||
|
|
||||||
const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] =
|
const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
@ -122,9 +131,21 @@ const NextPrevImageButtons = () => {
|
|||||||
useHotkeys(
|
useHotkeys(
|
||||||
'right',
|
'right',
|
||||||
() => {
|
() => {
|
||||||
|
if (isOnLastImage && areMoreImagesAvailable && !isFetching) {
|
||||||
|
handleLoadMoreImages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isOnLastImage) {
|
||||||
handleNextImage();
|
handleNextImage();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[nextImageId]
|
[
|
||||||
|
nextImageId,
|
||||||
|
isOnLastImage,
|
||||||
|
areMoreImagesAvailable,
|
||||||
|
handleLoadMoreImages,
|
||||||
|
isFetching,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -173,16 +194,34 @@ const NextPrevImageButtons = () => {
|
|||||||
sx={nextPrevButtonStyles}
|
sx={nextPrevButtonStyles}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{shouldShowNextPrevButtons && isOnLastImage && (
|
{shouldShowNextPrevButtons &&
|
||||||
|
isOnLastImage &&
|
||||||
|
areMoreImagesAvailable &&
|
||||||
|
!isFetching && (
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label={t('accessibility.loadMore')}
|
aria-label={t('accessibility.loadMore')}
|
||||||
icon={<FaRedo size={42} />}
|
icon={<FaAngleDoubleRight size={64} />}
|
||||||
variant="unstyled"
|
variant="unstyled"
|
||||||
onClick={handleLoadMoreImages}
|
onClick={handleLoadMoreImages}
|
||||||
boxSize={16}
|
boxSize={16}
|
||||||
sx={nextPrevButtonStyles}
|
sx={nextPrevButtonStyles}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{shouldShowNextPrevButtons &&
|
||||||
|
isOnLastImage &&
|
||||||
|
areMoreImagesAvailable &&
|
||||||
|
isFetching && (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
w: 16,
|
||||||
|
h: 16,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Spinner opacity={0.5} size="xl" />
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user