1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-26 22:42:50 -05:00

feat: configurable app id substitutions (#1317)

* feat: add configurable app ID substitutions setting

* feat: add live icon updates when substitutions change

* fix: cursor not showing on headerActions in non-collapsible cards

* fix: address PR review feedback

- add tags for search index
- remove hardcoded height from text fields
This commit is contained in:
shalevc1098
2026-01-11 04:00:15 +02:00
committed by GitHub
parent bb2234d328
commit 510ea5d2e4
11 changed files with 294 additions and 47 deletions

View File

@@ -56,6 +56,13 @@ BasePill {
}
}
Connections {
target: SettingsData
function onAppIdSubstitutionsChanged() {
root.updateDesktopEntry();
}
}
function updateDesktopEntry() {
if (activeWindow && activeWindow.appId) {
const moddedId = Paths.moddedAppId(activeWindow.appId);

View File

@@ -69,6 +69,7 @@ Item {
property int _desktopEntriesUpdateTrigger: 0
property int _toplevelsUpdateTrigger: 0
property int _appIdSubstitutionsTrigger: 0
readonly property var sortedToplevels: {
_toplevelsUpdateTrigger;
@@ -95,6 +96,13 @@ Item {
_desktopEntriesUpdateTrigger++;
}
}
Connections {
target: SettingsData
function onAppIdSubstitutionsChanged() {
_appIdSubstitutionsTrigger++;
}
}
readonly property var groupedWindows: {
if (!SettingsData.runningAppsGroupByApp) {
return [];
@@ -364,6 +372,7 @@ Item {
height: Theme.barIconSize(root.barThickness)
source: {
root._desktopEntriesUpdateTrigger;
root._appIdSubstitutionsTrigger;
if (!appId)
return "";
const moddedId = Paths.moddedAppId(appId);
@@ -596,6 +605,7 @@ Item {
height: Theme.barIconSize(root.barThickness)
source: {
root._desktopEntriesUpdateTrigger;
root._appIdSubstitutionsTrigger;
if (!appId)
return "";
const moddedId = Paths.moddedAppId(appId);

View File

@@ -265,7 +265,8 @@ Item {
if (!byApp[key]) {
const isQuickshell = keyBase === "org.quickshell";
const desktopEntry = DesktopEntries.heuristicLookup(keyBase);
const moddedId = Paths.moddedAppId(keyBase);
const desktopEntry = DesktopEntries.heuristicLookup(moddedId);
const icon = Paths.getAppIcon(keyBase, desktopEntry);
byApp[key] = {
"type": "icon",
@@ -1367,6 +1368,9 @@ Item {
function onWorkspaceNameIconsChanged() {
delegateRoot.updateAllData();
}
function onAppIdSubstitutionsChanged() {
delegateRoot.updateAllData();
}
}
Connections {
target: DwlService

View File

@@ -49,6 +49,13 @@ Item {
updateDesktopEntry();
}
}
Connections {
target: SettingsData
function onAppIdSubstitutionsChanged() {
updateDesktopEntry();
}
}
property bool isWindowFocused: {
if (!appData) {
return false;

View File

@@ -32,6 +32,159 @@ Item {
onToggled: checked => SettingsData.set("runningAppsCurrentWorkspace", checked)
}
}
SettingsCard {
width: parent.width
iconName: "find_replace"
title: I18n.tr("App ID Substitutions")
settingKey: "appIdSubstitutions"
tags: ["app", "icon", "substitution", "replacement", "pattern", "window", "class", "regex"]
headerActions: [
DankActionButton {
buttonSize: 36
iconName: "restart_alt"
iconSize: 20
visible: JSON.stringify(SettingsData.appIdSubstitutions) !== JSON.stringify(SettingsData.getDefaultAppIdSubstitutions())
backgroundColor: Theme.surfaceContainer
iconColor: Theme.surfaceVariantText
onClicked: SettingsData.resetAppIdSubstitutions()
},
DankActionButton {
buttonSize: 36
iconName: "add"
iconSize: 20
backgroundColor: Theme.surfaceContainer
iconColor: Theme.primary
onClicked: SettingsData.addAppIdSubstitution("", "", "exact")
}
]
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Map window class names to icon names for proper icon display")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
bottomPadding: Theme.spacingS
}
Repeater {
model: SettingsData.appIdSubstitutions
delegate: Rectangle {
id: subItem
width: parent.width
height: subColumn.implicitHeight + Theme.spacingM
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
Column {
id: subColumn
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: Theme.spacingS
Row {
width: parent.width
spacing: Theme.spacingS
Column {
width: (parent.width - deleteBtn.width - Theme.spacingS) / 2
spacing: 2
StyledText {
text: I18n.tr("Pattern")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
DankTextField {
id: patternField
width: parent.width
text: modelData.pattern
font.pixelSize: Theme.fontSizeSmall
onEditingFinished: SettingsData.updateAppIdSubstitution(index, text, replacementField.text, modelData.type)
}
}
Column {
width: (parent.width - deleteBtn.width - Theme.spacingS) / 2
spacing: 2
StyledText {
text: I18n.tr("Replacement")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
DankTextField {
id: replacementField
width: parent.width
text: modelData.replacement
font.pixelSize: Theme.fontSizeSmall
onEditingFinished: SettingsData.updateAppIdSubstitution(index, patternField.text, text, modelData.type)
}
}
Item {
id: deleteBtn
width: 32
height: 40
anchors.verticalCenter: parent.verticalCenter
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent"
}
DankIcon {
anchors.centerIn: parent
name: "delete"
size: 18
color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText
}
MouseArea {
id: deleteArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: SettingsData.removeAppIdSubstitution(index)
}
}
}
Column {
width: 120
spacing: 2
StyledText {
text: I18n.tr("Type")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
DankDropdown {
width: parent.width
compactMode: true
dropdownWidth: 120
currentValue: modelData.type
options: ["exact", "contains", "regex"]
onValueChanged: value => SettingsData.updateAppIdSubstitution(index, modelData.pattern, modelData.replacement, value)
}
}
}
}
}
}
}
}
}
}

View File

@@ -142,7 +142,7 @@ StyledRect {
Row {
id: headerActionsRow
anchors.right: caretIcon.left
anchors.right: root.collapsible ? caretIcon.left : parent.right
anchors.rightMargin: root.collapsible ? Theme.spacingS : 0
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
@@ -172,6 +172,7 @@ StyledRect {
}
MouseArea {
visible: root.collapsible
anchors.left: caretIcon.left
anchors.right: parent.right
anchors.top: parent.top

View File

@@ -33,8 +33,8 @@ Item {
property var iconToWindowRatio: 0.25
property var iconToWindowRatioCompact: 0.45
property var entry: DesktopEntries.heuristicLookup(windowData?.class)
property var iconPath: Quickshell.iconPath(entry?.icon ?? windowData?.class ?? "application-x-executable", "image-missing")
property var entry: DesktopEntries.heuristicLookup(Paths.moddedAppId(windowData?.class ?? ""))
property var iconPath: Paths.getAppIcon(windowData?.class ?? "", entry) || Quickshell.iconPath("application-x-executable", "image-missing")
property bool compactMode: Theme.fontSizeSmall * 4 > targetWindowHeight || Theme.fontSizeSmall * 4 > targetWindowWidth
x: initX