From 72054fe17f5cc8fe632f1f489908111d41b50d7b Mon Sep 17 00:00:00 2001 From: DanS Date: Fri, 9 Oct 2026 21:09:48 -0500 Subject: [PATCH] perf(settings): save opacity, chat and contacts sliders on release Six sliders (noise opacity, UI opacity, window opacity, chat font size, chat poll rate, contacts list scale) rewrote settings.json, with its two fsyncs, on every frame the value changed: 60-300 durable writes per drag, at 1-4 ms each on NVMe, 3-20 ms on a Windows SSD, 20-60 ms on a HDD and seconds while dragonxd is busy on the disk. The value still applies live and is kept in Settings for the per-frame readers; settings.json is written once, when the slider is released, as the blur and font-scale sliders already did. A drag cut off before its release (a dialog closed mid-drag) is persisted by the next save or at exit. Co-Authored-By: Claude Opus 5.5 --- src/ui/pages/settings_page.cpp | 9 ++++++--- src/ui/windows/chat_tab.cpp | 6 ++++-- src/ui/windows/contacts_tab.cpp | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ui/pages/settings_page.cpp b/src/ui/pages/settings_page.cpp index a55ea52..3fecddb 100644 --- a/src/ui/pages/settings_page.cpp +++ b/src/ui/pages/settings_page.cpp @@ -1115,9 +1115,10 @@ void RenderSettingsPage(App* app) { if (ImGui::SliderFloat("##NoiseOpacity", &s_settingsState.noise_opacity, 0.0f, 1.0f, noise_fmt, ImGuiSliderFlags_AlwaysClamp)) { effects::ImGuiAcrylic::SetNoiseOpacity(s_settingsState.noise_opacity); - saveSettingsPageState(app->settings()); + if (app->settings()) app->settings()->setNoiseOpacity(s_settingsState.noise_opacity); // live; persisted on release } } + if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings()); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_noise")); ImGui::SetCursorScreenPos(ImVec2(baseX, afterRow1Y)); @@ -1131,9 +1132,10 @@ void RenderSettingsPage(App* app) { if (ImGui::SliderFloat("##UIOpacity", &s_settingsState.ui_opacity, 0.3f, 1.0f, uiop_fmt, ImGuiSliderFlags_AlwaysClamp)) { effects::ImGuiAcrylic::SetUIOpacity(s_settingsState.ui_opacity); - saveSettingsPageState(app->settings()); + if (app->settings()) app->settings()->setUIOpacity(s_settingsState.ui_opacity); // live; persisted on release } } + if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings()); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_ui_opacity")); float afterRow2Y = ImGui::GetCursorScreenPos().y; @@ -1146,9 +1148,10 @@ void RenderSettingsPage(App* app) { snprintf(winop_fmt, sizeof(winop_fmt), "%.0f%%%%", s_settingsState.window_opacity * 100.0f); if (ImGui::SliderFloat("##WindowOpacity", &s_settingsState.window_opacity, 0.3f, 1.0f, winop_fmt, ImGuiSliderFlags_AlwaysClamp)) { - saveSettingsPageState(app->settings()); + if (app->settings()) app->settings()->setWindowOpacity(s_settingsState.window_opacity); // live; persisted on release } } + if (ImGui::IsItemDeactivatedAfterEdit()) saveSettingsPageState(app->settings()); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_window_opacity")); ImGui::SetCursorScreenPos(ImVec2(baseX, afterRow2Y)); diff --git a/src/ui/windows/chat_tab.cpp b/src/ui/windows/chat_tab.cpp index 400833c..146a288 100644 --- a/src/ui/windows/chat_tab.cpp +++ b/src/ui/windows/chat_tab.cpp @@ -2220,8 +2220,9 @@ void RenderChatSettingsControls(App* app, float contentWidth, bool drawCards) beginRow(TR("chat_opt_font_size")); float v = st->getChatFontScale(); if (ImGui::SliderFloat("##chat_font", &v, 0.8f, 1.5f, "%.2fx", ImGuiSliderFlags_AlwaysClamp)) { - st->setChatFontScale(v); st->save(); + st->setChatFontScale(v); // live (readers poll Settings); persisted on release } + if (ImGui::IsItemDeactivatedAfterEdit()) st->save(); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_chat_font_size")); } @@ -2242,8 +2243,9 @@ void RenderChatSettingsControls(App* app, float contentWidth, bool drawCards) beginRow(TR("chat_opt_poll")); float v = st->getChatPollRateSec(); if (ImGui::SliderFloat("##chat_poll", &v, 0.5f, 15.0f, "%.1f s", ImGuiSliderFlags_AlwaysClamp)) { - st->setChatPollRateSec(v); st->save(); + st->setChatPollRateSec(v); // live (App::update polls it); persisted on release } + if (ImGui::IsItemDeactivatedAfterEdit()) st->save(); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_chat_poll_rate")); } // Chat timestamps (segmented) — overrides the app-wide clock (Settings → General) for this tab only. diff --git a/src/ui/windows/contacts_tab.cpp b/src/ui/windows/contacts_tab.cpp index 95a58d1..03f0acb 100644 --- a/src/ui/windows/contacts_tab.cpp +++ b/src/ui/windows/contacts_tab.cpp @@ -1446,8 +1446,9 @@ void RenderContactsTab(App* app) rowStart(TR("contacts_list_scale")); float v = st->getContactsListScale(); if (ImGui::SliderFloat("##contactsScale", &v, 0.8f, 1.5f, "%.2fx", ImGuiSliderFlags_AlwaysClamp)) { - st->setContactsListScale(v); st->save(); + st->setContactsListScale(v); // live; persisted on release } + if (ImGui::IsItemDeactivatedAfterEdit()) st->save(); } ImGui::Dummy(ImVec2(0.0f, 8.0f * dp)); {