From 9ada66a78ea58d8b498f1dd26bf0783e1a442c51 Mon Sep 17 00:00:00 2001 From: Laurens Duin <85798751+Laurens256@users.noreply.github.com> Date: Tue, 5 Aug 2025 08:04:53 +0200 Subject: bar/popouts: add audio device switcher (#319) * feat: basic audio switcher * feat: replace VerticalSlider with StyledSlider * fix: styling * fix: formatting * chore: make sound icons consistent, change slider styling * feat: styled slider component variants * chore: cleanup * chore: cleanup * fix: pr fixes * fix: remove redundant code * chore: remove old code * fix: controls styling * fixes * more tweaks * radiobtn: add interaction stuff Anim slider --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> --- modules/bar/components/StatusIcons.qml | 2 +- modules/bar/popouts/Audio.qml | 145 +++++++++++++++++++++++++-------- 2 files changed, 114 insertions(+), 33 deletions(-) (limited to 'modules/bar') diff --git a/modules/bar/components/StatusIcons.qml b/modules/bar/components/StatusIcons.qml index ad8c35e..c364d6b 100644 --- a/modules/bar/components/StatusIcons.qml +++ b/modules/bar/components/StatusIcons.qml @@ -58,7 +58,7 @@ Item { sourceComponent: MaterialIcon { animate: true - text: Audio.muted ? "volume_off" : Audio.volume >= 0.66 ? "volume_up" : Audio.volume >= 0.33 ? "volume_down" : "volume_mute" + text: Icons.getVolumeIcon(Audio.volume, Audio.muted) color: root.colour } } diff --git a/modules/bar/popouts/Audio.qml b/modules/bar/popouts/Audio.qml index e6e5514..84378c9 100644 --- a/modules/bar/popouts/Audio.qml +++ b/modules/bar/popouts/Audio.qml @@ -1,58 +1,139 @@ +pragma ComponentBehavior: Bound + import qs.components import qs.components.controls import qs.services import qs.config -import QtQuick.Layouts import Quickshell +import Quickshell.Services.Pipewire +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls -ColumnLayout { +Item { id: root required property var wrapper - spacing: Appearance.spacing.normal + implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: layout.implicitHeight + Appearance.padding.normal * 2 + + ButtonGroup { + id: sinks + } + + ButtonGroup { + id: sources + } + + ColumnLayout { + id: layout - VerticalSlider { - id: volumeSlider + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + spacing: 0 - icon: { - if (Audio.muted) - return "no_sound"; - if (value >= 0.5) - return "volume_up"; - if (value > 0) - return "volume_down"; - return "volume_mute"; + StyledText { + Layout.bottomMargin: Appearance.spacing.small / 2 + text: qsTr("Output") + font.weight: 500 } - value: Audio.volume - onMoved: Audio.setVolume(value) + Repeater { + model: Audio.sinks - implicitWidth: Config.osd.sizes.sliderWidth - implicitHeight: Config.osd.sizes.sliderHeight - } + StyledRadioButton { + id: control + + required property PwNode modelData + + ButtonGroup.group: sinks + checked: Audio.sink?.id === modelData.id + onClicked: Audio.setAudioSink(modelData) + text: modelData.description + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.small + Layout.bottomMargin: Appearance.spacing.small / 2 + text: qsTr("Input") + font.weight: 500 + } - StyledRect { - id: pavuButton + Repeater { + model: Audio.sources - implicitWidth: implicitHeight - implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + StyledRadioButton { + required property PwNode modelData - radius: Appearance.rounding.normal - color: Colours.palette.m3surfaceContainer + ButtonGroup.group: sources + checked: Audio.source?.id === modelData.id + onClicked: Audio.setAudioSource(modelData) + text: modelData.description + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.small + Layout.bottomMargin: Appearance.spacing.small / 2 + text: qsTr("Volume") + font.weight: 500 + } - StateLayer { - function onClicked(): void { - root.wrapper.hasCurrent = false; - Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.audio]); + StyledSlider { + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + value: Audio.volume + onMoved: Audio.setVolume(value) + + Behavior on value { + NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } } } - MaterialIcon { - id: icon + StyledRect { + Layout.topMargin: Appearance.spacing.normal + visible: Config.general.apps.audio.length > 0 + + implicitWidth: expandBtn.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: expandBtn.implicitHeight + Appearance.padding.small + + radius: Appearance.rounding.normal + color: Colours.palette.m3primaryContainer - anchors.centerIn: parent - text: "settings" + StateLayer { + color: Colours.palette.m3onPrimaryContainer + + function onClicked(): void { + root.wrapper.hasCurrent = false; + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.audio]); + } + } + + RowLayout { + id: expandBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small + + StyledText { + Layout.leftMargin: Appearance.padding.smaller + text: qsTr("Open settings") + color: Colours.palette.m3onPrimaryContainer + } + + MaterialIcon { + text: "chevron_right" + color: Colours.palette.m3onPrimaryContainer + font.pointSize: Appearance.font.size.large + } + } } } } -- cgit v1.2.3-freya