mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): gallery filter dropdown -> Images/Assets toggle
This commit is contained in:
parent
1ddc620192
commit
7004430380
@ -122,7 +122,9 @@
|
||||
"noImagesInGallery": "No Images In Gallery",
|
||||
"deleteImage": "Delete Image",
|
||||
"deleteImageBin": "Deleted images will be sent to your operating system's Bin.",
|
||||
"deleteImagePermanent": "Deleted images cannot be restored."
|
||||
"deleteImagePermanent": "Deleted images cannot be restored.",
|
||||
"images": "Images",
|
||||
"assets": "Assets"
|
||||
},
|
||||
"hotkeys": {
|
||||
"keyboardShortcuts": "Keyboard Shortcuts",
|
||||
|
@ -69,6 +69,7 @@ import {
|
||||
} from './listeners/receivedPageOfImages';
|
||||
import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved';
|
||||
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
|
||||
import { addImageCategoriesChangedListener } from './listeners/imageCategoriesChanged';
|
||||
|
||||
export const listenerMiddleware = createListenerMiddleware();
|
||||
|
||||
@ -166,6 +167,9 @@ addSessionCanceledPendingListener();
|
||||
addSessionCanceledFulfilledListener();
|
||||
addSessionCanceledRejectedListener();
|
||||
|
||||
// Images
|
||||
// Fetching images
|
||||
addReceivedPageOfImagesFulfilledListener();
|
||||
addReceivedPageOfImagesRejectedListener();
|
||||
|
||||
// Gallery
|
||||
addImageCategoriesChangedListener();
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import {
|
||||
imageCategoriesChanged,
|
||||
selectFilteredImagesAsArray,
|
||||
} from 'features/gallery/store/imagesSlice';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'gallery' });
|
||||
|
||||
export const addImageCategoriesChangedListener = () => {
|
||||
startAppListening({
|
||||
actionCreator: imageCategoriesChanged,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const filteredImagesCount = selectFilteredImagesAsArray(
|
||||
getState()
|
||||
).length;
|
||||
|
||||
if (!filteredImagesCount) {
|
||||
dispatch(receivedPageOfImages());
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
@ -11,7 +11,7 @@ export const addReceivedPageOfImagesFulfilledListener = () => {
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const page = action.payload;
|
||||
moduleLog.debug(
|
||||
{ data: { page } },
|
||||
{ data: { payload: action.payload } },
|
||||
`Received ${page.items.length} images`
|
||||
);
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
Box,
|
||||
ButtonGroup,
|
||||
Checkbox,
|
||||
CheckboxGroup,
|
||||
Flex,
|
||||
@ -36,7 +37,13 @@ import {
|
||||
} from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
|
||||
import { FaFilter, FaWrench } from 'react-icons/fa';
|
||||
import {
|
||||
FaFilter,
|
||||
FaImage,
|
||||
FaImages,
|
||||
FaServer,
|
||||
FaWrench,
|
||||
} from 'react-icons/fa';
|
||||
import { MdPhotoLibrary } from 'react-icons/md';
|
||||
import HoverableImage from './HoverableImage';
|
||||
|
||||
@ -47,18 +54,15 @@ import { Virtuoso, VirtuosoGrid } from 'react-virtuoso';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { ImageCategory } from 'services/api';
|
||||
import { imageCategoriesChanged, selectImagesAll } from '../store/imagesSlice';
|
||||
import {
|
||||
ASSETS_CATEGORIES,
|
||||
IMAGE_CATEGORIES,
|
||||
imageCategoriesChanged,
|
||||
selectImagesAll,
|
||||
} from '../store/imagesSlice';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import { capitalize } from 'lodash-es';
|
||||
|
||||
const IMAGE_CATEGORIES: ImageCategory[] = [
|
||||
'general',
|
||||
'control',
|
||||
'mask',
|
||||
'user',
|
||||
'other',
|
||||
];
|
||||
|
||||
const categorySelector = createSelector(
|
||||
[(state: RootState) => state],
|
||||
(state) => {
|
||||
@ -179,6 +183,14 @@ const ImageGalleryContent = () => {
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleClickImagesCategory = useCallback(() => {
|
||||
dispatch(imageCategoriesChanged(IMAGE_CATEGORIES));
|
||||
}, [dispatch]);
|
||||
|
||||
const handleClickAssetsCategory = useCallback(() => {
|
||||
dispatch(imageCategoriesChanged(ASSETS_CATEGORIES));
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
@ -194,35 +206,31 @@ const ImageGalleryContent = () => {
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<IAIPopover
|
||||
triggerComponent={
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
aria-label="Gallery Filter"
|
||||
tooltip={t('gallery.images')}
|
||||
aria-label={t('gallery.images')}
|
||||
onClick={handleClickImagesCategory}
|
||||
isChecked={categories === IMAGE_CATEGORIES}
|
||||
size="sm"
|
||||
icon={<FaFilter />}
|
||||
icon={<FaImage />}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Flex sx={{ flexDirection: 'column', gap: 2 }}>
|
||||
<CheckboxGroup
|
||||
value={categories}
|
||||
onChange={handleCategoriesChanged}
|
||||
>
|
||||
{IMAGE_CATEGORIES.map((c) => (
|
||||
<Checkbox key={c} value={c}>
|
||||
{capitalize(c)}
|
||||
</Checkbox>
|
||||
))}
|
||||
</CheckboxGroup>
|
||||
</Flex>
|
||||
</IAIPopover>
|
||||
|
||||
<IAIIconButton
|
||||
tooltip={t('gallery.assets')}
|
||||
aria-label={t('gallery.assets')}
|
||||
onClick={handleClickAssetsCategory}
|
||||
isChecked={categories === ASSETS_CATEGORIES}
|
||||
size="sm"
|
||||
icon={<FaServer />}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
<Flex gap={2}>
|
||||
<IAIPopover
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
size="sm"
|
||||
tooltip={t('gallery.gallerySettings')}
|
||||
aria-label={t('gallery.gallerySettings')}
|
||||
size="sm"
|
||||
icon={<FaWrench />}
|
||||
/>
|
||||
}
|
||||
|
@ -15,6 +15,14 @@ export const imagesAdapter = createEntityAdapter<ImageDTO>({
|
||||
sortComparer: (a, b) => dateComparator(b.created_at, a.created_at),
|
||||
});
|
||||
|
||||
export const IMAGE_CATEGORIES: ImageCategory[] = ['general'];
|
||||
export const ASSETS_CATEGORIES: ImageCategory[] = [
|
||||
'control',
|
||||
'mask',
|
||||
'user',
|
||||
'other',
|
||||
];
|
||||
|
||||
type AdditionaImagesState = {
|
||||
offset: number;
|
||||
limit: number;
|
||||
@ -29,7 +37,7 @@ export const initialImagesState =
|
||||
limit: 0,
|
||||
total: 0,
|
||||
isLoading: false,
|
||||
categories: ['general', 'control', 'mask', 'other', 'user'],
|
||||
categories: IMAGE_CATEGORIES,
|
||||
});
|
||||
|
||||
export type ImagesState = typeof initialImagesState;
|
||||
|
@ -91,6 +91,8 @@ export const receivedPageOfImages = createAppAsyncThunk(
|
||||
categories.includes(i.image_category)
|
||||
).length;
|
||||
|
||||
console.log(categories);
|
||||
|
||||
const response = await ImagesService.listImagesWithMetadata({
|
||||
categories,
|
||||
isIntermediate: false,
|
||||
|
Loading…
Reference in New Issue
Block a user