feat(ui): on accept staged image, switch to raster layer if raster layer currently selected

Also clean up some jank w/ the handling of accepting staging images - there was this no-op action & a listener for it... should just be a simple callback.
This commit is contained in:
psychedelicious
2024-09-23 10:05:02 +10:00
committed by Kent Keirsey
parent f25e28a933
commit f920c8837c
4 changed files with 20 additions and 37 deletions

View File

@@ -2,15 +2,10 @@ import { isAnyOf } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
import { canvasReset } from 'features/controlLayers/store/actions';
import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice';
import { stagingAreaImageAccepted, stagingAreaReset } from 'features/controlLayers/store/canvasStagingAreaSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import type { CanvasRasterLayerState } from 'features/controlLayers/store/types';
import { imageDTOToImageObject } from 'features/controlLayers/store/util';
import { stagingAreaReset } from 'features/controlLayers/store/canvasStagingAreaSlice';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { queueApi } from 'services/api/endpoints/queue';
import { assert } from 'tsafe';
const log = logger('canvas');
@@ -48,26 +43,4 @@ export const addStagingListeners = (startAppListening: AppStartListening) => {
}
},
});
startAppListening({
actionCreator: stagingAreaImageAccepted,
effect: (action, api) => {
const { index } = action.payload;
const state = api.getState();
const stagingAreaImage = state.canvasStagingArea.stagedImages[index];
assert(stagingAreaImage, 'No staged image found to accept');
const { x, y } = selectCanvasSlice(state).bbox.rect;
const { imageDTO, offsetX, offsetY } = stagingAreaImage;
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: x + offsetX, y: y + offsetY },
objects: [imageObject],
};
api.dispatch(rasterLayerAdded({ overrides, isSelected: false }));
api.dispatch(stagingAreaReset());
},
});
};

View File

@@ -3,12 +3,15 @@ import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { INTERACTION_SCOPES } from 'common/hooks/interactionScopes';
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice';
import {
selectImageCount,
selectSelectedImage,
selectStagedImageIndex,
stagingAreaImageAccepted,
stagingAreaReset,
} from 'features/controlLayers/store/canvasStagingAreaSlice';
import { selectBboxRect, selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
import type { CanvasRasterLayerState } from 'features/controlLayers/store/types';
import { imageDTOToImageObject } from 'features/controlLayers/store/util';
import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
@@ -17,8 +20,9 @@ import { PiCheckBold } from 'react-icons/pi';
export const StagingAreaToolbarAcceptButton = memo(() => {
const dispatch = useAppDispatch();
const canvasManager = useCanvasManager();
const index = useAppSelector(selectStagedImageIndex);
const bboxRect = useAppSelector(selectBboxRect);
const selectedImage = useAppSelector(selectSelectedImage);
const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier);
const imageCount = useAppSelector(selectImageCount);
const shouldShowStagedImage = useStore(canvasManager.stagingArea.$shouldShowStagedImage);
const isCanvasActive = useStore(INTERACTION_SCOPES.canvas.$isActive);
@@ -29,8 +33,17 @@ export const StagingAreaToolbarAcceptButton = memo(() => {
if (!selectedImage) {
return;
}
dispatch(stagingAreaImageAccepted({ index }));
}, [dispatch, index, selectedImage]);
const { x, y } = bboxRect;
const { imageDTO, offsetX, offsetY } = selectedImage;
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: x + offsetX, y: y + offsetY },
objects: [imageObject],
};
dispatch(rasterLayerAdded({ overrides, isSelected: selectedEntityIdentifier?.type === 'raster_layer' }));
dispatch(stagingAreaReset());
}, [bboxRect, dispatch, selectedEntityIdentifier?.type, selectedImage]);
useHotkeys(
['enter'],

View File

@@ -40,9 +40,6 @@ export const canvasStagingAreaSlice = createSlice({
state.stagedImages = [];
state.selectedStagedImageIndex = 0;
},
stagingAreaImageAccepted: (_state, _action: PayloadAction<{ index: number }>) => {
// no-op, handled in a listener
},
},
extraReducers(builder) {
builder.addCase(canvasReset, () => deepClone(initialState));
@@ -55,7 +52,6 @@ export const {
stagingAreaReset,
stagingAreaNextStagedImageSelected,
stagingAreaPrevStagedImageSelected,
stagingAreaImageAccepted,
} = canvasStagingAreaSlice.actions;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */

View File

@@ -328,6 +328,7 @@ export const selectAspectRatioID = createSelector(selectCanvasSlice, (canvas) =>
export const selectAspectRatioValue = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.value);
export const selectScaledSize = createSelector(selectBbox, (bbox) => bbox.scaledSize);
export const selectScaleMethod = createSelector(selectBbox, (bbox) => bbox.scaleMethod);
export const selectBboxRect = createSelector(selectBbox, (bbox) => bbox.rect);
export const selectCanvasMetadata = createSelector(
selectCanvasSlice,