diff --git a/src/ui/applicationShell.js b/src/ui/applicationShell.js index ec912be87..064024920 100644 --- a/src/ui/applicationShell.js +++ b/src/ui/applicationShell.js @@ -598,6 +598,8 @@ export class StyleManager extends ShellFacade { _setScope: (...args) => this._visualSettings._setScope(...args), _applyGlobalPostDefaults: (...args) => this._applyGlobalPostDefaults(...args), + _adoptDetectionAsRestore: () => + this._visualSettings.adoptDetectionAsRestore(), setCelestialRingEnabled: (...args) => this.setCelestialRingEnabled(...args), _setModels3dEnabled: (...args) => this._setModels3dEnabled(...args), diff --git a/src/ui/displayBindings.js b/src/ui/displayBindings.js index 40e4a1edb..827cd51cd 100644 --- a/src/ui/displayBindings.js +++ b/src/ui/displayBindings.js @@ -185,6 +185,12 @@ export class DisplayBindings { this._setModels3dEnabled(true); this._setModels3dMode('proximity'); this._syncModels3dModeRow?.(); + // Inside Contacts the detection shown is lent for the session, and + // leaving puts back the state from before. A reset there is the user's + // choice, so the defaults become what leaving puts back and what a + // share link carries. + this.claimDetection(); + this._adoptDetectionAsRestore?.(); this._syncShareState(); }, }); diff --git a/src/ui/displayPanelActions.test.mjs b/src/ui/displayPanelActions.test.mjs index 32a8e8d1b..59cb064dd 100644 --- a/src/ui/displayPanelActions.test.mjs +++ b/src/ui/displayPanelActions.test.mjs @@ -8,6 +8,7 @@ import { createApp, h, nextTick } from 'vue'; import { createPinia } from 'pinia'; import { useDisplayStore } from './stores/display.js'; import { DisplayBindings } from './displayBindings.js'; +import { VisualSettings } from './visualSettings.js'; import CommandDockView from './views/CommandDockView.vue'; import DisplayControlsView from './views/DisplayControlsView.vue'; import DrawControls from './views/panels/DrawControls.vue'; @@ -296,13 +297,14 @@ test('DisplayBindings sets the scope opacity and resets Visual to its defaults', _setModels3dMode: (mode) => calls.push(['models3dMode', mode]), _syncModels3dModeRow: () => calls.push(['models3dRow']), _syncShareState: () => calls.push(['share']), + _adoptDetectionAsRestore: () => calls.push(['adoptDetection']), }, readState: () => ({ shareLinkManager: { claimRestoreLane: (lane) => calls.push(['claim', lane]), }, }), - claimDetection: () => {}, + claimDetection: () => calls.push(['claimDetection']), displayStore: store, }); bindings._initUI(); @@ -325,6 +327,29 @@ test('DisplayBindings sets the scope opacity and resets Visual to its defaults', ['models3d', true], ['models3dMode', 'proximity'], ['models3dRow'], + ['claimDetection'], + ['adoptDetection'], ['share'], ]); }); + +test('a reset inside Contacts makes the shown detection what leaving puts back', () => { + const adopt = VisualSettings.prototype.adoptDetectionAsRestore; + const live = { detectionMode: 'DENSE', densityPct: 75 }; + const inContacts = { + _contactsDetectionRestore: { mode: 'OFF', densityPct: 50 }, + getDetectionState: () => live, + }; + adopt.call(inContacts); + assert.deepEqual(inContacts._contactsDetectionRestore, { + mode: 'DENSE', + densityPct: 75, + }); + // Outside Contacts there is no saved state to change. + const outside = { + _contactsDetectionRestore: null, + getDetectionState: () => live, + }; + adopt.call(outside); + assert.equal(outside._contactsDetectionRestore, null); +}); diff --git a/src/ui/visualSettings.js b/src/ui/visualSettings.js index e6cf4d180..3282038d0 100644 --- a/src/ui/visualSettings.js +++ b/src/ui/visualSettings.js @@ -355,6 +355,20 @@ export class VisualSettings { this._syncShareState(); } + /** + * While Contacts holds detection, make the detection shown now the state + * leaving Contacts puts back (and a share link carries): the user chose it, + * as with Reset in Visual. Nothing changes outside Contacts. + */ + adoptDetectionAsRestore() { + if (!this._contactsDetectionRestore) return; + const state = this.getDetectionState(); + this._contactsDetectionRestore = { + mode: state.detectionMode, + densityPct: state.densityPct, + }; + } + _setCockpitVision(mode, active, { revealParameters = false } = {}) { const next = active ? normalizeCockpitVisionMode(mode) : 'optical'; if (!this.stages) return;