From 07f8a72d6db605d82f3fe2e5f4fd48029c24a857 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 23 Nov 2025 21:35:43 +0100 Subject: [PATCH] wactioncenter: media controls --- .../ii/assets/icons/fluent/next-filled.svg | 1 + .../ii/assets/icons/fluent/next.svg | 1 + .../ii/assets/icons/fluent/pause-filled.svg | 1 + .../ii/assets/icons/fluent/pause.svg | 1 + .../ii/assets/icons/fluent/play-filled.svg | 1 + .../ii/assets/icons/fluent/play.svg | 1 + .../assets/icons/fluent/previous-filled.svg | 1 + .../ii/assets/icons/fluent/previous.svg | 1 + .../ii/mediaControls/MediaControls.qml | 25 +-- .../actionCenter/ActionCenterContent.qml | 61 +++++-- .../waffle/actionCenter/MediaPaneContent.qml | 156 ++++++++++++++++++ .../actionCenter/WaffleActionCenter.qml | 5 +- .../bluetooth/BluetoothControl.qml | 2 +- .../actionCenter/mainPage/MainPageFooter.qml | 4 +- .../waffle/actionCenter/wifi/WifiControl.qml | 2 +- .../ii/modules/waffle/bar/AppButton.qml | 2 +- .../waffle/looks/WBarAttachedPanelContent.qml | 54 ++---- ...FooterButton.qml => WBorderlessButton.qml} | 0 .../ii/modules/waffle/looks/WPane.qml | 58 +++++++ .../ii/modules/waffle/looks/WStackView.qml | 6 +- .../waffle/onScreenDisplay/OSDValue.qml | 65 ++++---- .../waffle/onScreenDisplay/WaffleOSD.qml | 5 +- .../ii/services/MprisController.qml | 25 +++ 23 files changed, 348 insertions(+), 130 deletions(-) create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/next.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/pause.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/play.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/previous.svg create mode 100644 dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml rename dots/.config/quickshell/ii/modules/waffle/looks/{WPanelFooterButton.qml => WBorderlessButton.qml} (100%) create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg new file mode 100644 index 000000000..d3741963d --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/next-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/next.svg b/dots/.config/quickshell/ii/assets/icons/fluent/next.svg new file mode 100644 index 000000000..26bdcb05e --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg new file mode 100644 index 000000000..595435fe7 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/pause-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg b/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg new file mode 100644 index 000000000..a334eb60d --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg new file mode 100644 index 000000000..ae2a12370 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/play-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/play.svg b/dots/.config/quickshell/ii/assets/icons/fluent/play.svg new file mode 100644 index 000000000..777cf8903 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg new file mode 100644 index 000000000..b994af7e1 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/previous-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg b/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg new file mode 100644 index 000000000..bb61b7779 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/previous.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml b/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml index fa60e0474..3cd620834 100644 --- a/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml +++ b/dots/.config/quickshell/ii/modules/ii/mediaControls/MediaControls.qml @@ -16,7 +16,7 @@ Scope { id: root property bool visible: false readonly property MprisPlayer activePlayer: MprisController.activePlayer - readonly property var realPlayers: Mpris.players.values.filter(player => isRealPlayer(player)) + readonly property var realPlayers: MprisController.players readonly property var meaningfulPlayers: filterDuplicatePlayers(realPlayers) readonly property real osdWidth: Appearance.sizes.osdWidth readonly property real widgetWidth: Appearance.sizes.mediaControlsWidth @@ -24,27 +24,6 @@ Scope { property real popupRounding: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1 property list visualizerPoints: [] - property bool hasPlasmaIntegration: false - Process { - id: plasmaIntegrationAvailabilityCheckProc - running: true - command: ["bash", "-c", "command -v plasma-browser-integration-host"] - onExited: (exitCode, exitStatus) => { - root.hasPlasmaIntegration = (exitCode === 0); - } - } - function isRealPlayer(player) { - if (!Config.options.media.filterDuplicatePlayers) { - return true; - } - return ( - // Remove unecessary native buses from browsers if there's plasma integration - !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.firefox')) && !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) && - // playerctld just copies other buses and we don't need duplicates - !player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') && - // Non-instance mpd bus - !(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd'))); - } function filterDuplicatePlayers(players) { let filtered = []; let used = new Set(); @@ -96,7 +75,7 @@ Scope { id: mediaControlsLoader active: GlobalStates.mediaControlsOpen onActiveChanged: { - if (!mediaControlsLoader.active && Mpris.players.values.filter(player => isRealPlayer(player)).length === 0) { + if (!mediaControlsLoader.active && root.realPlayers.length === 0) { GlobalStates.mediaControlsOpen = false; } } diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml index 4d45df92e..284f72013 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -12,28 +13,52 @@ import qs.modules.waffle.actionCenter.mainPage WBarAttachedPanelContent { id: root - contentItem: WStackView { - id: stackView - anchors.fill: parent - implicitWidth: initItem.implicitWidth - implicitHeight: initItem.implicitHeight - - initialItem: PageColumn { - id: initItem - MainPageBody {} - Separator {} - MainPageFooter {} + readonly property bool barAtBottom: Config.options.waffles.bar.bottom + + contentItem: Column { + // This somewhat sophisticated anchoring is needed to make opening anim not jump abruptly when stuff appear + anchors { + left: parent.left + right: parent.right + top: root.barAtBottom ? undefined : parent.top + bottom: root.barAtBottom ? parent.bottom : undefined + margins: root.visualMargin } + spacing: 12 - Component.onCompleted: { - ActionCenterContext.stackView = this + WPane { + visible: MprisController.activePlayer != null && MprisController.isRealPlayer(MprisController.activePlayer) + anchors { + left: parent.left + right: parent.right + } + contentItem: MediaPaneContent {} } + WPane { + contentItem: WStackView { + id: stackView + anchors.fill: parent + implicitWidth: initItem.implicitWidth + implicitHeight: initItem.implicitHeight - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.BackButton - onClicked: { - ActionCenterContext.back() + initialItem: PageColumn { + id: initItem + MainPageBody {} + Separator {} + MainPageFooter {} + } + + Component.onCompleted: { + ActionCenterContext.stackView = this; + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.BackButton + onClicked: { + ActionCenterContext.back(); + } + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml new file mode 100644 index 000000000..5c4c6df97 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/MediaPaneContent.qml @@ -0,0 +1,156 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +Rectangle { + id: root + implicitHeight: 176 + implicitWidth: 358 + color: Looks.colors.bgPanelBody + anchors.fill: parent + + readonly property var activePlayer: MprisController.activePlayer + + Column { + anchors { + fill: parent + leftMargin: 23 + rightMargin: 23 + topMargin: 16 + bottomMargin: 20 + } + spacing: 25 + + AppInfoRow { + anchors { + left: parent.left + right: parent.right + } + } + + TrackInfoRow { + anchors { + left: parent.left + right: parent.right + } + } + + ControlButtonsRow { + anchors.horizontalCenter: parent.horizontalCenter + } + } + + component AppInfoRow: RowLayout { + id: appInfo + spacing: 8 + + property var desktopEntry: { + const desktopEntryString = root.activePlayer?.desktopEntry ?? ""; + return DesktopEntries.byId(desktopEntryString); + } + + FluentIcon { + implicitSize: 20 + icon: appInfo.desktopEntry?.icon || "music-note-2" + monochrome: !appInfo.desktopEntry?.icon + } + + WText { + Layout.fillWidth: true + text: appInfo.desktopEntry?.name ?? Translation.tr("Media") + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + } + } + + component TrackInfoRow: RowLayout { + spacing: 16 + + ColumnLayout { + id: trackInfo + Layout.fillWidth: true + spacing: 0 + + WText { + Layout.fillWidth: true + font.weight: Looks.font.weight.strong + font.pixelSize: Looks.font.pixelSize.large + elide: Text.ElideRight + text: StringUtils.cleanMusicTitle(root.activePlayer?.trackTitle) || Translation.tr("Unknown Title") + } + + WText { + Layout.fillWidth: true + elide: Text.ElideRight + text: root.activePlayer?.trackArtist || Translation.tr("Unknown Artist") + } + } + + StyledImage { + id: artImage + Layout.preferredWidth: 58 + Layout.preferredHeight: trackInfo.implicitHeight + source: MprisController.activeTrack?.artUrl || "" + fillMode: Image.PreserveAspectFit + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: artImage.width + height: artImage.height + Rectangle { + anchors.centerIn: parent + width: artImage.paintedWidth + height: artImage.paintedHeight + radius: Looks.radius.medium + } + } + } + } + } + + component ControlButtonsRow: RowLayout { + spacing: 26 + + MediaControlButton { + iconName: "previous" + enabled: root.activePlayer?.canGoPrevious ?? false + onClicked: root.activePlayer?.previous() + } + MediaControlButton { + readonly property bool playing: root.activePlayer?.isPlaying ?? false + iconName: playing ? "pause" : "play" + enabled: (playing && root.activePlayer?.canPause) || (!playing && root.activePlayer?.canPlay) + onClicked: root.activePlayer?.togglePlaying() + } + MediaControlButton { + iconName: "next" + enabled: root.activePlayer?.canGoNext ?? false + onClicked: root.activePlayer?.next() + } + } + + component MediaControlButton: WBorderlessButton { + id: controlButton + required property string iconName + implicitHeight: 40 + implicitWidth: 40 + + contentItem: Item { + FluentIcon { + anchors.centerIn: parent + icon: controlButton.iconName + monochrome: true + filled: true + implicitSize: 18 + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml index 174b7851f..8fe33fa47 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/WaffleActionCenter.qml @@ -35,8 +35,8 @@ Scope { right: true } - implicitWidth: content.implicitWidth + content.visualMargin * 2 - implicitHeight: content.implicitHeight + content.visualMargin * 2 + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight HyprlandFocusGrab { id: focusGrab @@ -55,7 +55,6 @@ Scope { ActionCenterContent { id: content anchors.fill: parent - anchors.margins: visualMargin focus: true Keys.onPressed: event => { // Esc to close diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml index c8d3a036a..e0e6327a6 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothControl.qml @@ -110,7 +110,7 @@ Item { Quickshell.execDetached(["bash", "-c", Config.options.apps.bluetooth]); } } - WPanelFooterButton { + WBorderlessButton { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 12 diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml index 1190bd38e..3d5c8d882 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/mainPage/MainPageFooter.qml @@ -11,7 +11,7 @@ import qs.modules.waffle.actionCenter FooterRectangle { // Battery button - WPanelFooterButton { + WBorderlessButton { visible: Battery.available anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left @@ -36,7 +36,7 @@ FooterRectangle { } // Settings button - WPanelFooterButton { + WBorderlessButton { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 12 diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml index 6f07462be..e6c91292a 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WifiControl.qml @@ -100,7 +100,7 @@ Item { Quickshell.execDetached(["bash", "-c", Config.options.apps.network]); } } - WPanelFooterButton { + WBorderlessButton { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 12 diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml index 9d8d323fe..20af517fe 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml @@ -54,7 +54,7 @@ BarButton { contentItem: Item { id: contentItem - anchors.centerIn: background + anchors.centerIn: root.background implicitHeight: iconWidget.implicitHeight implicitWidth: iconWidget.implicitWidth diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml index 3035a6511..657897ef1 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WBarAttachedPanelContent.qml @@ -12,8 +12,6 @@ Item { signal closed() - property alias border: borderRect - property alias borderColor: borderRect.border.color required property Item contentItem property real visualMargin: 12 property int closeAnimDuration: 150 @@ -24,32 +22,19 @@ Item { readonly property bool barAtBottom: Config.options.waffles.bar.bottom - implicitHeight: borderRect.implicitHeight - implicitWidth: borderRect.implicitWidth - - WRectangularShadow { - target: borderRect - } - - Rectangle { - id: borderRect - z: 1 - - color: "transparent" - radius: Looks.radius.large - border.color: Looks.colors.bg2Border - border.width: 1 - implicitWidth: contentItem.implicitWidth + border.width * 2 - implicitHeight: contentItem.implicitHeight + border.width * 2 + implicitHeight: contentItem.implicitHeight + visualMargin * 2 + implicitWidth: contentItem.implicitWidth + visualMargin * 2 + Item { + id: panelContent anchors { left: parent.left right: parent.right top: root.barAtBottom ? undefined : parent.top bottom: root.barAtBottom ? parent.bottom : undefined // Opening anim - bottomMargin: root.barAtBottom ? sourceEdgeMargin : 0 - topMargin: root.barAtBottom ? 0 : sourceEdgeMargin + bottomMargin: root.barAtBottom ? sourceEdgeMargin : root.visualMargin + topMargin: root.barAtBottom ? root.visualMargin : sourceEdgeMargin } Component.onCompleted: { @@ -59,9 +44,9 @@ Item { property real sourceEdgeMargin: -(implicitHeight + root.visualMargin) PropertyAnimation { id: openAnim - target: borderRect + target: panelContent property: "sourceEdgeMargin" - to: 0 + to: root.visualMargin duration: 200 easing.type: Easing.BezierSpline easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn @@ -69,7 +54,7 @@ Item { SequentialAnimation { id: closeAnim PropertyAnimation { - target: borderRect + target: panelContent property: "sourceEdgeMargin" to: -(implicitHeight + root.visualMargin) duration: root.closeAnimDuration @@ -82,23 +67,8 @@ Item { } } } - } - - Item { - id: contentArea - z: 0 - anchors.fill: borderRect - anchors.margins: borderRect.border.width - implicitWidth: contentItem.implicitWidth - implicitHeight: contentItem.implicitHeight - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Rectangle { - width: contentArea.width - height: contentArea.height - radius: borderRect.radius - borderRect.border.width - } - } + implicitWidth: root.contentItem.implicitWidth + implicitHeight: root.contentItem.implicitHeight children: [root.contentItem] - } + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPanelFooterButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/waffle/looks/WPanelFooterButton.qml rename to dots/.config/quickshell/ii/modules/waffle/looks/WBorderlessButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml new file mode 100644 index 000000000..806afcd37 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml @@ -0,0 +1,58 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +Item { + id: root + required property Item contentItem + property real radius: Looks.radius.large + property alias border: borderRect + property alias borderColor: borderRect.border.color + + implicitWidth: contentItem.implicitWidth + implicitHeight: contentItem.implicitHeight + + WRectangularShadow { + target: borderRect + } + + Rectangle { + id: borderRect + z: 1 + + color: "transparent" + radius: root.radius + border.color: Looks.colors.bg2Border + border.width: 1 + implicitWidth: contentItem.implicitWidth + border.width * 2 + implicitHeight: contentItem.implicitHeight + border.width * 2 + anchors.fill: contentRect + anchors.margins: -border.width + } + + Rectangle { + id: contentRect + anchors.centerIn: parent + z: 0 + + color: Looks.colors.bgPanelFooterBase + implicitWidth: contentItem.implicitWidth + implicitHeight: contentItem.implicitHeight + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + id: contentAreaMask + width: contentRect.width + height: contentRect.height + radius: root.radius - borderRect.border.width + } + } + children: [root.contentItem] + } +} \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml index 218ec15fa..b566c91ab 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WStackView.qml @@ -11,11 +11,7 @@ StackView { property list fadeBezierCurve: Looks.transition.easing.bezierCurve.easeInOut clip: true - property alias color: background.color - background: Rectangle { - id: background - color: Looks.colors.bgPanelFooterBase - } + background: null pushEnter: Transition { XAnimator { diff --git a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml index 8d48a6f92..32db99479 100644 --- a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml +++ b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/OSDValue.qml @@ -13,7 +13,6 @@ WBarAttachedPanelContent { required property string iconName property real value property bool showNumber: true - borderColor: Looks.colors.ambientShadow property Timer timer: Timer { id: autoCloseTimer @@ -21,44 +20,48 @@ WBarAttachedPanelContent { interval: Config.options.osd.timeout repeat: false onTriggered: { - root.close() + root.close(); } } - contentItem: Rectangle { + contentItem: WPane { anchors.centerIn: parent - color: Looks.colors.bg1Base - radius: Looks.radius.medium - implicitWidth: root.showNumber ? 192 : 170 - implicitHeight: 46 - - RowLayout { - id: contentRow - anchors.fill: parent - anchors.margins: 12 + borderColor: Looks.colors.ambientShadow - spacing: 12 + contentItem: Item { + // color: Looks.colors.bg1Base + // radius: Looks.radius.medium + implicitWidth: root.showNumber ? 192 : 170 + implicitHeight: 46 - FluentIcon { - Layout.alignment: Qt.AlignVCenter - icon: root.iconName - implicitSize: 18 - } + RowLayout { + id: contentRow + anchors.fill: parent + anchors.margins: 12 - WProgressBar { - id: progressBar - value: root.value - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - Layout.rightMargin: root.showNumber ? 0 : 3 - } + spacing: 12 - WTextWithFixedWidth { - visible: root.showNumber - text: Math.round(root.value * 100) - // longestText: "100" - implicitWidth: 16 - horizontalAlignment: Text.AlignHCenter + FluentIcon { + Layout.alignment: Qt.AlignVCenter + icon: root.iconName + implicitSize: 18 + } + + WProgressBar { + id: progressBar + value: root.value + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: root.showNumber ? 0 : 3 + } + + WTextWithFixedWidth { + visible: root.showNumber + text: Math.round(root.value * 100) + // longestText: "100" + implicitWidth: 16 + horizontalAlignment: Text.AlignHCenter + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml index f2f06b2ae..569ed4f44 100644 --- a/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml +++ b/dots/.config/quickshell/ii/modules/waffle/onScreenDisplay/WaffleOSD.qml @@ -104,13 +104,12 @@ Scope { item: osdIndicatorLoader } - implicitWidth: osdIndicatorLoader.implicitWidth + osdIndicatorLoader.item.visualMargin * 2 - implicitHeight: osdIndicatorLoader.implicitHeight + osdIndicatorLoader.item.visualMargin * 2 + implicitWidth: osdIndicatorLoader.implicitWidth + implicitHeight: osdIndicatorLoader.implicitHeight Loader { id: osdIndicatorLoader anchors.fill: parent - anchors.margins: item.visualMargin source: root.indicators.find(i => i.id === root.currentIndicator)?.sourceUrl Connections { diff --git a/dots/.config/quickshell/ii/services/MprisController.qml b/dots/.config/quickshell/ii/services/MprisController.qml index 1dc42da2b..02151f1c1 100644 --- a/dots/.config/quickshell/ii/services/MprisController.qml +++ b/dots/.config/quickshell/ii/services/MprisController.qml @@ -9,12 +9,14 @@ import QtQuick import Quickshell import Quickshell.Io import Quickshell.Services.Mpris +import qs.modules.common /** * A service that provides easy access to the active Mpris player. */ Singleton { id: root; + property list players: Mpris.players.values.filter(player => isRealPlayer(player)); property MprisPlayer trackedPlayer: null; property MprisPlayer activePlayer: trackedPlayer ?? Mpris.players.values[0] ?? null; signal trackChanged(reverse: bool); @@ -23,6 +25,29 @@ Singleton { property var activeTrack; + property bool hasPlasmaIntegration: false + Process { + id: plasmaIntegrationAvailabilityCheckProc + running: true + command: ["bash", "-c", "command -v plasma-browser-integration-host"] + onExited: (exitCode, exitStatus) => { + root.hasPlasmaIntegration = (exitCode === 0); + } + } + function isRealPlayer(player) { + if (!Config.options.media.filterDuplicatePlayers) { + return true; + } + return ( + // Remove unecessary native buses from browsers if there's plasma integration + !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.firefox')) && !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) && + // playerctld just copies other buses and we don't need duplicates + !player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') && + // Non-instance mpd bus + !(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd'))); + } + + // Original stuff from fox below Instantiator { model: Mpris.players;