import { Box, Flex } from '@invoke-ai/ui-library'; import { createSelector } from '@reduxjs/toolkit'; import { skipToken } from '@reduxjs/toolkit/query'; import { useAppSelector } from 'app/store/storeHooks'; import IAIDndImage from 'common/components/IAIDndImage'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types'; import ProgressImage from 'features/gallery/components/CurrentImage/ProgressImage'; import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer'; import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons'; import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors'; import type { AnimationProps } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion'; import type { CSSProperties } from 'react'; import { memo, useCallback, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { PiImageBold } from 'react-icons/pi'; import { useGetImageDTOQuery } from 'services/api/endpoints/images'; const selectLastSelectedImageName = createSelector( selectLastSelectedImage, (lastSelectedImage) => lastSelectedImage?.image_name ); const CurrentImagePreview = () => { const shouldShowImageDetails = useAppSelector((s) => s.ui.shouldShowImageDetails); const imageName = useAppSelector(selectLastSelectedImageName); const hasDenoiseProgress = useAppSelector((s) => Boolean(s.system.denoiseProgress)); const shouldShowProgressInViewer = useAppSelector((s) => s.ui.shouldShowProgressInViewer); const { currentData: imageDTO } = useGetImageDTOQuery(imageName ?? skipToken); const draggableData = useMemo(() => { if (imageDTO) { return { id: 'current-image', payloadType: 'IMAGE_DTO', payload: { imageDTO }, }; } }, [imageDTO]); const droppableData = useMemo( () => ({ id: 'current-image', actionType: 'SET_CURRENT_IMAGE', }), [] ); // Show and hide the next/prev buttons on mouse move const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] = useState(false); const timeoutId = useRef(0); const { t } = useTranslation(); const handleMouseOver = useCallback(() => { setShouldShowNextPrevButtons(true); window.clearTimeout(timeoutId.current); }, []); const handleMouseOut = useCallback(() => { timeoutId.current = window.setTimeout(() => { setShouldShowNextPrevButtons(false); }, 500); }, []); return ( {hasDenoiseProgress && shouldShowProgressInViewer ? ( ) : ( } dataTestId="image-preview" /> )} {shouldShowImageDetails && imageDTO && ( )} {!shouldShowImageDetails && imageDTO && shouldShowNextPrevButtons && ( )} ); }; export default memo(CurrentImagePreview); const initial: AnimationProps['initial'] = { opacity: 0, }; const animate: AnimationProps['animate'] = { opacity: 1, transition: { duration: 0.1 }, }; const exit: AnimationProps['exit'] = { opacity: 0, transition: { duration: 0.1 }, }; const motionStyles: CSSProperties = { position: 'absolute', top: '0', width: '100%', height: '100%', pointerEvents: 'none', };