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,
"axis": "abs",
"open_air": false,
"axis": "real",
"data_limitation": "ph_only_1",
"cut": 2.0,
"max": 5.0,
"cut": 0.816,
"max": 3.8,
"gain": 0.0,
"start_freq": 100.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.
"""
# Best-effort persistence
try:
self.data_storage.store_result(processor_id, result)
except Exception: # noqa: BLE001
logger.error("Failed to store processor result")
# try:
# self.data_storage.store_result(processor_id, result)
# except Exception: # noqa: BLE001
# logger.error("Failed to store processor result")
# Broadcast to clients
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.settingDebounceTimers = {};
this.lastUiParameters = new Map();
this.lastUserInteractionTime = new Map();
this.parameterChangeTimestamps = {};
this.containerListeners = new Map(); // Store listeners per container
}
updateSettings(processorId, settingsContainer, latestData) {
@ -26,6 +29,13 @@ export class ChartSettingsManager {
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}`);
this.lastUiParameters.set(processorId, uiParameters ? JSON.parse(JSON.stringify(uiParameters)) : null);
@ -47,13 +57,18 @@ export class ChartSettingsManager {
return;
}
// Generate settings HTML
const settingsHtml = uiParameters.map(param =>
createParameterControl(param, processorId, 'chart')
).join('');
settingsContainer.innerHTML = settingsHtml;
this.setupEvents(settingsContainer, processorId);
// 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 =>
createParameterControl(param, processorId, 'chart')
).join('');
settingsContainer.innerHTML = settingsHtml;
this.setupEvents(settingsContainer, processorId);
}
// Initialize last values
if (uiParameters) {
@ -66,6 +81,73 @@ export class ChartSettingsManager {
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) {
const onParamChange = (e) => {
if (!e.target.closest('.chart-setting')) return;
@ -77,16 +159,52 @@ export class ChartSettingsManager {
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('change', onParamChange);
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) {
const settingElement = event.target.closest('.chart-setting');
if (!settingElement) return;
const now = Date.now();
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;
let value;
@ -105,18 +223,21 @@ export class ChartSettingsManager {
value = value === 'true';
}
const settingKey = `${processorId}_${paramName}`;
let lastValue = this.lastSettingValues[settingKey];
if (typeof lastValue === 'string' && (lastValue === 'true' || lastValue === 'false')) {
lastValue = lastValue === 'true';
}
console.log(`[CHANGE] ${processorId}.${paramName}: ${lastValue} -> ${value} (type: ${typeof value})`);
// Check for duplicate
if (lastValue === value) {
console.log(`Skipping duplicate value for ${processorId}.${paramName}: ${value}`);
return;
}
this.lastSettingValues[settingKey] = value;
console.log(`[SAVED] lastSettingValues["${settingKey}"] = ${value}`);
// Debounce updates
const debounceKey = `${processorId}_${paramName}`;

View File

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