diff --git a/shell/bar/volume/ApplicationMixer.qml b/shell/bar/volume/ApplicationMixer.qml deleted file mode 100644 index 584be77..0000000 --- a/shell/bar/volume/ApplicationMixer.qml +++ /dev/null @@ -1,70 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Widgets -import Quickshell.Services.Pipewire -import "../../widgets/" as Widgets -import "../.." - -ColumnLayout { - id: root - - Loader { - id: sinkLoader - active: sink - - property PwNode sink: Pipewire.defaultAudioSink - - sourceComponent: WrapperItem { - PwNodeLinkTracker { - id: linkTracker - node: sinkLoader.sink - } - - ColumnLayout { - Repeater { - model: linkTracker.linkGroups - - delegate: Loader { - id: nodeLoader - active: modelData.source !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - required property PwLinkGroup modelData - - sourceComponent: VolumeCard { - id: nodeCard - node: nodeLoader.modelData.source - text: node.properties["media.name"] ?? "" - - // if icon-name is undefined, just gonna fallback on the application name - icon: IconImage { - source: { - if (nodeCard.node.properties["application.icon-name"] !== undefined) - return `image://icon/${nodeCard.node.properties["application.icon-name"]}`; - - let applicationName = nodeCard.node.properties["application.name"]; - return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`; - } - } - - button: Widgets.FontIconButton { - hoverEnabled: false - iconName: nodeCard.node.audio.muted ? "volume_off" : "volume_up" - checked: !nodeCard.node.audio.muted - inactiveColor: ShellSettings.colors["surface_container_highest"] - onClicked: { - nodeCard.node.audio.muted = !nodeCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } - } - } - } - } -} diff --git a/shell/bar/volume/DeviceMixer.qml b/shell/bar/volume/DeviceMixer.qml deleted file mode 100644 index e7076dc..0000000 --- a/shell/bar/volume/DeviceMixer.qml +++ /dev/null @@ -1,65 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Services.Pipewire -import Quickshell.Widgets -import qs -import qs.widgets - -ColumnLayout { - id: root - - // headphones - // don't load until the node is not null - Loader { - id: sinkLoader - active: sink !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - property PwNode sink: Pipewire.defaultAudioSink - - sourceComponent: VolumeCard { - id: sinkCard - node: sinkLoader.sink - button: StyledMouseArea { - property bool checked: !sinkCard.node.audio.muted - - // IconImage {} - - onClicked: { - sinkCard.node.audio.muted = !sinkCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } - - // microphone, same as above - Loader { - id: sourceLoader - active: source !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - property PwNode source: Pipewire.defaultAudioSource - - sourceComponent: VolumeCard { - id: sourceCard - node: sourceLoader.source - button: StyledMouseArea { - property bool checked: !sourceCard.node.audio.muted - - // IconImage {} - - onClicked: { - sourceCard.node.audio.muted = !sourceCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } -} diff --git a/shell/bar/volume/VolumeCard.qml b/shell/bar/volume/VolumeCard.qml index c431c30..56c3e26 100644 --- a/shell/bar/volume/VolumeCard.qml +++ b/shell/bar/volume/VolumeCard.qml @@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts -import QtQuick.Controls import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.widgets @@ -13,34 +12,34 @@ Loader { active: node != null required property PwNode node - property string label: node.nickname + property string label: node.nickname ?? node.name - sourceComponent: WrapperRectangle { - id: comp - color: ShellSettings.colors.surface_container_translucent - radius: 12 + property Component leftWidget + + PwObjectTracker { + id: tracker + objects: [root.node] + } + + sourceComponent: WrapperItem { margin: 6 - border { - width: 1 - color: ShellSettings.colors.active_translucent - } - - // property Component button - // property Component icon - - PwObjectTracker { - id: tracker - objects: [root.node] - } - RowLayout { + spacing: 10 + + Loader { + id: leftWidget + sourceComponent: root.leftWidget + Layout.preferredWidth: this.height + Layout.fillHeight: true + } + ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Text { - text: root.label + text: root.label color: ShellSettings.colors.active elide: Text.ElideRight Layout.fillWidth: true @@ -49,8 +48,6 @@ Loader { StyledSlider { value: root.node.audio.volume ?? 0 - // text: root.text - // icon: root.icon onValueChanged: { // only allow changes when the node is ready other wise you will combust @@ -64,42 +61,6 @@ Loader { Layout.fillHeight: true } } - - // StyledMouseArea { - // id: rightArrow - // Layout.preferredWidth: rightArrow.height - // // Layout.fillWidth: true - // Layout.fillHeight: true - // - // IconImage { - // source: "root:resources/general/right-arrow.svg" - // anchors.fill: parent - // } - // } - - // Loader { - // id: buttonLoader - // sourceComponent: root.button - // - // Layout.preferredWidth: this.height - // Layout.fillHeight: true - // } } } - - // sourceComponent: VolumeCard { - // id: sinkCard - // node: sinkLoader.sink - // button: StyledMouseArea { - // property bool checked: !sinkCard.node.audio.muted - // - // // IconImage {} - // - // onClicked: { - // sinkCard.node.audio.muted = !sinkCard.node.audio.muted; - // } - // } - // - // anchors.fill: parent - // } } diff --git a/shell/bar/volume/VolumeControl.qml b/shell/bar/volume/VolumeControl.qml deleted file mode 100644 index bcb4f48..0000000 --- a/shell/bar/volume/VolumeControl.qml +++ /dev/null @@ -1,36 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Widgets -import qs.widgets - -DeviceMixer {} - -// WrapperItem { -// id: root -// -// ColumnLayout { -// spacing: 10 -// -// // TabBar { -// // id: tabBar -// // model: ["headphones", "tune"] -// // Layout.fillWidth: true -// // Layout.preferredHeight: 35 -// // } -// -// -// // StackLayout { -// // id: page -// // currentIndex: tabBar.currentIndex -// // Layout.fillWidth: true -// // Layout.preferredHeight: currentItem ? currentItem.implicitHeight : 0 -// // -// // readonly property Item currentItem: children[currentIndex] -// // -// // DeviceMixer {} -// // ApplicationMixer {} -// // } -// } -// } diff --git a/shell/bar/volume/VolumeIndicator.qml b/shell/bar/volume/VolumeIndicator.qml index 20b51ef..886a10a 100644 --- a/shell/bar/volume/VolumeIndicator.qml +++ b/shell/bar/volume/VolumeIndicator.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import QtQuick.Effects import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.widgets @@ -49,12 +50,29 @@ StyledMouseArea { // Default Audio VolumeCard { + id: defaultCard node: menu.sink Layout.fillWidth: true Layout.preferredHeight: menu.entryHeight + + leftWidget: StyledMouseArea { + onClicked: defaultCard.node.audio.muted = !defaultCard.node.audio.muted + + IconImage { + anchors.fill: parent + source: { + if (defaultCard.node.audio.muted) { + return "root:resources/volume/volume-mute.svg"; + } else { + return "root:resources/volume/volume-full.svg"; + } + } + } + } } Rectangle { + visible: linkTracker.linkGroups.length !== 0 color: ShellSettings.colors.active_translucent radius: height / 2 Layout.leftMargin: 3 @@ -64,34 +82,55 @@ StyledMouseArea { } // Application Mixer - Loader { - id: sinkLoader - active: menu.sink + PwNodeLinkTracker { + id: linkTracker + node: menu.sink + } + + StyledListView { + id: appList + visible: linkTracker.linkGroups.length !== 0 + spacing: 6 + model: linkTracker.linkGroups + clip: true Layout.fillWidth: true - Layout.preferredHeight: 5 * menu.entryHeight + Layout.preferredHeight: { + const entryHeight = Math.min(5, linkTracker.linkGroups.length); - PwNodeLinkTracker { - id: linkTracker - node: menu.sink + return entryHeight * (menu.entryHeight + appList.spacing); } - sourceComponent: ListView { - anchors.fill: parent - spacing: 6 - model: linkTracker.linkGroups + delegate: VolumeCard { + id: appCard + node: modelData.source + label: node.properties["media.name"] ?? "" + width: ListView.view.width + height: menu.entryHeight - delegate: Loader { - id: nodeLoader - active: modelData.source != null - width: ListView.view.width - height: menu.entryHeight + required property PwLinkGroup modelData - required property PwLinkGroup modelData + leftWidget: StyledMouseArea { + onClicked: appCard.node.audio.muted = !appCard.node.audio.muted - sourceComponent: VolumeCard { - node: nodeLoader.modelData.source - label: node.properties["media.name"] ?? "" + IconImage { + id: appIcon + visible: false + anchors.fill: parent + + source: { + if (appCard.node.properties["application.icon-name"] !== undefined) + return `image://icon/${appCard.node.properties["application.icon-name"]}`; + + let applicationName = appCard.node.properties["application.name"]; + return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`; + } + } + + MultiEffect { + source: appIcon + anchors.fill: appIcon + saturation: appCard.node.audio.muted ? -1.0 : 0.0 } } } diff --git a/shell/launcher/Controller.qml b/shell/launcher/Controller.qml index e56f366..099d407 100644 --- a/shell/launcher/Controller.qml +++ b/shell/launcher/Controller.qml @@ -64,7 +64,7 @@ Singleton { anchors { horizontalCenter: parent.horizontalCenter top: parent.top - topMargin: screen.height / 2.75 + topMargin: screen.height / 3 } ColumnLayout { diff --git a/shell/shell.qml b/shell/shell.qml index 8527c2d..7986317 100644 --- a/shell/shell.qml +++ b/shell/shell.qml @@ -6,7 +6,7 @@ import QtQuick import "bar" import "notifications" as Notifications import "mpris" as Mpris -import "volume-osd" as VolumeOSD +import "volosd" as VolumeOSD import "settings" as Settings import "launcher" as Launcher import "lockscreen" as LockScreen diff --git a/shell/volume-osd/Controller.qml b/shell/volosd/Controller.qml similarity index 97% rename from shell/volume-osd/Controller.qml rename to shell/volosd/Controller.qml index 5e6bd3e..352e051 100644 --- a/shell/volume-osd/Controller.qml +++ b/shell/volosd/Controller.qml @@ -21,7 +21,6 @@ Scope { target: Pipewire.defaultAudioSink?.audio function onVolumeChanged() { - console.log("Volume Changed, showing OSD."); root.shouldShowOsd = true; hideTimer.restart(); } diff --git a/shell/widgets/StyledListView.qml b/shell/widgets/StyledListView.qml new file mode 100644 index 0000000..c53f7f9 --- /dev/null +++ b/shell/widgets/StyledListView.qml @@ -0,0 +1,53 @@ +import QtQuick + +ListView { + id: root + + add: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 100 + } + } + + displaced: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + move: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + remove: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 0 + duration: 100 + } + } +} diff --git a/shell/widgets/StyledSlider.qml b/shell/widgets/StyledSlider.qml index 11b653a..d7b59c8 100644 --- a/shell/widgets/StyledSlider.qml +++ b/shell/widgets/StyledSlider.qml @@ -7,15 +7,18 @@ import ".." Slider { id: slider - implicitHeight: 8 + implicitHeight: 7 + property var accentColor: ShellSettings.colors.active background: Rectangle { id: sliderContainer width: slider.availableWidth height: slider.implicitHeight - color: ShellSettings.colors.inactive - radius: 4 + color: "transparent" + border.color: ShellSettings.colors.active_translucent + border.width: 1 + radius: 5 anchors.verticalCenter: parent.verticalCenter layer.enabled: true @@ -39,7 +42,7 @@ Slider { id: fill width: slider.handle.width / 2 + slider.visualPosition * (sliderContainer.width - slider.handle.width) height: sliderContainer.height - color: Qt.color(slider.accentColor ?? "purple").darker(1.2) + color: ShellSettings.colors.active_translucent } }