mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-08 04:09:15 -04:00
89f86be00a
* feat: unify media controls dropdown interactions, hover behavior and cycle controls - Implement hover-to-show and hover-to-hide for all media control dropdowns. - Make clicking the Output Devices and Media Players buttons cycle through items when expanded. - Always display the 'speaker' icon for Output Devices to maintain visual consistency. - Bind dropdown player properties dynamically to fix list stale rendering states. * fix(DankDash): use trackArtist property for artist label in MediaPlayerTab * fix(DankDash): simplify active player label for consistency with output devices * feat(DankDash): display volume levels for audio output devices in dropdown * fix(DankDash): display Unknown Artist when artist is empty in player list * feat(DankDash): add keyboard shortcuts for seeking, track cycling and playback control in Media popout * feat(DankDash): change Up/Down arrow keys to adjust volume in Media popout * feat(DankDash): auto-open volume dropdown overlay when using Up/Down shortcuts * feat(DankDash): add Key M shortcut to toggle mute in Media popout * fix(mpris): clamp minimum seek position to 0.1s to prevent browser player reset * fix(mpris): cache stable length to prevent browser transient reset issues * fix(mpris): persist activePlayerStableLength in MprisController singleton * fix(mpris): resolve browser player album art with raw metadata and YouTube url fallbacks * fix(mpris): resolve browser player album art with local caching and 16:9 youtube fallbacks * style(mpris): trim trailing whitespace in TrackArtService * fix(mpris): address code review feedback on remote caching, stale artwork, and hover state * fix: secure curl commands and prevent premature dropdown overlays closing on button re-hover
212 lines
6.6 KiB
QML
212 lines
6.6 KiB
QML
import QtQuick
|
|
import Quickshell.Services.Mpris
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Card {
|
|
id: root
|
|
clip: false
|
|
|
|
signal clicked
|
|
|
|
property MprisPlayer activePlayer: MprisController.activePlayer
|
|
property real currentPosition: activePlayer?.positionSupported ? activePlayer.position : 0
|
|
property real displayPosition: currentPosition
|
|
|
|
readonly property real ratio: {
|
|
const len = MprisController.activePlayerStableLength;
|
|
if (!activePlayer || !activePlayer.lengthSupported || len <= 0)
|
|
return 0;
|
|
const pos = displayPosition % Math.max(1, len);
|
|
const calculatedRatio = pos / len;
|
|
return Math.max(0, Math.min(1, calculatedRatio));
|
|
}
|
|
|
|
onActivePlayerChanged: {
|
|
if (activePlayer?.positionSupported) {
|
|
currentPosition = Qt.binding(() => activePlayer?.position || 0);
|
|
} else {
|
|
currentPosition = 0;
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
interval: 300
|
|
running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking
|
|
repeat: true
|
|
onTriggered: activePlayer?.positionSupported && activePlayer.positionChanged()
|
|
}
|
|
|
|
property bool isSeeking: false
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: Theme.spacingS
|
|
visible: !activePlayer
|
|
|
|
DankIcon {
|
|
name: "music_note"
|
|
size: Theme.iconSize
|
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
StyledText {
|
|
text: I18n.tr("No Media")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
width: parent.width - Theme.spacingXS * 2
|
|
spacing: Theme.spacingL
|
|
visible: activePlayer
|
|
|
|
Item {
|
|
width: 140
|
|
height: 110
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
clip: false
|
|
|
|
DankAlbumArt {
|
|
width: 110
|
|
height: 80
|
|
anchors.centerIn: parent
|
|
activePlayer: root.activePlayer
|
|
albumSize: 76
|
|
animationScale: 1.05
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingXS
|
|
topPadding: Theme.spacingL
|
|
|
|
StyledText {
|
|
text: activePlayer?.trackTitle || I18n.tr("Unknown")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.Medium
|
|
color: Theme.surfaceText
|
|
width: parent.width
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
StyledText {
|
|
text: activePlayer?.trackArtist || I18n.tr("Unknown Artist")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
|
width: parent.width
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
}
|
|
|
|
DankSeekbar {
|
|
width: parent.width + 4
|
|
height: 20
|
|
x: -2
|
|
activePlayer: root.activePlayer
|
|
isSeeking: root.isSeeking
|
|
onIsSeekingChanged: root.isSeeking = isSeeking
|
|
}
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: 32
|
|
|
|
Row {
|
|
spacing: Theme.spacingS
|
|
anchors.centerIn: parent
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
anchors.verticalCenter: playPauseButton.verticalCenter
|
|
color: prevArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "skip_previous"
|
|
size: 14
|
|
color: Theme.surfaceText
|
|
}
|
|
|
|
MouseArea {
|
|
id: prevArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: MprisController.previousOrRewind()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: playPauseButton
|
|
width: 32
|
|
height: 32
|
|
radius: 16
|
|
color: Theme.primary
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
|
|
size: 16
|
|
color: Theme.background
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: activePlayer?.togglePlaying()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
anchors.verticalCenter: playPauseButton.verticalCenter
|
|
color: nextArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "skip_next"
|
|
size: 14
|
|
color: Theme.surfaceText
|
|
}
|
|
|
|
MouseArea {
|
|
id: nextArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: activePlayer?.next()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 123
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.clicked()
|
|
visible: activePlayer
|
|
}
|
|
}
|