fixed realtime processor settings managment

This commit is contained in:
Ayzen
2025-09-30 20:00:07 +03:00
parent 6b30e8a6fd
commit 0ef860111e
6 changed files with 4153 additions and 17 deletions

View File

@ -1,9 +1,9 @@
{ {
"open_air": true, "open_air": false,
"axis": "abs", "axis": "real",
"data_limitation": "ph_only_1", "data_limitation": "ph_only_1",
"cut": 2.0, "cut": 0.816,
"max": 5.0, "max": 3.8,
"gain": 0.0, "gain": 0.0,
"start_freq": 100.0, "start_freq": 100.0,
"stop_freq": 8800.0, "stop_freq": 8800.0,

View File

@ -229,10 +229,10 @@ class ProcessorWebSocketHandler:
- Schedule a coroutine on the main event loop to broadcast to clients. - Schedule a coroutine on the main event loop to broadcast to clients.
""" """
# Best-effort persistence # Best-effort persistence
try: # try:
self.data_storage.store_result(processor_id, result) # self.data_storage.store_result(processor_id, result)
except Exception: # noqa: BLE001 # except Exception: # noqa: BLE001
logger.error("Failed to store processor result") # logger.error("Failed to store processor result")
# Broadcast to clients # Broadcast to clients
self._broadcast_result_sync(processor_id, result) self._broadcast_result_sync(processor_id, result)

View File

@ -0,0 +1,7 @@
{
"name": "ыфвф",
"timestamp": "2025-09-30T19:05:27.995476",
"preset_filename": "s11_start100_stop8800_points1000_bw1khz.bin",
"description": "фывфф",
"metadata": {}
}

View File

@ -11,6 +11,9 @@ export class ChartSettingsManager {
this.lastSettingValues = {}; this.lastSettingValues = {};
this.settingDebounceTimers = {}; this.settingDebounceTimers = {};
this.lastUiParameters = new Map(); this.lastUiParameters = new Map();
this.lastUserInteractionTime = new Map();
this.parameterChangeTimestamps = {};
this.containerListeners = new Map(); // Store listeners per container
} }
updateSettings(processorId, settingsContainer, latestData) { updateSettings(processorId, settingsContainer, latestData) {
@ -26,6 +29,13 @@ export class ChartSettingsManager {
return; return;
} }
// Check if user recently interacted with controls
const lastInteraction = this.lastUserInteractionTime.get(processorId);
if (lastInteraction && Date.now() - lastInteraction < 1000) {
console.log(`Skipping update for ${processorId} - user is actively editing`);
return;
}
console.log(`Updating settings for ${processorId}`); console.log(`Updating settings for ${processorId}`);
this.lastUiParameters.set(processorId, uiParameters ? JSON.parse(JSON.stringify(uiParameters)) : null); this.lastUiParameters.set(processorId, uiParameters ? JSON.parse(JSON.stringify(uiParameters)) : null);
@ -47,13 +57,18 @@ export class ChartSettingsManager {
return; return;
} }
// Generate settings HTML // Smart update: only update changed parameters, skip focused elements
const hasExistingControls = settingsContainer.children.length > 0;
if (hasExistingControls) {
this.updateParametersSelectively(processorId, settingsContainer, uiParameters);
} else {
// Initial render: full rebuild
const settingsHtml = uiParameters.map(param => const settingsHtml = uiParameters.map(param =>
createParameterControl(param, processorId, 'chart') createParameterControl(param, processorId, 'chart')
).join(''); ).join('');
settingsContainer.innerHTML = settingsHtml; settingsContainer.innerHTML = settingsHtml;
this.setupEvents(settingsContainer, processorId); this.setupEvents(settingsContainer, processorId);
}
// Initialize last values // Initialize last values
if (uiParameters) { if (uiParameters) {
@ -66,6 +81,73 @@ export class ChartSettingsManager {
renderIcons(settingsContainer); renderIcons(settingsContainer);
} }
updateParametersSelectively(processorId, settingsContainer, newParameters) {
const now = Date.now();
// Temporarily remove event listeners to prevent programmatic changes from triggering events
this.removeEventListeners(settingsContainer);
for (const param of newParameters) {
const settingElement = settingsContainer.querySelector(`[data-param="${param.name}"]`);
if (!settingElement) continue;
const settingKey = `${processorId}_${param.name}`;
const currentValue = this.lastSettingValues[settingKey];
console.log(`[UPDATE CHECK] ${param.name}: currentValue=${currentValue}, newValue=${param.value}`);
// ALWAYS sync lastSettingValues with backend value
const valueChanged = currentValue !== param.value;
if (valueChanged) {
this.lastSettingValues[settingKey] = param.value;
console.log(`[SYNCED] lastSettingValues["${settingKey}"] = ${param.value}`);
} else {
console.log(`[SKIP] ${param.name}: value unchanged`);
continue;
}
// Skip UI update if element has focus
if (settingElement.contains(document.activeElement)) {
console.log(`Skipping UI update for ${param.name} - has focus`);
continue;
}
// Skip UI update if user recently changed this parameter
const lastChange = this.parameterChangeTimestamps[settingKey];
if (lastChange && now - lastChange < 2000) {
console.log(`Skipping UI update for ${param.name} - user changed it ${now - lastChange}ms ago`);
continue;
}
// Update UI control based on type (without triggering events)
if (param.type === 'toggle') {
const checkbox = settingElement.querySelector('input[type="checkbox"]');
if (checkbox && checkbox.checked !== param.value) {
console.log(`[UPDATE] Toggle ${param.name}: ${checkbox.checked} -> ${param.value}`);
checkbox.checked = param.value;
}
} else if (param.type === 'slider') {
const slider = settingElement.querySelector('input[type="range"]');
const valueDisplay = settingElement.querySelector('.chart-setting__value');
if (slider && parseFloat(slider.value) !== param.value) {
slider.value = param.value;
if (valueDisplay) {
valueDisplay.textContent = param.value;
}
}
} else if (param.type === 'select') {
const select = settingElement.querySelector('select');
if (select && select.value !== String(param.value)) {
console.log(`[UPDATE] Select ${param.name}: ${select.value} -> ${param.value}`);
select.value = String(param.value);
}
}
}
// Re-add event listeners after all updates are complete
this.restoreEventListeners(settingsContainer, processorId);
}
setupEvents(settingsContainer, processorId) { setupEvents(settingsContainer, processorId) {
const onParamChange = (e) => { const onParamChange = (e) => {
if (!e.target.closest('.chart-setting')) return; if (!e.target.closest('.chart-setting')) return;
@ -77,16 +159,52 @@ export class ChartSettingsManager {
this.handleButtonClick(e, processorId); this.handleButtonClick(e, processorId);
}; };
// Store listeners for later removal/restoration
this.containerListeners.set(settingsContainer, {
input: onParamChange,
change: onParamChange,
click: onButtonClick
});
settingsContainer.addEventListener('input', onParamChange); settingsContainer.addEventListener('input', onParamChange);
settingsContainer.addEventListener('change', onParamChange); settingsContainer.addEventListener('change', onParamChange);
settingsContainer.addEventListener('click', onButtonClick); settingsContainer.addEventListener('click', onButtonClick);
} }
removeEventListeners(settingsContainer) {
const listeners = this.containerListeners.get(settingsContainer);
if (!listeners) return;
settingsContainer.removeEventListener('input', listeners.input);
settingsContainer.removeEventListener('change', listeners.change);
settingsContainer.removeEventListener('click', listeners.click);
}
restoreEventListeners(settingsContainer, processorId) {
const listeners = this.containerListeners.get(settingsContainer);
if (!listeners) {
// If listeners don't exist, set them up
this.setupEvents(settingsContainer, processorId);
return;
}
settingsContainer.addEventListener('input', listeners.input);
settingsContainer.addEventListener('change', listeners.change);
settingsContainer.addEventListener('click', listeners.click);
}
handleSettingChange(event, processorId) { handleSettingChange(event, processorId) {
const settingElement = event.target.closest('.chart-setting'); const settingElement = event.target.closest('.chart-setting');
if (!settingElement) return; if (!settingElement) return;
const now = Date.now();
const paramName = settingElement.dataset.param; const paramName = settingElement.dataset.param;
const settingKey = `${processorId}_${paramName}`;
// Mark user interaction time for both processor and specific parameter
this.lastUserInteractionTime.set(processorId, now);
this.parameterChangeTimestamps[settingKey] = now;
const input = event.target; const input = event.target;
let value; let value;
@ -105,18 +223,21 @@ export class ChartSettingsManager {
value = value === 'true'; value = value === 'true';
} }
const settingKey = `${processorId}_${paramName}`;
let lastValue = this.lastSettingValues[settingKey]; let lastValue = this.lastSettingValues[settingKey];
if (typeof lastValue === 'string' && (lastValue === 'true' || lastValue === 'false')) { if (typeof lastValue === 'string' && (lastValue === 'true' || lastValue === 'false')) {
lastValue = lastValue === 'true'; lastValue = lastValue === 'true';
} }
console.log(`[CHANGE] ${processorId}.${paramName}: ${lastValue} -> ${value} (type: ${typeof value})`);
// Check for duplicate // Check for duplicate
if (lastValue === value) { if (lastValue === value) {
console.log(`Skipping duplicate value for ${processorId}.${paramName}: ${value}`);
return; return;
} }
this.lastSettingValues[settingKey] = value; this.lastSettingValues[settingKey] = value;
console.log(`[SAVED] lastSettingValues["${settingKey}"] = ${value}`);
// Debounce updates // Debounce updates
const debounceKey = `${processorId}_${paramName}`; const debounceKey = `${processorId}_${paramName}`;

View File

@ -67,7 +67,8 @@ export class ReferenceManager {
return; return;
} }
if (previousPreset !== newPreset) { // Clear current reference only if preset actually changed (not on initial load)
if (previousPreset !== null && previousPreset !== newPreset) {
await this.clearServerCurrentReference(); await this.clearServerCurrentReference();
} }