media controls: outside click dismissal, no player placeholder

This commit is contained in:
end-4
2025-08-28 18:17:11 +07:00
parent f74ed76850
commit b52440bcc1
2 changed files with 60 additions and 15 deletions
@@ -40,37 +40,34 @@ Scope {
} }
return ( return (
// Remove unecessary native buses from browsers if there's plasma integration // 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.firefox')) && !(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) &&
!(hasPlasmaIntegration && player.dbusName.startsWith('org.mpris.MediaPlayer2.chromium')) &&
// playerctld just copies other buses and we don't need duplicates // playerctld just copies other buses and we don't need duplicates
!player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') && !player.dbusName?.startsWith('org.mpris.MediaPlayer2.playerctld') &&
// Non-instance mpd bus // Non-instance mpd bus
!(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd')) !(player.dbusName?.endsWith('.mpd') && !player.dbusName.endsWith('MediaPlayer2.mpd')));
);
} }
function filterDuplicatePlayers(players) { function filterDuplicatePlayers(players) {
let filtered = []; let filtered = [];
let used = new Set(); let used = new Set();
for (let i = 0; i < players.length; ++i) { for (let i = 0; i < players.length; ++i) {
if (used.has(i)) continue; if (used.has(i))
continue;
let p1 = players[i]; let p1 = players[i];
let group = [i]; let group = [i];
// Find duplicates by trackTitle prefix // Find duplicates by trackTitle prefix
for (let j = i + 1; j < players.length; ++j) { for (let j = i + 1; j < players.length; ++j) {
let p2 = players[j]; let p2 = players[j];
if (p1.trackTitle && p2.trackTitle && if (p1.trackTitle && p2.trackTitle && (p1.trackTitle.includes(p2.trackTitle) || p2.trackTitle.includes(p1.trackTitle)) || (p1.position - p2.position <= 2 && p1.length - p2.length <= 2)) {
(p1.trackTitle.includes(p2.trackTitle)
|| p2.trackTitle.includes(p1.trackTitle))
|| (p1.position - p2.position <= 2 && p1.length - p2.length <= 2)) {
group.push(j); group.push(j);
} }
} }
// Pick the one with non-empty trackArtUrl, or fallback to the first // Pick the one with non-empty trackArtUrl, or fallback to the first
let chosenIdx = group.find(idx => players[idx].trackArtUrl && players[idx].trackArtUrl.length > 0); let chosenIdx = group.find(idx => players[idx].trackArtUrl && players[idx].trackArtUrl.length > 0);
if (chosenIdx === undefined) chosenIdx = group[0]; if (chosenIdx === undefined)
chosenIdx = group[0];
filtered.push(players[chosenIdx]); filtered.push(players[chosenIdx]);
group.forEach(idx => used.add(idx)); group.forEach(idx => used.add(idx));
@@ -133,6 +130,16 @@ Scope {
item: playerColumnLayout item: playerColumnLayout
} }
HyprlandFocusGrab {
windows: [mediaControlsRoot]
active: mediaControlsLoader.active
onCleared: () => {
if (!active) {
GlobalStates.mediaControlsOpen = false;
}
}
}
ColumnLayout { ColumnLayout {
id: playerColumnLayout id: playerColumnLayout
anchors.fill: parent anchors.fill: parent
@@ -148,6 +155,43 @@ Scope {
visualizerPoints: root.visualizerPoints visualizerPoints: root.visualizerPoints
implicitWidth: widgetWidth implicitWidth: widgetWidth
implicitHeight: widgetHeight implicitHeight: widgetHeight
radius: root.popupRounding
}
}
Item { // No player placeholder
Layout.fillWidth: true
visible: root.meaningfulPlayers.length === 0
implicitWidth: placeholderBackground.implicitWidth + Appearance.sizes.elevationMargin
implicitHeight: placeholderBackground.implicitHeight + Appearance.sizes.elevationMargin
StyledRectangularShadow {
target: placeholderBackground
}
Rectangle {
id: placeholderBackground
anchors.centerIn: parent
color: Appearance.colors.colLayer0
radius: root.popupRounding
property real padding: 20
implicitWidth: placeholderLayout.implicitWidth + padding * 2
implicitHeight: placeholderLayout.implicitHeight + padding * 2
ColumnLayout {
id: placeholderLayout
anchors.centerIn: parent
StyledText {
text: Translation.tr("No active player")
font.pixelSize: Appearance.font.pixelSize.large
}
StyledText {
color: Appearance.colors.colSubtext
text: Translation.tr("Make sure your player has MPRIS support\nor try turning off duplicate player filtering")
font.pixelSize: Appearance.font.pixelSize.small
}
}
} }
} }
} }
@@ -159,7 +203,8 @@ Scope {
function toggle(): void { function toggle(): void {
mediaControlsLoader.active = !mediaControlsLoader.active; mediaControlsLoader.active = !mediaControlsLoader.active;
if(mediaControlsLoader.active) Notifications.timeoutAll(); if (mediaControlsLoader.active)
Notifications.timeoutAll();
} }
function close(): void { function close(): void {
@@ -196,5 +241,4 @@ Scope {
GlobalStates.mediaControlsOpen = false; GlobalStates.mediaControlsOpen = false;
} }
} }
}
}
@@ -22,6 +22,7 @@ Item { // Player instance
property list<real> visualizerPoints: [] property list<real> visualizerPoints: []
property real maxVisualizerValue: 1000 // Max value in the data points property real maxVisualizerValue: 1000 // Max value in the data points
property int visualizerSmoothing: 2 // Number of points to average for smoothing property int visualizerSmoothing: 2 // Number of points to average for smoothing
property real radius
component TrackChangeButton: RippleButton { component TrackChangeButton: RippleButton {
implicitWidth: 24 implicitWidth: 24
@@ -107,7 +108,7 @@ Item { // Player instance
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.sizes.elevationMargin anchors.margins: Appearance.sizes.elevationMargin
color: blendedColors.colLayer0 color: blendedColors.colLayer0
radius: root.popupRounding radius: playerController.radius
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
@@ -141,7 +142,7 @@ Item { // Player instance
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: ColorUtils.transparentize(blendedColors.colLayer0, 0.3) color: ColorUtils.transparentize(blendedColors.colLayer0, 0.3)
radius: root.popupRounding radius: playerController.radius
} }
} }