refactor(ui): canvas flow (wip)

This commit is contained in:
psychedelicious
2025-05-22 17:41:19 +10:00
parent c4d1e78f59
commit cf2d67ef3d
14 changed files with 315 additions and 192 deletions

View File

@@ -1,13 +1,6 @@
import {
ContextMenu,
Flex,
IconButton,
Menu,
MenuButton,
MenuList,
type SystemStyleObject,
} from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Button, ContextMenu, Flex, IconButton, Image, Menu, MenuButton, MenuList, Text } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
import { CanvasAlertsPreserveMask } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsPreserveMask';
import { CanvasAlertsSelectedEntityStatus } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSelectedEntityStatus';
@@ -25,7 +18,13 @@ import { StagingAreaToolbar } from 'features/controlLayers/components/StagingAre
import { CanvasToolbar } from 'features/controlLayers/components/Toolbar/CanvasToolbar';
import { Transform } from 'features/controlLayers/components/Transform/Transform';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { newCanvasSessionRequested } from 'features/controlLayers/store/actions';
import { selectDynamicGrid, selectShowHUD } from 'features/controlLayers/store/canvasSettingsSlice';
import {
selectIsStaging,
selectSelectedImage,
selectStagedImages,
} from 'features/controlLayers/store/canvasStagingAreaSlice';
import { selectIsCanvasEmpty, selectIsSessionStarted } from 'features/controlLayers/store/selectors';
import { memo, useCallback } from 'react';
import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi';
@@ -54,7 +53,11 @@ export const CanvasMainPanelContent = memo(() => {
const isCanvasEmpty = useAppSelector(selectIsCanvasEmpty);
if (!isSessionStarted && isCanvasEmpty) {
return <CanvasNoSession />;
return <NoActiveSession />;
}
if (isSessionStarted && isCanvasEmpty) {
return <SimpleActiveSession />;
}
return <CanvasActiveSession />;
@@ -62,14 +65,64 @@ export const CanvasMainPanelContent = memo(() => {
CanvasMainPanelContent.displayName = 'CanvasMainPanelContent';
const CanvasNoSession = memo(() => {
const NoActiveSession = memo(() => {
const dispatch = useAppDispatch();
const newSesh = useCallback(() => {
dispatch(newCanvasSessionRequested());
}, [dispatch]);
return (
<Flex w="full" h="full" alignItems="center" justifyContent="center">
FRESH CANVAS is fresh when: - No control layers - No inpaint masks - No regions - No Raster Layers
<Flex flexDir="column" w="full" h="full" alignItems="center" justifyContent="center">
<Text fontSize="lg" fontWeight="bold">
No Active Session
</Text>
<Button display="flex" flexDir="column" gap={2} p={8} minH={0} minW={0} onClick={newSesh}>
<Text>New Canvas Session</Text>
<Text>- New Canvas Session</Text>
<Text>- 1 Inpaint mask layer added</Text>
</Button>
<Flex flexDir="column" gap={2} p={8} border="dashed yellow 2px">
<Text>Generate with Starting Image</Text>
<Text>- New Canvas Session</Text>
<Text>- Dropped image as raster layer</Text>
<Text>- Bbox resized</Text>
</Flex>
<Flex flexDir="column" gap={2} p={8} border="dashed yellow 2px">
<Text>Generate with Control Image</Text>
<Text>- New Canvas Session</Text>
<Text>- Dropped image as control layer</Text>
<Text>- Bbox resized</Text>
</Flex>
<Flex flexDir="column" gap={2} p={8} border="dashed yellow 2px">
<Text>Edit Image</Text>
<Text>- New Canvas Session</Text>
<Text>- Dropped image as raster layer</Text>
<Text>- Bbox resized</Text>
<Text>- 1 Inpaint mask layer added</Text>
</Flex>
</Flex>
);
});
CanvasNoSession.displayName = 'CanvasNoSession';
NoActiveSession.displayName = 'NoActiveSession';
const SimpleActiveSession = memo(() => {
const isStaging = useAppSelector(selectIsStaging);
const selectedImage = useAppSelector(selectSelectedImage);
const stagedImages = useAppSelector(selectStagedImages);
return (
<Flex flexDir="column" w="full" h="full" alignItems="center" justifyContent="center">
<Text fontSize="lg" fontWeight="bold">
Simple Session (staging view) {isStaging && 'STAGING'}
</Text>
{selectedImage && <Image src={selectedImage.imageDTO.image_url} />}
<Flex gap={2} maxW="full" overflow='scroll'>
{stagedImages.map(({ imageDTO }) => (
<Image key={imageDTO.image_name} maxW={108} src={imageDTO.thumbnail_url} />
))}
</Flex>
</Flex>
);
});
SimpleActiveSession.displayName = 'SimpleActiveSession';
const CanvasActiveSession = memo(() => {
const dynamicGrid = useAppSelector(selectDynamicGrid);

View File

@@ -5,7 +5,11 @@ import { moveOneToEnd, moveOneToStart, moveToEnd, moveToStart } from 'common/uti
import { deepClone } from 'common/util/deepClone';
import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { canvasReset, newSessionRequested } from 'features/controlLayers/store/actions';
import {
canvasReset,
newCanvasSessionRequested,
newGallerySessionRequested,
} from 'features/controlLayers/store/actions';
import { modelChanged } from 'features/controlLayers/store/paramsSlice';
import {
selectAllEntities,
@@ -1802,9 +1806,14 @@ export const canvasSlice = createSlice({
syncScaledSize(state);
}
});
builder.addMatcher(newSessionRequested, (state) => {
builder.addCase(newGallerySessionRequested, (state) => {
return resetState(state);
});
builder.addCase(newCanvasSessionRequested, (state) => {
const newState = resetState(state);
newState.isSessionStarted = true;
return newState;
});
},
});

View File

@@ -97,6 +97,10 @@ export const selectSelectedImage = createSelector(
[selectCanvasStagingAreaSlice, selectStagedImageIndex],
(stagingArea, index) => stagingArea.stagedImages[index] ?? null
);
export const selectStagedImages = createSelector(
selectCanvasStagingAreaSlice,
(stagingArea) => stagingArea.stagedImages
);
export const selectImageCount = createSelector(
selectCanvasStagingAreaSlice,
(stagingArea) => stagingArea.stagedImages.length