From 1712ba206801b2271e1ccb07d91d3fa9ddbb543f Mon Sep 17 00:00:00 2001 From: Igor Zinken <730069+igorski@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:21:04 +0100 Subject: [PATCH] Shuffling layer order now triggers a tile re-render --- src/store/actions/layer-reorder.ts | 21 +++++-- src/store/modules/document-module.ts | 8 +-- .../unit/store/actions/layer-reorder.spec.ts | 62 +++++++++++++------ .../store/modules/document-module.spec.ts | 2 +- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/store/actions/layer-reorder.ts b/src/store/actions/layer-reorder.ts index 96df868..2c0c551 100644 --- a/src/store/actions/layer-reorder.ts +++ b/src/store/actions/layer-reorder.ts @@ -21,9 +21,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { type Store } from "vuex"; -import { type Document } from "@/definitions/document"; +import type { Document, RelId } from "@/definitions/document"; import { enqueueState } from "@/factories/history-state-factory"; +import { createGroupTile } from "@/rendering/cache/tile-cache"; import { type BitMapperyState } from "@/store"; +import { getTileByLayer } from "@/utils/timeline-util"; /** * layerIds represents an ordered list @@ -45,15 +47,22 @@ export const reorderLayers = ( store: Store, activeDocument: Do subsetIndices.forEach(( idx: number, i: number ) => { updatedOrder[ idx ] = layerIds[ i ]; }); - + + const tileIds = activeDocument.type === "timeline" ? [ ...layerIds.reduce(( acc, layerId ) => { + acc.add( getTileByLayer( activeDocument, layerId )); + return acc; + }, new Set())] : []; + const commit = () => { - store.commit( "reorderLayers", { document: activeDocument, layerIds: updatedOrder } ); - } + store.commit( "reorderLayers", { activeDocument, layerIds: updatedOrder } ); + tileIds.forEach( tileId => createGroupTile( tileId, activeDocument )); + }; commit(); enqueueState( `reorderLayers_${layerIds.join()}`, { - undo() { - store.commit( "reorderLayers", { document: activeDocument, layerIds: originalOrder }); + undo(): void { + store.commit( "reorderLayers", { activeDocument, layerIds: originalOrder }); + tileIds.forEach( tileId => createGroupTile( tileId, activeDocument )); }, redo: commit, }); diff --git a/src/store/modules/document-module.ts b/src/store/modules/document-module.ts index 02bbbdf..6bfdbdf 100644 --- a/src/store/modules/document-module.ts +++ b/src/store/modules/document-module.ts @@ -147,14 +147,14 @@ const DocumentModule: Module = { layers[ index1 ] = layers[ index2 ]; layers[ index2 ] = obj1; }, - reorderLayers( _state: DocumentState, { document, layerIds }: { document: Document, layerIds: string[] }): void { - const oldLayers = [ ...document.layers ]; - const layers = [ ...document.layers ]; + reorderLayers( _state: DocumentState, { activeDocument, layerIds }: { activeDocument: Document, layerIds: string[] }): void { + const oldLayers = [ ...activeDocument.layers ]; + const layers = [ ...activeDocument.layers ]; layers.splice( 0, oldLayers.length ); layerIds.forEach( id => { layers.push( oldLayers.find( layer => layer.id === id )); }); - document.layers = layers; + activeDocument.layers = layers; flushBlendedLayerCache( true ); }, removeLayer( state: DocumentState, index: number ): void { diff --git a/tests/unit/store/actions/layer-reorder.spec.ts b/tests/unit/store/actions/layer-reorder.spec.ts index c259f6e..19ec2f6 100644 --- a/tests/unit/store/actions/layer-reorder.spec.ts +++ b/tests/unit/store/actions/layer-reorder.spec.ts @@ -4,6 +4,7 @@ import { createStore, mockZCanvas } from "../../mocks"; mockZCanvas(); +import type { Document } from "@/definitions/document"; import DocumentFactory from "@/factories/document-factory"; import LayerFactory from "@/factories/layer-factory"; import { type BitMapperyState } from "@/store"; @@ -14,6 +15,11 @@ vi.mock( "@/factories/history-state-factory", () => ({ enqueueState: ( ...args: any[] ) => mockEnqueueState( ...args ), })); +const mockCreateGroupTile = vi.fn(); +vi.mock( "@/rendering/cache/tile-cache", () => ({ + createGroupTile: ( ...args: any[] ) => mockCreateGroupTile( ...args ), +})); + describe( "reorder layers action", () => { const tile1layer1 = LayerFactory.create({ rel: { type: "tile", id: 0 }}); const tile1layer2 = LayerFactory.create({ rel: { type: "tile", id: 0 }}); @@ -24,24 +30,27 @@ describe( "reorder layers action", () => { const tile3layer1 = LayerFactory.create({ rel: { type: "tile", id: 2 }}); - const document = DocumentFactory.create({ - layers: [ - tile1layer1, tile1layer2, - tile2layer1, tile2layer2, tile2layer3, - tile3layer1, - ] - }); - - const originalLayerIds = document.layers.map( layer => layer.id ); const shuffledLayerIds = [ tile1layer1.id, tile1layer2.id, tile2layer3.id, tile2layer1.id, tile2layer2.id, // reorder is on this line! tile3layer1.id, ]; + let originalLayerIds: string[]; + let activeDocument: Document; let store: Store; beforeEach(() => { store = createStore(); + + activeDocument = DocumentFactory.create({ + type: "timeline", + layers: [ + tile1layer1, tile1layer2, + tile2layer1, tile2layer2, tile2layer3, + tile3layer1, + ] + }); + originalLayerIds = activeDocument.layers.map( layer => layer.id ); }); afterEach(() => { @@ -49,28 +58,28 @@ describe( "reorder layers action", () => { }); it( "should be able to reorder the Layers within the Document by their ids", () => { - reorderLayers( store, document, shuffledLayerIds); + reorderLayers( store, activeDocument, shuffledLayerIds); expect( store.commit ).toHaveBeenCalledTimes( 1 ); expect( store.commit ).toHaveBeenCalledWith( "reorderLayers", { - document, + activeDocument, layerIds: shuffledLayerIds, }); }); it( "should be able to reorder the Layers within the Document when receiving only a subset of all Layer content", () => { const shuffledSubSet = [ tile2layer3.id, tile2layer1.id, tile2layer2.id ]; - reorderLayers( store, document, shuffledSubSet); + reorderLayers( store, activeDocument, shuffledSubSet); expect( store.commit ).toHaveBeenCalledTimes( 1 ); expect( store.commit ).toHaveBeenCalledWith( "reorderLayers", { - document, + activeDocument, layerIds: shuffledLayerIds, // expect shuffled set to have been applied to full content }); }); it( "should store the action in state history", () => { - reorderLayers( store, document, shuffledLayerIds ); + reorderLayers( store, activeDocument, shuffledLayerIds ); expect( mockEnqueueState ).toHaveBeenCalledWith( `reorderLayers_${shuffledLayerIds.join()}`, { @@ -81,20 +90,20 @@ describe( "reorder layers action", () => { }); it( "should restore the original order when calling undo in state history", () => { - reorderLayers( store, document, shuffledLayerIds ); + reorderLayers( store, activeDocument, shuffledLayerIds ); const { undo } = mockEnqueueState.mock.calls[ 0 ][ 1 ]; undo(); expect( store.commit ).toHaveBeenCalledTimes( 2 ); expect( store.commit ).toHaveBeenNthCalledWith( 2, "reorderLayers", { - document, + activeDocument, layerIds: originalLayerIds, }); }); it( "should reapply the new order when calling redo in state history", () => { - reorderLayers( store, document, shuffledLayerIds ); + reorderLayers( store, activeDocument, shuffledLayerIds ); const { undo, redo } = mockEnqueueState.mock.calls[ 0 ][ 1 ]; undo(); @@ -102,8 +111,25 @@ describe( "reorder layers action", () => { expect( store.commit ).toHaveBeenCalledTimes( 3 ); expect( store.commit ).toHaveBeenNthCalledWith( 3, "reorderLayers", { - document, + activeDocument, layerIds: shuffledLayerIds, }); }); + + it( "should request a re-render of tiles associated with the layers", () => { + reorderLayers( store, activeDocument, shuffledLayerIds ); + + expect( mockCreateGroupTile ).toHaveBeenCalledTimes( 3 ); + expect( mockCreateGroupTile ).toHaveBeenNthCalledWith( 1, 0, activeDocument ); + expect( mockCreateGroupTile ).toHaveBeenNthCalledWith( 2, 1, activeDocument ); + expect( mockCreateGroupTile ).toHaveBeenNthCalledWith( 3, 2, activeDocument ); + }); + + it( "should not request a re-render of tiles associated with the layers for non-timeline type Documents", () => { + activeDocument.type = "default"; + + reorderLayers( store, activeDocument, shuffledLayerIds ); + + expect( mockCreateGroupTile ).not.toHaveBeenCalled(); + }); }); \ No newline at end of file diff --git a/tests/unit/store/modules/document-module.spec.ts b/tests/unit/store/modules/document-module.spec.ts index a4d9981..fa6212a 100644 --- a/tests/unit/store/modules/document-module.spec.ts +++ b/tests/unit/store/modules/document-module.spec.ts @@ -523,7 +523,7 @@ describe( "Vuex document module", () => { documents: [ DocumentFactory.create({ name: "foo", layers })], activeIndex: 0 }); - mutations.reorderLayers( state, { document: state.documents[ 0 ], layerIds: [ + mutations.reorderLayers( state, { activeDocument: state.documents[ 0 ], layerIds: [ layers[ 1 ].id, layers[ 2 ].id, layers[ 0 ].id, layers[ 3 ].id ] }); // note we check by reference to ensure all bindings remain