mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
settings: refactor for read-only handling
- Remove default-* copying logic - Allow in-memory changes of settings/session datas - Convert SessionData to newer spec pattern - Migrate weather coords to Session data - Bricks home manager (temporarily)
This commit is contained in:
@@ -7,16 +7,20 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import "settings/SessionSpec.js" as Spec
|
||||
import "settings/SessionStore.js" as Store
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int sessionConfigVersion: 1
|
||||
readonly property int sessionConfigVersion: 2
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
property bool hasTriedDefaultSession: false
|
||||
property bool _parseError: false
|
||||
property bool _hasLoaded: false
|
||||
property bool _isReadOnly: false
|
||||
property bool _hasUnsavedChanges: false
|
||||
property var _loadedSessionSnapshot: null
|
||||
readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation)
|
||||
readonly property string _stateDir: Paths.strip(_stateUrl)
|
||||
|
||||
@@ -95,18 +99,52 @@ Singleton {
|
||||
property string wifiDeviceOverride: ""
|
||||
property bool weatherHourlyDetailed: true
|
||||
|
||||
property string weatherLocation: "New York, NY"
|
||||
property string weatherCoordinates: "40.7128,-74.0060"
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
property var _pendingMigration: null
|
||||
|
||||
function loadSettings() {
|
||||
_hasUnsavedChanges = false;
|
||||
_pendingMigration = null;
|
||||
|
||||
if (isGreeterMode) {
|
||||
parseSettings(greeterSessionFile.text());
|
||||
} else {
|
||||
parseSettings(settingsFile.text());
|
||||
return;
|
||||
}
|
||||
parseSettings(settingsFile.text());
|
||||
_checkSessionWritable();
|
||||
}
|
||||
|
||||
function _checkSessionWritable() {
|
||||
sessionWritableCheckProcess.running = true;
|
||||
}
|
||||
|
||||
function _onWritableCheckComplete(writable) {
|
||||
_isReadOnly = !writable;
|
||||
if (_isReadOnly) {
|
||||
console.info("SessionData: session.json is read-only (NixOS home-manager mode)");
|
||||
} else if (_pendingMigration) {
|
||||
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
|
||||
}
|
||||
_pendingMigration = null;
|
||||
}
|
||||
|
||||
function _checkForUnsavedChanges() {
|
||||
if (!_hasLoaded || !_loadedSessionSnapshot)
|
||||
return false;
|
||||
const current = getCurrentSessionJson();
|
||||
return current !== _loadedSessionSnapshot;
|
||||
}
|
||||
|
||||
function getCurrentSessionJson() {
|
||||
return JSON.stringify(Store.toJson(root), null, 2);
|
||||
}
|
||||
|
||||
function parseSettings(content) {
|
||||
@@ -116,79 +154,48 @@ Singleton {
|
||||
_parseError = true;
|
||||
return;
|
||||
}
|
||||
var settings = JSON.parse(content);
|
||||
isLightMode = settings.isLightMode !== undefined ? settings.isLightMode : false;
|
||||
|
||||
if (settings.wallpaperPath && settings.wallpaperPath.startsWith("we:")) {
|
||||
let obj = JSON.parse(content);
|
||||
|
||||
if (obj.brightnessLogarithmicDevices && !obj.brightnessExponentialDevices) {
|
||||
obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices;
|
||||
}
|
||||
|
||||
if (obj.nightModeStartTime !== undefined) {
|
||||
const parts = obj.nightModeStartTime.split(":");
|
||||
obj.nightModeStartHour = parseInt(parts[0]) || 18;
|
||||
obj.nightModeStartMinute = parseInt(parts[1]) || 0;
|
||||
}
|
||||
if (obj.nightModeEndTime !== undefined) {
|
||||
const parts = obj.nightModeEndTime.split(":");
|
||||
obj.nightModeEndHour = parseInt(parts[0]) || 6;
|
||||
obj.nightModeEndMinute = parseInt(parts[1]) || 0;
|
||||
}
|
||||
|
||||
const oldVersion = obj.configVersion ?? 0;
|
||||
if (oldVersion === 0) {
|
||||
migrateFromUndefinedToV1(obj);
|
||||
}
|
||||
|
||||
if (oldVersion < sessionConfigVersion) {
|
||||
const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null;
|
||||
const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef);
|
||||
if (migrated) {
|
||||
_pendingMigration = migrated;
|
||||
obj = migrated;
|
||||
}
|
||||
}
|
||||
|
||||
Store.parse(root, obj);
|
||||
|
||||
if (wallpaperPath && wallpaperPath.startsWith("we:")) {
|
||||
console.warn("WallpaperEngine wallpaper detected, resetting wallpaper");
|
||||
wallpaperPath = "";
|
||||
Quickshell.execDetached(["notify-send", "-u", "critical", "-a", "DMS", "-i", "dialog-warning", "WallpaperEngine Support Moved", "WallpaperEngine support has been moved to a plugin. Please enable the Linux Wallpaper Engine plugin in Settings → Plugins to continue using WallpaperEngine."]);
|
||||
} else {
|
||||
wallpaperPath = settings.wallpaperPath !== undefined ? settings.wallpaperPath : "";
|
||||
}
|
||||
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false;
|
||||
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {};
|
||||
perModeWallpaper = settings.perModeWallpaper !== undefined ? settings.perModeWallpaper : false;
|
||||
wallpaperPathLight = settings.wallpaperPathLight !== undefined ? settings.wallpaperPathLight : "";
|
||||
wallpaperPathDark = settings.wallpaperPathDark !== undefined ? settings.wallpaperPathDark : "";
|
||||
monitorWallpapersLight = settings.monitorWallpapersLight !== undefined ? settings.monitorWallpapersLight : {};
|
||||
monitorWallpapersDark = settings.monitorWallpapersDark !== undefined ? settings.monitorWallpapersDark : {};
|
||||
brightnessExponentialDevices = settings.brightnessExponentialDevices !== undefined ? settings.brightnessExponentialDevices : (settings.brightnessLogarithmicDevices || {});
|
||||
brightnessUserSetValues = settings.brightnessUserSetValues !== undefined ? settings.brightnessUserSetValues : {};
|
||||
brightnessExponentValues = settings.brightnessExponentValues !== undefined ? settings.brightnessExponentValues : {};
|
||||
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false;
|
||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false;
|
||||
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500;
|
||||
nightModeHighTemperature = settings.nightModeHighTemperature !== undefined ? settings.nightModeHighTemperature : 6500;
|
||||
nightModeAutoEnabled = settings.nightModeAutoEnabled !== undefined ? settings.nightModeAutoEnabled : false;
|
||||
nightModeAutoMode = settings.nightModeAutoMode !== undefined ? settings.nightModeAutoMode : "time";
|
||||
if (settings.nightModeStartTime !== undefined) {
|
||||
const parts = settings.nightModeStartTime.split(":");
|
||||
nightModeStartHour = parseInt(parts[0]) || 18;
|
||||
nightModeStartMinute = parseInt(parts[1]) || 0;
|
||||
} else {
|
||||
nightModeStartHour = settings.nightModeStartHour !== undefined ? settings.nightModeStartHour : 18;
|
||||
nightModeStartMinute = settings.nightModeStartMinute !== undefined ? settings.nightModeStartMinute : 0;
|
||||
}
|
||||
if (settings.nightModeEndTime !== undefined) {
|
||||
const parts = settings.nightModeEndTime.split(":");
|
||||
nightModeEndHour = parseInt(parts[0]) || 6;
|
||||
nightModeEndMinute = parseInt(parts[1]) || 0;
|
||||
} else {
|
||||
nightModeEndHour = settings.nightModeEndHour !== undefined ? settings.nightModeEndHour : 6;
|
||||
nightModeEndMinute = settings.nightModeEndMinute !== undefined ? settings.nightModeEndMinute : 0;
|
||||
}
|
||||
latitude = settings.latitude !== undefined ? settings.latitude : 0.0;
|
||||
longitude = settings.longitude !== undefined ? settings.longitude : 0.0;
|
||||
nightModeUseIPLocation = settings.nightModeUseIPLocation !== undefined ? settings.nightModeUseIPLocation : false;
|
||||
nightModeLocationProvider = settings.nightModeLocationProvider !== undefined ? settings.nightModeLocationProvider : "";
|
||||
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : [];
|
||||
hiddenTrayIds = settings.hiddenTrayIds !== undefined ? settings.hiddenTrayIds : [];
|
||||
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0;
|
||||
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false;
|
||||
nonNvidiaGpuTempEnabled = settings.nonNvidiaGpuTempEnabled !== undefined ? settings.nonNvidiaGpuTempEnabled : false;
|
||||
enabledGpuPciIds = settings.enabledGpuPciIds !== undefined ? settings.enabledGpuPciIds : [];
|
||||
wifiDeviceOverride = settings.wifiDeviceOverride !== undefined ? settings.wifiDeviceOverride : "";
|
||||
weatherHourlyDetailed = settings.weatherHourlyDetailed !== undefined ? settings.weatherHourlyDetailed : true;
|
||||
wallpaperCyclingEnabled = settings.wallpaperCyclingEnabled !== undefined ? settings.wallpaperCyclingEnabled : false;
|
||||
wallpaperCyclingMode = settings.wallpaperCyclingMode !== undefined ? settings.wallpaperCyclingMode : "interval";
|
||||
wallpaperCyclingInterval = settings.wallpaperCyclingInterval !== undefined ? settings.wallpaperCyclingInterval : 300;
|
||||
wallpaperCyclingTime = settings.wallpaperCyclingTime !== undefined ? settings.wallpaperCyclingTime : "06:00";
|
||||
monitorCyclingSettings = settings.monitorCyclingSettings !== undefined ? settings.monitorCyclingSettings : {};
|
||||
lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : "";
|
||||
launchPrefix = settings.launchPrefix !== undefined ? settings.launchPrefix : "";
|
||||
wallpaperTransition = settings.wallpaperTransition !== undefined ? settings.wallpaperTransition : "fade";
|
||||
includedTransitions = settings.includedTransitions !== undefined ? settings.includedTransitions : availableWallpaperTransitions.filter(t => t !== "none");
|
||||
recentColors = settings.recentColors !== undefined ? settings.recentColors : [];
|
||||
showThirdPartyPlugins = settings.showThirdPartyPlugins !== undefined ? settings.showThirdPartyPlugins : false;
|
||||
_hasLoaded = true;
|
||||
|
||||
if (settings.configVersion === undefined) {
|
||||
migrateFromUndefinedToV1(settings);
|
||||
saveSettings();
|
||||
} else if (settings.configVersion === sessionConfigVersion) {
|
||||
cleanupUnusedKeys();
|
||||
}
|
||||
_hasLoaded = true;
|
||||
_loadedSessionSnapshot = getCurrentSessionJson();
|
||||
|
||||
if (!isGreeterMode && typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme();
|
||||
@@ -208,54 +215,11 @@ Singleton {
|
||||
function saveSettings() {
|
||||
if (isGreeterMode || _parseError || !_hasLoaded)
|
||||
return;
|
||||
settingsFile.setText(JSON.stringify({
|
||||
"isLightMode": isLightMode,
|
||||
"wallpaperPath": wallpaperPath,
|
||||
"perMonitorWallpaper": perMonitorWallpaper,
|
||||
"monitorWallpapers": monitorWallpapers,
|
||||
"perModeWallpaper": perModeWallpaper,
|
||||
"wallpaperPathLight": wallpaperPathLight,
|
||||
"wallpaperPathDark": wallpaperPathDark,
|
||||
"monitorWallpapersLight": monitorWallpapersLight,
|
||||
"monitorWallpapersDark": monitorWallpapersDark,
|
||||
"brightnessExponentialDevices": brightnessExponentialDevices,
|
||||
"brightnessUserSetValues": brightnessUserSetValues,
|
||||
"brightnessExponentValues": brightnessExponentValues,
|
||||
"doNotDisturb": doNotDisturb,
|
||||
"nightModeEnabled": nightModeEnabled,
|
||||
"nightModeTemperature": nightModeTemperature,
|
||||
"nightModeHighTemperature": nightModeHighTemperature,
|
||||
"nightModeAutoEnabled": nightModeAutoEnabled,
|
||||
"nightModeAutoMode": nightModeAutoMode,
|
||||
"nightModeStartHour": nightModeStartHour,
|
||||
"nightModeStartMinute": nightModeStartMinute,
|
||||
"nightModeEndHour": nightModeEndHour,
|
||||
"nightModeEndMinute": nightModeEndMinute,
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"nightModeUseIPLocation": nightModeUseIPLocation,
|
||||
"nightModeLocationProvider": nightModeLocationProvider,
|
||||
"pinnedApps": pinnedApps,
|
||||
"hiddenTrayIds": hiddenTrayIds,
|
||||
"selectedGpuIndex": selectedGpuIndex,
|
||||
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
|
||||
"nonNvidiaGpuTempEnabled": nonNvidiaGpuTempEnabled,
|
||||
"enabledGpuPciIds": enabledGpuPciIds,
|
||||
"wifiDeviceOverride": wifiDeviceOverride,
|
||||
"weatherHourlyDetailed": weatherHourlyDetailed,
|
||||
"wallpaperCyclingEnabled": wallpaperCyclingEnabled,
|
||||
"wallpaperCyclingMode": wallpaperCyclingMode,
|
||||
"wallpaperCyclingInterval": wallpaperCyclingInterval,
|
||||
"wallpaperCyclingTime": wallpaperCyclingTime,
|
||||
"monitorCyclingSettings": monitorCyclingSettings,
|
||||
"lastBrightnessDevice": lastBrightnessDevice,
|
||||
"launchPrefix": launchPrefix,
|
||||
"wallpaperTransition": wallpaperTransition,
|
||||
"includedTransitions": includedTransitions,
|
||||
"recentColors": recentColors,
|
||||
"showThirdPartyPlugins": showThirdPartyPlugins,
|
||||
"configVersion": sessionConfigVersion
|
||||
}, null, 2));
|
||||
if (_isReadOnly) {
|
||||
_hasUnsavedChanges = _checkForUnsavedChanges();
|
||||
return;
|
||||
}
|
||||
settingsFile.setText(getCurrentSessionJson());
|
||||
}
|
||||
|
||||
function migrateFromUndefinedToV1(settings) {
|
||||
@@ -306,32 +270,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
const validKeys = ["isLightMode", "wallpaperPath", "perMonitorWallpaper", "monitorWallpapers", "perModeWallpaper", "wallpaperPathLight", "wallpaperPathDark", "monitorWallpapersLight", "monitorWallpapersDark", "doNotDisturb", "nightModeEnabled", "nightModeTemperature", "nightModeHighTemperature", "nightModeAutoEnabled", "nightModeAutoMode", "nightModeStartHour", "nightModeStartMinute", "nightModeEndHour", "nightModeEndMinute", "latitude", "longitude", "nightModeUseIPLocation", "nightModeLocationProvider", "pinnedApps", "hiddenTrayIds", "selectedGpuIndex", "nvidiaGpuTempEnabled", "nonNvidiaGpuTempEnabled", "enabledGpuPciIds", "wifiDeviceOverride", "weatherHourlyDetailed", "wallpaperCyclingEnabled", "wallpaperCyclingMode", "wallpaperCyclingInterval", "wallpaperCyclingTime", "monitorCyclingSettings", "lastBrightnessDevice", "brightnessExponentialDevices", "brightnessUserSetValues", "brightnessExponentValues", "launchPrefix", "wallpaperTransition", "includedTransitions", "recentColors", "showThirdPartyPlugins", "configVersion"];
|
||||
|
||||
try {
|
||||
const content = settingsFile.text();
|
||||
if (!content || !content.trim())
|
||||
return;
|
||||
const settings = JSON.parse(content);
|
||||
let needsSave = false;
|
||||
|
||||
for (const key in settings) {
|
||||
if (!validKeys.includes(key)) {
|
||||
console.log("SessionData: Removing unused key:", key);
|
||||
delete settings[key];
|
||||
needsSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
settingsFile.setText(JSON.stringify(settings, null, 2));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SessionData: Failed to cleanup unused keys:", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function setLightMode(lightMode) {
|
||||
isSwitchingMode = true;
|
||||
isLightMode = lightMode;
|
||||
@@ -923,6 +861,12 @@ Singleton {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function setWeatherLocation(displayName, coordinates) {
|
||||
weatherLocation = displayName;
|
||||
weatherCoordinates = coordinates;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function syncWallpaperForCurrentMode() {
|
||||
if (!perModeWallpaper)
|
||||
return;
|
||||
@@ -1005,14 +949,8 @@ Singleton {
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
_hasUnsavedChanges = false;
|
||||
parseSettings(settingsFile.text());
|
||||
hasTriedDefaultSession = false;
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSession) {
|
||||
hasTriedDefaultSession = true;
|
||||
defaultSessionCheckProcess.running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1037,14 +975,17 @@ Singleton {
|
||||
}
|
||||
|
||||
Process {
|
||||
id: defaultSessionCheckProcess
|
||||
id: sessionWritableCheckProcess
|
||||
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + _stateDir + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-session.json\" ] && [ ! -f \"$CONFIG_DIR/session.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-session.json\" \"$CONFIG_DIR/session.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
property string sessionPath: Paths.strip(settingsFile.path)
|
||||
|
||||
command: ["sh", "-c", "[ -w \"" + sessionPath + "\" ] && echo 'writable' || echo 'readonly'"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
console.info("Copied default-session.json to session.json");
|
||||
settingsFile.reload();
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const result = text.trim();
|
||||
root._onWritableCheckComplete(result === "writable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import "settings/SettingsStore.js" as Store
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int settingsConfigVersion: 4
|
||||
readonly property int settingsConfigVersion: 5
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
|
||||
@@ -58,7 +58,9 @@ Singleton {
|
||||
property bool _parseError: false
|
||||
property bool _pluginParseError: false
|
||||
property bool _hasLoaded: false
|
||||
property bool hasTriedDefaultSettings: false
|
||||
property bool _isReadOnly: false
|
||||
property bool _hasUnsavedChanges: false
|
||||
property var _loadedSettingsSnapshot: null
|
||||
property var pluginSettings: ({})
|
||||
|
||||
property alias dankBarLeftWidgetsModel: leftWidgetsModel
|
||||
@@ -202,8 +204,10 @@ Singleton {
|
||||
property bool spotlightCloseNiriOverview: true
|
||||
property bool niriOverviewOverlayEnabled: true
|
||||
|
||||
property string weatherLocation: "New York, NY"
|
||||
property string weatherCoordinates: "40.7128,-74.0060"
|
||||
property string _legacyWeatherLocation: "New York, NY"
|
||||
property string _legacyWeatherCoordinates: "40.7128,-74.0060"
|
||||
readonly property string weatherLocation: SessionData.weatherLocation
|
||||
readonly property string weatherCoordinates: SessionData.weatherCoordinates
|
||||
property bool useAutoLocation: false
|
||||
property bool weatherEnabled: true
|
||||
|
||||
@@ -776,6 +780,9 @@ Singleton {
|
||||
function loadSettings() {
|
||||
_loading = true;
|
||||
_parseError = false;
|
||||
_hasUnsavedChanges = false;
|
||||
_pendingMigration = null;
|
||||
|
||||
try {
|
||||
const txt = settingsFile.text();
|
||||
let obj = (txt && txt.trim()) ? JSON.parse(txt) : null;
|
||||
@@ -784,16 +791,25 @@ Singleton {
|
||||
if (oldVersion < settingsConfigVersion) {
|
||||
const migrated = Store.migrateToVersion(obj, settingsConfigVersion);
|
||||
if (migrated) {
|
||||
settingsFile.setText(JSON.stringify(migrated, null, 2));
|
||||
_pendingMigration = migrated;
|
||||
obj = migrated;
|
||||
}
|
||||
}
|
||||
|
||||
Store.parse(root, obj);
|
||||
|
||||
if (obj.weatherLocation !== undefined)
|
||||
_legacyWeatherLocation = obj.weatherLocation;
|
||||
if (obj.weatherCoordinates !== undefined)
|
||||
_legacyWeatherCoordinates = obj.weatherCoordinates;
|
||||
|
||||
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
|
||||
_hasLoaded = true;
|
||||
applyStoredTheme();
|
||||
applyStoredIconTheme();
|
||||
Processes.detectQtTools();
|
||||
|
||||
_checkSettingsWritable();
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
const msg = e.message;
|
||||
@@ -807,6 +823,33 @@ Singleton {
|
||||
loadPluginSettings();
|
||||
}
|
||||
|
||||
property var _pendingMigration: null
|
||||
|
||||
function _checkSettingsWritable() {
|
||||
settingsWritableCheckProcess.running = true;
|
||||
}
|
||||
|
||||
function _onWritableCheckComplete(writable) {
|
||||
_isReadOnly = !writable;
|
||||
if (_isReadOnly) {
|
||||
console.info("SettingsData: settings.json is read-only (NixOS home-manager mode)");
|
||||
} else if (_pendingMigration) {
|
||||
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
|
||||
}
|
||||
_pendingMigration = null;
|
||||
}
|
||||
|
||||
function _checkForUnsavedChanges() {
|
||||
if (!_hasLoaded || !_loadedSettingsSnapshot)
|
||||
return false;
|
||||
const current = JSON.stringify(Store.toJson(root));
|
||||
return current !== _loadedSettingsSnapshot;
|
||||
}
|
||||
|
||||
function getCurrentSettingsJson() {
|
||||
return JSON.stringify(Store.toJson(root), null, 2);
|
||||
}
|
||||
|
||||
function loadPluginSettings() {
|
||||
_pluginSettingsLoading = true;
|
||||
parsePluginSettings(pluginSettingsFile.text());
|
||||
@@ -836,6 +879,10 @@ Singleton {
|
||||
function saveSettings() {
|
||||
if (_loading || _parseError || !_hasLoaded)
|
||||
return;
|
||||
if (_isReadOnly) {
|
||||
_hasUnsavedChanges = _checkForUnsavedChanges();
|
||||
return;
|
||||
}
|
||||
settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2));
|
||||
}
|
||||
|
||||
@@ -1400,9 +1447,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function setWeatherLocation(displayName, coordinates) {
|
||||
weatherLocation = displayName;
|
||||
weatherCoordinates = coordinates;
|
||||
saveSettings();
|
||||
SessionData.setWeatherLocation(displayName, coordinates);
|
||||
}
|
||||
|
||||
function setIconTheme(themeName) {
|
||||
@@ -1800,6 +1845,7 @@ Singleton {
|
||||
if (isGreeterMode)
|
||||
return;
|
||||
_loading = true;
|
||||
_hasUnsavedChanges = false;
|
||||
try {
|
||||
const txt = settingsFile.text();
|
||||
if (!txt || !txt.trim()) {
|
||||
@@ -1809,6 +1855,13 @@ Singleton {
|
||||
const obj = JSON.parse(txt);
|
||||
_parseError = false;
|
||||
Store.parse(root, obj);
|
||||
|
||||
if (obj.weatherLocation !== undefined)
|
||||
_legacyWeatherLocation = obj.weatherLocation;
|
||||
if (obj.weatherCoordinates !== undefined)
|
||||
_legacyWeatherCoordinates = obj.weatherCoordinates;
|
||||
|
||||
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
|
||||
_hasLoaded = true;
|
||||
applyStoredTheme();
|
||||
applyStoredIconTheme();
|
||||
@@ -1820,13 +1873,9 @@ Singleton {
|
||||
} finally {
|
||||
_loading = false;
|
||||
}
|
||||
hasTriedDefaultSettings = false;
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
||||
hasTriedDefaultSettings = true;
|
||||
Processes.checkDefaultSettings();
|
||||
} else if (!isGreeterMode) {
|
||||
if (!isGreeterMode) {
|
||||
applyStoredTheme();
|
||||
}
|
||||
}
|
||||
@@ -1853,4 +1902,20 @@ Singleton {
|
||||
}
|
||||
|
||||
property bool pluginSettingsFileExists: false
|
||||
|
||||
Process {
|
||||
id: settingsWritableCheckProcess
|
||||
|
||||
property string settingsPath: Paths.strip(settingsFile.path)
|
||||
|
||||
command: ["sh", "-c", "[ -w \"" + settingsPath + "\" ] && echo 'writable' || echo 'readonly'"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const result = text.trim();
|
||||
root._onWritableCheckComplete(result === "writable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@ Singleton {
|
||||
pluginSettingsCheckProcess.running = true;
|
||||
}
|
||||
|
||||
function checkDefaultSettings() {
|
||||
defaultSettingsCheckProcess.running = true;
|
||||
}
|
||||
|
||||
property var qtToolsDetectionProcess: Process {
|
||||
command: ["sh", "-c", "echo -n 'qt5ct:'; command -v qt5ct >/dev/null && echo 'true' || echo 'false'; echo -n 'qt6ct:'; command -v qt6ct >/dev/null && echo 'true' || echo 'false'; echo -n 'gtk:'; (command -v gsettings >/dev/null || command -v dconf >/dev/null) && echo 'true' || echo 'false'"]
|
||||
running: false
|
||||
@@ -51,25 +47,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
property var defaultSettingsCheckProcess: Process {
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + (settingsRoot?._configDir || "") + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
running: false
|
||||
onExited: function (exitCode) {
|
||||
if (!settingsRoot)
|
||||
return;
|
||||
if (exitCode === 0) {
|
||||
console.info("Copied default-settings.json to settings.json");
|
||||
if (settingsRoot.settingsFile) {
|
||||
settingsRoot.settingsFile.reload();
|
||||
}
|
||||
} else {
|
||||
if (typeof ThemeApplier !== "undefined") {
|
||||
ThemeApplier.applyStoredTheme(settingsRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var fprintdDetectionProcess: Process {
|
||||
command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"]
|
||||
running: false
|
||||
|
||||
63
quickshell/Common/settings/SessionSpec.js
Normal file
63
quickshell/Common/settings/SessionSpec.js
Normal file
@@ -0,0 +1,63 @@
|
||||
.pragma library
|
||||
|
||||
var SPEC = {
|
||||
isLightMode: { def: false },
|
||||
doNotDisturb: { def: false },
|
||||
|
||||
wallpaperPath: { def: "" },
|
||||
perMonitorWallpaper: { def: false },
|
||||
monitorWallpapers: { def: {} },
|
||||
perModeWallpaper: { def: false },
|
||||
wallpaperPathLight: { def: "" },
|
||||
wallpaperPathDark: { def: "" },
|
||||
monitorWallpapersLight: { def: {} },
|
||||
monitorWallpapersDark: { def: {} },
|
||||
wallpaperTransition: { def: "fade" },
|
||||
includedTransitions: { def: ["fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] },
|
||||
|
||||
wallpaperCyclingEnabled: { def: false },
|
||||
wallpaperCyclingMode: { def: "interval" },
|
||||
wallpaperCyclingInterval: { def: 300 },
|
||||
wallpaperCyclingTime: { def: "06:00" },
|
||||
monitorCyclingSettings: { def: {} },
|
||||
|
||||
nightModeEnabled: { def: false },
|
||||
nightModeTemperature: { def: 4500 },
|
||||
nightModeHighTemperature: { def: 6500 },
|
||||
nightModeAutoEnabled: { def: false },
|
||||
nightModeAutoMode: { def: "time" },
|
||||
nightModeStartHour: { def: 18 },
|
||||
nightModeStartMinute: { def: 0 },
|
||||
nightModeEndHour: { def: 6 },
|
||||
nightModeEndMinute: { def: 0 },
|
||||
latitude: { def: 0.0 },
|
||||
longitude: { def: 0.0 },
|
||||
nightModeUseIPLocation: { def: false },
|
||||
nightModeLocationProvider: { def: "" },
|
||||
|
||||
weatherLocation: { def: "New York, NY" },
|
||||
weatherCoordinates: { def: "40.7128,-74.0060" },
|
||||
|
||||
pinnedApps: { def: [] },
|
||||
hiddenTrayIds: { def: [] },
|
||||
recentColors: { def: [] },
|
||||
showThirdPartyPlugins: { def: false },
|
||||
launchPrefix: { def: "" },
|
||||
lastBrightnessDevice: { def: "" },
|
||||
|
||||
brightnessExponentialDevices: { def: {} },
|
||||
brightnessUserSetValues: { def: {} },
|
||||
brightnessExponentValues: { def: {} },
|
||||
|
||||
selectedGpuIndex: { def: 0 },
|
||||
nvidiaGpuTempEnabled: { def: false },
|
||||
nonNvidiaGpuTempEnabled: { def: false },
|
||||
enabledGpuPciIds: { def: [] },
|
||||
|
||||
wifiDeviceOverride: { def: "" },
|
||||
weatherHourlyDetailed: { def: true }
|
||||
};
|
||||
|
||||
function getValidKeys() {
|
||||
return Object.keys(SPEC).concat(["configVersion"]);
|
||||
}
|
||||
92
quickshell/Common/settings/SessionStore.js
Normal file
92
quickshell/Common/settings/SessionStore.js
Normal file
@@ -0,0 +1,92 @@
|
||||
.pragma library
|
||||
|
||||
.import "./SessionSpec.js" as SpecModule
|
||||
|
||||
function parse(root, jsonObj) {
|
||||
var SPEC = SpecModule.SPEC;
|
||||
for (var k in SPEC) {
|
||||
root[k] = SPEC[k].def;
|
||||
}
|
||||
|
||||
if (!jsonObj) return;
|
||||
|
||||
for (var k in jsonObj) {
|
||||
if (!SPEC[k]) continue;
|
||||
var raw = jsonObj[k];
|
||||
var spec = SPEC[k];
|
||||
var coerce = spec.coerce;
|
||||
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
|
||||
}
|
||||
}
|
||||
|
||||
function toJson(root) {
|
||||
var SPEC = SpecModule.SPEC;
|
||||
var out = {};
|
||||
for (var k in SPEC) {
|
||||
if (SPEC[k].persist === false) continue;
|
||||
out[k] = root[k];
|
||||
}
|
||||
out.configVersion = root.sessionConfigVersion;
|
||||
return out;
|
||||
}
|
||||
|
||||
function migrateToVersion(obj, targetVersion, settingsData) {
|
||||
if (!obj) return null;
|
||||
|
||||
var session = JSON.parse(JSON.stringify(obj));
|
||||
var currentVersion = session.configVersion || 0;
|
||||
|
||||
if (currentVersion >= targetVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (currentVersion < 2) {
|
||||
console.info("SessionData: Migrating session from version", currentVersion, "to version 2");
|
||||
console.info("SessionData: Importing weather location and coordinates from settings");
|
||||
|
||||
if (settingsData && typeof settingsData !== "undefined") {
|
||||
if (session.weatherLocation === undefined || session.weatherLocation === "New York, NY") {
|
||||
var settingsWeatherLocation = settingsData._legacyWeatherLocation;
|
||||
if (settingsWeatherLocation && settingsWeatherLocation !== "New York, NY") {
|
||||
session.weatherLocation = settingsWeatherLocation;
|
||||
console.info("SessionData: Migrated weatherLocation:", settingsWeatherLocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (session.weatherCoordinates === undefined || session.weatherCoordinates === "40.7128,-74.0060") {
|
||||
var settingsWeatherCoordinates = settingsData._legacyWeatherCoordinates;
|
||||
if (settingsWeatherCoordinates && settingsWeatherCoordinates !== "40.7128,-74.0060") {
|
||||
session.weatherCoordinates = settingsWeatherCoordinates;
|
||||
console.info("SessionData: Migrated weatherCoordinates:", settingsWeatherCoordinates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.configVersion = 2;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
function cleanup(fileText) {
|
||||
var getValidKeys = SpecModule.getValidKeys;
|
||||
if (!fileText || !fileText.trim()) return null;
|
||||
|
||||
try {
|
||||
var session = JSON.parse(fileText);
|
||||
var validKeys = getValidKeys();
|
||||
var needsSave = false;
|
||||
|
||||
for (var key in session) {
|
||||
if (validKeys.indexOf(key) < 0) {
|
||||
delete session[key];
|
||||
needsSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
return needsSave ? JSON.stringify(session, null, 2) : null;
|
||||
} catch (e) {
|
||||
console.warn("SessionData: Failed to cleanup unused keys:", e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -112,8 +112,6 @@ var SPEC = {
|
||||
spotlightCloseNiriOverview: { def: true },
|
||||
niriOverviewOverlayEnabled: { def: true },
|
||||
|
||||
weatherLocation: { def: "New York, NY" },
|
||||
weatherCoordinates: { def: "40.7128,-74.0060" },
|
||||
useAutoLocation: { def: false },
|
||||
weatherEnabled: { def: true },
|
||||
|
||||
|
||||
@@ -214,6 +214,16 @@ function migrateToVersion(obj, targetVersion) {
|
||||
settings.configVersion = 4;
|
||||
}
|
||||
|
||||
if (currentVersion < 5) {
|
||||
console.info("Migrating settings from version", currentVersion, "to version 5");
|
||||
console.info("Moving sensitive data (weather location, coordinates) to session.json");
|
||||
|
||||
delete settings.weatherLocation;
|
||||
delete settings.weatherCoordinates;
|
||||
|
||||
settings.configVersion = 5;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,9 +220,91 @@ FloatingWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: readOnlyBanner
|
||||
|
||||
property bool showBanner: (SettingsData._isReadOnly && SettingsData._hasUnsavedChanges) || (SessionData._isReadOnly && SessionData._hasUnsavedChanges)
|
||||
|
||||
width: parent.width
|
||||
height: showBanner ? bannerContent.implicitHeight + Theme.spacingM * 2 : 0
|
||||
color: Theme.surfaceContainerHigh
|
||||
visible: showBanner
|
||||
clip: true
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: bannerContent
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: bannerText
|
||||
|
||||
text: I18n.tr("Settings are read-only. Changes will not persist.", "read-only settings warning for NixOS home-manager users")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Math.max(100, parent.width - (copySettingsButton.visible ? copySettingsButton.width + Theme.spacingM : 0) - (copySessionButton.visible ? copySessionButton.width + Theme.spacingM : 0) - Theme.spacingM * 2 - Theme.iconSize)
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: copySettingsButton
|
||||
|
||||
visible: SettingsData._isReadOnly && SettingsData._hasUnsavedChanges
|
||||
text: "settings.json"
|
||||
iconName: "content_copy"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
buttonHeight: 32
|
||||
horizontalPadding: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
Quickshell.execDetached(["dms", "cl", "copy", SettingsData.getCurrentSettingsJson()]);
|
||||
ToastService.showInfo(I18n.tr("Copied to clipboard"));
|
||||
}
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: copySessionButton
|
||||
|
||||
visible: SessionData._isReadOnly && SessionData._hasUnsavedChanges
|
||||
text: "session.json"
|
||||
iconName: "content_copy"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
buttonHeight: 32
|
||||
horizontalPadding: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
Quickshell.execDetached(["dms", "cl", "copy", SessionData.getCurrentSessionJson()]);
|
||||
ToastService.showInfo(I18n.tr("Copied to clipboard"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: parent.height - 48
|
||||
height: parent.height - 48 - readOnlyBanner.height
|
||||
clip: true
|
||||
|
||||
SettingsSidebar {
|
||||
|
||||
@@ -455,8 +455,8 @@ Item {
|
||||
onTextEdited: {
|
||||
if (text && longitudeInput.text) {
|
||||
const coords = text + "," + longitudeInput.text;
|
||||
SettingsData.weatherCoordinates = coords;
|
||||
SettingsData.saveSettings();
|
||||
SessionData.weatherCoordinates = coords;
|
||||
SessionData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,8 +505,8 @@ Item {
|
||||
onTextEdited: {
|
||||
if (text && latitudeInput.text) {
|
||||
const coords = latitudeInput.text + "," + text;
|
||||
SettingsData.weatherCoordinates = coords;
|
||||
SettingsData.saveSettings();
|
||||
SessionData.weatherCoordinates = coords;
|
||||
SessionData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ Rectangle {
|
||||
radius: parent.radius
|
||||
color: {
|
||||
if (pressed)
|
||||
return Theme.primaryPressed;
|
||||
return Theme.withAlpha(root.textColor, 0.20);
|
||||
if (hovered)
|
||||
return Theme.primaryHover;
|
||||
return Theme.withAlpha(root.textColor, 0.12);
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user