diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index bc0dfcd8..3460372a 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -503,6 +503,7 @@ Singleton { property int osdPosition: SettingsData.Position.BottomCenter property bool osdVolumeEnabled: true property bool osdMediaVolumeEnabled: true + property bool osdMediaPlaybackEnabled: true property bool osdBrightnessEnabled: true property bool osdIdleInhibitorEnabled: true property bool osdMicMuteEnabled: true diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 1e712261..1d63053b 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -331,6 +331,7 @@ var SPEC = { osdPosition: { def: 5 }, osdVolumeEnabled: { def: true }, osdMediaVolumeEnabled: { def: true }, + osdMediaPlaybackEnabled: { def: true }, osdBrightnessEnabled: { def: true }, osdIdleInhibitorEnabled: { def: true }, osdMicMuteEnabled: { def: true }, diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index ba7c9b3c..7bc0f651 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -841,6 +841,14 @@ Item { } } + Variants { + model: SettingsData.getFilteredScreens("osd") + + delegate: MediaPlaybackOSD { + modelData: item + } + } + Variants { model: SettingsData.getFilteredScreens("osd") diff --git a/quickshell/Modules/OSD/MediaPlaybackOSD.qml b/quickshell/Modules/OSD/MediaPlaybackOSD.qml new file mode 100644 index 00000000..c2856bac --- /dev/null +++ b/quickshell/Modules/OSD/MediaPlaybackOSD.qml @@ -0,0 +1,132 @@ +import QtQuick +import qs.Common +import qs.Services +import qs.Widgets +import Quickshell.Services.Mpris + +DankOSD { + id: root + + readonly property bool useVertical: isVerticalLayout + readonly property var player: MprisController.activePlayer + + osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) + osdHeight: useVertical ? (Theme.iconSize * 2) : (40 + Theme.spacingS * 2) + autoHideInterval: 3000 + enableMouseInteraction: true + + function getPlaybackIcon() { + if (player.playbackState === MprisPlaybackState.Playing) + return "play_arrow" + if (player.playbackState === MprisPlaybackState.Paused || player.playbackState === MprisPlaybackState.Stopped) + return "pause" + return "music_note" + } + + function togglePlaying() { + if (player?.canTogglePlaying) { + player.togglePlaying(); + } + } + + Connections { + target: player + + function handleUpdate() { + if (SettingsData.osdMediaPlaybackEnabled) { + root.show() + } + } + + function onIsPlayingChanged() { handleUpdate() } + // Not enough room to show track name vertically - skip it + function onTrackChanged() { if (!useVertical) handleUpdate() } + } + + content: Loader { + anchors.fill: parent + sourceComponent: useVertical ? verticalContent : horizontalContent + } + + Component { + id: horizontalContent + + Item { + property int gap: Theme.spacingS + + anchors.centerIn: parent + width: parent.width - Theme.spacingS * 2 + height: 40 + + Rectangle { + width: Theme.iconSize + height: Theme.iconSize + radius: Theme.iconSize / 2 + color: "transparent" + x: parent.gap + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + anchors.centerIn: parent + name: getPlaybackIcon() + size: Theme.iconSize + color: playPauseButton.containsMouse ? Theme.primary : Theme.surfaceText + } + + MouseArea { + id: playPauseButton + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: togglePlaying() + } + } + + StyledText { + id: textItem + x: parent.gap * 2 + Theme.iconSize + width: parent.width - Theme.iconSize - parent.gap * 3 + anchors.verticalCenter: parent.verticalCenter + text: (`${player.trackTitle || I18n.tr("Unknown Title")} • ${player.trackArtist || I18n.tr("Unknown Artist")}`) + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: Theme.surfaceText + elide: Text.ElideRight + } + } + } + + Component { + id: verticalContent + + Item { + property int gap: Theme.spacingS + + Rectangle { + width: Theme.iconSize + height: Theme.iconSize + radius: Theme.iconSize / 2 + color: "transparent" + anchors.centerIn: parent + y: gap + + DankIcon { + anchors.centerIn: parent + name: getPlaybackIcon() + size: Theme.iconSize + color: playPauseButtonVert.containsMouse ? Theme.primary : Theme.surfaceText + } + + MouseArea { + id: playPauseButtonVert + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: togglePlaying() + } + } + } + } +} diff --git a/quickshell/Modules/Settings/OSDTab.qml b/quickshell/Modules/Settings/OSDTab.qml index f105cf85..b576599b 100644 --- a/quickshell/Modules/Settings/OSDTab.qml +++ b/quickshell/Modules/Settings/OSDTab.qml @@ -100,6 +100,13 @@ Item { onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked) } + SettingsToggleRow { + text: I18n.tr("Media Playback") + description: I18n.tr("Show on-screen display when media playback status changes") + checked: SettingsData.osdMediaPlaybackEnabled + onToggled: checked => SettingsData.set("osdMediaPlaybackEnabled", checked) + } + SettingsToggleRow { text: I18n.tr("Brightness") description: I18n.tr("Show on-screen display when brightness changes")