refactor: separate application shell state and lifecycle owners

This commit is contained in:
Sameh Khamis committed 2026-09-15 11:17:10 -07:00
1 parent 81b82da056
commit bfefa875e1
20 files changed
+3510 -2481

No files matched your search

+117
View File
@@ -36,6 +36,123 @@ const DETECTION_ALLOCATION_STORAGE_KEY = 'gev:detection-allocation:v1';
/** Own visual preferences, detection overrides and display-control state. */
export class VisualSettings {
async restoreShareState(state) {
const {
setScopeMaskEnabled,
setScopeMaskFeather,
setScopeTerminusOverride,
clampScopeTerminusPct,
} = this.services;
const {
style,
bloom,
sharpen,
bloomIntensity,
bloomVersion,
sharpenIntensity,
hudVariant,
hudVisible,
detectionMode,
detectionDensity,
detectionAllocation,
detectionFadePct,
detectionOutsideOpacityPct,
celestialRing,
scopeEnabled,
scopeFeatherPct,
scopeTerminusPct,
mapStack,
panelState,
styleParams,
} = state || {};
// Ignore the retired 'ai-edit' style from older share links.
if (style && style !== 'normal' && style !== 'ai-edit') {
this.setStyle(style, {
applyPreset: true,
revealParameters: false,
restore: true,
});
}
if (styleParams && style && this.stages[style] && STYLES[style]?.uniforms) {
for (const [uniformName, uniformValue] of Object.entries(styleParams)) {
if (!Object.hasOwn(STYLES[style].uniforms, uniformName)) continue;
this.stages[style].uniforms[uniformName] = uniformValue;
}
this._updateSliderPanel(style, { reveal: false });
}
if (typeof bloomIntensity === 'number' && this._bloomSlider) {
const intensity = decodeBloomIntensity(bloomIntensity, bloomVersion);
this._setBloomIntensity(intensity, { syncShare: false });
}
if (typeof sharpenIntensity === 'number' && this._sharpenSlider) {
const pct = Math.max(0, Math.min(100, Math.round(sharpenIntensity)));
this._sharpenSlider.value = String(pct);
this._sharpenSliderValue.textContent = `${pct}%`;
this._applySharpenIntensity(pct / 100);
}
if (typeof bloom === 'boolean') this._setBloomEnabled(bloom);
if (typeof sharpen === 'boolean') this._setSharpenEnabled(sharpen);
if (hudVariant) this._setHudVariant(hudVariant);
if (typeof hudVisible === 'boolean') {
this.hud.setMode(hudVisible ? 'on' : 'off');
this._updateHudButtonState();
}
if (typeof detectionDensity === 'number' && this._detectionDensitySlider) {
const pct = canonicalizeDensity(detectionDensity);
this._detectionDensitySlider.value = String(pct);
this._detectionDensityValue.textContent = `${pct}%`;
this._applyDetectionDensityFromUi();
}
if (detectionAllocation) {
this._setDetectionAllocation(detectionAllocation, {
syncShare: false,
persist: false,
});
}
if (typeof detectionFadePct === 'number' && this._detectionFadeSlider) {
this._detectionFadeSlider.value = String(detectionFadePct);
}
if (
typeof detectionOutsideOpacityPct === 'number' &&
this._detectionOpacitySlider
) {
this._detectionOpacitySlider.value = String(detectionOutsideOpacityPct);
}
this._applyDetectionFadeFromUi();
if (detectionMode) this._setDetectionMode(detectionMode);
if (typeof celestialRing === 'boolean') {
this.setCelestialRingEnabled(celestialRing, {
syncShare: false,
focus: false,
});
}
if (typeof scopeEnabled === 'boolean') {
setScopeMaskEnabled(scopeEnabled);
this._scopeBtn?.classList.toggle('active', scopeEnabled);
this._scopeBtn?.setAttribute('aria-pressed', String(scopeEnabled));
}
if (typeof scopeFeatherPct === 'number' && this._scopeFeatherSlider) {
const pct = Math.max(0, Math.min(100, Math.round(scopeFeatherPct)));
this._scopeFeatherSlider.value = String(pct);
if (this._scopeFeatherValue)
this._scopeFeatherValue.textContent = `${pct}%`;
setScopeMaskFeather(pct / 100);
}
// null restores the altitude-adaptive ramp; a number pins the terminus
// (clamped to the supported 94..100 band, same as the `sce` hash key).
if (scopeTerminusPct === null) setScopeTerminusOverride(null);
else if (typeof scopeTerminusPct === 'number') {
const pinned = clampScopeTerminusPct(scopeTerminusPct);
setScopeTerminusOverride(pinned == null ? null : pinned / 100);
}
const mapStackRestore = mapStack
? this._setMapStack(mapStack, { syncShare: false })
: Promise.resolve();
if (panelState) this._restorePanelState(panelState);
await mapStackRestore;
this._syncShareState();
}
constructor({
viewer,
services,