feat: Handle IP Adapter Image being reset on being deleted.

This commit is contained in:
blessedcoolant 2023-09-16 12:50:30 +12:00 committed by Kent Keirsey
parent b60b1e359e
commit 4dd289b337
10 changed files with 52 additions and 5 deletions

View File

@ -49,6 +49,7 @@
"close": "Close", "close": "Close",
"communityLabel": "Community", "communityLabel": "Community",
"controlNet": "Controlnet", "controlNet": "Controlnet",
"ipAdapter": "IP Adapter",
"darkMode": "Dark Mode", "darkMode": "Dark Mode",
"discordLabel": "Discord", "discordLabel": "Discord",
"dontAskMeAgain": "Don't ask me again", "dontAskMeAgain": "Don't ask me again",

View File

@ -1,5 +1,8 @@
import { resetCanvas } from 'features/canvas/store/canvasSlice'; import { resetCanvas } from 'features/canvas/store/canvasSlice';
import { controlNetReset } from 'features/controlNet/store/controlNetSlice'; import {
controlNetReset,
ipAdapterStateReset,
} from 'features/controlNet/store/controlNetSlice';
import { getImageUsage } from 'features/deleteImageModal/store/selectors'; import { getImageUsage } from 'features/deleteImageModal/store/selectors';
import { nodeEditorReset } from 'features/nodes/store/nodesSlice'; import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
import { clearInitialImage } from 'features/parameters/store/generationSlice'; import { clearInitialImage } from 'features/parameters/store/generationSlice';
@ -18,6 +21,7 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
let wasCanvasReset = false; let wasCanvasReset = false;
let wasNodeEditorReset = false; let wasNodeEditorReset = false;
let wasControlNetReset = false; let wasControlNetReset = false;
let wasIPAdapterReset = false;
const state = getState(); const state = getState();
deleted_images.forEach((image_name) => { deleted_images.forEach((image_name) => {
@ -42,6 +46,11 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
dispatch(controlNetReset()); dispatch(controlNetReset());
wasControlNetReset = true; wasControlNetReset = true;
} }
if (imageUsage.isIPAdapterImage && !wasIPAdapterReset) {
dispatch(ipAdapterStateReset());
wasIPAdapterReset = true;
}
}); });
}, },
}); });

View File

@ -3,6 +3,7 @@ import { resetCanvas } from 'features/canvas/store/canvasSlice';
import { import {
controlNetImageChanged, controlNetImageChanged,
controlNetProcessedImageChanged, controlNetProcessedImageChanged,
ipAdapterImageChanged,
} from 'features/controlNet/store/controlNetSlice'; } from 'features/controlNet/store/controlNetSlice';
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions'; import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice'; import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
@ -110,6 +111,14 @@ export const addRequestedSingleImageDeletionListener = () => {
} }
}); });
// Remove IP Adapter Set Image if image is deleted.
if (
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
imageDTO.image_name
) {
dispatch(ipAdapterImageChanged(null));
}
// reset nodes that use the deleted images // reset nodes that use the deleted images
getState().nodes.nodes.forEach((node) => { getState().nodes.nodes.forEach((node) => {
if (!isInvocationNode(node)) { if (!isInvocationNode(node)) {
@ -227,6 +236,14 @@ export const addRequestedMultipleImageDeletionListener = () => {
} }
}); });
// Remove IP Adapter Set Image if image is deleted.
if (
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
imageDTO.image_name
) {
dispatch(ipAdapterImageChanged(null));
}
// reset nodes that use the deleted images // reset nodes that use the deleted images
getState().nodes.nodes.forEach((node) => { getState().nodes.nodes.forEach((node) => {
if (!isInvocationNode(node)) { if (!isInvocationNode(node)) {

View File

@ -19,6 +19,7 @@ export const addImageToDeleteSelectedListener = () => {
imagesUsage.some((i) => i.isCanvasImage) || imagesUsage.some((i) => i.isCanvasImage) ||
imagesUsage.some((i) => i.isInitialImage) || imagesUsage.some((i) => i.isInitialImage) ||
imagesUsage.some((i) => i.isControlNetImage) || imagesUsage.some((i) => i.isControlNetImage) ||
imagesUsage.some((i) => i.isIPAdapterImage) ||
imagesUsage.some((i) => i.isNodesImage); imagesUsage.some((i) => i.isNodesImage);
if (shouldConfirmOnDelete || isImageInUse) { if (shouldConfirmOnDelete || isImageInUse) {

View File

@ -386,6 +386,14 @@ export const controlNetSlice = createSlice({
) => { ) => {
state.ipAdapterInfo.model = action.payload; state.ipAdapterInfo.model = action.payload;
}, },
ipAdapterStateReset: (state) => {
state.isIPAdapterEnabled = false;
state.ipAdapterInfo = {
adapterImage: null,
model: null,
weight: 1,
};
},
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder.addCase(controlNetImageProcessed, (state, action) => { builder.addCase(controlNetImageProcessed, (state, action) => {
@ -449,6 +457,7 @@ export const {
ipAdapterImageChanged, ipAdapterImageChanged,
ipAdapterWeightChanged, ipAdapterWeightChanged,
ipAdapterModelChanged, ipAdapterModelChanged,
ipAdapterStateReset,
} = controlNetSlice.actions; } = controlNetSlice.actions;
export default controlNetSlice.reducer; export default controlNetSlice.reducer;

View File

@ -10,20 +10,20 @@ import {
Text, Text,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIButton from 'common/components/IAIButton'; import IAIButton from 'common/components/IAIButton';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice'; import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
import { stateSelector } from 'app/store/store';
import { some } from 'lodash-es'; import { some } from 'lodash-es';
import { ChangeEvent, memo, useCallback, useRef } from 'react'; import { ChangeEvent, memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { imageDeletionConfirmed } from '../store/actions'; import { imageDeletionConfirmed } from '../store/actions';
import { getImageUsage, selectImageUsage } from '../store/selectors'; import { getImageUsage, selectImageUsage } from '../store/selectors';
import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice'; import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice';
import ImageUsageMessage from './ImageUsageMessage';
import { ImageUsage } from '../store/types'; import { ImageUsage } from '../store/types';
import ImageUsageMessage from './ImageUsageMessage';
const selector = createSelector( const selector = createSelector(
[stateSelector, selectImageUsage], [stateSelector, selectImageUsage],
@ -42,6 +42,7 @@ const selector = createSelector(
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage), isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
isNodesImage: some(allImageUsage, (i) => i.isNodesImage), isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage), isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
}; };
return { return {

View File

@ -1,8 +1,8 @@
import { ListItem, Text, UnorderedList } from '@chakra-ui/react'; import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
import { some } from 'lodash-es'; import { some } from 'lodash-es';
import { memo } from 'react'; import { memo } from 'react';
import { ImageUsage } from '../store/types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ImageUsage } from '../store/types';
type Props = { type Props = {
imageUsage?: ImageUsage; imageUsage?: ImageUsage;
@ -38,6 +38,9 @@ const ImageUsageMessage = (props: Props) => {
{imageUsage.isControlNetImage && ( {imageUsage.isControlNetImage && (
<ListItem>{t('common.controlNet')}</ListItem> <ListItem>{t('common.controlNet')}</ListItem>
)} )}
{imageUsage.isIPAdapterImage && (
<ListItem>{t('common.ipAdapter')}</ListItem>
)}
{imageUsage.isNodesImage && ( {imageUsage.isNodesImage && (
<ListItem>{t('common.nodeEditor')}</ListItem> <ListItem>{t('common.nodeEditor')}</ListItem>
)} )}

View File

@ -1,9 +1,9 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { isInvocationNode } from 'features/nodes/types/types';
import { some } from 'lodash-es'; import { some } from 'lodash-es';
import { ImageUsage } from './types'; import { ImageUsage } from './types';
import { isInvocationNode } from 'features/nodes/types/types';
export const getImageUsage = (state: RootState, image_name: string) => { export const getImageUsage = (state: RootState, image_name: string) => {
const { generation, canvas, nodes, controlNet } = state; const { generation, canvas, nodes, controlNet } = state;
@ -27,11 +27,15 @@ export const getImageUsage = (state: RootState, image_name: string) => {
c.controlImage === image_name || c.processedControlImage === image_name c.controlImage === image_name || c.processedControlImage === image_name
); );
const isIPAdapterImage =
controlNet.ipAdapterInfo.adapterImage?.image_name === image_name;
const imageUsage: ImageUsage = { const imageUsage: ImageUsage = {
isInitialImage, isInitialImage,
isCanvasImage, isCanvasImage,
isNodesImage, isNodesImage,
isControlNetImage, isControlNetImage,
isIPAdapterImage,
}; };
return imageUsage; return imageUsage;

View File

@ -10,4 +10,5 @@ export type ImageUsage = {
isCanvasImage: boolean; isCanvasImage: boolean;
isNodesImage: boolean; isNodesImage: boolean;
isControlNetImage: boolean; isControlNetImage: boolean;
isIPAdapterImage: boolean;
}; };

View File

@ -53,6 +53,7 @@ const DeleteBoardModal = (props: Props) => {
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage), isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
isNodesImage: some(allImageUsage, (i) => i.isNodesImage), isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage), isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
}; };
return { imageUsageSummary }; return { imageUsageSummary };
}), }),