mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-29 14:32:08 -04:00
feat(mpris): allow excluding specific media players by identity (#2712)
* feat(mpris): allow excluding specific media players by identity * chore(translation): update settings search index and clean trailing whitespace
This commit is contained in:
@@ -448,6 +448,7 @@ Singleton {
|
|||||||
property string audioScrollMode: "volume"
|
property string audioScrollMode: "volume"
|
||||||
property int audioWheelScrollAmount: 5
|
property int audioWheelScrollAmount: 5
|
||||||
property bool audioDeviceScrollVolumeEnabled: false
|
property bool audioDeviceScrollVolumeEnabled: false
|
||||||
|
property var mediaExcludePlayers: []
|
||||||
property bool clockCompactMode: false
|
property bool clockCompactMode: false
|
||||||
property int focusedWindowSize: 1
|
property int focusedWindowSize: 1
|
||||||
property bool focusedWindowCompactMode: false
|
property bool focusedWindowCompactMode: false
|
||||||
@@ -3062,6 +3063,32 @@ Singleton {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMediaExcludePlayer(identity) {
|
||||||
|
if (identity === undefined || identity === null)
|
||||||
|
return;
|
||||||
|
var normalizedIdentity = identity.toString().trim().toLowerCase();
|
||||||
|
if (!normalizedIdentity)
|
||||||
|
return;
|
||||||
|
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
|
||||||
|
var normalizedList = list.map(function(id) {
|
||||||
|
return id ? id.toString().trim().toLowerCase() : "";
|
||||||
|
});
|
||||||
|
if (normalizedList.indexOf(normalizedIdentity) >= 0)
|
||||||
|
return;
|
||||||
|
list.push(normalizedIdentity);
|
||||||
|
mediaExcludePlayers = list;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMediaExcludePlayer(index) {
|
||||||
|
var list = mediaExcludePlayers ? mediaExcludePlayers.slice() : [];
|
||||||
|
if (index < 0 || index >= list.length)
|
||||||
|
return;
|
||||||
|
list.splice(index, 1);
|
||||||
|
mediaExcludePlayers = list;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
property bool _pendingExpandNotificationRules: false
|
property bool _pendingExpandNotificationRules: false
|
||||||
property int _pendingNotificationRuleIndex: -1
|
property int _pendingNotificationRuleIndex: -1
|
||||||
|
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ var SPEC = {
|
|||||||
audioScrollMode: { def: "volume" },
|
audioScrollMode: { def: "volume" },
|
||||||
audioWheelScrollAmount: { def: 5 },
|
audioWheelScrollAmount: { def: 5 },
|
||||||
audioDeviceScrollVolumeEnabled: { def: false },
|
audioDeviceScrollVolumeEnabled: { def: false },
|
||||||
|
mediaExcludePlayers: { def: [] },
|
||||||
clockCompactMode: { def: false },
|
clockCompactMode: { def: false },
|
||||||
focusedWindowCompactMode: { def: false },
|
focusedWindowCompactMode: { def: false },
|
||||||
focusedWindowSize: { def: 1 },
|
focusedWindowSize: { def: 1 },
|
||||||
|
|||||||
@@ -434,7 +434,9 @@ FocusScope {
|
|||||||
visible: active
|
visible: active
|
||||||
focus: active
|
focus: active
|
||||||
|
|
||||||
sourceComponent: MediaPlayerTab {}
|
sourceComponent: MediaPlayerTab {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (active && item)
|
if (active && item)
|
||||||
|
|||||||
@@ -2,10 +2,22 @@ import QtQuick
|
|||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.Settings.Widgets
|
import qs.Modules.Settings.Widgets
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property var desktopApps: []
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
desktopApps = AppSearchService.getVisibleApplications() || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
desktopApps = [];
|
||||||
|
}
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
@@ -121,6 +133,149 @@ Item {
|
|||||||
onToggled: checked => SettingsData.set("audioDeviceScrollVolumeEnabled", checked)
|
onToggled: checked => SettingsData.set("audioDeviceScrollVolumeEnabled", checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
width: parent.width
|
||||||
|
iconName: "do_not_disturb_on"
|
||||||
|
title: I18n.tr("Excluded Media Players")
|
||||||
|
settingKey: "mediaExcludePlayers"
|
||||||
|
tags: ["media", "music", "exclude", "ignore", "player", "mpris"]
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Prevent specific applications from displaying in the media controllers (e.g., browser audio streams, background tools). Matches player identity or desktop file name case-insensitively.")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: newExcludePlayerField
|
||||||
|
width: parent.width - addBtn.width - selectAppBtn.width - Theme.spacingS * 2
|
||||||
|
height: 36
|
||||||
|
placeholderText: I18n.tr("App name or identity (e.g., firefox)")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
onAccepted: {
|
||||||
|
if (text.trim() !== "") {
|
||||||
|
SettingsData.addMediaExcludePlayer(text.trim());
|
||||||
|
text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: addBtn
|
||||||
|
buttonSize: 36
|
||||||
|
iconName: "add"
|
||||||
|
iconSize: 20
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
iconColor: Theme.onPrimary
|
||||||
|
onClicked: {
|
||||||
|
if (newExcludePlayerField.text.trim() !== "") {
|
||||||
|
SettingsData.addMediaExcludePlayer(newExcludePlayerField.text.trim());
|
||||||
|
newExcludePlayerField.text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: selectAppBtn
|
||||||
|
buttonSize: 36
|
||||||
|
iconName: "apps"
|
||||||
|
iconSize: 20
|
||||||
|
backgroundColor: Theme.surfaceContainer
|
||||||
|
iconColor: Theme.primary
|
||||||
|
onClicked: appBrowserPopup.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SettingsData.mediaExcludePlayers
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 48
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width - deleteBtn.width - Theme.spacingS
|
||||||
|
height: parent.height
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "music_off"
|
||||||
|
size: 20
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: deleteBtn
|
||||||
|
buttonSize: 32
|
||||||
|
iconName: "delete"
|
||||||
|
iconSize: 18
|
||||||
|
iconColor: Theme.error
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: SettingsData.removeMediaExcludePlayer(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: !SettingsData.mediaExcludePlayers || SettingsData.mediaExcludePlayers.length === 0
|
||||||
|
text: I18n.tr("No excluded players configured")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.italic: true
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
width: parent.width
|
||||||
|
topPadding: Theme.spacingS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppBrowserPopup {
|
||||||
|
id: appBrowserPopup
|
||||||
|
appsModel: root.desktopApps
|
||||||
|
parentModal: root.parentModal
|
||||||
|
onAppSelected: appId => {
|
||||||
|
var name = appId;
|
||||||
|
if (name.endsWith(".desktop")) {
|
||||||
|
name = name.slice(0, -8);
|
||||||
|
}
|
||||||
|
SettingsData.addMediaExcludePlayer(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,38 @@ import qs.Common
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property list<MprisPlayer> availablePlayers: Mpris.players.values
|
readonly property list<MprisPlayer> availablePlayers: {
|
||||||
|
const players = Mpris.players.values;
|
||||||
|
const excluded = SettingsData.mediaExcludePlayers || [];
|
||||||
|
if (excluded.length === 0)
|
||||||
|
return players;
|
||||||
|
return players.filter(p => {
|
||||||
|
const identity = (p.identity || "").toLowerCase();
|
||||||
|
const desktopEntry = ("desktopEntry" in p && p.desktopEntry) ? String(p.desktopEntry).toLowerCase() : "";
|
||||||
|
return !excluded.some(ex => {
|
||||||
|
const exLower = String(ex).toLowerCase().trim();
|
||||||
|
if (!exLower) return false;
|
||||||
|
|
||||||
|
// 1. Substring match
|
||||||
|
if (identity.includes(exLower) || desktopEntry.includes(exLower))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 2. Match reverse-DNS segments (e.g. app.zen_browser.zen -> zen)
|
||||||
|
if (exLower.indexOf(".") !== -1) {
|
||||||
|
const parts = exLower.split(".");
|
||||||
|
const lastPart = parts[parts.length - 1];
|
||||||
|
if (lastPart && (identity.includes(lastPart) || desktopEntry.includes(lastPart)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Bidirectional match (longer excluded name contains shorter player identity)
|
||||||
|
if (identity.length >= 3 && exLower.includes(identity))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
property MprisPlayer activePlayer: null
|
property MprisPlayer activePlayer: null
|
||||||
property real activePlayerStableLength: 0
|
property real activePlayerStableLength: 0
|
||||||
|
|
||||||
|
|||||||
@@ -5643,6 +5643,26 @@
|
|||||||
],
|
],
|
||||||
"description": "Play sound when volume is adjusted"
|
"description": "Play sound when volume is adjusted"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "mediaExcludePlayers",
|
||||||
|
"label": "Excluded Media Players",
|
||||||
|
"tabIndex": 16,
|
||||||
|
"category": "Media Player",
|
||||||
|
"keywords": [
|
||||||
|
"audio",
|
||||||
|
"exclude",
|
||||||
|
"excluded",
|
||||||
|
"ignore",
|
||||||
|
"media",
|
||||||
|
"mpris",
|
||||||
|
"music",
|
||||||
|
"playback",
|
||||||
|
"player",
|
||||||
|
"players",
|
||||||
|
"spotify"
|
||||||
|
],
|
||||||
|
"icon": "do_not_disturb_on"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "_tab_16",
|
"section": "_tab_16",
|
||||||
"label": "Media Player",
|
"label": "Media Player",
|
||||||
|
|||||||
Reference in New Issue
Block a user