diff --git a/invokeai/frontend/webv2/src/workbench/workbenchState.test.ts b/invokeai/frontend/webv2/src/workbench/workbenchState.test.ts index 80c9f9b140a..be7b77ad3ee 100644 --- a/invokeai/frontend/webv2/src/workbench/workbenchState.test.ts +++ b/invokeai/frontend/webv2/src/workbench/workbenchState.test.ts @@ -5601,6 +5601,26 @@ describe('workbenchReducer Phase 5 generation flow', () => { expect(getActiveProject(state).settings.showProgressImagesInViewer).toBe(false); }); + it('keeps an explicit live-follow opt-out through later Gallery selections and submissions', () => { + let state = primeGenerate(); + state = workbenchReducer(state, { destination: 'gallery', type: 'setInvocationDestination' }); + state = workbenchReducer(state, { + settings: { showProgressImagesInViewer: false }, + type: 'setActiveProjectSettings', + }); + state = workbenchReducer(state, { item: createGalleryImageItem('selected.png'), type: 'selectGalleryItem' }); + state = workbenchReducer(state, { + image: createGalleryImageItem('compare.png'), + type: 'setGalleryCompareImage', + }); + + state = submitGenerate(state); + + const project = getActiveProject(state); + expect(project.settings.showProgressImagesInViewer).toBe(false); + expect(getProjectWidgetValues(project, 'gallery').selectedImageName).toBe('image:selected.png'); + }); + it('lifts the selection pause when live-follow is toggled explicitly', () => { let state = createInitialWorkbenchState(); state = workbenchReducer(state, { item: createGalleryImageItem('selected.png'), type: 'selectGalleryItem' }); diff --git a/invokeai/frontend/webv2/src/workbench/workbenchState.ts b/invokeai/frontend/webv2/src/workbench/workbenchState.ts index 4bd67fd72eb..4687858eeb7 100644 --- a/invokeai/frontend/webv2/src/workbench/workbenchState.ts +++ b/invokeai/frontend/webv2/src/workbench/workbenchState.ts @@ -3153,29 +3153,35 @@ const reconcileDeletedGalleryBoard = ( return didChangeQueue ? { ...withBoardReferencesCleared, projects } : withBoardReferencesCleared; }; -/** A deliberate selection pauses live-follow; only generations submitted after that selection may take the preview. */ +const getLiveFollowPausedAt = (project: Project): string | null => { + const pausedAt = getWidgetValues(project, 'gallery').liveFollowPausedAt; + + return typeof pausedAt === 'string' ? pausedAt : null; +}; + +/** + * A deliberate selection pauses live-follow; only generations submitted after that selection may take the preview. + * With live-follow explicitly off there is nothing to pause, and a pause recorded then would let the next submission + * turn it back on. + */ const updateGalleryValuesAndPauseLiveFollow = ( state: WorkbenchState, getValues: (values: Record) => Record, projectId = state.activeProjectId ): WorkbenchState => updateProjectById(state, projectId, (project) => - updateProjectWidgetValues( - { - ...project, - settings: { ...project.settings, showProgressImagesInViewer: false }, - }, - 'gallery', - (values) => ({ ...getValues(values), liveFollowPausedAt: now() }) - ) + !project.settings.showProgressImagesInViewer && getLiveFollowPausedAt(project) === null + ? updateProjectWidgetValues(project, 'gallery', getValues) + : updateProjectWidgetValues( + { + ...project, + settings: { ...project.settings, showProgressImagesInViewer: false }, + }, + 'gallery', + (values) => ({ ...getValues(values), liveFollowPausedAt: now() }) + ) ); -const getLiveFollowPausedAt = (project: Project): string | null => { - const pausedAt = getWidgetValues(project, 'gallery').liveFollowPausedAt; - - return typeof pausedAt === 'string' ? pausedAt : null; -}; - /** Submission resumes selection-paused live-follow, but preserves an explicit opt-out. */ const shouldResumeLiveFollowOnSubmit = (project: Project): boolean => !project.settings.showProgressImagesInViewer && getLiveFollowPausedAt(project) !== null;