mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
Default settings generation completed!
This commit is contained in:
182
Assets/settings-default.json
Normal file
182
Assets/settings-default.json
Normal file
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"settingsVersion": 3,
|
||||
"bar": {
|
||||
"position": "top",
|
||||
"backgroundOpacity": 1,
|
||||
"monitors": [],
|
||||
"density": "default",
|
||||
"showCapsule": true,
|
||||
"floating": false,
|
||||
"marginVertical": 0.25,
|
||||
"marginHorizontal": 0.25,
|
||||
"widgets": {
|
||||
"left": [
|
||||
{
|
||||
"id": "SystemMonitor"
|
||||
},
|
||||
{
|
||||
"id": "ActiveWindow"
|
||||
},
|
||||
{
|
||||
"id": "MediaMini"
|
||||
}
|
||||
],
|
||||
"center": [
|
||||
{
|
||||
"id": "Workspace"
|
||||
}
|
||||
],
|
||||
"right": [
|
||||
{
|
||||
"id": "ScreenRecorderIndicator"
|
||||
},
|
||||
{
|
||||
"id": "Tray"
|
||||
},
|
||||
{
|
||||
"id": "NotificationHistory"
|
||||
},
|
||||
{
|
||||
"id": "WiFi"
|
||||
},
|
||||
{
|
||||
"id": "Bluetooth"
|
||||
},
|
||||
{
|
||||
"id": "Battery"
|
||||
},
|
||||
{
|
||||
"id": "Volume"
|
||||
},
|
||||
{
|
||||
"id": "Brightness"
|
||||
},
|
||||
{
|
||||
"id": "NightLight"
|
||||
},
|
||||
{
|
||||
"id": "Clock"
|
||||
},
|
||||
{
|
||||
"id": "SidePanelToggle"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"avatarImage": "",
|
||||
"dimDesktop": true,
|
||||
"showScreenCorners": false,
|
||||
"forceBlackScreenCorners": false,
|
||||
"radiusRatio": 1,
|
||||
"screenRadiusRatio": 1,
|
||||
"animationSpeed": 1
|
||||
},
|
||||
"location": {
|
||||
"name": "Tokyo",
|
||||
"useFahrenheit": false,
|
||||
"use12hourFormat": false,
|
||||
"showWeekNumberInCalendar": false
|
||||
},
|
||||
"screenRecorder": {
|
||||
"directory": "",
|
||||
"frameRate": 60,
|
||||
"audioCodec": "opus",
|
||||
"videoCodec": "h264",
|
||||
"quality": "very_high",
|
||||
"colorRange": "limited",
|
||||
"showCursor": true,
|
||||
"audioSource": "default_output",
|
||||
"videoSource": "portal"
|
||||
},
|
||||
"wallpaper": {
|
||||
"enabled": true,
|
||||
"directory": "",
|
||||
"enableMultiMonitorDirectories": false,
|
||||
"setWallpaperOnAllMonitors": true,
|
||||
"fillMode": "crop",
|
||||
"fillColor": "#000000",
|
||||
"randomEnabled": false,
|
||||
"randomIntervalSec": 300,
|
||||
"transitionDuration": 1500,
|
||||
"transitionType": "random",
|
||||
"transitionEdgeSmoothness": 0.05,
|
||||
"monitors": []
|
||||
},
|
||||
"appLauncher": {
|
||||
"enableClipboardHistory": false,
|
||||
"position": "center",
|
||||
"backgroundOpacity": 1,
|
||||
"pinnedExecs": [],
|
||||
"useApp2Unit": false,
|
||||
"sortByMostUsed": true
|
||||
},
|
||||
"dock": {
|
||||
"autoHide": false,
|
||||
"exclusive": false,
|
||||
"backgroundOpacity": 1,
|
||||
"floatingRatio": 1,
|
||||
"monitors": []
|
||||
},
|
||||
"network": {
|
||||
"wifiEnabled": true,
|
||||
"bluetoothEnabled": true
|
||||
},
|
||||
"notifications": {
|
||||
"doNotDisturb": false,
|
||||
"monitors": [],
|
||||
"lastSeenTs": 0,
|
||||
"lowUrgencyDuration": 3,
|
||||
"normalUrgencyDuration": 8,
|
||||
"criticalUrgencyDuration": 15
|
||||
},
|
||||
"audio": {
|
||||
"volumeStep": 5,
|
||||
"cavaFrameRate": 60,
|
||||
"visualizerType": "linear",
|
||||
"mprisBlacklist": [],
|
||||
"preferredPlayer": ""
|
||||
},
|
||||
"ui": {
|
||||
"fontDefault": "Roboto",
|
||||
"fontFixed": "DejaVu Sans Mono",
|
||||
"fontBillboard": "Inter",
|
||||
"monitorsScaling": [],
|
||||
"idleInhibitorEnabled": false
|
||||
},
|
||||
"brightness": {
|
||||
"brightnessStep": 5
|
||||
},
|
||||
"colorSchemes": {
|
||||
"useWallpaperColors": false,
|
||||
"predefinedScheme": "",
|
||||
"darkMode": true
|
||||
},
|
||||
"matugen": {
|
||||
"gtk4": false,
|
||||
"gtk3": false,
|
||||
"qt6": false,
|
||||
"qt5": false,
|
||||
"kitty": false,
|
||||
"ghostty": false,
|
||||
"foot": false,
|
||||
"fuzzel": false,
|
||||
"vesktop": false,
|
||||
"pywalfox": false,
|
||||
"enableUserTemplates": false
|
||||
},
|
||||
"nightLight": {
|
||||
"enabled": false,
|
||||
"forced": false,
|
||||
"autoSchedule": true,
|
||||
"nightTemp": "4000",
|
||||
"dayTemp": "6500",
|
||||
"manualSunrise": "06:30",
|
||||
"manualSunset": "18:30"
|
||||
},
|
||||
"hooks": {
|
||||
"enabled": false,
|
||||
"wallpaperChange": "",
|
||||
"darkModeChange": ""
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,16 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import "../Helpers/QtObj2JS.js" as QtObj2JS
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Used to access via Settings.data.xxx.yyy
|
||||
readonly property alias data: adapter
|
||||
property bool isLoaded: false
|
||||
property bool directoriesCreated: false
|
||||
|
||||
// Define our app directories
|
||||
// Default config directory: ~/.config/noctalia
|
||||
// Default cache directory: ~/.cache/noctalia
|
||||
@@ -18,20 +24,14 @@ Singleton {
|
||||
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 defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"
|
||||
|
||||
property string defaultAvatar: Quickshell.env("HOME") + "/.face"
|
||||
property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos"
|
||||
property string defaultLocation: "Tokyo"
|
||||
property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers"
|
||||
property string defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"
|
||||
|
||||
// Used to access via Settings.data.xxx.yyy
|
||||
readonly property alias data: adapter
|
||||
|
||||
property bool isLoaded: false
|
||||
property bool directoriesCreated: false
|
||||
|
||||
// Signal emitted when settings are loaded after startupcale changes
|
||||
signal settingsLoaded
|
||||
@@ -50,11 +50,18 @@ Singleton {
|
||||
// Mark directories as created and trigger file loading
|
||||
directoriesCreated = true
|
||||
|
||||
generateDefaultSettings();
|
||||
|
||||
settingsFileView.adapter = adapter;
|
||||
// This should only be activated once when the settings structure has changed
|
||||
// Then it should be commented out again, regular users don't need to generate
|
||||
// default settings on every start
|
||||
//generateDefaultSettings()
|
||||
|
||||
// Patch-in the local default, resolved to user's home
|
||||
adapter.general.avatarImage = defaultAvatar
|
||||
adapter.screenRecorder.directory = defaultVideosDirectory
|
||||
adapter.wallpaper.directory = defaultWallpapersDirectory
|
||||
|
||||
// Set the adapter to the settingsFileView to trigger the real settings load
|
||||
settingsFileView.adapter = adapter
|
||||
}
|
||||
|
||||
// Don't write settings to disk immediately
|
||||
@@ -162,7 +169,7 @@ Singleton {
|
||||
|
||||
// general
|
||||
property JsonObject general: JsonObject {
|
||||
property string avatarImage: defaultAvatar
|
||||
property string avatarImage: ""
|
||||
property bool dimDesktop: true
|
||||
property bool showScreenCorners: false
|
||||
property bool forceBlackScreenCorners: false
|
||||
@@ -181,7 +188,7 @@ Singleton {
|
||||
|
||||
// screen recorder
|
||||
property JsonObject screenRecorder: JsonObject {
|
||||
property string directory: defaultVideosDirectory
|
||||
property string directory: ""
|
||||
property int frameRate: 60
|
||||
property string audioCodec: "opus"
|
||||
property string videoCodec: "h264"
|
||||
@@ -195,7 +202,7 @@ Singleton {
|
||||
// wallpaper
|
||||
property JsonObject wallpaper: JsonObject {
|
||||
property bool enabled: true
|
||||
property string directory: defaultWallpapersDirectory
|
||||
property string directory: ""
|
||||
property bool enableMultiMonitorDirectories: false
|
||||
property bool setWallpaperOnAllMonitors: true
|
||||
property string fillMode: "crop"
|
||||
@@ -271,7 +278,7 @@ Singleton {
|
||||
|
||||
property JsonObject colorSchemes: JsonObject {
|
||||
property bool useWallpaperColors: false
|
||||
property string predefinedScheme: ""
|
||||
property string predefinedScheme: "Noctalia (default)"
|
||||
property bool darkMode: true
|
||||
}
|
||||
|
||||
@@ -310,18 +317,21 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Generate default settings at the root of the repo
|
||||
function generateDefaultSettings() {
|
||||
try {
|
||||
Logger.log("Settings", "Generating default settings file...")
|
||||
Logger.log("Settings", "Generating settings-default.json")
|
||||
|
||||
var defaultPath = configDir + "settings-default.json"
|
||||
var jsonData = JSON.stringify(adapter, null, 2)
|
||||
var tempFile = "/tmp/noctalia-default-settings.json"
|
||||
// Prepare a clean JSON
|
||||
var plainAdapter = QtObj2JS.qtObjectToPlainObject(adapter)
|
||||
var jsonData = JSON.stringify(plainAdapter, null, 2)
|
||||
|
||||
// Write to temp file first, then copy to final location
|
||||
Quickshell.execDetached(["sh", "-c", `echo '${jsonData}' > "${tempFile}" && cp "${tempFile}" "${defaultPath}" && rm "${tempFile}"`])
|
||||
var defaultPath = Quickshell.shellDir + "/Assets/settings-default.json"
|
||||
|
||||
Logger.log("Settings", "Generated settings-default.json with default values")
|
||||
// Encode transfer it has base64 to avoid any escaping issue
|
||||
var base64Data = Qt.btoa(jsonData)
|
||||
Quickshell.execDetached(["sh", "-c", `echo "${base64Data}" | base64 -d > "${defaultPath}"`])
|
||||
} catch (error) {
|
||||
Logger.error("Settings", "Failed to generate default settings file: " + error)
|
||||
}
|
||||
@@ -467,6 +477,7 @@ Singleton {
|
||||
const widgetAfter = JSON.stringify(widget)
|
||||
return (widgetAfter !== widgetBefore)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Kickoff essential services
|
||||
function kickOffServices() {
|
||||
|
||||
114
Helpers/QtObj2JS.js
Normal file
114
Helpers/QtObj2JS.js
Normal file
@@ -0,0 +1,114 @@
|
||||
// -----------------------------------------------------
|
||||
// Helper function to convert Qt objects to plain JavaScript objects
|
||||
// Only used when generating settings-default.json
|
||||
function qtObjectToPlainObject(obj) {
|
||||
if (obj === null || obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Handle primitive types
|
||||
if (typeof obj !== "object") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Handle native JavaScript arrays
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => qtObjectToPlainObject(item));
|
||||
}
|
||||
|
||||
// Detect QML arrays FIRST (before color detection)
|
||||
// QML arrays have a numeric length property and indexed properties
|
||||
if (typeof obj.length === "number" && obj.length >= 0) {
|
||||
// Check if it has indexed properties - be more flexible about detection
|
||||
var hasIndexedProps = true;
|
||||
var hasNumericKeys = false;
|
||||
|
||||
// Check if we have at least some numeric properties
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
if (obj.hasOwnProperty(i) || obj[i] !== undefined) {
|
||||
hasNumericKeys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have length > 0 and some numeric keys, treat as array
|
||||
if (obj.length > 0 && hasNumericKeys) {
|
||||
var arr = [];
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
// Use direct property access, handle undefined gracefully
|
||||
var item = obj[i];
|
||||
if (item !== undefined) {
|
||||
arr.push(qtObjectToPlainObject(item));
|
||||
}
|
||||
}
|
||||
return arr; // Return here to avoid processing as object
|
||||
}
|
||||
|
||||
// Handle empty arrays (length = 0)
|
||||
if (obj.length === 0) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Detect and convert QML color objects to hex strings
|
||||
if (
|
||||
typeof obj.r === "number" &&
|
||||
typeof obj.g === "number" &&
|
||||
typeof obj.b === "number" &&
|
||||
typeof obj.a === "number" &&
|
||||
typeof obj.valid === "boolean"
|
||||
) {
|
||||
// This looks like a QML color object
|
||||
try {
|
||||
// Try to get the string representation (should be hex like "#000000")
|
||||
if (typeof obj.toString === "function") {
|
||||
return obj.toString();
|
||||
} else {
|
||||
// Fallback: convert RGBA to hex manually
|
||||
var r = Math.round(obj.r * 255);
|
||||
var g = Math.round(obj.g * 255);
|
||||
var b = Math.round(obj.b * 255);
|
||||
var hex =
|
||||
"#" +
|
||||
r.toString(16).padStart(2, "0") +
|
||||
g.toString(16).padStart(2, "0") +
|
||||
b.toString(16).padStart(2, "0");
|
||||
return hex;
|
||||
}
|
||||
} catch (e) {
|
||||
// If conversion fails, fall through to regular object handling
|
||||
}
|
||||
}
|
||||
|
||||
// Handle regular objects
|
||||
var plainObj = {};
|
||||
|
||||
// Get all property names, but filter out Qt-specific ones
|
||||
var propertyNames = Object.getOwnPropertyNames(obj);
|
||||
|
||||
for (var i = 0; i < propertyNames.length; i++) {
|
||||
var propName = propertyNames[i];
|
||||
|
||||
// Skip Qt-specific properties, functions, and array-like properties
|
||||
if (
|
||||
propName === "objectName" ||
|
||||
propName === "objectNameChanged" ||
|
||||
propName === "length" || // Skip length property
|
||||
/^\d+$/.test(propName) || // Skip numeric keys (0, 1, 2, etc.)
|
||||
propName.endsWith("Changed") ||
|
||||
typeof obj[propName] === "function"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
var value = obj[propName];
|
||||
plainObj[propName] = qtObjectToPlainObject(value);
|
||||
} catch (e) {
|
||||
// Skip properties that can't be accessed
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return plainObj;
|
||||
}
|
||||
Reference in New Issue
Block a user