feat(ui): gallery filter dropdown -> Images/Assets toggle

This commit is contained in:
psychedelicious 2023-05-29 19:54:04 +10:00 committed by Kent Keirsey
parent 1ddc620192
commit 7004430380
7 changed files with 86 additions and 38 deletions

View File

@ -122,7 +122,9 @@
"noImagesInGallery": "No Images In Gallery", "noImagesInGallery": "No Images In Gallery",
"deleteImage": "Delete Image", "deleteImage": "Delete Image",
"deleteImageBin": "Deleted images will be sent to your operating system's Bin.", "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": { "hotkeys": {
"keyboardShortcuts": "Keyboard Shortcuts", "keyboardShortcuts": "Keyboard Shortcuts",

View File

@ -69,6 +69,7 @@ import {
} from './listeners/receivedPageOfImages'; } from './listeners/receivedPageOfImages';
import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved'; import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved';
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener'; import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
import { addImageCategoriesChangedListener } from './listeners/imageCategoriesChanged';
export const listenerMiddleware = createListenerMiddleware(); export const listenerMiddleware = createListenerMiddleware();
@ -166,6 +167,9 @@ addSessionCanceledPendingListener();
addSessionCanceledFulfilledListener(); addSessionCanceledFulfilledListener();
addSessionCanceledRejectedListener(); addSessionCanceledRejectedListener();
// Images // Fetching images
addReceivedPageOfImagesFulfilledListener(); addReceivedPageOfImagesFulfilledListener();
addReceivedPageOfImagesRejectedListener(); addReceivedPageOfImagesRejectedListener();
// Gallery
addImageCategoriesChangedListener();

View File

@ -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());
}
},
});
};

View File

@ -11,7 +11,7 @@ export const addReceivedPageOfImagesFulfilledListener = () => {
effect: (action, { getState, dispatch }) => { effect: (action, { getState, dispatch }) => {
const page = action.payload; const page = action.payload;
moduleLog.debug( moduleLog.debug(
{ data: { page } }, { data: { payload: action.payload } },
`Received ${page.items.length} images` `Received ${page.items.length} images`
); );
}, },

View File

@ -1,5 +1,6 @@
import { import {
Box, Box,
ButtonGroup,
Checkbox, Checkbox,
CheckboxGroup, CheckboxGroup,
Flex, Flex,
@ -36,7 +37,13 @@ import {
} from 'react'; } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; 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 { MdPhotoLibrary } from 'react-icons/md';
import HoverableImage from './HoverableImage'; import HoverableImage from './HoverableImage';
@ -47,18 +54,15 @@ import { Virtuoso, VirtuosoGrid } from 'react-virtuoso';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import { ImageCategory } from 'services/api'; 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 { receivedPageOfImages } from 'services/thunks/image';
import { capitalize } from 'lodash-es'; import { capitalize } from 'lodash-es';
const IMAGE_CATEGORIES: ImageCategory[] = [
'general',
'control',
'mask',
'user',
'other',
];
const categorySelector = createSelector( const categorySelector = createSelector(
[(state: RootState) => state], [(state: RootState) => state],
(state) => { (state) => {
@ -179,6 +183,14 @@ const ImageGalleryContent = () => {
[dispatch] [dispatch]
); );
const handleClickImagesCategory = useCallback(() => {
dispatch(imageCategoriesChanged(IMAGE_CATEGORIES));
}, [dispatch]);
const handleClickAssetsCategory = useCallback(() => {
dispatch(imageCategoriesChanged(ASSETS_CATEGORIES));
}, [dispatch]);
return ( return (
<Flex <Flex
sx={{ sx={{
@ -194,35 +206,31 @@ const ImageGalleryContent = () => {
alignItems="center" alignItems="center"
justifyContent="space-between" justifyContent="space-between"
> >
<IAIPopover <ButtonGroup isAttached>
triggerComponent={ <IAIIconButton
<IAIIconButton tooltip={t('gallery.images')}
aria-label="Gallery Filter" aria-label={t('gallery.images')}
size="sm" onClick={handleClickImagesCategory}
icon={<FaFilter />} isChecked={categories === IMAGE_CATEGORIES}
/> size="sm"
} icon={<FaImage />}
> />
<Flex sx={{ flexDirection: 'column', gap: 2 }}> <IAIIconButton
<CheckboxGroup tooltip={t('gallery.assets')}
value={categories} aria-label={t('gallery.assets')}
onChange={handleCategoriesChanged} onClick={handleClickAssetsCategory}
> isChecked={categories === ASSETS_CATEGORIES}
{IMAGE_CATEGORIES.map((c) => ( size="sm"
<Checkbox key={c} value={c}> icon={<FaServer />}
{capitalize(c)} />
</Checkbox> </ButtonGroup>
))}
</CheckboxGroup>
</Flex>
</IAIPopover>
<Flex gap={2}> <Flex gap={2}>
<IAIPopover <IAIPopover
triggerComponent={ triggerComponent={
<IAIIconButton <IAIIconButton
size="sm" tooltip={t('gallery.gallerySettings')}
aria-label={t('gallery.gallerySettings')} aria-label={t('gallery.gallerySettings')}
size="sm"
icon={<FaWrench />} icon={<FaWrench />}
/> />
} }

View File

@ -15,6 +15,14 @@ export const imagesAdapter = createEntityAdapter<ImageDTO>({
sortComparer: (a, b) => dateComparator(b.created_at, a.created_at), 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 = { type AdditionaImagesState = {
offset: number; offset: number;
limit: number; limit: number;
@ -29,7 +37,7 @@ export const initialImagesState =
limit: 0, limit: 0,
total: 0, total: 0,
isLoading: false, isLoading: false,
categories: ['general', 'control', 'mask', 'other', 'user'], categories: IMAGE_CATEGORIES,
}); });
export type ImagesState = typeof initialImagesState; export type ImagesState = typeof initialImagesState;

View File

@ -91,6 +91,8 @@ export const receivedPageOfImages = createAppAsyncThunk(
categories.includes(i.image_category) categories.includes(i.image_category)
).length; ).length;
console.log(categories);
const response = await ImagesService.listImagesWithMetadata({ const response = await ImagesService.listImagesWithMetadata({
categories, categories,
isIntermediate: false, isIntermediate: false,