From 8cb519e5f4a8d22235699ede5c9d2706ce8f0437 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 12 Aug 2025 00:45:53 +0200 Subject: [PATCH] Add basic settings, gotta fix layout --- Modules/Settings/Tabs/About.qml | 157 +++++++++++++++++++++-- Modules/Settings/Tabs/Bar.qml | 43 ++++++- Modules/Settings/Tabs/Display.qml | 89 +++++++++++-- Modules/Settings/Tabs/Misc.qml | 21 ++- Modules/Settings/Tabs/Network.qml | 40 ++++-- Modules/Settings/Tabs/ScreenRecorder.qml | 92 +++++++++++-- Modules/Settings/Tabs/TimeWeather.qml | 51 ++++++-- Modules/Settings/Tabs/Wallpaper.qml | 107 +++++++++++++-- Services/Settings.qml | 8 +- 9 files changed, 537 insertions(+), 71 deletions(-) diff --git a/Modules/Settings/Tabs/About.qml b/Modules/Settings/Tabs/About.qml index 4824386..5eb8af1 100644 --- a/Modules/Settings/Tabs/About.qml +++ b/Modules/Settings/Tabs/About.qml @@ -1,29 +1,170 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts +import QtQuick.Effects +import Quickshell +import Quickshell.Io import qs.Services import qs.Widgets Item { + id: root property real scaling: 1 readonly property string tabIcon: "info" readonly property string tabLabel: "About" readonly property int tabIndex: 8 anchors.fill: parent + property string latestVersion: "Unknown" + property string currentVersion: "Unknown" + property var contributors: [] + property string githubDataPath: Settings.configDir + "github_data.json" + + function loadFromFile() { + const now = Date.now() + const data = githubData + if (!data.timestamp || (now - data.timestamp > 3600 * 1000)) { // 1h cache + fetchFromGitHub() + return + } + if (data.version) root.latestVersion = data.version + if (data.contributors) root.contributors = data.contributors + } + + function fetchFromGitHub() { + versionProcess.running = true + contributorsProcess.running = true + } + + function saveData() { + githubData.timestamp = Date.now() + Qt.callLater(function () { githubDataFile.writeAdapter() }) + } + ColumnLayout { anchors.fill: parent + anchors.margins: Style.marginLarge * scaling spacing: Style.marginMedium * scaling - NText { - text: "About" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary + + // Header + NText { text: "Noctalia: quiet by design"; font.weight: Style.fontWeightBold; color: Colors.textPrimary } + NText { text: "It may just be another quickshell setup but it won't get in your way."; color: Colors.textSecondary } + + // Versions grid + RowLayout { + spacing: Style.marginLarge * scaling + ColumnLayout { NText { text: "Latest Version:"; color: Colors.textSecondary }; NText { text: root.latestVersion; font.weight: Style.fontWeightBold; color: Colors.textPrimary } } + ColumnLayout { NText { text: "Installed Version:"; color: Colors.textSecondary }; NText { text: root.currentVersion; font.weight: Style.fontWeightBold; color: Colors.textPrimary } } + Item { Layout.fillWidth: true } + NIconButton { + icon: "system_update" + tooltipText: "Open latest release" + onClicked: Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"]) } } - NText { - text: "Coming soon" - color: Colors.textSecondary + + NDivider { Layout.fillWidth: true } + + // Contributors + RowLayout { spacing: Style.marginSmall * scaling + NText { text: "Contributors"; font.weight: Style.fontWeightBold; color: Colors.textPrimary } + NText { text: "(" + root.contributors.length + ")"; color: Colors.textSecondary } } - Item { + + GridView { + id: contributorsGrid + Layout.fillWidth: true Layout.fillHeight: true + cellWidth: 200 * scaling + cellHeight: 100 * scaling + model: root.contributors + delegate: Rectangle { + width: contributorsGrid.cellWidth - 8 * scaling + height: contributorsGrid.cellHeight - 4 * scaling + radius: Style.radiusLarge * scaling + color: contributorArea.containsMouse ? Colors.highlight : "transparent" + RowLayout { + anchors.fill: parent + anchors.margins: Style.marginSmall * scaling + spacing: Style.marginSmall * scaling + Item { + Layout.preferredWidth: 40 * scaling + Layout.preferredHeight: 40 * scaling + Image { id: avatarImage; anchors.fill: parent; source: modelData.avatar_url || ""; asynchronous: true; visible: false; fillMode: Image.PreserveAspectCrop } + MultiEffect { anchors.fill: parent; source: avatarImage; maskEnabled: true; maskSource: mask } + Item { id: mask; anchors.fill: parent; visible: false; Rectangle { anchors.fill: parent; radius: width / 2 } } + NText { anchors.centerIn: parent; text: "person"; font.family: "Material Symbols Outlined"; color: contributorArea.containsMouse ? Colors.backgroundPrimary : Colors.textPrimary; visible: !avatarImage.source || avatarImage.status !== Image.Ready } + } + ColumnLayout { Layout.fillWidth: true; spacing: 2 * scaling + NText { text: modelData.login || "Unknown"; color: contributorArea.containsMouse ? Colors.backgroundPrimary : Colors.textPrimary } + NText { text: (modelData.contributions || 0) + " commits"; color: contributorArea.containsMouse ? Colors.backgroundPrimary : Colors.textSecondary } + } + } + MouseArea { id: contributorArea; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: if (modelData.html_url) Quickshell.execDetached(["xdg-open", modelData.html_url]) } + } + } + + Item { Layout.fillHeight: true } + } + + // Processes and persistence + Process { + id: currentVersionProcess + command: ["sh", "-c", "cd " + Quickshell.shellDir + " && git describe --tags --abbrev=0 2>/dev/null || echo 'Unknown'"] + Component.onCompleted: running = true + stdout: StdioCollector { + onStreamFinished: { + const version = text.trim() + if (version && version !== "Unknown") { + root.currentVersion = version + } else { + currentVersionProcess.command = ["sh", "-c", "cd " + Quickshell.shellDir + " && cat package.json 2>/dev/null | grep '\"version\"' | cut -d'\"' -f4 || echo 'Unknown'"] + currentVersionProcess.running = true + } + } + } + } + + FileView { + id: githubDataFile + path: root.githubDataPath + blockLoading: true + printErrors: true + watchChanges: true + onFileChanged: githubDataFile.reload() + onLoaded: loadFromFile() + onLoadFailed: { + githubData.version = "Unknown"; githubData.contributors = []; githubData.timestamp = 0; githubDataFile.writeAdapter(); fetchFromGitHub() + } + Component.onCompleted: { if (path) reload() } + JsonAdapter { id: githubData; property string version: "Unknown"; property var contributors: []; property double timestamp: 0 } + } + + Process { + id: versionProcess + command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/releases/latest"] + stdout: StdioCollector { + onStreamFinished: { + try { + const data = JSON.parse(text) + if (data.tag_name) { const version = data.tag_name; githubData.version = version; root.latestVersion = version } + saveData() + } catch (e) { console.error("Failed to parse version:", e) } + } + } + } + + Process { + id: contributorsProcess + command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/contributors?per_page=100"] + stdout: StdioCollector { + onStreamFinished: { + try { + const data = JSON.parse(text) + githubData.contributors = data || [] + root.contributors = githubData.contributors + saveData() + } catch (e) { console.error("Failed to parse contributors:", e); root.contributors = [] } + } } } } diff --git a/Modules/Settings/Tabs/Bar.qml b/Modules/Settings/Tabs/Bar.qml index 2079a2e..3154cda 100644 --- a/Modules/Settings/Tabs/Bar.qml +++ b/Modules/Settings/Tabs/Bar.qml @@ -15,17 +15,48 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling + NText { - text: "Bar" + text: "Elements" font.weight: Style.fontWeightBold color: Colors.accentSecondary } - NText { - text: "Coming soon" - color: Colors.textSecondary + + NToggle { + label: "Show Active Window" + description: "Display the title of the currently focused window below the bar" + value: Settings.data.bar.showActiveWindow + onToggled: function (newValue) { Settings.data.bar.showActiveWindow = newValue } } - Item { - Layout.fillHeight: true + + NToggle { + label: "Show Active Window Icon" + description: "Display the icon of the currently focused window" + value: Settings.data.bar.showActiveWindowIcon + onToggled: function (newValue) { Settings.data.bar.showActiveWindowIcon = newValue } } + + NToggle { + label: "Show System Info" + description: "Display system information (CPU, RAM, Temperature)" + value: Settings.data.bar.showSystemInfo + onToggled: function (newValue) { Settings.data.bar.showSystemInfo = newValue } + } + + NToggle { + label: "Show Taskbar" + description: "Display a taskbar showing currently open windows" + value: Settings.data.bar.showTaskbar + onToggled: function (newValue) { Settings.data.bar.showTaskbar = newValue } + } + + NToggle { + label: "Show Media" + description: "Display media controls and information" + value: Settings.data.bar.showMedia + onToggled: function (newValue) { Settings.data.bar.showMedia = newValue } + } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/Display.qml b/Modules/Settings/Tabs/Display.qml index 3916c9e..83a52ff 100644 --- a/Modules/Settings/Tabs/Display.qml +++ b/Modules/Settings/Tabs/Display.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import Quickshell import qs.Services import qs.Widgets @@ -10,20 +11,86 @@ Item { readonly property int tabIndex: 5 anchors.fill: parent + // Helper functions to update arrays immutably + function addMonitor(list, name) { + const arr = (list || []).slice(); if (!arr.includes(name)) arr.push(name); return arr + } + function removeMonitor(list, name) { + return (list || []).filter(function (n) { return n !== name }) + } + ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling - NText { - text: "Display" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } - NText { - text: "Coming soon" - color: Colors.textSecondary - } - Item { - Layout.fillHeight: true + + NText { text: "Per‑monitor configuration"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + Repeater { + model: Quickshell.screens || [] + delegate: Rectangle { + Layout.fillWidth: true + radius: Style.radiusMedium * scaling + color: Colors.surface + border.color: Colors.outline + border.width: Math.max(1, Style.borderThin * scaling) + implicitHeight: contentCol.implicitHeight + Style.marginLarge * scaling + + ColumnLayout { + id: contentCol + anchors.fill: parent + anchors.margins: Style.marginMedium * scaling + spacing: Style.marginSmall * scaling + + NText { text: (modelData.name || "Unknown"); font.weight: Style.fontWeightBold; color: Colors.accentPrimary } + + RowLayout { + spacing: Style.marginMedium * scaling + NText { text: `Resolution: ${modelData.width}x${modelData.height}`; color: Colors.textSecondary } + NText { text: `Position: (${modelData.x}, ${modelData.y})`; color: Colors.textSecondary } + } + + NToggle { + label: "Bar" + description: "Display the top bar on this monitor" + value: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name) + } else { + Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name) + } + } + } + + NToggle { + label: "Dock" + description: "Display the dock on this monitor" + value: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name) + } else { + Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name) + } + } + } + + NToggle { + label: "Notifications" + description: "Display notifications on this monitor" + value: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, modelData.name) + } else { + Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, modelData.name) + } + } + } + } + } } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/Misc.qml b/Modules/Settings/Tabs/Misc.qml index e52057b..976331f 100644 --- a/Modules/Settings/Tabs/Misc.qml +++ b/Modules/Settings/Tabs/Misc.qml @@ -13,17 +13,24 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling + NText { - text: "Misc" + text: "Media" font.weight: Style.fontWeightBold color: Colors.accentSecondary } - NText { - text: "Coming soon" - color: Colors.textSecondary - } - Item { - Layout.fillHeight: true + + NText { text: "Visualizer Type"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Choose the style of the audio visualizer"; color: Colors.textSecondary } + + NComboBox { + id: visualizerTypeComboBox + optionsKeys: ["radial", "fire", "diamond"] + optionsLabels: ["Radial", "Fire", "Diamond"] + currentKey: Settings.data.audioVisualizer.type + onSelected: function (key) { Settings.data.audioVisualizer.type = key } } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/Network.qml b/Modules/Settings/Tabs/Network.qml index 2a15699..8e922a7 100644 --- a/Modules/Settings/Tabs/Network.qml +++ b/Modules/Settings/Tabs/Network.qml @@ -1,5 +1,7 @@ import QtQuick import QtQuick.Layouts +import Quickshell +import Quickshell.Bluetooth import qs.Services import qs.Widgets @@ -13,17 +15,35 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling - NText { - text: "Network" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary + + NText { text: "Wi‑Fi"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NToggle { + label: "Enable Wi‑Fi" + description: "Turn Wi‑Fi radio on or off" + value: Settings.data.network.wifiEnabled + onToggled: function (newValue) { + Settings.data.network.wifiEnabled = newValue + Quickshell.execDetached(["nmcli", "radio", "wifi", newValue ? "on" : "off"]) } } - NText { - text: "Coming soon" - color: Colors.textSecondary - } - Item { - Layout.fillHeight: true + + NDivider { Layout.fillWidth: true } + + NText { text: "Bluetooth"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NToggle { + label: "Enable Bluetooth" + description: "Turn Bluetooth radio on or off" + value: Settings.data.network.bluetoothEnabled + onToggled: function (newValue) { + Settings.data.network.bluetoothEnabled = newValue + if (Bluetooth.defaultAdapter) { + Bluetooth.defaultAdapter.enabled = newValue + if (Bluetooth.defaultAdapter.enabled) Bluetooth.defaultAdapter.discovering = true + } + } } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/ScreenRecorder.qml b/Modules/Settings/Tabs/ScreenRecorder.qml index 3e2cff3..0b3c972 100644 --- a/Modules/Settings/Tabs/ScreenRecorder.qml +++ b/Modules/Settings/Tabs/ScreenRecorder.qml @@ -13,17 +13,91 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling - NText { - text: "Screen Recorder" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary + + NText { text: "Screen Recording"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + // Output Directory + NText { text: "Output Directory"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Directory where screen recordings will be saved"; color: Colors.textSecondary } + NTextBox { + text: Settings.data.screenRecorder.directory + Layout.fillWidth: true + onEditingFinished: Settings.data.screenRecorder.directory = text } - NText { - text: "Coming soon" - color: Colors.textSecondary + + // Frame Rate + NText { text: "Frame Rate"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Target frame rate for screen recordings (default: 60)"; color: Colors.textSecondary } + RowLayout { + Layout.fillWidth: true + NText { text: Settings.data.screenRecorder.frameRate + " FPS"; color: Colors.textPrimary } + Item { Layout.fillWidth: true } } - Item { - Layout.fillHeight: true + NSlider { + Layout.fillWidth: true + from: 24; to: 144; stepSize: 1 + value: Settings.data.screenRecorder.frameRate + onMoved: Settings.data.screenRecorder.frameRate = Math.round(value) + cutoutColor: Colors.surface } + + // Audio Source + NText { text: "Audio Source"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Audio source to capture during recording"; color: Colors.textSecondary } + NComboBox { + optionsKeys: ["default_output", "default_input", "both"] + optionsLabels: ["System Audio", "Microphone", "System Audio + Microphone"] + currentKey: Settings.data.screenRecorder.audioSource + onSelected: function (key) { Settings.data.screenRecorder.audioSource = key } + } + + // Video Quality + NText { text: "Video Quality"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Higher quality results in larger file sizes"; color: Colors.textSecondary } + NComboBox { + optionsKeys: ["medium", "high", "very_high", "ultra"] + optionsLabels: ["Medium", "High", "Very High", "Ultra"] + currentKey: Settings.data.screenRecorder.quality + onSelected: function (key) { Settings.data.screenRecorder.quality = key } + } + + // Video Codec + NText { text: "Video Codec"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Different codecs offer different compression and compatibility"; color: Colors.textSecondary } + NComboBox { + optionsKeys: ["h264", "hevc", "av1", "vp8", "vp9"] + optionsLabels: ["H264", "HEVC", "AV1", "VP8", "VP9"] + currentKey: Settings.data.screenRecorder.videoCodec + onSelected: function (key) { Settings.data.screenRecorder.videoCodec = key } + } + + // Audio Codec + NText { text: "Audio Codec"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Opus is recommended for best performance and smallest audio size"; color: Colors.textSecondary } + NComboBox { + optionsKeys: ["opus", "aac"] + optionsLabels: ["OPUS", "AAC"] + currentKey: Settings.data.screenRecorder.audioCodec + onSelected: function (key) { Settings.data.screenRecorder.audioCodec = key } + } + + // Color Range + NText { text: "Color Range"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Limited is recommended for better compatibility"; color: Colors.textSecondary } + NComboBox { + optionsKeys: ["limited", "full"] + optionsLabels: ["Limited", "Full"] + currentKey: Settings.data.screenRecorder.colorRange + onSelected: function (key) { Settings.data.screenRecorder.colorRange = key } + } + + NToggle { + label: "Show Cursor" + description: "Record mouse cursor in the video" + value: Settings.data.screenRecorder.showCursor + onToggled: function (newValue) { Settings.data.screenRecorder.showCursor = newValue } + } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/TimeWeather.qml b/Modules/Settings/Tabs/TimeWeather.qml index 6bf1b1c..a3496db 100644 --- a/Modules/Settings/Tabs/TimeWeather.qml +++ b/Modules/Settings/Tabs/TimeWeather.qml @@ -13,17 +13,50 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling - NText { - text: "Time & Weather" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary + + NText { text: "Time"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NToggle { + label: "Use 12 Hour Clock" + description: "Display time in 12-hour format (e.g., 2:30 PM) instead of 24-hour format" + value: Settings.data.location.use12HourClock + onToggled: function (newValue) { Settings.data.location.use12HourClock = newValue } } - NText { - text: "Coming soon" - color: Colors.textSecondary + + NToggle { + label: "US Style Date" + description: "Display dates in MM/DD/YYYY format instead of DD/MM/YYYY" + value: Settings.data.location.reverseDayMonth + onToggled: function (newValue) { Settings.data.location.reverseDayMonth = newValue } } - Item { - Layout.fillHeight: true + + NDivider { Layout.fillWidth: true } + + NText { text: "Weather"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NText { text: "City"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Your city name for weather information"; color: Colors.textSecondary } + NTextBox { + text: Settings.data.location.name + Layout.fillWidth: true + onEditingFinished: Settings.data.location.name = text } + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginSmall * scaling + ColumnLayout { Layout.fillWidth: true; spacing: 2 * scaling + NText { text: "Temperature Unit"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Choose between Celsius and Fahrenheit"; color: Colors.textSecondary; wrapMode: Text.WordWrap } + } + NComboBox { + optionsKeys: ["c", "f"] + optionsLabels: ["Celsius", "Fahrenheit"] + currentKey: Settings.data.location.useFahrenheit ? "f" : "c" + onSelected: function (key) { Settings.data.location.useFahrenheit = (key === "f") } + } + } + + Item { Layout.fillHeight: true } } } diff --git a/Modules/Settings/Tabs/Wallpaper.qml b/Modules/Settings/Tabs/Wallpaper.qml index cd90098..b426a83 100644 --- a/Modules/Settings/Tabs/Wallpaper.qml +++ b/Modules/Settings/Tabs/Wallpaper.qml @@ -13,17 +13,106 @@ Item { ColumnLayout { anchors.fill: parent spacing: Style.marginMedium * scaling - NText { - text: "Wallpaper" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary + + NText { text: "Wallpaper Settings"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + // Folder + NText { text: "Wallpaper Folder"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Path to your wallpaper folder"; color: Colors.textSecondary; wrapMode: Text.WordWrap } + NTextBox { + text: Settings.data.wallpaper.directory + Layout.fillWidth: true + onEditingFinished: Settings.data.wallpaper.directory = text } - NText { - text: "Coming soon" - color: Colors.textSecondary + + NDivider { Layout.fillWidth: true } + + NText { text: "Automation"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NToggle { + label: "Random Wallpaper" + description: "Automatically select random wallpapers from the folder" + value: Settings.data.wallpaper.isRandom + onToggled: function (newValue) { Settings.data.wallpaper.isRandom = newValue } } - Item { - Layout.fillHeight: true + + NToggle { + label: "Use Wallpaper Theme" + description: "Automatically adjust theme colors based on wallpaper" + value: Settings.data.wallpaper.generateTheme + onToggled: function (newValue) { Settings.data.wallpaper.generateTheme = newValue } } + + NText { text: "Wallpaper Interval"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "How often to change wallpapers automatically (in seconds)"; color: Colors.textSecondary } + RowLayout { + Layout.fillWidth: true + NText { text: Settings.data.wallpaper.randomInterval + " seconds"; color: Colors.textPrimary } + Item { Layout.fillWidth: true } + } + NSlider { + Layout.fillWidth: true + from: 10; to: 900; stepSize: 10 + value: Settings.data.wallpaper.randomInterval + onMoved: Settings.data.wallpaper.randomInterval = Math.round(value) + cutoutColor: Colors.backgroundPrimary + } + + NDivider { Layout.fillWidth: true } + + NText { text: "SWWW"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary } + + NToggle { + label: "Use SWWW" + description: "Use SWWW daemon for advanced wallpaper management" + value: Settings.data.wallpaper.swww.enabled + onToggled: function (newValue) { Settings.data.wallpaper.swww.enabled = newValue } + } + + // SWWW settings + ColumnLayout { + spacing: Style.marginSmall * scaling + visible: Settings.data.wallpaper.swww.enabled + + NText { text: "Resize Mode"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "How SWWW should resize wallpapers to fit the screen"; color: Colors.textSecondary; wrapMode: Text.WordWrap } + NComboBox { + optionsKeys: ["no", "crop", "fit", "stretch"] + optionsLabels: ["No", "Crop", "Fit", "Stretch"] + currentKey: Settings.data.wallpaper.swww.resizeMethod + onSelected: function (key) { Settings.data.wallpaper.swww.resizeMethod = key } + } + + NText { text: "Transition Type"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + NText { text: "Animation type when switching between wallpapers"; color: Colors.textSecondary; wrapMode: Text.WordWrap } + NComboBox { + optionsKeys: ["none", "simple", "fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer", "random"] + optionsLabels: ["None", "Simple", "Fade", "Left", "Right", "Top", "Bottom", "Wipe", "Wave", "Grow", "Center", "Any", "Outer", "Random"] + currentKey: Settings.data.wallpaper.swww.transitionType + onSelected: function (key) { Settings.data.wallpaper.swww.transitionType = key } + } + + NText { text: "Transition FPS"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + RowLayout { Layout.fillWidth: true; NText { text: Settings.data.wallpaper.swww.transitionFps + " FPS"; color: Colors.textPrimary }; Item { Layout.fillWidth: true } } + NSlider { + Layout.fillWidth: true + from: 30; to: 500; stepSize: 5 + value: Settings.data.wallpaper.swww.transitionFps + onMoved: Settings.data.wallpaper.swww.transitionFps = Math.round(value) + cutoutColor: Colors.backgroundPrimary + } + + NText { text: "Transition Duration"; color: Colors.textPrimary; font.weight: Style.fontWeightBold } + RowLayout { Layout.fillWidth: true; NText { text: Settings.data.wallpaper.swww.transitionDuration.toFixed(2) + " s"; color: Colors.textPrimary }; Item { Layout.fillWidth: true } } + NSlider { + Layout.fillWidth: true + from: 0.25; to: 10; stepSize: 0.05 + value: Settings.data.wallpaper.swww.transitionDuration + onMoved: Settings.data.wallpaper.swww.transitionDuration = value + cutoutColor: Colors.backgroundPrimary + } + } + + Item { Layout.fillHeight: true } } } diff --git a/Services/Settings.qml b/Services/Settings.qml index f13de43..4f1a444 100644 --- a/Services/Settings.qml +++ b/Services/Settings.qml @@ -26,8 +26,8 @@ Singleton { // Used to access via Settings.data.xxx.yyy property var data: adapter - // Needed to only have one NPanel loaded at a time. - // property var openPanel: null + // Needed to only have one NPanel loaded at a time. <--- VERY BROKEN + //property var openPanel: null Item { Component.onCompleted: { @@ -68,6 +68,8 @@ Singleton { property bool showActiveWindowIcon: false property bool showSystemInfo: false property bool showMedia: false + // New: optional taskbar visibility in bar + property bool showTaskbar: false property list monitors: [] } @@ -102,6 +104,8 @@ Singleton { property string quality: "very_high" property string colorRange: "limited" property bool showCursor: true + // New: optional audio source selection (default: system output) + property string audioSource: "default_output" } // wallpaper