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:
@@ -56,6 +56,13 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onAppIdSubstitutionsChanged() {
|
||||
root.updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
|
||||
function updateDesktopEntry() {
|
||||
if (activeWindow && activeWindow.appId) {
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -49,6 +49,13 @@ Item {
|
||||
updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onAppIdSubstitutionsChanged() {
|
||||
updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
property bool isWindowFocused: {
|
||||
if (!appData) {
|
||||
return false;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user