mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): "stagingArea" -> "session"
This commit is contained in:
parent
0c539ff00b
commit
d4da00e607
@ -4,8 +4,8 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
||||
import {
|
||||
layerAdded,
|
||||
layerImageAdded,
|
||||
stagingAreaCanceledStaging,
|
||||
stagingAreaImageAccepted,
|
||||
sessionStagingCanceled,
|
||||
sessionStagedImageAccepted,
|
||||
} from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { t } from 'i18next';
|
||||
@ -14,7 +14,7 @@ import { assert } from 'tsafe';
|
||||
|
||||
export const addStagingListeners = (startAppListening: AppStartListening) => {
|
||||
startAppListening({
|
||||
matcher: isAnyOf(stagingAreaCanceledStaging, stagingAreaImageAccepted),
|
||||
matcher: isAnyOf(sessionStagingCanceled, sessionStagedImageAccepted),
|
||||
effect: async (_, { dispatch }) => {
|
||||
const log = logger('canvas');
|
||||
|
||||
@ -47,7 +47,7 @@ export const addStagingListeners = (startAppListening: AppStartListening) => {
|
||||
});
|
||||
|
||||
startAppListening({
|
||||
actionCreator: stagingAreaImageAccepted,
|
||||
actionCreator: sessionStagedImageAccepted,
|
||||
effect: async (action, api) => {
|
||||
const { imageDTO } = action.payload;
|
||||
const { layers, selectedEntityIdentifier, bbox } = api.getState().canvasV2;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { enqueueRequested } from 'app/store/actions';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { getCanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||
import { stagingAreaCanceledStaging, stagingAreaStartedStaging } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { sessionStagingCanceled, sessionStartedStaging } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
|
||||
import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph';
|
||||
import { buildSDXLGraph } from 'features/nodes/util/graph/generation/buildSDXLGraph';
|
||||
@ -18,8 +18,8 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
|
||||
const { prepend } = action.payload;
|
||||
|
||||
let didStartStaging = false;
|
||||
if (!state.canvasV2.stagingArea.isStaging) {
|
||||
dispatch(stagingAreaStartedStaging());
|
||||
if (!state.canvasV2.session.isStaging) {
|
||||
dispatch(sessionStartedStaging());
|
||||
didStartStaging = true;
|
||||
}
|
||||
|
||||
@ -48,8 +48,8 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
|
||||
req.reset();
|
||||
await req.unwrap();
|
||||
} catch {
|
||||
if (didStartStaging && getState().canvasV2.stagingArea.isStaging) {
|
||||
dispatch(stagingAreaCanceledStaging());
|
||||
if (didStartStaging && getState().canvasV2.session.isStaging) {
|
||||
dispatch(sessionStagingCanceled());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import { logger } from 'app/logging/logger';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { parseify } from 'common/util/serialize';
|
||||
import { stagingAreaImageAdded } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { sessionImageStaged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { boardIdSelected, galleryViewChanged, imageSelected, offsetChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState';
|
||||
import { zNodeStatus } from 'features/nodes/types/invocation';
|
||||
@ -42,8 +42,8 @@ export const addInvocationCompleteEventListener = (startAppListening: AppStartLi
|
||||
|
||||
// handle tab-specific logic
|
||||
if (data.origin === 'canvas') {
|
||||
if (data.invocation_source_id === CANVAS_OUTPUT && canvasV2.stagingArea.isStaging) {
|
||||
dispatch(stagingAreaImageAdded({ imageDTO }));
|
||||
if (data.invocation_source_id === CANVAS_OUTPUT && canvasV2.session.isStaging) {
|
||||
dispatch(sessionImageStaged({ imageDTO }));
|
||||
}
|
||||
} else if (data.origin === 'workflows') {
|
||||
const nes = deepClone($nodeExecutionStates.get()[invocation_source_id]);
|
||||
|
@ -3,11 +3,11 @@ import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
$shouldShowStagedImage,
|
||||
stagingAreaCanceledStaging,
|
||||
stagingAreaImageAccepted,
|
||||
stagingAreaImageDiscarded,
|
||||
stagingAreaNextImageSelected,
|
||||
stagingAreaPreviousImageSelected,
|
||||
sessionStagingCanceled,
|
||||
sessionStagedImageAccepted,
|
||||
sessionStagedImageDiscarded,
|
||||
sessionNextStagedImageSelected,
|
||||
sessionPrevStagedImageSelected,
|
||||
} from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
@ -24,7 +24,7 @@ import {
|
||||
} from 'react-icons/pi';
|
||||
|
||||
export const StagingAreaToolbar = memo(() => {
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging);
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
|
||||
if (!isStaging) {
|
||||
return null;
|
||||
@ -37,30 +37,30 @@ StagingAreaToolbar.displayName = 'StagingAreaToolbar';
|
||||
|
||||
export const StagingAreaToolbarContent = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const stagingArea = useAppSelector((s) => s.canvasV2.stagingArea);
|
||||
const stagingArea = useAppSelector((s) => s.canvasV2.session);
|
||||
const shouldShowStagedImage = useStore($shouldShowStagedImage);
|
||||
const images = useMemo(() => stagingArea.images, [stagingArea]);
|
||||
const images = useMemo(() => stagingArea.stagedImages, [stagingArea]);
|
||||
const selectedImageDTO = useMemo(() => {
|
||||
return images[stagingArea.selectedImageIndex] ?? null;
|
||||
}, [images, stagingArea.selectedImageIndex]);
|
||||
return images[stagingArea.selectedStagedImageIndex] ?? null;
|
||||
}, [images, stagingArea.selectedStagedImageIndex]);
|
||||
|
||||
// const [changeIsImageIntermediate] = useChangeImageIsIntermediateMutation();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onPrev = useCallback(() => {
|
||||
dispatch(stagingAreaPreviousImageSelected());
|
||||
dispatch(sessionPrevStagedImageSelected());
|
||||
}, [dispatch]);
|
||||
|
||||
const onNext = useCallback(() => {
|
||||
dispatch(stagingAreaNextImageSelected());
|
||||
dispatch(sessionNextStagedImageSelected());
|
||||
}, [dispatch]);
|
||||
|
||||
const onAccept = useCallback(() => {
|
||||
if (!selectedImageDTO) {
|
||||
return;
|
||||
}
|
||||
dispatch(stagingAreaImageAccepted({ imageDTO: selectedImageDTO }));
|
||||
dispatch(sessionStagedImageAccepted({ imageDTO: selectedImageDTO }));
|
||||
}, [dispatch, selectedImageDTO]);
|
||||
|
||||
const onDiscardOne = useCallback(() => {
|
||||
@ -68,14 +68,14 @@ export const StagingAreaToolbarContent = memo(() => {
|
||||
return;
|
||||
}
|
||||
if (images.length === 1) {
|
||||
dispatch(stagingAreaCanceledStaging());
|
||||
dispatch(sessionStagingCanceled());
|
||||
} else {
|
||||
dispatch(stagingAreaImageDiscarded({ imageDTO: selectedImageDTO }));
|
||||
dispatch(sessionStagedImageDiscarded({ imageDTO: selectedImageDTO }));
|
||||
}
|
||||
}, [dispatch, selectedImageDTO, images.length]);
|
||||
|
||||
const onDiscardAll = useCallback(() => {
|
||||
dispatch(stagingAreaCanceledStaging());
|
||||
dispatch(sessionStagingCanceled());
|
||||
}, [dispatch]);
|
||||
|
||||
const onToggleShouldShowStagedImage = useCallback(() => {
|
||||
@ -109,11 +109,11 @@ export const StagingAreaToolbarContent = memo(() => {
|
||||
|
||||
const counterText = useMemo(() => {
|
||||
if (images.length > 0) {
|
||||
return `${(stagingArea.selectedImageIndex ?? 0) + 1} of ${images.length}`;
|
||||
return `${(stagingArea.selectedStagedImageIndex ?? 0) + 1} of ${images.length}`;
|
||||
} else {
|
||||
return `0 of 0`;
|
||||
}
|
||||
}, [images.length, stagingArea.selectedImageIndex]);
|
||||
}, [images.length, stagingArea.selectedStagedImageIndex]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -43,7 +43,7 @@ export const ToolChooser: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier);
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging);
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isDrawingToolDisabled = useMemo(
|
||||
() => !getIsDrawingToolEnabled(selectedEntityIdentifier),
|
||||
[selectedEntityIdentifier]
|
||||
|
@ -281,7 +281,7 @@ export class CanvasManager {
|
||||
// debouncedUpdateBboxes(stage, canvasV2.layers, canvasV2.controlAdapters, canvasV2.regions, onBboxChanged);
|
||||
}
|
||||
|
||||
if (this.isFirstRender || state.stagingArea !== this.prevState.stagingArea) {
|
||||
if (this.isFirstRender || state.session !== this.prevState.session) {
|
||||
log.debug('Rendering staging area');
|
||||
this.preview.stagingArea.render();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export class CanvasStagingArea {
|
||||
const shouldShowStagedImage = this.manager.stateApi.getShouldShowStagedImage();
|
||||
const lastProgressEvent = this.manager.stateApi.getLastProgressEvent();
|
||||
|
||||
this.imageDTO = stagingArea.images[stagingArea.selectedImageIndex] ?? null;
|
||||
this.imageDTO = stagingArea.stagedImages[stagingArea.selectedStagedImageIndex] ?? null;
|
||||
|
||||
if (this.imageDTO) {
|
||||
if (this.image) {
|
||||
|
@ -232,7 +232,7 @@ export class CanvasStateApi {
|
||||
return this.getState().settings.maskOpacity;
|
||||
};
|
||||
getStagingAreaState = () => {
|
||||
return this.getState().stagingArea;
|
||||
return this.getState().session;
|
||||
};
|
||||
getIsSelected = (id: string) => {
|
||||
return this.getSelectedEntity()?.id === id;
|
||||
|
@ -13,8 +13,8 @@ import { layersReducers } from 'features/controlLayers/store/layersReducers';
|
||||
import { lorasReducers } from 'features/controlLayers/store/lorasReducers';
|
||||
import { paramsReducers } from 'features/controlLayers/store/paramsReducers';
|
||||
import { regionsReducers } from 'features/controlLayers/store/regionsReducers';
|
||||
import { sessionReducers } from 'features/controlLayers/store/sessionReducers';
|
||||
import { settingsReducers } from 'features/controlLayers/store/settingsReducers';
|
||||
import { stagingAreaReducers } from 'features/controlLayers/store/stagingAreaReducers';
|
||||
import { toolReducers } from 'features/controlLayers/store/toolReducers';
|
||||
import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
|
||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
@ -122,10 +122,11 @@ const initialState: CanvasV2State = {
|
||||
refinerNegativeAestheticScore: 2.5,
|
||||
refinerStart: 0.8,
|
||||
},
|
||||
stagingArea: {
|
||||
session: {
|
||||
isActive: false,
|
||||
isStaging: false,
|
||||
images: [],
|
||||
selectedImageIndex: 0,
|
||||
stagedImages: [],
|
||||
selectedStagedImageIndex: 0,
|
||||
},
|
||||
};
|
||||
|
||||
@ -144,7 +145,7 @@ export const canvasV2Slice = createSlice({
|
||||
...toolReducers,
|
||||
...bboxReducers,
|
||||
...inpaintMaskReducers,
|
||||
...stagingAreaReducers,
|
||||
...sessionReducers,
|
||||
widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => {
|
||||
const { width, updateAspectRatio, clamp } = action.payload;
|
||||
state.document.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width;
|
||||
@ -184,7 +185,7 @@ export const canvasV2Slice = createSlice({
|
||||
state.layers = deepClone(initialState.layers);
|
||||
state.regions = deepClone(initialState.regions);
|
||||
state.selectedEntityIdentifier = deepClone(initialState.selectedEntityIdentifier);
|
||||
state.stagingArea = deepClone(initialState.stagingArea);
|
||||
state.session = deepClone(initialState.session);
|
||||
state.tool = deepClone(initialState.tool);
|
||||
},
|
||||
},
|
||||
@ -350,13 +351,14 @@ export const {
|
||||
imEraserLineAdded,
|
||||
imRectShapeAdded,
|
||||
// Staging
|
||||
stagingAreaStartedStaging,
|
||||
stagingAreaImageAdded,
|
||||
stagingAreaImageDiscarded,
|
||||
stagingAreaImageAccepted,
|
||||
stagingAreaCanceledStaging,
|
||||
stagingAreaNextImageSelected,
|
||||
stagingAreaPreviousImageSelected,
|
||||
sessionStarted,
|
||||
sessionStartedStaging,
|
||||
sessionImageStaged,
|
||||
sessionStagedImageDiscarded,
|
||||
sessionStagedImageAccepted,
|
||||
sessionStagingCanceled,
|
||||
sessionNextStagedImageSelected,
|
||||
sessionPrevStagedImageSelected,
|
||||
} = canvasV2Slice.actions;
|
||||
|
||||
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
|
||||
|
@ -0,0 +1,62 @@
|
||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||
import type { CanvasV2State } from 'features/controlLayers/store/types';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
export const sessionReducers = {
|
||||
sessionStarted: (state) => {
|
||||
state.session.isActive = true;
|
||||
},
|
||||
sessionStartedStaging: (state) => {
|
||||
state.session.isStaging = true;
|
||||
state.session.selectedStagedImageIndex = 0;
|
||||
// When we start staging, the user should not be interacting with the stage except to move it around. Set the tool
|
||||
// to view.
|
||||
state.tool.selectedBuffer = state.tool.selected;
|
||||
state.tool.selected = 'view';
|
||||
},
|
||||
sessionImageStaged: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
const { imageDTO } = action.payload;
|
||||
state.session.stagedImages.push(imageDTO);
|
||||
state.session.selectedStagedImageIndex = state.session.stagedImages.length - 1;
|
||||
},
|
||||
sessionNextStagedImageSelected: (state) => {
|
||||
state.session.selectedStagedImageIndex =
|
||||
(state.session.selectedStagedImageIndex + 1) % state.session.stagedImages.length;
|
||||
},
|
||||
sessionPrevStagedImageSelected: (state) => {
|
||||
state.session.selectedStagedImageIndex =
|
||||
(state.session.selectedStagedImageIndex - 1 + state.session.stagedImages.length) %
|
||||
state.session.stagedImages.length;
|
||||
},
|
||||
sessionStagedImageDiscarded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
const { imageDTO } = action.payload;
|
||||
state.session.stagedImages = state.session.stagedImages.filter((image) => image.image_name !== imageDTO.image_name);
|
||||
state.session.selectedStagedImageIndex = Math.min(
|
||||
state.session.selectedStagedImageIndex,
|
||||
state.session.stagedImages.length - 1
|
||||
);
|
||||
if (state.session.stagedImages.length === 0) {
|
||||
state.session.isStaging = false;
|
||||
}
|
||||
},
|
||||
sessionStagedImageAccepted: (state, _: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
// When we finish staging, reset the tool back to the previous selection.
|
||||
state.session.isStaging = false;
|
||||
state.session.stagedImages = [];
|
||||
state.session.selectedStagedImageIndex = 0;
|
||||
if (state.tool.selectedBuffer) {
|
||||
state.tool.selected = state.tool.selectedBuffer;
|
||||
state.tool.selectedBuffer = null;
|
||||
}
|
||||
},
|
||||
sessionStagingCanceled: (state) => {
|
||||
state.session.isStaging = false;
|
||||
state.session.stagedImages = [];
|
||||
state.session.selectedStagedImageIndex = 0;
|
||||
// When we finish staging, reset the tool back to the previous selection.
|
||||
if (state.tool.selectedBuffer) {
|
||||
state.tool.selected = state.tool.selectedBuffer;
|
||||
state.tool.selectedBuffer = null;
|
||||
}
|
||||
},
|
||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
@ -1,57 +0,0 @@
|
||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||
import type { CanvasV2State } from 'features/controlLayers/store/types';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
export const stagingAreaReducers = {
|
||||
stagingAreaStartedStaging: (state) => {
|
||||
state.stagingArea.isStaging = true;
|
||||
state.stagingArea.selectedImageIndex = 0;
|
||||
// When we start staging, the user should not be interacting with the stage except to move it around. Set the tool
|
||||
// to view.
|
||||
state.tool.selectedBuffer = state.tool.selected;
|
||||
state.tool.selected = 'view';
|
||||
},
|
||||
stagingAreaImageAdded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
const { imageDTO } = action.payload;
|
||||
state.stagingArea.images.push(imageDTO);
|
||||
state.stagingArea.selectedImageIndex = state.stagingArea.images.length - 1;
|
||||
},
|
||||
stagingAreaNextImageSelected: (state) => {
|
||||
state.stagingArea.selectedImageIndex = (state.stagingArea.selectedImageIndex + 1) % state.stagingArea.images.length;
|
||||
},
|
||||
stagingAreaPreviousImageSelected: (state) => {
|
||||
state.stagingArea.selectedImageIndex =
|
||||
(state.stagingArea.selectedImageIndex - 1 + state.stagingArea.images.length) % state.stagingArea.images.length;
|
||||
},
|
||||
stagingAreaImageDiscarded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
const { imageDTO } = action.payload;
|
||||
state.stagingArea.images = state.stagingArea.images.filter((image) => image.image_name !== imageDTO.image_name);
|
||||
state.stagingArea.selectedImageIndex = Math.min(
|
||||
state.stagingArea.selectedImageIndex,
|
||||
state.stagingArea.images.length - 1
|
||||
);
|
||||
if (state.stagingArea.images.length === 0) {
|
||||
state.stagingArea.isStaging = false;
|
||||
}
|
||||
},
|
||||
stagingAreaImageAccepted: (state, _: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||
// When we finish staging, reset the tool back to the previous selection.
|
||||
state.stagingArea.isStaging = false;
|
||||
state.stagingArea.images = [];
|
||||
state.stagingArea.selectedImageIndex = 0;
|
||||
if (state.tool.selectedBuffer) {
|
||||
state.tool.selected = state.tool.selectedBuffer;
|
||||
state.tool.selectedBuffer = null;
|
||||
}
|
||||
},
|
||||
stagingAreaCanceledStaging: (state) => {
|
||||
state.stagingArea.isStaging = false;
|
||||
state.stagingArea.images = [];
|
||||
state.stagingArea.selectedImageIndex = 0;
|
||||
// When we finish staging, reset the tool back to the previous selection.
|
||||
if (state.tool.selectedBuffer) {
|
||||
state.tool.selected = state.tool.selectedBuffer;
|
||||
state.tool.selectedBuffer = null;
|
||||
}
|
||||
},
|
||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
@ -895,10 +895,11 @@ export type CanvasV2State = {
|
||||
refinerNegativeAestheticScore: number;
|
||||
refinerStart: number;
|
||||
};
|
||||
stagingArea: {
|
||||
session: {
|
||||
isActive: boolean;
|
||||
isStaging: boolean;
|
||||
images: ImageDTO[];
|
||||
selectedImageIndex: number;
|
||||
stagedImages: ImageDTO[];
|
||||
selectedStagedImageIndex: number;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,7 @@ import { useListImagesQuery } from 'services/api/endpoints/images';
|
||||
* Registers gallery hotkeys. This hook is a singleton.
|
||||
*/
|
||||
export const useGalleryHotkeys = () => {
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging);
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
|
||||
const { goNext, goPrev, isNextEnabled, isPrevEnabled } = useGalleryPagination();
|
||||
const queryArgs = useAppSelector(selectListImagesQueryArgs);
|
||||
|
Loading…
Reference in New Issue
Block a user