mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-13 14:36:32 -04:00
feat: unify media controls dropdown interactions, hover behavior and cycle controls (#2470)
* 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
This commit is contained in:
@@ -25,14 +25,14 @@ DankPopout {
|
||||
property int __dropdownType: 0
|
||||
property point __dropdownAnchor: Qt.point(0, 0)
|
||||
property bool __dropdownRightEdge: false
|
||||
property var __dropdownPlayer: null
|
||||
property var __dropdownPlayers: []
|
||||
property var __dropdownPlayer: MprisController.activePlayer
|
||||
property var __dropdownPlayers: MprisController.availablePlayers
|
||||
|
||||
function __showVolumeDropdown(pos, rightEdge, player, players) {
|
||||
__dropdownAnchor = pos;
|
||||
__dropdownRightEdge = rightEdge;
|
||||
__dropdownPlayer = player;
|
||||
__dropdownPlayers = players;
|
||||
__dropdownPlayer = Qt.binding(() => MprisController.activePlayer);
|
||||
__dropdownPlayers = Qt.binding(() => MprisController.availablePlayers);
|
||||
__dropdownType = 1;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ DankPopout {
|
||||
function __showPlayersDropdown(pos, rightEdge, player, players) {
|
||||
__dropdownAnchor = pos;
|
||||
__dropdownRightEdge = rightEdge;
|
||||
__dropdownPlayer = player;
|
||||
__dropdownPlayers = players;
|
||||
__dropdownPlayer = Qt.binding(() => MprisController.activePlayer);
|
||||
__dropdownPlayers = Qt.binding(() => MprisController.availablePlayers);
|
||||
__dropdownType = 3;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ DankPopout {
|
||||
id: __volumeCloseTimer
|
||||
interval: 400
|
||||
onTriggered: {
|
||||
if (__dropdownType === 1) {
|
||||
if (__dropdownType !== 0) {
|
||||
__hideDropdowns();
|
||||
}
|
||||
}
|
||||
@@ -230,6 +230,13 @@ DankPopout {
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.currentTabIndex === 1 && mediaLoader.item?.handleKeyEvent) {
|
||||
if (mediaLoader.item.handleKeyEvent(event)) {
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (root.currentTabIndex === 2 && wallpaperLoader.item?.handleKeyEvent) {
|
||||
if (wallpaperLoader.item.handleKeyEvent(event)) {
|
||||
event.accepted = true;
|
||||
@@ -394,7 +401,8 @@ DankPopout {
|
||||
root.__showPlayersDropdown(pos, rightEdge, player, players);
|
||||
}
|
||||
onHideDropdowns: root.__hideDropdowns()
|
||||
onVolumeButtonExited: root.__startCloseTimer()
|
||||
onDropdownButtonExited: root.__startCloseTimer()
|
||||
onDropdownButtonEntered: root.__stopCloseTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,16 +42,22 @@ Item {
|
||||
signal panelEntered
|
||||
signal panelExited
|
||||
|
||||
property int __volumeHoverCount: 0
|
||||
property int __panelHoverCount: 0
|
||||
|
||||
function volumeAreaEntered() {
|
||||
__volumeHoverCount++;
|
||||
onDropdownTypeChanged: {
|
||||
if (dropdownType === 0) {
|
||||
__panelHoverCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function panelAreaEntered() {
|
||||
__panelHoverCount++;
|
||||
panelEntered();
|
||||
}
|
||||
|
||||
function volumeAreaExited() {
|
||||
__volumeHoverCount = Math.max(0, __volumeHoverCount - 1);
|
||||
if (__volumeHoverCount === 0)
|
||||
function panelAreaExited() {
|
||||
__panelHoverCount = Math.max(0, __panelHoverCount - 1);
|
||||
if (__panelHoverCount === 0)
|
||||
panelExited();
|
||||
}
|
||||
|
||||
@@ -131,8 +137,8 @@ Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -12
|
||||
hoverEnabled: true
|
||||
onEntered: volumeAreaEntered()
|
||||
onExited: volumeAreaExited()
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -190,8 +196,8 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: true
|
||||
|
||||
onEntered: volumeAreaEntered()
|
||||
onExited: volumeAreaExited()
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
onPressed: mouse => updateVolume(mouse)
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed)
|
||||
@@ -269,6 +275,14 @@ Item {
|
||||
shadowEnabled: Theme.elevationEnabled && !BlurService.enabled
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -12
|
||||
hoverEnabled: true
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
@@ -349,7 +363,13 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData === AudioService.sink ? "Active" : "Available"
|
||||
text: {
|
||||
if (!modelData?.audio)
|
||||
return modelData === AudioService.sink ? I18n.tr("Active") : I18n.tr("Available");
|
||||
if (modelData.audio.muted)
|
||||
return I18n.tr("Muted", "audio status");
|
||||
return Math.round(modelData.audio.volume * 100) + "%";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
@@ -369,6 +389,8 @@ Item {
|
||||
root.deviceSelected(modelData);
|
||||
}
|
||||
}
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,6 +447,14 @@ Item {
|
||||
shadowEnabled: Theme.elevationEnabled && !BlurService.enabled
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -12
|
||||
hoverEnabled: true
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
@@ -498,15 +528,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!modelData)
|
||||
return "";
|
||||
const artist = modelData.trackArtist || "";
|
||||
const isActive = modelData === activePlayer;
|
||||
if (artist.length > 0)
|
||||
return artist + (isActive ? " (Active)" : "");
|
||||
return isActive ? "Active" : "Available";
|
||||
}
|
||||
text: modelData?.trackArtist || I18n.tr("Unknown Artist")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
@@ -526,6 +548,8 @@ Item {
|
||||
root.playerSelected(modelData);
|
||||
}
|
||||
}
|
||||
onEntered: panelAreaEntered()
|
||||
onExited: panelAreaExited()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ Item {
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
property MprisPlayer activePlayer: MprisController.activePlayer
|
||||
readonly property real stableLength: MprisController.activePlayerStableLength
|
||||
property var allPlayers: MprisController.availablePlayers
|
||||
property var targetScreen: null
|
||||
property real popoutX: 0
|
||||
@@ -27,7 +28,8 @@ Item {
|
||||
signal showAudioDevicesDropdown(point pos, var screen, bool rightEdge)
|
||||
signal showPlayersDropdown(point pos, var screen, bool rightEdge, var player, var players)
|
||||
signal hideDropdowns
|
||||
signal volumeButtonExited
|
||||
signal dropdownButtonExited
|
||||
signal dropdownButtonEntered
|
||||
|
||||
property bool volumeExpanded: false
|
||||
property bool devicesExpanded: false
|
||||
@@ -39,9 +41,7 @@ Item {
|
||||
playersExpanded = false;
|
||||
}
|
||||
|
||||
DankTooltipV2 {
|
||||
id: sharedTooltip
|
||||
}
|
||||
|
||||
|
||||
readonly property bool isRightEdge: {
|
||||
if (barPosition === SettingsData.Position.Right)
|
||||
@@ -85,7 +85,6 @@ Item {
|
||||
isSwitching = true;
|
||||
_switchHold = true;
|
||||
_switchHoldTimer.restart();
|
||||
TrackArtService.loadArtwork(activePlayer.trackArtUrl);
|
||||
}
|
||||
|
||||
function maybeFinishSwitch() {
|
||||
@@ -96,11 +95,11 @@ Item {
|
||||
}
|
||||
|
||||
readonly property real ratio: {
|
||||
if (!activePlayer || !activePlayer.length || activePlayer.length <= 0) {
|
||||
if (!activePlayer || stableLength <= 0) {
|
||||
return 0;
|
||||
}
|
||||
const pos = (activePlayer.position || 0) % Math.max(1, activePlayer.length);
|
||||
const calculatedRatio = pos / activePlayer.length;
|
||||
const pos = (activePlayer.position || 0) % Math.max(1, stableLength);
|
||||
const calculatedRatio = pos / stableLength;
|
||||
return Math.max(0, Math.min(1, calculatedRatio));
|
||||
}
|
||||
|
||||
@@ -109,13 +108,11 @@ Item {
|
||||
|
||||
Connections {
|
||||
target: activePlayer
|
||||
ignoreUnknownSignals: true
|
||||
function onTrackTitleChanged() {
|
||||
_switchHoldTimer.restart();
|
||||
maybeFinishSwitch();
|
||||
}
|
||||
function onTrackArtUrlChanged() {
|
||||
TrackArtService.loadArtwork(activePlayer.trackArtUrl);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -186,6 +183,102 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function triggerVolumeDropdown() {
|
||||
if (!volumeAvailable)
|
||||
return;
|
||||
if (volumeExpanded)
|
||||
return;
|
||||
hideDropdowns();
|
||||
volumeExpanded = true;
|
||||
const buttonsOnRight = !isRightEdge;
|
||||
const btnY = volumeButton.y + volumeButton.height / 2;
|
||||
const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX;
|
||||
const screenY = popoutY + contentOffsetY + btnY;
|
||||
showVolumeDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers);
|
||||
}
|
||||
|
||||
function toggleMute() {
|
||||
if (!volumeAvailable)
|
||||
return;
|
||||
SessionData.suppressOSDTemporarily();
|
||||
if (currentVolume > 0) {
|
||||
volumeButton.previousVolume = currentVolume;
|
||||
if (usePlayerVolume) {
|
||||
activePlayer.volume = 0;
|
||||
} else if (AudioService.sink?.audio) {
|
||||
AudioService.sink.audio.volume = 0;
|
||||
}
|
||||
} else {
|
||||
const restoreVolume = volumeButton.previousVolume > 0 ? volumeButton.previousVolume : 0.5;
|
||||
if (usePlayerVolume) {
|
||||
activePlayer.volume = restoreVolume;
|
||||
} else if (AudioService.sink?.audio) {
|
||||
AudioService.sink.audio.volume = restoreVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyEvent(event) {
|
||||
if (!activePlayer)
|
||||
return false;
|
||||
|
||||
// 1. Number keys 0-9 to seek to 0%-90%
|
||||
if (event.key >= Qt.Key_0 && event.key <= Qt.Key_9) {
|
||||
if (activePlayer.canSeek && stableLength > 0) {
|
||||
const ratio = (event.key - Qt.Key_0) * 0.1;
|
||||
const targetPosition = ratio * stableLength;
|
||||
activePlayer.position = Math.max(0.1, Math.min(targetPosition, stableLength * 0.99));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Left / Right arrows to seek backward / forward 5s
|
||||
if (event.key === Qt.Key_Left) {
|
||||
if (activePlayer.canSeek) {
|
||||
activePlayer.position = Math.max(0.1, activePlayer.position - 5);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (event.key === Qt.Key_Right) {
|
||||
if (activePlayer.canSeek && stableLength > 0) {
|
||||
activePlayer.position = Math.max(0.1, Math.min(stableLength - 1, activePlayer.position + 5));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Up / Down arrows to adjust volume
|
||||
if (event.key === Qt.Key_Up) {
|
||||
adjustVolume(5);
|
||||
triggerVolumeDropdown();
|
||||
dropdownButtonExited();
|
||||
return true;
|
||||
}
|
||||
if (event.key === Qt.Key_Down) {
|
||||
adjustVolume(-5);
|
||||
triggerVolumeDropdown();
|
||||
dropdownButtonExited();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. Spacebar to play/pause
|
||||
if (event.key === Qt.Key_Space) {
|
||||
if (activePlayer.canTogglePlaying) {
|
||||
activePlayer.togglePlaying();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. M key to toggle mute
|
||||
if (event.key === Qt.Key_M) {
|
||||
toggleMute();
|
||||
triggerVolumeDropdown();
|
||||
dropdownButtonExited();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
property bool isSeeking: false
|
||||
|
||||
Timer {
|
||||
@@ -198,14 +291,14 @@ Item {
|
||||
Item {
|
||||
id: bgContainer
|
||||
anchors.fill: parent
|
||||
visible: TrackArtService._bgArtSource !== ""
|
||||
visible: TrackArtService.resolvedArtUrl !== ""
|
||||
|
||||
Image {
|
||||
id: bgImage
|
||||
anchors.centerIn: parent
|
||||
width: Math.max(parent.width, parent.height) * 1.1
|
||||
height: width
|
||||
source: TrackArtService._bgArtSource
|
||||
source: TrackArtService.resolvedArtUrl
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: true
|
||||
@@ -331,7 +424,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: activePlayer?.trackTitle || I18n.tr("Unknown Artist")
|
||||
text: activePlayer?.trackArtist || I18n.tr("Unknown Artist")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
|
||||
width: parent.width
|
||||
@@ -389,7 +482,7 @@ Item {
|
||||
if (!activePlayer)
|
||||
return "0:00";
|
||||
const rawPos = Math.max(0, activePlayer.position || 0);
|
||||
const pos = activePlayer.length ? rawPos % Math.max(1, activePlayer.length) : rawPos;
|
||||
const pos = stableLength ? rawPos % Math.max(1, stableLength) : rawPos;
|
||||
const minutes = Math.floor(pos / 60);
|
||||
const seconds = Math.floor(pos % 60);
|
||||
const timeStr = minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
|
||||
@@ -403,9 +496,9 @@ Item {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
if (!activePlayer || !activePlayer.length)
|
||||
return "0:00";
|
||||
const dur = Math.max(0, activePlayer.length || 0);
|
||||
if (!activePlayer || stableLength <= 0)
|
||||
return "--:--";
|
||||
const dur = stableLength;
|
||||
const minutes = Math.floor(dur / 60);
|
||||
const seconds = Math.floor(dur % 60);
|
||||
return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
|
||||
@@ -647,7 +740,17 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (playersExpanded) {
|
||||
hideDropdowns();
|
||||
if (allPlayers && allPlayers.length > 1) {
|
||||
let currentIndex = -1;
|
||||
for (let i = 0; i < allPlayers.length; i++) {
|
||||
if (allPlayers[i] === activePlayer) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % allPlayers.length;
|
||||
MprisController.setActivePlayer(allPlayers[nextIndex]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
hideDropdowns();
|
||||
@@ -658,8 +761,22 @@ Item {
|
||||
const screenY = popoutY + contentOffsetY + btnY;
|
||||
showPlayersDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers);
|
||||
}
|
||||
onEntered: sharedTooltip.show(I18n.tr("Media Players"), playerSelectorButton, 0, 0, isRightEdge ? "right" : "left")
|
||||
onExited: sharedTooltip.hide()
|
||||
onEntered: {
|
||||
dropdownButtonEntered();
|
||||
if (playersExpanded)
|
||||
return;
|
||||
hideDropdowns();
|
||||
playersExpanded = true;
|
||||
const buttonsOnRight = !isRightEdge;
|
||||
const btnY = playerSelectorButton.y + playerSelectorButton.height / 2;
|
||||
const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX;
|
||||
const screenY = popoutY + contentOffsetY + btnY;
|
||||
showPlayersDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers);
|
||||
}
|
||||
onExited: {
|
||||
if (playersExpanded)
|
||||
dropdownButtonExited();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,6 +808,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: {
|
||||
dropdownButtonEntered();
|
||||
if (volumeExpanded)
|
||||
return;
|
||||
hideDropdowns();
|
||||
@@ -703,25 +821,10 @@ Item {
|
||||
}
|
||||
onExited: {
|
||||
if (volumeExpanded)
|
||||
volumeButtonExited();
|
||||
dropdownButtonExited();
|
||||
}
|
||||
onClicked: {
|
||||
SessionData.suppressOSDTemporarily();
|
||||
if (currentVolume > 0) {
|
||||
volumeButton.previousVolume = currentVolume;
|
||||
if (usePlayerVolume) {
|
||||
activePlayer.volume = 0;
|
||||
} else if (AudioService.sink?.audio) {
|
||||
AudioService.sink.audio.volume = 0;
|
||||
}
|
||||
} else {
|
||||
const restoreVolume = volumeButton.previousVolume > 0 ? volumeButton.previousVolume : 0.5;
|
||||
if (usePlayerVolume) {
|
||||
activePlayer.volume = restoreVolume;
|
||||
} else if (AudioService.sink?.audio) {
|
||||
AudioService.sink.audio.volume = restoreVolume;
|
||||
}
|
||||
}
|
||||
toggleMute();
|
||||
}
|
||||
onWheel: wheelEvent => {
|
||||
SessionData.suppressOSDTemporarily();
|
||||
@@ -754,7 +857,7 @@ Item {
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: devicesExpanded ? "expand_less" : "speaker"
|
||||
name: "speaker"
|
||||
size: 18
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
@@ -766,7 +869,18 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (devicesExpanded) {
|
||||
hideDropdowns();
|
||||
const sinks = AudioService.getAvailableSinks();
|
||||
if (sinks && sinks.length > 1) {
|
||||
let currentIndex = -1;
|
||||
for (let i = 0; i < sinks.length; i++) {
|
||||
if (sinks[i]?.name === AudioService.sink?.name) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % sinks.length;
|
||||
AudioService.setSink(sinks[nextIndex]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
hideDropdowns();
|
||||
@@ -777,8 +891,22 @@ Item {
|
||||
const screenY = popoutY + contentOffsetY + btnY;
|
||||
showAudioDevicesDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight);
|
||||
}
|
||||
onEntered: sharedTooltip.show(I18n.tr("Output Device"), audioDevicesButton, 0, 0, isRightEdge ? "right" : "left")
|
||||
onExited: sharedTooltip.hide()
|
||||
onEntered: {
|
||||
dropdownButtonEntered();
|
||||
if (devicesExpanded)
|
||||
return;
|
||||
hideDropdowns();
|
||||
devicesExpanded = true;
|
||||
const buttonsOnRight = !isRightEdge;
|
||||
const btnY = audioDevicesButton.y + audioDevicesButton.height / 2;
|
||||
const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX;
|
||||
const screenY = popoutY + contentOffsetY + btnY;
|
||||
showAudioDevicesDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight);
|
||||
}
|
||||
onExited: {
|
||||
if (devicesExpanded)
|
||||
dropdownButtonExited();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@ Card {
|
||||
property real displayPosition: currentPosition
|
||||
|
||||
readonly property real ratio: {
|
||||
if (!activePlayer || activePlayer.length <= 0)
|
||||
const len = MprisController.activePlayerStableLength;
|
||||
if (!activePlayer || !activePlayer.lengthSupported || len <= 0)
|
||||
return 0;
|
||||
const pos = displayPosition % Math.max(1, activePlayer.length);
|
||||
const calculatedRatio = pos / activePlayer.length;
|
||||
const pos = displayPosition % Math.max(1, len);
|
||||
const calculatedRatio = pos / len;
|
||||
return Math.max(0, Math.min(1, calculatedRatio));
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ DankOSD {
|
||||
|
||||
Image {
|
||||
id: artPreloader
|
||||
source: TrackArtService._bgArtSource
|
||||
source: TrackArtService.resolvedArtUrl
|
||||
visible: false
|
||||
asynchronous: true
|
||||
cache: true
|
||||
@@ -78,7 +78,7 @@ DankOSD {
|
||||
function onLoadingChanged() {
|
||||
if (TrackArtService.loading || !root._pendingShow)
|
||||
return;
|
||||
if (!TrackArtService._bgArtSource || artPreloader.status === Image.Ready) {
|
||||
if (!TrackArtService.resolvedArtUrl || artPreloader.status === Image.Ready) {
|
||||
root._pendingShow = false;
|
||||
root.show();
|
||||
}
|
||||
@@ -116,9 +116,9 @@ DankOSD {
|
||||
root._displayAlbum = player.trackAlbum || "";
|
||||
|
||||
root.updatePlaybackIcon();
|
||||
TrackArtService.loadArtwork(player.trackArtUrl);
|
||||
const resolvedArtUrl = TrackArtService.resolvedArtUrl;
|
||||
|
||||
if (!player.trackArtUrl || player.trackArtUrl === "") {
|
||||
if (!resolvedArtUrl || resolvedArtUrl === "") {
|
||||
root.show();
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ DankOSD {
|
||||
root._pendingShow = true;
|
||||
return;
|
||||
}
|
||||
if (!TrackArtService._bgArtSource || artPreloader.status === Image.Ready) {
|
||||
if (!TrackArtService.resolvedArtUrl || artPreloader.status === Image.Ready) {
|
||||
root.show();
|
||||
return;
|
||||
}
|
||||
@@ -134,7 +134,10 @@ DankOSD {
|
||||
}
|
||||
|
||||
function onTrackArtUrlChanged() {
|
||||
TrackArtService.loadArtwork(player.trackArtUrl);
|
||||
handleUpdate();
|
||||
}
|
||||
function onMetadataChanged() {
|
||||
handleUpdate();
|
||||
}
|
||||
function onIsPlayingChanged() {
|
||||
handleUpdate();
|
||||
@@ -168,14 +171,14 @@ DankOSD {
|
||||
Item {
|
||||
id: bgContainer
|
||||
anchors.fill: parent
|
||||
visible: TrackArtService._bgArtSource !== ""
|
||||
visible: TrackArtService.resolvedArtUrl !== ""
|
||||
|
||||
Image {
|
||||
id: bgImage
|
||||
anchors.centerIn: parent
|
||||
width: Math.max(parent.width, parent.height)
|
||||
height: width
|
||||
source: TrackArtService._bgArtSource
|
||||
source: TrackArtService.resolvedArtUrl
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: true
|
||||
|
||||
Reference in New Issue
Block a user