mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-31 07:27:47 -04:00
feat(mpris): pin preferred media source (#3150)
* feat(mpris): pin preferred media source Add a minimal "pin media source" option so the bar media widget and OSD keep showing a preferred player (e.g. a music player) even when another source (e.g. YouTube in the browser) starts playing. - MprisController: new pinnedIdentity property + setPinned(identity); _bestPlayingPlayer() prefers a playing pinned player (exact identity match, then case-insensitive substring fallback). Existing behavior is unchanged when no pin is set. - Persistence via SessionData.pinnedPlayerIdentity (spec entry added so SessionData.set() accepts the key); empty string clears the pin. - MediaDropdownOverlay (Media Players panel): each player row gets a theme-colored circle indicator on the right. Empty circle = no pin (initial state). Right-click a row to make it the default source (circle fills); right-click another row to move the pin; right-click the pinned row again to clear (back to empty). Left-click behavior unchanged (selects the player). * Update quickshell/Services/MprisController.qml Concur with Claude's suggestion. Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> * Update quickshell/Services/MprisController.qml Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
151aedbb68
commit
393a54f7eb
4 files changed
+44
-2
No files matched your search
@@ -219,6 +219,7 @@ Singleton {
|
||||
property string bluetoothAdapterOverride: ""
|
||||
|
||||
property string lastPlayerIdentity: ""
|
||||
property string pinnedPlayerIdentity: ""
|
||||
|
||||
property var deviceMaxVolumes: ({})
|
||||
property var hiddenOutputDeviceNames: []
|
||||
|
||||
@@ -87,6 +87,7 @@ var SPEC = {
|
||||
bluetoothAdapterOverride: { def: "" },
|
||||
|
||||
lastPlayerIdentity: { def: "" },
|
||||
pinnedPlayerIdentity: { def: "" },
|
||||
|
||||
deviceMaxVolumes: { def: {} },
|
||||
hiddenOutputDeviceNames: { def: [] },
|
||||
|
||||
@@ -578,7 +578,7 @@ Item {
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
width: parent.width - Theme.spacingM * 2 - pinIndicator.width - Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "music_note"
|
||||
@@ -618,12 +618,36 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: pinIndicator
|
||||
readonly property bool pinned: !!modelData?.identity && MprisController.pinnedIdentity === modelData.identity
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
color: pinned ? Theme.primary : "transparent"
|
||||
border.color: pinned ? Theme.primary : Theme.outlineHeavy
|
||||
border.width: 2
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: playerMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
if (modelData?.identity) {
|
||||
if (MprisController.pinnedIdentity === modelData.identity)
|
||||
MprisController.setPinned("");
|
||||
else
|
||||
MprisController.setPinned(modelData.identity);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (modelData?.identity) {
|
||||
root.playerSelected(modelData);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ Singleton {
|
||||
});
|
||||
}
|
||||
property MprisPlayer activePlayer: null
|
||||
property string pinnedIdentity: SessionData.pinnedPlayerIdentity || ""
|
||||
property real activePlayerStableLength: 0
|
||||
// Chromium can report blank metadata between tracks
|
||||
property string stableTitle: ""
|
||||
@@ -247,6 +248,15 @@ Singleton {
|
||||
if (playing.length === 0)
|
||||
return null;
|
||||
|
||||
if (pinnedIdentity !== "") {
|
||||
const pinLower = pinnedIdentity.toLowerCase();
|
||||
const exact = playing.filter(player => player.identity === pinnedIdentity);
|
||||
const matches = exact.length > 0 ? exact : playing.filter(player => (player.identity || "").toLowerCase().includes(pinLower));
|
||||
const pinned = matches.find(player => player.canControl) ?? matches[0];
|
||||
if (pinned)
|
||||
return pinned;
|
||||
}
|
||||
|
||||
const controllable = playing.filter(player => player.canControl);
|
||||
if (activePlayer?.isPlaying) {
|
||||
if (activePlayer.canControl || controllable.length === 0)
|
||||
@@ -301,6 +311,12 @@ Singleton {
|
||||
_persistIdentity(player.identity);
|
||||
}
|
||||
|
||||
function setPinned(identity: string): void {
|
||||
if (SessionData.pinnedPlayerIdentity !== identity)
|
||||
SessionData.set("pinnedPlayerIdentity", identity);
|
||||
_resolveActivePlayer();
|
||||
}
|
||||
|
||||
function _persistIdentity(identity: string): void {
|
||||
if (identity && SessionData.lastPlayerIdentity !== identity)
|
||||
SessionData.set("lastPlayerIdentity", identity);
|
||||
|
||||
Reference in new issue
Block a user