From faa6bcd2225dded0ad467a408ac0349fdbe7d84b Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 13 Aug 2025 14:00:06 +0200 Subject: [PATCH 1/2] Add Audio Settings, split NotificationHistory --- Modules/Bar/Bar.qml | 2 + Modules/Bar/NotificationHistory.qml | 29 ++ Modules/Bar/NotificationHistoryPanel.qml | 162 ++++++++++ Modules/Bar/Volume.qml | 17 +- Modules/Notification/NotificationHistory.qml | 180 ----------- Modules/Settings/SettingsPanel.qml | 5 + Modules/Settings/Tabs/Audio.qml | 308 +++++++++++++++++++ Modules/Settings/Tabs/Misc.qml | 12 +- Services/NotificationService.qml | 7 + Services/Settings.qml | 42 ++- 10 files changed, 555 insertions(+), 209 deletions(-) create mode 100644 Modules/Bar/NotificationHistory.qml create mode 100644 Modules/Bar/NotificationHistoryPanel.qml delete mode 100644 Modules/Notification/NotificationHistory.qml create mode 100644 Modules/Settings/Tabs/Audio.qml diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index a494664..4948ddb 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -15,6 +15,8 @@ Variants { required property ShellScreen modelData readonly property real scaling: Scaling.scale(screen) + property var settingsPanel: null + screen: modelData implicitHeight: Style.barHeight * scaling color: "transparent" diff --git a/Modules/Bar/NotificationHistory.qml b/Modules/Bar/NotificationHistory.qml new file mode 100644 index 0000000..2d0b638 --- /dev/null +++ b/Modules/Bar/NotificationHistory.qml @@ -0,0 +1,29 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell +import Quickshell.Wayland +import qs.Services +import qs.Widgets + +NIconButton { + id: root + + readonly property real scaling: Scaling.scale(screen) + sizeMultiplier: 0.8 + showBorder: false + icon: "notifications" + tooltipText: "Notification History" + onClicked: { + if (!notificationHistoryPanelLoader.active) { + notificationHistoryPanelLoader.isLoaded = true + } + if (notificationHistoryPanelLoader.item) { + notificationHistoryPanelLoader.item.visible = !notificationHistoryPanelLoader.item.visible + } + } + + NotificationHistoryPanel { + id: notificationHistoryPanelLoader + } +} \ No newline at end of file diff --git a/Modules/Bar/NotificationHistoryPanel.qml b/Modules/Bar/NotificationHistoryPanel.qml new file mode 100644 index 0000000..db1fd42 --- /dev/null +++ b/Modules/Bar/NotificationHistoryPanel.qml @@ -0,0 +1,162 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell +import Quickshell.Wayland +import Quickshell.Services.Notifications +import qs.Services +import qs.Widgets + +// Loader for Notification History panel +NLoader { + id: root + + content: Component { + NPanel { + id: notificationPanel + + Connections { + target: notificationPanel + ignoreUnknownSignals: true + function onDismissed() { + notificationPanel.visible = false + } + } + + WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand + + Rectangle { + color: Colors.backgroundSecondary + radius: Style.radiusMedium * scaling + border.color: Colors.backgroundTertiary + border.width: Math.max(1, Style.borderMedium * scaling) + width: 400 * scaling + height: 500 * scaling + anchors.top: parent.top + anchors.right: parent.right + anchors.topMargin: Style.marginTiny * scaling + anchors.rightMargin: Style.marginTiny * scaling + + ColumnLayout { + anchors.fill: parent + anchors.margins: Style.marginLarge * scaling + spacing: Style.marginMedium * scaling + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginMedium * scaling + + NText { + text: "notifications" + font.family: "Material Symbols Outlined" + font.pointSize: Style.fontSizeXL * scaling + color: Colors.accentPrimary + } + + NText { + text: "Notification History" + font.pointSize: Style.fontSizeLarge * scaling + font.bold: true + color: Colors.textPrimary + Layout.fillWidth: true + } + + NIconButton { + icon: "delete" + sizeMultiplier: 0.8 + tooltipText: "Clear history" + onClicked: NotificationService.clearHistory() + } + + NIconButton { + icon: "close" + sizeMultiplier: 0.8 + onClicked: { + notificationPanel.visible = false + } + } + } + + NDivider {} + + ListView { + id: notificationList + Layout.fillWidth: true + Layout.fillHeight: true + model: NotificationService.historyModel + spacing: Style.marginMedium * scaling + clip: true + boundsBehavior: Flickable.StopAtBounds + + delegate: Rectangle { + width: notificationList ? (notificationList.width - 20) : 380 * scaling + height: 80 + radius: Style.radiusMedium * scaling + color: notificationMouseArea.containsMouse ? Colors.accentPrimary : "transparent" + + RowLayout { + anchors { + fill: parent + margins: 15 + } + spacing: 15 + + // Notification content + Column { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + spacing: 5 + + NText { + text: (summary || "No summary").substring(0, 100) + font.pointSize: Style.fontSizeMedium * scaling + font.weight: Font.Medium + color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textPrimary + wrapMode: Text.Wrap + width: parent.width - 30 + maximumLineCount: 2 + elide: Text.ElideRight + } + + NText { + text: (body || "").substring(0, 150) + font.pointSize: Style.fontSizeSmall * scaling + color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textSecondary + wrapMode: Text.Wrap + width: parent.width - 30 + maximumLineCount: 3 + elide: Text.ElideRight + } + + NText { + text: NotificationService.formatTimestamp(timestamp) + font.pointSize: Style.fontSizeSmall * scaling + color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textSecondary + } + } + } + + MouseArea { + id: notificationMouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + console.log("[NotificationHistory] Removing notification:", summary) + NotificationService.historyModel.remove(index) + NotificationService.saveHistory() + } + } + } + + ScrollBar.vertical: ScrollBar { + active: true + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Modules/Bar/Volume.qml b/Modules/Bar/Volume.qml index ee7b690..3f14d22 100644 --- a/Modules/Bar/Volume.qml +++ b/Modules/Bar/Volume.qml @@ -10,6 +10,13 @@ Item { width: pill.width height: pill.height + // Reference to settings panel + property var settingsPanel: null + + Component.onCompleted: { + console.log("[Volume] settingsPanel received:", !!settingsPanel) + } + // Used to avoid opening the pill on Quickshell startup property bool firstVolumeReceived: false @@ -71,7 +78,15 @@ Item { } } onClicked: { - audioDeviceSelector.isLoaded = !audioDeviceSelector.isLoaded + // Open settings panel and navigate to Audio tab + console.log("[Volume] Attempting to open settings panel...") + try { + settingsPanel.isLoaded = true + settingsPanel.content.currentTabIndex = 5 // Audio tab index + console.log("[Volume] Settings panel opened successfully") + } catch (error) { + console.log("[Volume] Error opening settings panel:", error) + } } } } diff --git a/Modules/Notification/NotificationHistory.qml b/Modules/Notification/NotificationHistory.qml deleted file mode 100644 index 80fa1d6..0000000 --- a/Modules/Notification/NotificationHistory.qml +++ /dev/null @@ -1,180 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Services.Notifications -import qs.Services -import qs.Widgets - -NIconButton { - id: root - - readonly property real scaling: Scaling.scale(screen) - sizeMultiplier: 0.8 - showBorder: false - icon: "notifications" - tooltipText: "Notification History" - onClicked: { - notificationHistoryLoader.active = !notificationHistoryLoader.active - } - - // Loader for Notification History menu - NLoader { - id: notificationHistoryLoader - active: false - - content: Component { - NPanel { - id: notificationPanel - - Connections { - target: notificationPanel - ignoreUnknownSignals: true - function onDismissed() { - notificationHistoryLoader.active = false - } - } - - WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand - - Rectangle { - color: Colors.backgroundSecondary - radius: Style.radiusMedium * scaling - border.color: Colors.backgroundTertiary - border.width: Math.max(1, Style.borderMedium * scaling) - width: 400 * scaling - height: 500 * scaling - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Style.marginTiny * scaling - anchors.rightMargin: Style.marginTiny * scaling - - ColumnLayout { - anchors.fill: parent - anchors.margins: Style.marginLarge * scaling - spacing: Style.marginMedium * scaling - - RowLayout { - Layout.fillWidth: true - spacing: Style.marginMedium * scaling - - NText { - text: "notifications" - font.family: "Material Symbols Outlined" - font.pointSize: Style.fontSizeXL * scaling - color: Colors.accentPrimary - } - - NText { - text: "Notification History" - font.pointSize: Style.fontSizeLarge * scaling - font.bold: true - color: Colors.textPrimary - Layout.fillWidth: true - } - - NIconButton { - icon: "delete" - sizeMultiplier: 0.8 - tooltipText: "Clear history" - onClicked: NotificationService.clearHistory() - } - - NIconButton { - icon: "close" - sizeMultiplier: 0.8 - onClicked: { - notificationHistoryLoader.active = false - } - } - } - - NDivider {} - - ListView { - id: notificationList - Layout.fillWidth: true - Layout.fillHeight: true - model: NotificationService.historyModel - spacing: Style.marginMedium * scaling - clip: true - boundsBehavior: Flickable.StopAtBounds - - delegate: Rectangle { - width: notificationList ? (notificationList.width - 20) : 380 * scaling - height: 80 - radius: Style.radiusMedium * scaling - color: notificationMouseArea.containsMouse ? Colors.accentPrimary : "transparent" - - RowLayout { - anchors { - fill: parent - margins: 15 - } - spacing: 15 - - - - // Notification content - Column { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - spacing: 5 - - NText { - text: (summary || "No summary").substring(0, 100) - font.pointSize: Style.fontSizeMedium * scaling - font.weight: Font.Medium - color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textPrimary - wrapMode: Text.Wrap - width: parent.width - 30 - maximumLineCount: 2 - elide: Text.ElideRight - } - - NText { - text: (body || "").substring(0, 150) - font.pointSize: Style.fontSizeSmall * scaling - color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textSecondary - wrapMode: Text.Wrap - width: parent.width - 30 - maximumLineCount: 3 - elide: Text.ElideRight - } - - NText { - text: NotificationService.formatTimestamp(timestamp) - font.pointSize: Style.fontSizeSmall * scaling - color: notificationMouseArea.containsMouse ? Colors.backgroundPrimary : Colors.textSecondary - } - } - - - } - - MouseArea { - id: notificationMouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: { - console.log("[NotificationHistory] Removing notification:", summary) - NotificationService.historyModel.remove(index) - NotificationService.saveHistory() - } - } - } - - ScrollBar.vertical: ScrollBar { - active: true - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/Modules/Settings/SettingsPanel.qml b/Modules/Settings/SettingsPanel.qml index b001c39..189e969 100644 --- a/Modules/Settings/SettingsPanel.qml +++ b/Modules/Settings/SettingsPanel.qml @@ -39,6 +39,10 @@ NLoader { "label": "Network", "icon": "wifi", "source": "Tabs/Network.qml" + }, { + "label": "Audio", + "icon": "volume_up", + "source": "Tabs/Audio.qml" }, { "label": "Display", "icon": "monitor", @@ -212,6 +216,7 @@ NLoader { Tabs.TimeWeather {} Tabs.ScreenRecorder {} Tabs.Network {} + Tabs.Audio {} Tabs.Display {} Tabs.Wallpaper {} Tabs.WallpaperSelector {} diff --git a/Modules/Settings/Tabs/Audio.qml b/Modules/Settings/Tabs/Audio.qml new file mode 100644 index 0000000..1874607 --- /dev/null +++ b/Modules/Settings/Tabs/Audio.qml @@ -0,0 +1,308 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.Pipewire + +import qs.Modules.Settings +import qs.Widgets +import qs.Services + +ColumnLayout { + id: root + + spacing: 0 + + ScrollView { + id: scrollView + + Layout.fillWidth: true + Layout.fillHeight: true + padding: Style.marginMedium * scaling + 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 + } + + ColumnLayout { + spacing: Style.marginTiny * scaling + Layout.fillWidth: true + + NText { + text: "Audio" + font.pointSize: Style.fontSizeXL * scaling + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: Style.marginSmall * scaling + } + + // Volume Controls + ColumnLayout { + spacing: Style.marginSmall * scaling + Layout.fillWidth: true + Layout.topMargin: Style.marginSmall * scaling + + // Master Volume + ColumnLayout { + spacing: Style.marginSmall * scaling + Layout.fillWidth: true + + NText { + text: "Master Volume" + font.weight: Style.fontWeightBold + color: Colors.textPrimary + } + + NText { + text: "System-wide volume level" + font.pointSize: Style.fontSizeSmall * scaling + color: Colors.textSecondary + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + RowLayout { + NSlider { + id: masterVolumeSlider + Layout.fillWidth: true + from: 0 + to: allowOverdrive.value ? 200 : 100 + value: (Audio.volume || 0) * 100 + stepSize: 5 + onValueChanged: { + Audio.volumeSet(value / 100) + } + } + + NText { + text: Math.round(masterVolumeSlider.value) + "%" + Layout.alignment: Qt.AlignVCenter + color: Colors.textSecondary + } + } + + NToggle { + id: allowOverdrive + label: "Allow Volume Overdrive" + description: "Enable volume levels above 100% (up to 200%)" + value: Settings.data.audio ? Settings.data.audio.volumeOverdrive : false + onToggled: function (checked) { + Settings.data.audio.volumeOverdrive = checked + + // If overdrive is disabled and current volume is above 100%, cap it + if (!checked && Audio.volume > 1.0) { + Audio.volumeSet(1.0) + } + } + } + } + + // Mute Toggle + ColumnLayout { + spacing: Style.marginSmall * scaling + Layout.fillWidth: true + Layout.topMargin: Style.marginMedium * scaling + + NToggle { + label: "Mute Audio" + description: "Mute or unmute the default audio output" + value: Audio.muted + onToggled: function (newValue) { + if (Audio.sink && Audio.sink.audio) { + Audio.sink.audio.muted = newValue + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginLarge * 2 * scaling + Layout.bottomMargin: Style.marginLarge * scaling + } + + // Audio Devices + ColumnLayout { + spacing: Style.marginLarge * scaling + Layout.fillWidth: true + + NText { + text: "Audio Devices" + font.pointSize: Style.fontSizeXL * scaling + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: Style.marginSmall * scaling + } + + // Output Device + NComboBox { + id: outputDeviceCombo + label: "Output Device" + description: "Default audio output device" + optionsKeys: outputDeviceKeys + optionsLabels: outputDeviceLabels + currentKey: Audio.sink ? Audio.sink.id.toString() : "" + onSelected: function (key) { + // Find the node by ID and set it as preferred + for (let i = 0; i < Pipewire.nodes.count; i++) { + let node = Pipewire.nodes.get(i) + if (node.id.toString() === key && node.isSink) { + Pipewire.preferredDefaultAudioSink = node + break + } + } + } + } + + // Input Device + NComboBox { + id: inputDeviceCombo + label: "Input Device" + description: "Default audio input device" + optionsKeys: inputDeviceKeys + optionsLabels: inputDeviceLabels + currentKey: Audio.source ? Audio.source.id.toString() : "" + onSelected: function (key) { + // Find the node by ID and set it as preferred + for (let i = 0; i < Pipewire.nodes.count; i++) { + let node = Pipewire.nodes.get(i) + if (node.id.toString() === key && !node.isSink) { + Pipewire.preferredDefaultAudioSource = node + break + } + } + } + } + + + } + + // Divider + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginLarge * scaling + Layout.bottomMargin: Style.marginMedium * scaling + } + + // Audio Visualizer Category + ColumnLayout { + spacing: Style.marginSmall * scaling + Layout.fillWidth: true + + NText { + text: "Audio Visualizer" + font.pointSize: Style.fontSizeXL * scaling + font.weight: Style.fontWeightBold + color: Colors.textPrimary + Layout.bottomMargin: Style.marginSmall * scaling + } + + // Audio Visualizer section + NComboBox { + id: audioVisualizerCombo + label: "Visualization Type" + description: "Choose a visualization type for media playback" + optionsKeys: ["radial", "bars", "wave"] + optionsLabels: ["Radial", "Bars", "Wave"] + currentKey: Settings.data.audio ? Settings.data.audio.audioVisualizer.type : "radial" + onSelected: function (key) { + if (!Settings.data.audio) { + Settings.data.audio = {} + } + if (!Settings.data.audio.audioVisualizer) { + Settings.data.audio.audioVisualizer = {} + } + Settings.data.audio.audioVisualizer.type = key + } + } + } + } + } + } + + // Device list properties + property var outputDeviceKeys: ["default"] + property var outputDeviceLabels: ["Default Output"] + property var inputDeviceKeys: ["default"] + property var inputDeviceLabels: ["Default Input"] + + // Bind Pipewire nodes + PwObjectTracker { + id: nodeTracker + objects: [Pipewire.nodes] + } + + // Update device lists when component is completed + Component.onCompleted: { + updateDeviceLists() + } + + // Timer to check if pipewire is ready and update device lists + Timer { + id: deviceUpdateTimer + interval: 100 + repeat: true + running: !(Pipewire && Pipewire.ready) + onTriggered: { + if (Pipewire && Pipewire.ready) { + updateDeviceLists() + running = false + } + } + } + + // Update device lists when nodes change + Connections { + target: nodeTracker + function onObjectsChanged() { + updateDeviceLists() + } + } + + Repeater { + id: nodesRepeater + model: Pipewire.nodes + delegate: Item { + Component.onCompleted: { + if (modelData && modelData.isSink && modelData.audio) { + // Add to output devices + let key = modelData.id.toString() + if (!outputDeviceKeys.includes(key)) { + outputDeviceKeys.push(key) + outputDeviceLabels.push(modelData.description || modelData.name || "Unknown Device") + } + } else if (modelData && !modelData.isSink && modelData.audio) { + // Add to input devices + let key = modelData.id.toString() + if (!inputDeviceKeys.includes(key)) { + inputDeviceKeys.push(key) + inputDeviceLabels.push(modelData.description || modelData.name || "Unknown Device") + } + } + } + } + } + + function updateDeviceLists() { + if (Pipewire && Pipewire.ready) { + // Update comboboxes + if (outputDeviceCombo) { + outputDeviceCombo.optionsKeys = outputDeviceKeys + outputDeviceCombo.optionsLabels = outputDeviceLabels + } + + if (inputDeviceCombo) { + inputDeviceCombo.optionsKeys = inputDeviceKeys + inputDeviceCombo.optionsLabels = inputDeviceLabels + } + } + } +} \ No newline at end of file diff --git a/Modules/Settings/Tabs/Misc.qml b/Modules/Settings/Tabs/Misc.qml index 6b98781..6ffa0a3 100644 --- a/Modules/Settings/Tabs/Misc.qml +++ b/Modules/Settings/Tabs/Misc.qml @@ -40,17 +40,7 @@ ColumnLayout { Layout.bottomMargin: Style.marginSmall * scaling } - // Audio Visualizer section - NComboBox { - label: "Audio Visualizer" - description: "Choose a visualization type" - optionsKeys: ["radial", "bars", "wave"] - optionsLabels: ["Radial", "Bars", "Wave"] - currentKey: Settings.data.audioVisualizer.type - onSelected: function (key) { - Settings.data.audioVisualizer.type = key - } - } + } } } diff --git a/Services/NotificationService.qml b/Services/NotificationService.qml index 9c80c2c..16ddb38 100644 --- a/Services/NotificationService.qml +++ b/Services/NotificationService.qml @@ -27,6 +27,13 @@ QtObject { // Signal when notification is received onNotification: function (notification) { + // Check if notifications are suppressed + if (Settings.data.notifications && Settings.data.notifications.suppressed) { + // Still add to history but don't show notification + root.addToHistory(notification) + return + } + // Track the notification notification.tracked = true diff --git a/Services/Settings.qml b/Services/Settings.qml index 7cf43a3..7305ef0 100644 --- a/Services/Settings.qml +++ b/Services/Settings.qml @@ -26,6 +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. <--- VERY BROKEN + //property var openPanel: null Item { Component.onCompleted: { @@ -36,17 +38,22 @@ Singleton { } FileView { + + // TBC ? needed for SWWW only ? + // Qt.callLater(function () { + // WallpaperManager.setCurrentWallpaper(settings.currentWallpaper, true); + // }) path: settingsFile watchChanges: true onFileChanged: reload() onAdapterUpdated: writeAdapter() - Component.onCompleted: { + Component.onCompleted: function () { reload() } - onLoaded: { + onLoaded: function () { Qt.callLater(function () { if (adapter.wallpaper.current !== "") { - + console.log("Settings: Initializing wallpaper to:", adapter.wallpaper.current) Wallpapers.setCurrentWallpaper(adapter.wallpaper.current, true) } }) @@ -80,6 +87,7 @@ Singleton { property string avatarImage: defaultAvatar property bool dimDesktop: true property bool showScreenCorners: false + property bool showDock: false } // location @@ -102,8 +110,9 @@ Singleton { property string videoCodec: "h264" property string quality: "very_high" property string colorRange: "limited" - property string audioSource: "default_output" property bool showCursor: true + // New: optional audio source selection (default: system output) + property string audioSource: "default_output" } // wallpaper @@ -160,11 +169,16 @@ Singleton { property list monitors: [] } - // audioVisualizer - property JsonObject audioVisualizer + // audio + property JsonObject audio - audioVisualizer: JsonObject { - property string type: "radial" + audio: JsonObject { + property bool volumeOverdrive: false + property JsonObject audioVisualizer + + audioVisualizer: JsonObject { + property string type: "radial" + } } // ui @@ -179,14 +193,8 @@ Singleton { Connections { target: adapter.wallpaper - function onIsRandomChanged() { - Wallpapers.toggleRandomWallpaper() - } - function onRandomIntervalChanged() { - Wallpapers.restartRandomWallpaperTimer() - } - function onDirectoryChanged() { - Wallpapers.loadWallpapers() - } + function onIsRandomChanged() { Wallpapers.toggleRandomWallpaper() } + function onRandomIntervalChanged() { Wallpapers.restartRandomWallpaperTimer() } + function onDirectoryChanged() { Wallpapers.loadWallpapers() } } } From e2a0e491a0e649457604d0348f126e26c1dd9c64 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 13 Aug 2025 14:03:02 +0200 Subject: [PATCH 2/2] Add audoOverdrive to Volume Symbol in bar --- Modules/Bar/Volume.qml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Modules/Bar/Volume.qml b/Modules/Bar/Volume.qml index 3f14d22..5e02908 100644 --- a/Modules/Bar/Volume.qml +++ b/Modules/Bar/Volume.qml @@ -28,17 +28,17 @@ Item { } function getIconColor() { - return (Audio.volume <= 1.0) ? Colors.textPrimary : getVolumeColor() + return (getDisplayVolume() <= 1.0) ? Colors.textPrimary : getVolumeColor() } function getVolumeColor() { - if (Audio.volume <= 1.0) { + if (getDisplayVolume() <= 1.0) { return Colors.accentPrimary } // Indicate that the volume is over 100% // Calculate interpolation factor (0 at 100%, 1.0 at 200%) - let factor = (Audio.volume - 1.0) + let factor = (getDisplayVolume() - 1.0) // Blend between accent and warning colors return Qt.rgba(Colors.accentPrimary.r + (Colors.error.r - Colors.accentPrimary.r) * factor, @@ -46,6 +46,15 @@ Item { Colors.accentPrimary.b + (Colors.error.b - Colors.accentPrimary.b) * factor, 1) } + function getDisplayVolume() { + // If volumeOverdrive is false, clamp to 100% + if (!Settings.data.audio || !Settings.data.audio.volumeOverdrive) { + return Math.min(Audio.volume, 1.0) + } + // If volumeOverdrive is true, allow up to 200% + return Math.min(Audio.volume, 2.0) + } + // Connection used to open the pill when volume changes Connections { target: Audio.sink?.audio ? Audio.sink?.audio : null @@ -66,9 +75,9 @@ Item { iconCircleColor: getVolumeColor() collapsedIconColor: getIconColor() autoHide: true - text: Math.round(Audio.volume * 100) + "%" + text: Math.round(getDisplayVolume() * 100) + "%" tooltipText: "Volume: " + Math.round( - Audio.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume." + getDisplayVolume() * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume." onWheel: function (angle) { if (angle > 0) {