From f10207a159c6e988cc9bf1201033324bfef2dfa7 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Wed, 26 Nov 2025 09:52:15 -0500 Subject: [PATCH] Settings / SetupWizard & OSD - Settings cleanup and avoid segfault by not using var. - SetupWizard simplified opening condition logic. Will only open when no settings available - OSD: simplified settings logic, updated translations to explain that no type selected = all types enabled. similar to bar and monitors logic. - Do not open changelog on a fresh install as we already open the SetupWizard --- Assets/Translations/de.json | 4 +- Assets/Translations/en.json | 10 +- Assets/Translations/es.json | 4 +- Assets/Translations/fr.json | 4 +- Assets/Translations/nl.json | 4 +- Assets/Translations/pt.json | 4 +- Assets/Translations/ru.json | 4 +- Assets/Translations/tr.json | 4 +- Assets/Translations/uk-UA.json | 4 +- Assets/Translations/zh-CN.json | 4 +- Assets/settings-default.json | 22 +- Commons/Settings.qml | 312 +++++++-------------- Modules/Panels/SetupWizard/SetupWizard.qml | 1 - Services/Noctalia/UpdateService.qml | 8 +- Services/UI/WallpaperService.qml | 2 +- shell.qml | 22 +- 16 files changed, 153 insertions(+), 260 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 321bf3e09..22e3bcd7c 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1690,8 +1690,8 @@ "label": "Feststelltasten" }, "section": { - "description": "Wähle, welche Ereignisse das On-Screen Display auslösen.", - "label": "OSD-Typen" + "description": "Wählen Sie die Ereignisse aus, die das OSD auslösen. Wenn keine Ereignisse ausgewählt werden, lösen alle verfügbaren Ereignisse das OSD aus.", + "label": "OSD-Auslöseereignisse" }, "volume": { "description": "OSD anzeigen, wenn sich die Ausgabelautstärke ändert.", diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index f9df474cb..f80785e42 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1683,19 +1683,19 @@ }, "input-volume": { "description": "Show OSD when microphone volume changes.", - "label": "Input Volume" + "label": "Input volume" }, "lockkey": { "description": "Show OSD when Caps Lock, Num Lock, or Scroll Lock are toggled.", - "label": "Lock Keys" + "label": "Lock keys" }, "section": { - "description": "Choose which events trigger the on-screen display.", - "label": "OSD Types" + "description": "Select the events that trigger the OSD. If no events are selected, all available events will trigger the OSD.", + "label": "OSD trigger events" }, "volume": { "description": "Show OSD when audio output volume changes.", - "label": "Output Volume" + "label": "Output volume" } } }, diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index c9b06176d..b16b9401a 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1690,8 +1690,8 @@ "label": "Teclas de bloqueo" }, "section": { - "description": "Elige qué eventos activan la visualización en pantalla.", - "label": "Tipos de OSD" + "description": "Seleccione los eventos que activan el OSD. Si no se selecciona ningún evento, todos los eventos disponibles activarán el OSD.", + "label": "Eventos de activación OSD" }, "volume": { "description": "Mostrar el OSD cuando cambie el volumen de salida de audio.", diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 8a366f98a..e132f1bb4 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1690,8 +1690,8 @@ "label": "Touches de verrouillage" }, "section": { - "description": "Choisissez quels événements déclenchent l'affichage à l'écran.", - "label": "Types d'OSD" + "description": "Sélectionnez les événements qui déclenchent l'OSD. Si aucun événement n'est sélectionné, tous les événements disponibles déclencheront l'OSD.", + "label": "Événements de déclenchement OSD" }, "volume": { "description": "Afficher l'OSD lorsque le volume de sortie audio change.", diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index c73c4978d..4f76b4933 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -1690,8 +1690,8 @@ "label": "Vergrendeltoetsen" }, "section": { - "description": "Kies welke gebeurtenissen de on-screenweergave activeren.", - "label": "OSD-typen" + "description": "Selecteer de gebeurtenissen die de OSD activeren. Als er geen gebeurtenissen zijn geselecteerd, activeren alle beschikbare gebeurtenissen de OSD.", + "label": "OSD triggergebeurtenissen" }, "volume": { "description": "Toon het OSD wanneer het uitvoervolume verandert.", diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 540a95349..a3465840b 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1690,8 +1690,8 @@ "label": "Teclas de bloqueio" }, "section": { - "description": "Escolha quais eventos disparam a exibição na tela.", - "label": "Tipos de OSD" + "description": "Selecione os eventos que acionam o OSD. Se nenhum evento for selecionado, todos os eventos disponíveis acionarão o OSD.", + "label": "Eventos de disparo OSD" }, "volume": { "description": "Mostrar o OSD quando o volume de saída de áudio mudar.", diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index f361e5a5b..1683694de 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -1690,8 +1690,8 @@ "label": "Клавиши блокировки" }, "section": { - "description": "Выберите события, которые запускают экранное отображение.", - "label": "Типы OSD" + "description": "Выберите события, которые должны запускать экранное меню (OSD). Если события не выбраны, экранное меню будет запускаться при любом доступном событии.", + "label": "События, запускающие экранное меню" }, "volume": { "description": "Показывать OSD при изменении громкости аудиовыхода.", diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 53e9b477f..690ca4b23 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -1690,8 +1690,8 @@ "label": "Kilit tuşları" }, "section": { - "description": "Ekran göstergesini tetikleyen olayları seçin.", - "label": "OSD türleri" + "description": "OSD'yi tetikleyecek olayları seçin. Hiçbir olay seçilmezse, mevcut tüm olaylar OSD'yi tetikleyecektir.", + "label": "OSD tetikleme olayları" }, "volume": { "description": "Ses çıkış düzeyi değiştiğinde OSD'yi göster.", diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index ad73408d8..26ca8d8fa 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -1690,8 +1690,8 @@ "label": "Клавіші блокування" }, "section": { - "description": "Виберіть події, які запускають екранну індикацію.", - "label": "Типи OSD" + "description": "Виберіть події, які запускають екранне меню. Якщо жодну подію не вибрано, екранне меню запускатиметься всіма доступними подіями.", + "label": "Події, що запускають OSD" }, "volume": { "description": "Показувати OSD, коли змінюється гучність аудіовиходу.", diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 0f3b9926a..454c54d68 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1690,8 +1690,8 @@ "label": "锁定键" }, "section": { - "description": "选择哪些事件会触发屏显菜单。", - "label": "OSD 类型" + "description": "选择触发OSD的事件。如果未选择任何事件,则所有可用事件都将触发OSD。", + "label": "OSD触发事件" }, "volume": { "description": "当音频输出音量发生变化时显示 OSD。", diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 0cc60a463..2f8907a28 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -1,6 +1,5 @@ { - "settingsVersion": 24, - "setupCompleted": false, + "settingsVersion": 25, "bar": { "position": "top", "backgroundOpacity": 1, @@ -118,7 +117,6 @@ "enableMultiMonitorDirectories": false, "recursiveSearch": false, "setWallpaperOnAllMonitors": true, - "defaultWallpaper": "", "fillMode": "crop", "fillColor": "#000000", "randomEnabled": false, @@ -126,7 +124,6 @@ "transitionDuration": 1500, "transitionType": "random", "transitionEdgeSmoothness": 0.05, - "monitors": [], "panelPosition": "follow_bar", "hideWallpaperFilenames": false, "useWallhaven": false, @@ -137,7 +134,9 @@ "wallhavenPurity": "100", "wallhavenResolutionMode": "atleast", "wallhavenResolutionWidth": "", - "wallhavenResolutionHeight": "" + "wallhavenResolutionHeight": "", + "defaultWallpaper": "", + "monitors": [] }, "appLauncher": { "enableClipboardHistory": false, @@ -221,7 +220,7 @@ }, "dock": { "enabled": true, - "displayMode": "always_visible", + "displayMode": "auto_hide", "backgroundOpacity": 1, "radiusRatio": 0.1, "floatingRatio": 1, @@ -280,17 +279,12 @@ }, "osd": { "enabled": true, - "enabledTypes": [ - 0, - 1, - 2, - 3 - ], "location": "top_right", - "monitors": [], "autoHideMs": 2000, "overlayLayer": true, - "backgroundOpacity": 1 + "backgroundOpacity": 1, + "enabledTypes": [], + "monitors": [] }, "audio": { "volumeStep": 5, diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 2bbb1bae8..69eb2c973 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -12,28 +12,30 @@ import qs.Services.UI Singleton { id: root - // Used to access via Settings.data.xxx.yyy - readonly property alias data: adapter property bool isLoaded: false property bool directoriesCreated: false - property int settingsVersion: 24 - property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" + property bool shouldOpenSetupWizard: false - // Define our app directories - // Default config directory: ~/.config/noctalia - // Default cache directory: ~/.cache/noctalia - property string shellName: "noctalia" - property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" - property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env("HOME") + "/.cache") + "/" + shellName + "/" - property string cacheDirImages: cacheDir + "images/" - property string cacheDirImagesWallpapers: cacheDir + "images/wallpapers/" - property string cacheDirImagesNotifications: cacheDir + "images/notifications/" - property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json") - - property string defaultLocation: "Tokyo" - property string defaultAvatar: Quickshell.env("HOME") + "/.face" - property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos" - property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers" + /* + Shell directories. + - Default config directory: ~/.config/noctalia + - Default cache directory: ~/.cache/noctalia + */ + readonly property alias data: adapter // Used to access via Settings.data.xxx.yyy + readonly property int settingsVersion: 25 + readonly property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" + readonly property string shellName: "noctalia" + readonly property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" + readonly property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env("HOME") + "/.cache") + "/" + shellName + "/" + readonly property string cacheDirImages: cacheDir + "images/" + readonly property string cacheDirImagesWallpapers: cacheDir + "images/wallpapers/" + readonly property string cacheDirImagesNotifications: cacheDir + "images/notifications/" + readonly property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json") + readonly property string defaultLocation: "Tokyo" + readonly property string defaultAvatar: Quickshell.env("HOME") + "/.face" + readonly property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos" + readonly property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers" + readonly property string defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png" // Signal emitted when settings are loaded after startupcale changes signal settingsLoaded @@ -64,7 +66,6 @@ Singleton { adapter.general.avatarImage = defaultAvatar; adapter.screenRecorder.directory = defaultVideosDirectory; adapter.wallpaper.directory = defaultWallpapersDirectory; - adapter.wallpaper.defaultWallpaper = Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"; // Set the adapter to the settingsFileView to trigger the real settings load settingsFileView.adapter = adapter; @@ -100,8 +101,8 @@ Singleton { Logger.i("Settings", "Settings loaded"); upgradeSettingsData(); - validateMonitorConfigurations(); - isLoaded = true; + + root.isLoaded = true; // Emit the signal root.settingsLoaded(); @@ -114,10 +115,14 @@ Singleton { if (error.toString().includes("No such file") || error === 2) { // File doesn't exist, create it with default values writeAdapter(); + // Also write to fallback if set if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) { settingsFallbackFileView.writeAdapter(); } + + // We started without settings, we should open the setupWizard + root.shouldOpenSetupWizard = true; } } } @@ -130,11 +135,11 @@ Singleton { printErrors: false watchChanges: false } + JsonAdapter { id: adapter property int settingsVersion: root.settingsVersion - property bool setupCompleted: false // bar property JsonObject bar: JsonObject { @@ -273,7 +278,6 @@ Singleton { property bool enableMultiMonitorDirectories: false property bool recursiveSearch: false property bool setWallpaperOnAllMonitors: true - property string defaultWallpaper: "" property string fillMode: "crop" property color fillColor: "#000000" property bool randomEnabled: false @@ -281,7 +285,6 @@ Singleton { property int transitionDuration: 1500 // 1500 ms property string transitionType: "random" property real transitionEdgeSmoothness: 0.05 - property list monitors: [] property string panelPosition: "follow_bar" property bool hideWallpaperFilenames: false // Wallhaven settings @@ -294,6 +297,9 @@ Singleton { property string wallhavenResolutionMode: "atleast" // "atleast" or "exact" property string wallhavenResolutionWidth: "" property string wallhavenResolutionHeight: "" + + property string defaultWallpaper: "" // TODO REMOVE + property list monitors: [] // TODO REMOVE } // applauncher @@ -389,7 +395,7 @@ Singleton { // dock property JsonObject dock: JsonObject { property bool enabled: true - property string displayMode: "always_visible" // "always_visible", "auto_hide", "exclusive" + property string displayMode: "auto_hide" // "always_visible", "auto_hide", "exclusive" property real backgroundOpacity: 1.0 property real radiusRatio: 0.1 property real floatingRatio: 1.0 @@ -457,12 +463,12 @@ Singleton { // on-screen display property JsonObject osd: JsonObject { property bool enabled: true - property var enabledTypes: [0, 1, 2, 3] property string location: "top_right" - property list monitors: [] property int autoHideMs: 2000 property bool overlayLayer: true property real backgroundOpacity: 1.0 + property list enabledTypes: [] + property list monitors: [] } // audio @@ -589,36 +595,39 @@ Singleton { } // ----------------------------------------------------- - // Function to validate monitor configurations - function validateMonitorConfigurations() { - var availableScreenNames = []; - for (var i = 0; i < Quickshell.screens.length; i++) { - availableScreenNames.push(Quickshell.screens[i].name); + // Function to clean up deprecated user/custom bar widgets settings + function upgradeWidget(widget) { + // Backup the widget definition before altering + const widgetBefore = JSON.stringify(widget); + + // Get all existing custom settings keys + const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id]); + + // Delete deprecated user settings from the wiget + for (const k of Object.keys(widget)) { + if (k === "id" || k === "allowUserSettings") { + continue; + } + if (!keys.includes(k)) { + delete widget[k]; + } } - Logger.d("Settings", "Available monitors: [" + availableScreenNames.join(", ") + "]"); - Logger.d("Settings", "Configured bar monitors: [" + adapter.bar.monitors.join(", ") + "]"); - - // Check bar monitors - if (adapter.bar.monitors.length > 0) { - var hasValidBarMonitor = false; - for (var j = 0; j < adapter.bar.monitors.length; j++) { - if (availableScreenNames.includes(adapter.bar.monitors[j])) { - hasValidBarMonitor = true; - break; - } + // Inject missing default setting (metaData) from BarWidgetRegistry + for (var i = 0; i < keys.length; i++) { + const k = keys[i]; + if (k === "id" || k === "allowUserSettings") { + continue; } - if (!hasValidBarMonitor) { - Logger.w("Settings", "No configured bar monitors found on system, clearing bar monitor list to show on all screens"); - adapter.bar.monitors = []; - } else - //Logger.i("Settings", "Found valid bar monitors, keeping configuration") - {} - } else + if (widget[k] === undefined) { + widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]; + } + } - //Logger.i("Settings", "Bar monitor list is empty, will show on all available screens") - {} + // Compare settings, to detect if something has been upgraded + const widgetAfter = JSON.stringify(widget); + return (widgetAfter !== widgetBefore); } // ----------------------------------------------------- @@ -720,91 +729,7 @@ Singleton { } // ----------------- - // 5th. Migrate Discord templates (version 20 → 21) - // Consolidate individual discord_* properties into unified discord property - if (adapter.settingsVersion < 21) { - // Read raw JSON file to access properties not in adapter schema - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - var anyDiscordEnabled = false; - - // Check if any Discord client was enabled - const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion", "discord_vencord"]; - - if (parsed.templates) { - for (var i = 0; i < discordClients.length; i++) { - if (parsed.templates[discordClients[i]]) { - anyDiscordEnabled = true; - break; - } - } - } - - // Set unified discord property - adapter.templates.discord = anyDiscordEnabled; - - Logger.i("Settings", "Migrated Discord templates to unified 'discord' property (enabled:", anyDiscordEnabled + ")"); - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for Discord migration:", error); - } - } - - // ----------------- - // 6th. Migrate panel background opacity (version 21 → 22) - // Move appLauncher.backgroundOpacity to ui.panelBackgroundOpacity - if (adapter.settingsVersion < 22) { - // Read raw JSON file to access properties not in adapter schema - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - if (parsed.appLauncher && parsed.appLauncher.backgroundOpacity !== undefined) { - var oldOpacity = parsed.appLauncher.backgroundOpacity; - if (adapter.ui) { - adapter.ui.panelBackgroundOpacity = oldOpacity; - Logger.i("Settings", "Migrated appLauncher.backgroundOpacity to ui.panelBackgroundOpacity (value:", oldOpacity + ")"); - } - } - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for migration:", error); - } - } - - // ----------------- - // 7th. Migrate dim desktop settings (version 22 → 23) - // If dimDesktop is enabled, set dimmerOpacity to 0.8 if it's not already set or is 0 - // Then remove dimDesktop property as it's no longer needed - if (adapter.settingsVersion < 23) { - // Read raw JSON file to access dimDesktop property - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - if (parsed.general && parsed.general.dimDesktop === true) { - // Check if dimmerOpacity exists in raw JSON (not adapter default) - var dimmerOpacityInJson = parsed.general.dimmerOpacity; - - // If dimmerOpacity wasn't explicitly set in JSON or was 0, set it to 0.8 (80% dimming) - if (dimmerOpacityInJson === undefined || dimmerOpacityInJson === 0) { - adapter.general.dimmerOpacity = 0.8; - Logger.i("Settings", "Migrated dimDesktop=true: set dimmerOpacity to 0.8 (80% dimming)"); - } - } - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for dimDesktop migration:", error); - } - } - - // ----------------- - // 9th. Normalize OSD enabled types and migrate legacy show* toggles + // TEMP Normalize OSD enabled types and migrate legacy show* toggles try { var osdRawJson = settingsFileView.text(); if (osdRawJson) { @@ -898,19 +823,49 @@ Singleton { // ----------------- // Migrate ShellState-related files from old cache files to ShellState - // This consolidates migrations that were previously in individual service files - if (typeof ShellState !== 'undefined' && ShellState.isLoaded) { - migrateShellStateFiles(); - } else { - // Wait for ShellState to be ready - Qt.callLater(() => { - if (typeof ShellState !== 'undefined' && ShellState.isLoaded) { - migrateShellStateFiles(); - } - }); + // This consolidates migrations that were previously in individual files + if (adapter.settingsVersion < 25) { + // Only migrate the settings once! + if (ShellState?.isLoaded) { + migrateShellStateFiles(); + } else { + // Wait for ShellState to be ready + Qt.callLater(() => { + if (ShellState?.isLoaded) { + migrateShellStateFiles(); + } + }); + } } } + // ----------------------------------------------------- + function buildStateSnapshot() { + try { + const settingsData = QtObj2JS.qtObjectToPlainObject(adapter); + const shellStateData = ShellState?.data ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {}; + + return { + settings: settingsData, + state: { + doNotDisturb: NotificationService.doNotDisturb, + noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode, + barVisible: BarService.isVisible, + display: shellStateData.display || {}, + wallpapers: shellStateData.wallpapers || {}, + notificationsState: shellStateData.notificationsState || {}, + changelogState: shellStateData.changelogState || {}, + colorSchemesList: shellStateData.colorSchemesList || {} + } + }; + } catch (error) { + Logger.e("Settings", "Failed to build state snapshot:", error); + return null; + } + } + + // ----------------------------------------------------- + // --- TO BE REMOVED // ----------------------------------------------------- // Migrate old cache files to ShellState function migrateShellStateFiles() { @@ -930,6 +885,7 @@ Singleton { migrateWallpaperPaths(); } + // ----------------------------------------------------- function migrateDisplayFile() { // Check if ShellState already has display data const cached = ShellState.getDisplay(); @@ -963,6 +919,7 @@ Singleton { `, root, "displayMigrationView"); } + // ----------------------------------------------------- function migrateNotificationsStateFile() { // Check if ShellState already has notifications state const cached = ShellState.getNotificationsState(); @@ -1110,63 +1067,4 @@ Singleton { } } } - - // ----------------------------------------------------- - function upgradeWidget(widget) { - // Backup the widget definition before altering - const widgetBefore = JSON.stringify(widget); - - // Get all existing custom settings keys - const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id]); - - // Delete deprecated user settings from the wiget - for (const k of Object.keys(widget)) { - if (k === "id" || k === "allowUserSettings") { - continue; - } - if (!keys.includes(k)) { - delete widget[k]; - } - } - - // Inject missing default setting (metaData) from BarWidgetRegistry - for (var i = 0; i < keys.length; i++) { - const k = keys[i]; - if (k === "id" || k === "allowUserSettings") { - continue; - } - - if (widget[k] === undefined) { - widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]; - } - } - - // Compare settings, to detect if something has been upgraded - const widgetAfter = JSON.stringify(widget); - return (widgetAfter !== widgetBefore); - } - - function buildStateSnapshot() { - try { - const settingsData = QtObj2JS.qtObjectToPlainObject(adapter); - const shellStateData = (typeof ShellState !== "undefined" && ShellState.data) ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {}; - - return { - settings: settingsData, - state: { - doNotDisturb: NotificationService.doNotDisturb, - noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode, - barVisible: BarService.isVisible, - display: shellStateData.display || {}, - wallpapers: shellStateData.wallpapers || {}, - notificationsState: shellStateData.notificationsState || {}, - changelogState: shellStateData.changelogState || {}, - colorSchemesList: shellStateData.colorSchemesList || {} - } - }; - } catch (error) { - Logger.e("Settings", "Failed to build state snapshot:", error); - return null; - } - } } diff --git a/Modules/Panels/SetupWizard/SetupWizard.qml b/Modules/Panels/SetupWizard/SetupWizard.qml index fc64cc861..7addb49f3 100644 --- a/Modules/Panels/SetupWizard/SetupWizard.qml +++ b/Modules/Panels/SetupWizard/SetupWizard.qml @@ -401,7 +401,6 @@ SmartPanel { Settings.data.general.scaleRatio = selectedScaleRatio; Settings.data.bar.position = selectedBarPosition; - Settings.data.setupCompleted = true; // Save settings immediately and wait for settingsSaved signal before closing Settings.saveImmediate(); diff --git a/Services/Noctalia/UpdateService.qml b/Services/Noctalia/UpdateService.qml index ce8fc292e..bfee6f676 100644 --- a/Services/Noctalia/UpdateService.qml +++ b/Services/Noctalia/UpdateService.qml @@ -79,6 +79,12 @@ Singleton { const fromVersion = changelogFromVersion || ""; const toVersion = changelogToVersion || ""; + if (Settings.shouldOpenSetupWizard) { + // If you'll see the setup wizard then you don't need to see the changelog + markChangelogSeen(toVersion); + return; + } + if (!toVersion) return; @@ -116,7 +122,7 @@ Singleton { // 'from' always need to be before 'to' // handle edge case that will show up as we changed -dev to -git - if (from === to) { + if (from >= to) { from = "v3.0.0"; } diff --git a/Services/UI/WallpaperService.qml b/Services/UI/WallpaperService.qml index a5487596c..f6c5cc4ad 100644 --- a/Services/UI/WallpaperService.qml +++ b/Services/UI/WallpaperService.qml @@ -250,7 +250,7 @@ Singleton { // ------------------------------------------------------------------- // Get specific monitor wallpaper - now from cache function getWallpaper(screenName) { - return currentWallpapers[screenName] || Settings.data.wallpaper.defaultWallpaper; + return currentWallpapers[screenName] || Settings.defaultWallpaper; } // ------------------------------------------------------------------- diff --git a/shell.qml b/shell.qml index b542c95a2..8f7507048 100644 --- a/shell.qml +++ b/shell.qml @@ -71,7 +71,7 @@ ShellRoot { } Connections { - target: typeof ShellState !== 'undefined' ? ShellState : null + target: ShellState ? ShellState : null function onIsLoadedChanged() { if (ShellState.isLoaded) { shellStateLoaded = true; @@ -100,10 +100,7 @@ ShellRoot { UpdateService.init(); UpdateService.showLatestChangelog(); - // Only open the setup wizard for new users - if (!Settings.data.setupCompleted) { - checkSetupWizard(); - } + checkSetupWizard(); } Overview {} @@ -134,7 +131,12 @@ ShellRoot { } function checkSetupWizard() { - // Wait for distro service + // Only open the setup wizard for new users + if (!Settings.shouldOpenSetupWizard) { + return; + } + + // Wait for HostService to be fully ready if (!HostService.isReady) { Qt.callLater(checkSetupWizard); return; @@ -142,16 +144,10 @@ ShellRoot { // No setup wizard on NixOS if (HostService.isNixOS) { - Settings.data.setupCompleted = true; return; } - if (Settings.data.settingsVersion >= Settings.settingsVersion) { - setupWizardTimer.start(); - } else { - Settings.data.setupCompleted = true; - Settings.saveImmediate(); - } + setupWizardTimer.start(); } function showSetupWizard() {