diff --git a/Modules/Background/Background.qml b/Modules/Background/Background.qml index a48f660..20752c9 100644 --- a/Modules/Background/Background.qml +++ b/Modules/Background/Background.qml @@ -8,9 +8,18 @@ Variants { delegate: PanelWindow { required property ShellScreen modelData - property string wallpaperSource: Settings.data.wallpaper.current + property string wallpaperSource: Wallpapers.currentWallpaper !== "" && !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : "" - visible: wallpaperSource !== "" + visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled + + // Force update when SWWW setting changes + onVisibleChanged: { + if (visible) { + console.log("Background: Showing wallpaper:", wallpaperSource) + } else { + console.log("Background: Hiding wallpaper (SWWW enabled)") + } + } color: "transparent" screen: modelData WlrLayershell.layer: WlrLayer.Background diff --git a/Modules/Background/Overview.qml b/Modules/Background/Overview.qml index 9dc5f6f..d2a7aad 100644 --- a/Modules/Background/Overview.qml +++ b/Modules/Background/Overview.qml @@ -9,9 +9,9 @@ Variants { delegate: PanelWindow { required property ShellScreen modelData - property string wallpaperSource: Qt.resolvedUrl("../../Assets/Tests/wallpaper.png") + property string wallpaperSource: Wallpapers.currentWallpaper !== "" && !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : "" - visible: wallpaperSource !== "" + visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled color: "transparent" screen: modelData WlrLayershell.layer: WlrLayer.Background diff --git a/Modules/Settings/SettingsWindow.qml b/Modules/Settings/SettingsWindow.qml index 359d221..c05e32b 100644 --- a/Modules/Settings/SettingsWindow.qml +++ b/Modules/Settings/SettingsWindow.qml @@ -46,7 +46,13 @@ NLoader { "label": "Wallpaper", "icon": "image", "source": "Tabs/Wallpaper.qml" - }, { + }, + { + "label": "Wallpaper Selector", + "icon": "wallpaper_slideshow", + "source": "Tabs/WallpaperSelector.qml" + }, + { "label": "Misc", "icon": "more_horiz", "source": "Tabs/Misc.qml" @@ -207,6 +213,7 @@ NLoader { Tabs.Network {} Tabs.Display {} Tabs.Wallpaper {} + Tabs.WallpaperSelector {} Tabs.Misc {} Tabs.About {} } diff --git a/Modules/Settings/Tabs/Bar.qml b/Modules/Settings/Tabs/Bar.qml index a44d0fd..b9b4406 100644 --- a/Modules/Settings/Tabs/Bar.qml +++ b/Modules/Settings/Tabs/Bar.qml @@ -1,75 +1,105 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - // Optional scaling prop to match other tabs - property real scaling: 1 - // Tab metadata - readonly property string tabIcon: "web_asset" - readonly property string tabLabel: "Bar" - readonly property int tabIndex: 1 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Elements" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - 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 + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 0 } - } - 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 + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Bar Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Elements section + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Elements" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + 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 + } + } + + 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 + } + } + } } } - - 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 ea587d7..86dea3d 100644 --- a/Modules/Settings/Tabs/Display.qml +++ b/Modules/Settings/Tabs/Display.qml @@ -116,4 +116,4 @@ Item { Layout.fillHeight: true } } -} +} \ No newline at end of file diff --git a/Modules/Settings/Tabs/General.qml b/Modules/Settings/Tabs/General.qml index 0202277..2d71032 100644 --- a/Modules/Settings/Tabs/General.qml +++ b/Modules/Settings/Tabs/General.qml @@ -1,113 +1,143 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - id: generalPage +ColumnLayout { + id: root - // Public API - // Scaling factor provided by the parent settings window - property real scaling: 1 - // Tab metadata - readonly property string tabIcon: "tune" - readonly property string tabLabel: "General" - readonly property int tabIndex: 0 + spacing: 0 - Layout.fillWidth: true - Layout.fillHeight: true + ScrollView { + id: scrollView - ColumnLayout { - anchors.fill: parent - anchors.margins: 0 - spacing: Style.marginMedium * scaling + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded - // Profile section - NText { - text: "Profile" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 - RowLayout { - Layout.fillWidth: true - spacing: Style.marginMedium * scaling - - // Avatar preview - NImageRounded { - width: 64 * scaling - height: 64 * scaling - imagePath: Settings.data.general.avatarImage - fallbackIcon: "person" - borderColor: Colors.accentPrimary - borderWidth: Math.max(1, Style.borderMedium * scaling) - } - ColumnLayout { + Item { Layout.fillWidth: true - spacing: 2 * scaling + Layout.preferredHeight: 0 + } + + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + NText { - text: "Profile Image" - color: Colors.textPrimary + text: "General Settings" + font.pointSize: 18 font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 } - NText { - text: "Your profile picture displayed in various places throughout the shell" - color: Colors.textSecondary - font.pointSize: Style.fontSizeSmall * scaling - } - NTextInput { - text: Settings.data.general.avatarImage - placeholderText: "/home/user/.face" + + // Profile section + ColumnLayout { + spacing: 8 Layout.fillWidth: true - onEditingFinished: function () { - Settings.data.general.avatarImage = text + Layout.topMargin: 8 + + NText { + text: "Profile" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + RowLayout { + Layout.fillWidth: true + spacing: 16 + + // Avatar preview + NImageRounded { + width: 64 + height: 64 + imagePath: Settings.data.general.avatarImage + fallbackIcon: "person" + borderColor: Colors.accentPrimary + borderWidth: Math.max(1, Style.borderMedium) + } + ColumnLayout { + Layout.fillWidth: true + spacing: 4 + NText { + text: "Profile Image" + color: Colors.textPrimary + font.weight: Style.fontWeightBold + } + NText { + text: "Your profile picture displayed in various places throughout the shell" + color: Colors.textSecondary + font.pointSize: 12 + } + NTextInput { + text: Settings.data.general.avatarImage + placeholderText: "/home/user/.face" + Layout.fillWidth: true + onEditingFinished: function () { + Settings.data.general.avatarImage = text + } + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "User Interface" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + NToggle { + label: "Show Corners" + description: "Display rounded corners on the edge of the screen" + value: Settings.data.general.showScreenCorners + onToggled: function (v) { + Settings.data.general.showScreenCorners = v + } + } + + NToggle { + label: "Show Dock" + description: "Display a dock at the bottom of the screen for quick access to applications" + value: Settings.data.general.showDock + onToggled: function (v) { + Settings.data.general.showDock = v + } + } + + NToggle { + label: "Dim Desktop" + description: "Dim the desktop when panels or menus are open" + value: Settings.data.general.dimDesktop + onToggled: function (v) { + Settings.data.general.dimDesktop = v } } } } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginSmall * scaling - Layout.bottomMargin: Style.marginSmall * scaling - } - - // UI section - NText { - text: "User Interface" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } - - NToggle { - label: "Show Corners" - description: "Display rounded corners on the edge of the screen" - value: Settings.data.general.showScreenCorners - onToggled: function (v) { - Settings.data.general.showScreenCorners = v - } - } - - NToggle { - label: "Show Dock" - description: "Display a dock at the bottom of the screen for quick access to applications" - value: Settings.data.general.showDock - onToggled: function (v) { - Settings.data.general.showDock = v - } - } - - NToggle { - label: "Dim Desktop" - description: "Dim the desktop when panels or menus are open" - value: Settings.data.general.dimDesktop - onToggled: function (v) { - Settings.data.general.dimDesktop = v - } - } - - Item { - Layout.fillHeight: true - } } } diff --git a/Modules/Settings/Tabs/Misc.qml b/Modules/Settings/Tabs/Misc.qml index 2a6dc6a..f99cdfa 100644 --- a/Modules/Settings/Tabs/Misc.qml +++ b/Modules/Settings/Tabs/Misc.qml @@ -1,48 +1,69 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - property real scaling: 1 - readonly property string tabIcon: "more_horiz" - readonly property string tabLabel: "Misc" - readonly property int tabIndex: 7 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Media" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - NText { - text: "Visualizer Type" - color: Colors.textPrimary - font.weight: Style.fontWeightBold - } - NText { - text: "Choose the style of the audio visualizer" - color: Colors.textSecondary - } + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded - NComboBox { - id: visualizerTypeComboBox - optionsKeys: ["radial", "fire", "diamond"] - optionsLabels: ["Radial", "Fire", "Diamond"] - currentKey: Settings.data.audioVisualizer.type - onSelected: function (key) { - Settings.data.audioVisualizer.type = key + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 0 } - } - Item { - Layout.fillHeight: true + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Miscellaneous Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Audio Visualizer section + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Audio Visualizer" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NComboBox { + optionsKeys: ["radial", "bars", "wave"] + optionsLabels: ["Radial", "Bars", "Wave"] + currentKey: Settings.data.audioVisualizer.type + onSelected: function (key) { + Settings.data.audioVisualizer.type = key + } + } + } + } } } } diff --git a/Modules/Settings/Tabs/Network.qml b/Modules/Settings/Tabs/Network.qml index ad9be23..3c31d74 100644 --- a/Modules/Settings/Tabs/Network.qml +++ b/Modules/Settings/Tabs/Network.qml @@ -1,64 +1,80 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import Quickshell import Quickshell.Bluetooth import qs.Services import qs.Widgets -Item { - property real scaling: 1 - readonly property string tabIcon: "wifi" - readonly property string tabLabel: "Network" - readonly property int tabIndex: 4 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Wi‑Fi" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - 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"]) + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 0 } - } - NDivider { - Layout.fillWidth: true - } + ColumnLayout { + spacing: 4 + Layout.fillWidth: true - NText { - text: "Bluetooth" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + NText { + text: "Network Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } - 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 + // Network interfaces section + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Network Interfaces" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NToggle { + label: "WiFi Enabled" + description: "Enable WiFi connectivity" + value: Settings.data.network.wifiEnabled + onToggled: function (newValue) { + Settings.data.network.wifiEnabled = newValue + } + } + + NToggle { + label: "Bluetooth Enabled" + description: "Enable Bluetooth connectivity" + value: Settings.data.network.bluetoothEnabled + onToggled: function (newValue) { + Settings.data.network.bluetoothEnabled = newValue + } + } } } } - - Item { - Layout.fillHeight: true - } } } diff --git a/Modules/Settings/Tabs/ScreenRecorder.qml b/Modules/Settings/Tabs/ScreenRecorder.qml index e2017ea..d102ce9 100644 --- a/Modules/Settings/Tabs/ScreenRecorder.qml +++ b/Modules/Settings/Tabs/ScreenRecorder.qml @@ -1,180 +1,327 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - property real scaling: 1 - readonly property string tabIcon: "videocam" - readonly property string tabLabel: "Screen Recorder" - readonly property int tabIndex: 3 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Screen Recording" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - // 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 - } - NTextInput { - text: Settings.data.screenRecorder.directory - Layout.fillWidth: true - onEditingFinished: function () { - Settings.data.screenRecorder.directory = text - } - } + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 - // 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 + Layout.preferredHeight: 0 } - } - NSlider { - Layout.fillWidth: true - from: 24 - to: 144 - stepSize: 1 - value: Settings.data.screenRecorder.frameRate - onPressedChanged: 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 + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Screen Recording" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Output Directory + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Output Directory" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Directory where screen recordings will be saved" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + NTextInput { + text: Settings.data.screenRecorder.directory + Layout.fillWidth: true + onEditingFinished: function () { + Settings.data.screenRecorder.directory = text + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + // Video Settings + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Video Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Frame Rate + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Frame Rate" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Target frame rate for screen recordings (default: 60)" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + + NText { + text: Settings.data.screenRecorder.frameRate + " FPS" + font.pointSize: 13 + color: Colors.textPrimary + } + + Item { + Layout.fillWidth: 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.backgroundPrimary + } + } + + // Video Quality + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Video Quality" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Higher quality results in larger file sizes" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + 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 + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Video Codec" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Different codecs offer different compression and compatibility" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + 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 + } + } + } + + // Color Range + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Color Range" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Limited is recommended for better compatibility" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + NComboBox { + optionsKeys: ["limited", "full"] + optionsLabels: ["Limited", "Full"] + currentKey: Settings.data.screenRecorder.colorRange + onSelected: function (key) { + Settings.data.screenRecorder.colorRange = key + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + // Audio Settings + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Audio Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Audio Source + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Audio Source" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Audio source to capture during recording" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + 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 + } + } + } + + // Audio Codec + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Audio Codec" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Opus is recommended for best performance and smallest audio size" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + NComboBox { + optionsKeys: ["opus", "aac"] + optionsLabels: ["OPUS", "AAC"] + currentKey: Settings.data.screenRecorder.audioCodec + onSelected: function (key) { + Settings.data.screenRecorder.audioCodec = key + } + } + } + + // Show Cursor + NToggle { + label: "Show Cursor" + description: "Record mouse cursor in the video" + value: Settings.data.screenRecorder.showCursor + onToggled: function (newValue) { + Settings.data.screenRecorder.showCursor = newValue + } + } + } } } - - // 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 - } } -} +} \ No newline at end of file diff --git a/Modules/Settings/Tabs/TimeWeather.qml b/Modules/Settings/Tabs/TimeWeather.qml index f329def..a5f1b1f 100644 --- a/Modules/Settings/Tabs/TimeWeather.qml +++ b/Modules/Settings/Tabs/TimeWeather.qml @@ -1,94 +1,136 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - property real scaling: 1 - readonly property string tabIcon: "schedule" - readonly property string tabLabel: "Time & Weather" - readonly property int tabIndex: 2 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Time" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - 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 + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 0 } - } - 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 + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Time & Weather Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Location section + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Location" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NTextInput { + text: Settings.data.location.name + placeholderText: "Enter city name" + Layout.fillWidth: true + onEditingFinished: function () { + Settings.data.location.name = text + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + // Time section + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Time Format" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + NToggle { + label: "Use 12-Hour Clock" + description: "Display time in 12-hour format (AM/PM) instead of 24-hour" + value: Settings.data.location.use12HourClock + onToggled: function (newValue) { + Settings.data.location.use12HourClock = newValue + } + } + + NToggle { + label: "Reverse Day/Month" + description: "Display date as DD/MM instead of MM/DD" + value: Settings.data.location.reverseDayMonth + onToggled: function (newValue) { + Settings.data.location.reverseDayMonth = newValue + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + // Weather section + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "Weather" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + NToggle { + label: "Use Fahrenheit" + description: "Display temperature in Fahrenheit instead of Celsius" + value: Settings.data.location.useFahrenheit + onToggled: function (newValue) { + Settings.data.location.useFahrenheit = newValue + } + } + } } } - - NDivider { - Layout.fillWidth: true - } - - NText { - text: "Weather" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } - - NText { - text: "Location" - color: Colors.textPrimary - font.weight: Style.fontWeightBold - } - NText { - text: "Your city name for weather information" - color: Colors.textSecondary - font.pointSize: Style.fontSizeSmall * scaling - } - NTextInput { - text: Settings.data.location.name - Layout.fillWidth: true - onEditingFinished: function () { - Settings.data.location.name = text - Location.resetWeather() - } - } - - NText { - text: "Temperature Unit" - color: Colors.textPrimary - font.weight: Style.fontWeightBold - } - NText { - text: "Choose between Celsius and Fahrenheit" - color: Colors.textSecondary - font.pointSize: Style.fontSizeSmall * scaling - } - 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 aa474b8..d121236 100644 --- a/Modules/Settings/Tabs/Wallpaper.qml +++ b/Modules/Settings/Tabs/Wallpaper.qml @@ -1,215 +1,357 @@ import QtQuick +import QtQuick.Controls import QtQuick.Layouts import qs.Services import qs.Widgets -Item { - property real scaling: 1 - readonly property string tabIcon: "image" - readonly property string tabLabel: "Wallpaper" - readonly property int tabIndex: 6 - Layout.fillWidth: true - Layout.fillHeight: true +ColumnLayout { + id: root - ColumnLayout { - anchors.fill: parent - spacing: Style.marginMedium * scaling + spacing: 0 - NText { - text: "Wallpaper Settings" - font.weight: Style.fontWeightBold - color: Colors.accentSecondary - } + ScrollView { + id: scrollView - // Folder - NText { - text: "Wallpaper Folder" + Layout.fillWidth: true + Layout.fillHeight: true + padding: 16 + rightPadding: 12 + clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded - font.weight: Style.fontWeightBold - } - NText { - text: "Path to your wallpaper folder" - color: Colors.textSecondary - wrapMode: Text.WordWrap - } - NTextInput { - text: Settings.data.wallpaper.directory - Layout.fillWidth: true - onEditingFinished: function () { - Settings.data.wallpaper.directory = text - } - } + ColumnLayout { + width: scrollView.availableWidth + spacing: 0 - 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 - } - } - - 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 - onPressedChanged: 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" - 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 - } + Layout.preferredHeight: 0 } - NText { - text: "Transition Type" - 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" - font.weight: Style.fontWeightBold - } - RowLayout { + ColumnLayout { + spacing: 4 Layout.fillWidth: true + NText { - text: Settings.data.wallpaper.swww.transitionFps + " FPS" + text: "Wallpaper Settings" + font.pointSize: 18 + font.weight: Style.fontWeightBold color: Colors.textPrimary + Layout.bottomMargin: 8 } - Item { + + // Wallpaper Settings Category + ColumnLayout { + spacing: 8 Layout.fillWidth: true + Layout.topMargin: 8 + + // Wallpaper Folder + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + + NText { + text: "Wallpaper Folder" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Path to your wallpaper folder" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + NTextInput { + text: Settings.data.wallpaper.directory + Layout.fillWidth: true + onEditingFinished: function () { + Settings.data.wallpaper.directory = text + } + } + } } } - NSlider { - Layout.fillWidth: true - from: 30 - to: 500 - stepSize: 5 - value: Settings.data.wallpaper.swww.transitionFps - onPressedChanged: Settings.data.wallpaper.swww.transitionFps = Math.round(value) - cutoutColor: Colors.backgroundPrimary - } - NText { - text: "Transition Duration" - color: Colors.textPrimary - font.weight: Style.fontWeightBold - } - RowLayout { + NDivider { Layout.fillWidth: true + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + NText { - text: Settings.data.wallpaper.swww.transitionDuration.toFixed(2) + " s" + text: "Automation" + font.pointSize: 18 + font.weight: Style.fontWeightBold color: Colors.textPrimary + Layout.bottomMargin: 8 } - Item { - Layout.fillWidth: true - } - } - NSlider { - Layout.fillWidth: true - from: 0.25 - to: 10 - stepSize: 0.05 - value: Settings.data.wallpaper.swww.transitionDuration - onPressedChanged: Settings.data.wallpaper.swww.transitionDuration = value - cutoutColor: Colors.backgroundPrimary - } - } - Item { - Layout.fillHeight: true + // Random Wallpaper + 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 + } + } + + // Use Wallpaper Theme + 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 + } + } + + // Wallpaper Interval + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Wallpaper Interval" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "How often to change wallpapers automatically (in seconds)" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + + NText { + text: Settings.data.wallpaper.randomInterval + " seconds" + font.pointSize: 13 + 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 + Layout.topMargin: 26 + Layout.bottomMargin: 18 + } + + ColumnLayout { + spacing: 4 + Layout.fillWidth: true + + NText { + text: "SWWW" + font.pointSize: 18 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: 8 + } + + // Use SWWW + 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 (only visible when useSWWW is enabled) + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + visible: Settings.data.wallpaper.swww.enabled + + // Resize Mode + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + + NText { + text: "Resize Mode" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "How SWWW should resize wallpapers to fit the screen" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + 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 + } + } + } + + // Transition Type + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Transition Type" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Animation type when switching between wallpapers" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + 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 + } + } + } + + // Transition FPS + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Transition FPS" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Frames per second for transition animations" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + + NText { + text: Settings.data.wallpaper.swww.transitionFps + " FPS" + font.pointSize: 13 + 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 + } + } + + // Transition Duration + ColumnLayout { + spacing: 8 + Layout.fillWidth: true + Layout.topMargin: 8 + + NText { + text: "Transition Duration" + font.pointSize: 13 + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Duration of transition animations in seconds" + font.pointSize: 12 + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + + NText { + text: Settings.data.wallpaper.swww.transitionDuration.toFixed(3) + " seconds" + font.pointSize: 13 + 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 + } + } + } + } } } } diff --git a/Modules/Settings/Tabs/WallpaperSelector.qml b/Modules/Settings/Tabs/WallpaperSelector.qml new file mode 100644 index 0000000..f1f0b5e --- /dev/null +++ b/Modules/Settings/Tabs/WallpaperSelector.qml @@ -0,0 +1,270 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Qt.labs.folderlistmodel +import qs.Services +import qs.Widgets + +Item { + property real scaling: 1 + readonly property string tabIcon: "photo_library" + readonly property string tabLabel: "Wallpaper Selector" + readonly property int tabIndex: 7 + Layout.fillWidth: true + Layout.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: Style.marginMedium * scaling + + NText { + text: "Wallpaper Selector" + font.weight: Style.fontWeightBold + color: Colors.accentSecondary + } + + NText { + text: "Select a wallpaper from your configured directory" + color: Colors.textSecondary + wrapMode: Text.WordWrap + } + + // Current wallpaper display + NText { + text: "Current Wallpaper" + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 120 * scaling + radius: Style.radiusMedium * scaling + color: Colors.backgroundSecondary + border.color: Colors.outline + border.width: Math.max(1, Style.borderThin * scaling) + clip: true + + Image { + id: currentWallpaperImage + anchors.fill: parent + anchors.margins: Style.marginSmall * scaling + source: Wallpapers.currentWallpaper + fillMode: Image.PreserveAspectCrop + asynchronous: true + cache: true + } + + // Fallback if no image + Rectangle { + anchors.fill: parent + anchors.margins: Style.marginSmall * scaling + color: Colors.backgroundTertiary + radius: Style.radiusSmall * scaling + visible: currentWallpaperImage.status !== Image.Ready + + ColumnLayout { + anchors.centerIn: parent + spacing: Style.marginSmall * scaling + + NText { + text: "image" + font.family: "Material Symbols Outlined" + font.pointSize: Style.fontSizeLarge * scaling + color: Colors.textSecondary + Layout.alignment: Qt.AlignHCenter + } + + NText { + text: "No wallpaper selected" + color: Colors.textSecondary + Layout.alignment: Qt.AlignHCenter + } + } + } + } + + NDivider { + Layout.fillWidth: true + } + + // Wallpaper grid + NText { + text: "Available Wallpapers" + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "Click on a wallpaper to set it as your current wallpaper" + color: Colors.textSecondary + wrapMode: Text.WordWrap + } + + NText { + text: Settings.data.wallpaper.swww.enabled ? + "Wallpapers will change with " + Settings.data.wallpaper.swww.transitionType + " transition" : + "Wallpapers will change instantly" + color: Colors.textSecondary + font.pointSize: Style.fontSizeSmall * scaling + visible: Settings.data.wallpaper.swww.enabled + } + + // Refresh button and status + RowLayout { + Layout.fillWidth: true + spacing: Style.marginSmall * scaling + + NIconButton { + icon: "refresh" + tooltipText: "Refresh wallpaper list" + onClicked: { + Wallpapers.loadWallpapers() + } + } + + NText { + text: "Refresh" + color: Colors.textSecondary + } + } + + // Wallpaper grid container + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + FolderListModel { + id: folderModel + folder: "file://" + (Settings.data.wallpaper.directory !== undefined ? Settings.data.wallpaper.directory : "") + nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"] + showDirs: false + sortField: FolderListModel.Name + } + + GridView { + id: wallpaperGridView + anchors.fill: parent + clip: true + model: folderModel + + // Fixed 5 items per row - more aggressive sizing + property int itemSize: Math.floor((width - leftMargin - rightMargin - (4 * Style.marginSmall * scaling)) / 5) + + cellWidth: Math.floor((width - leftMargin - rightMargin) / 5) + cellHeight: Math.floor(itemSize * 0.67) + Style.marginSmall * scaling + + leftMargin: Style.marginSmall * scaling + rightMargin: Style.marginSmall * scaling + topMargin: Style.marginSmall * scaling + bottomMargin: Style.marginSmall * scaling + + delegate: Rectangle { + id: wallpaperItem + property string wallpaperPath: Settings.data.wallpaper.directory + "/" + fileName + property bool isSelected: wallpaperPath === Wallpapers.currentWallpaper + + width: wallpaperGridView.itemSize + height: Math.floor(wallpaperGridView.itemSize * 0.67) + radius: Style.radiusMedium * scaling + color: isSelected ? Colors.accentPrimary : Colors.backgroundSecondary + border.color: isSelected ? Colors.accentSecondary : Colors.outline + border.width: Math.max(1, Style.borderThin * scaling) + clip: true + + Image { + anchors.fill: parent + anchors.margins: Style.marginTiny * scaling + source: wallpaperPath + fillMode: Image.PreserveAspectCrop + asynchronous: true + cache: true + smooth: true + } + + // Selection indicator + Rectangle { + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: Style.marginTiny * scaling + width: 20 * scaling + height: 20 * scaling + radius: width / 2 + color: Colors.accentPrimary + border.color: Colors.onAccent + border.width: Math.max(1, Style.borderThin * scaling) + visible: isSelected + + NText { + anchors.centerIn: parent + text: "check" + font.family: "Material Symbols Outlined" + font.pointSize: Style.fontSizeSmall * scaling + color: Colors.onAccent + } + } + + // Hover effect + Rectangle { + anchors.fill: parent + color: Colors.textPrimary + opacity: mouseArea.containsMouse ? 0.1 : 0 + radius: parent.radius + + Behavior on opacity { + NumberAnimation { duration: 150 } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.LeftButton + hoverEnabled: true + onClicked: { + Wallpapers.changeWallpaper(wallpaperPath) + } + } + } + } + + // Empty state + Rectangle { + anchors.fill: parent + color: Colors.backgroundSecondary + radius: Style.radiusMedium * scaling + border.color: Colors.outline + border.width: Math.max(1, Style.borderThin * scaling) + visible: folderModel.count === 0 && !Wallpapers.scanning + + ColumnLayout { + anchors.centerIn: parent + spacing: Style.marginMedium * scaling + + NText { + text: "folder_open" + font.family: "Material Symbols Outlined" + font.pointSize: Style.fontSizeLarge * scaling + color: Colors.textSecondary + Layout.alignment: Qt.AlignHCenter + } + + NText { + text: "No wallpapers found" + color: Colors.textSecondary + font.weight: Style.fontWeightBold + Layout.alignment: Qt.AlignHCenter + } + + NText { + text: "Make sure your wallpaper directory is configured and contains image files" + color: Colors.textSecondary + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + Layout.preferredWidth: 300 * scaling + } + } + } + } + } +} \ No newline at end of file diff --git a/Services/Settings.qml b/Services/Settings.qml index 3d31e06..7e7b0b4 100644 --- a/Services/Settings.qml +++ b/Services/Settings.qml @@ -50,7 +50,14 @@ Singleton { Component.onCompleted: function () { reload() } - onLoaded: function () {} + onLoaded: function () { + Qt.callLater(function () { + if (adapter.wallpaper.current !== "") { + console.log("Settings: Initializing wallpaper to:", adapter.wallpaper.current) + Wallpapers.setCurrentWallpaper(adapter.wallpaper.current, true) + } + }) + } onLoadFailed: function (error) { if (error.toString().includes("No such file") || error === 2) // File doesn't exist, create it with default values @@ -113,7 +120,7 @@ Singleton { wallpaper: JsonObject { property string directory: "/usr/share/wallpapers" - property string current: defaultWallpaper + property string current: "" property bool isRandom: false property int randomInterval: 300 property bool generateTheme: false @@ -178,4 +185,11 @@ Singleton { } } } + + Connections { + target: adapter.wallpaper + function onIsRandomChanged() { Wallpapers.toggleRandomWallpaper() } + function onRandomIntervalChanged() { Wallpapers.restartRandomWallpaperTimer() } + function onDirectoryChanged() { Wallpapers.loadWallpapers() } + } } diff --git a/Services/Wallpapers.qml b/Services/Wallpapers.qml index d18f3a5..e586a09 100644 --- a/Services/Wallpapers.qml +++ b/Services/Wallpapers.qml @@ -11,8 +11,13 @@ Singleton { Item { Component.onCompleted: { loadWallpapers() - setCurrentWallpaper(currentWallpaper, true) - toggleRandomWallpaper() + // Only set initial wallpaper if it's not empty + if (currentWallpaper !== "") { + console.log("Wallpapers: Initializing with wallpaper:", currentWallpaper) + setCurrentWallpaper(currentWallpaper, true) + } + // Don't start random wallpaper during initialization + // toggleRandomWallpaper() } } @@ -20,7 +25,7 @@ Singleton { property string currentWallpaper: Settings.data.wallpaper.current property bool scanning: false property string transitionType: Settings.data.wallpaper.swww.transitionType - property var randomChoices: ["fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer"] + property var randomChoices: ["simple", "fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer"] function loadWallpapers() { scanning = true @@ -29,10 +34,12 @@ Singleton { } function changeWallpaper(path) { - setCurrentWallpaper(path) + console.log("Wallpapers: changeWallpaper called with:", path) + setCurrentWallpaper(path, false) } function setCurrentWallpaper(path, isInitial) { + console.log("Wallpapers: Setting wallpaper to:", path, "isInitial:", isInitial) currentWallpaper = path if (!isInitial) { Settings.data.wallpaper.current = path @@ -43,7 +50,11 @@ Singleton { } else { transitionType = Settings.data.wallpaper.swww.transitionType } + console.log("SWWW: Changing wallpaper with transition type:", transitionType) changeWallpaperProcess.running = true + } else { + // Fallback: update the settings directly for non-SWWW mode + console.log("Non-SWWW mode: Setting wallpaper directly") } if (randomWallpaperTimer.running) { @@ -59,7 +70,7 @@ Singleton { if (!randomPath) { return } - setCurrentWallpaper(randomPath) + setCurrentWallpaper(randomPath, false) } function toggleRandomWallpaper() { @@ -84,6 +95,13 @@ Singleton { } } + function startSWWWDaemon() { + if (Settings.data.wallpaper.swww.enabled) { + console.log("SWWW: Attempting to start swww-daemon...") + startDaemonProcess.running = true + } + } + Timer { id: randomWallpaperTimer interval: Settings.data.wallpaper.randomInterval * 1000 @@ -120,6 +138,18 @@ Singleton { ), "--transition-type", transitionType, "--transition-duration", Settings.data.wallpaper.swww.transitionDuration.toString( ), currentWallpaper] running: false + + onStarted: { + console.log("SWWW: Process started with command:", command.join(" ")) + } + + onExited: function(exitCode, exitStatus) { + console.log("SWWW: Process finished with exit code:", exitCode, "status:", exitStatus) + if (exitCode !== 0) { + console.log("SWWW: Process failed. Make sure swww-daemon is running with: swww-daemon") + console.log("SWWW: You can start it with: swww-daemon --format xrgb") + } + } } Process { @@ -128,4 +158,23 @@ Singleton { workingDirectory: Quickshell.shellDir running: false } + + Process { + id: startDaemonProcess + command: ["swww-daemon", "--format", "xrgb"] + running: false + + onStarted: { + console.log("SWWW: Daemon start process initiated") + } + + onExited: function(exitCode, exitStatus) { + console.log("SWWW: Daemon start process finished with exit code:", exitCode) + if (exitCode === 0) { + console.log("SWWW: Daemon started successfully") + } else { + console.log("SWWW: Failed to start daemon. It might already be running.") + } + } + } }