1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

feat: Pinnable DMS coreApps w/Color options

This commit is contained in:
purian23
2026-01-22 17:45:38 -05:00
parent 2681fe87bb
commit 1edc8f468e
5 changed files with 167 additions and 30 deletions

View File

@@ -76,8 +76,6 @@ FocusScope {
function showContextMenu(item, x, y, fromKeyboard) {
if (!item)
return;
if (item.isCore)
return;
if (!contextMenu.hasContextMenuActions(item))
return;
contextMenu.show(x, y, item, fromKeyboard);

View File

@@ -20,7 +20,7 @@ Popup {
function hasContextMenuActions(spotlightItem) {
if (!spotlightItem)
return false;
if (spotlightItem.type === "app" && !spotlightItem.isCore)
if (spotlightItem.type === "app")
return true;
if (spotlightItem.type === "plugin" && spotlightItem.pluginId) {
var instance = PluginService.pluginInstances[spotlightItem.pluginId];
@@ -34,9 +34,16 @@ Popup {
return false;
}
readonly property var desktopEntry: item?.data ?? null
readonly property string appId: desktopEntry?.id || desktopEntry?.execString || ""
readonly property bool isPinned: SessionData.isPinnedApp(appId)
readonly property bool isCoreApp: item?.type === "app" && item?.isCore
readonly property var coreAppData: isCoreApp ? item?.data ?? null : null
readonly property var desktopEntry: !isCoreApp ? (item?.data ?? null) : null
readonly property string appId: {
if (isCoreApp) {
return item?.id || coreAppData?.builtInPluginId || "";
}
return desktopEntry?.id || desktopEntry?.execString || "";
}
readonly property bool isPinned: appId ? SessionData.isPinnedApp(appId) : false
readonly property bool isRegularApp: item?.type === "app" && !item.isCore && desktopEntry
readonly property bool isPluginItem: item?.type === "plugin"
@@ -82,15 +89,14 @@ Popup {
return items;
}
if (!desktopEntry)
return items;
if (item?.type === "app") {
items.push({
type: "item",
icon: isPinned ? "keep_off" : "push_pin",
text: isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock"),
action: togglePin
});
}
if (isRegularApp) {
items.push({
@@ -200,6 +206,14 @@ Popup {
}
function launchApp() {
if (isCoreApp) {
if (!coreAppData)
return;
AppSearchService.executeCoreApp(coreAppData);
controller?.itemExecuted();
hide();
return;
}
if (!desktopEntry)
return;
SessionService.launchDesktopEntry(desktopEntry);

View File

@@ -29,12 +29,29 @@ Item {
property bool showTooltip: mouseArea.containsMouse && !dragging
property var cachedDesktopEntry: null
property real actualIconSize: 40
readonly property string coreIconColorOverride: SettingsData.dockLauncherLogoColorOverride
readonly property bool coreIconHasCustomColor: coreIconColorOverride !== "" && coreIconColorOverride !== "primary" && coreIconColorOverride !== "surface"
readonly property color effectiveCoreIconColor: {
if (coreIconColorOverride === "primary")
return Theme.primary;
if (coreIconColorOverride === "surface")
return Theme.surfaceText;
if (coreIconColorOverride !== "")
return coreIconColorOverride;
return Theme.surfaceText;
}
readonly property real effectiveCoreIconBrightness: coreIconHasCustomColor ? SettingsData.dockLauncherLogoBrightness : 0.0
readonly property real effectiveCoreIconContrast: coreIconHasCustomColor ? SettingsData.dockLauncherLogoContrast : 0.0
function updateDesktopEntry() {
if (!appData || appData.appId === "__SEPARATOR__") {
cachedDesktopEntry = null;
return;
}
if (appData.isCoreApp) {
cachedDesktopEntry = null;
return;
}
const moddedId = Paths.moddedAppId(appData.appId);
cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId);
}
@@ -85,7 +102,12 @@ Item {
return "";
}
const appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
let appName;
if (appData.isCoreApp && appData.coreAppData) {
appName = appData.coreAppData.name || appData.appId;
} else {
appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
}
if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) {
const title = appData.type === "window" ? windowTitle : appData.windowTitle;
@@ -227,6 +249,10 @@ Item {
case "pinned":
if (!appData.appId)
return;
if (appData.isCoreApp && appData.coreAppData) {
AppSearchService.executeCoreApp(appData.coreAppData);
return;
}
const pinnedEntry = cachedDesktopEntry;
if (pinnedEntry) {
AppUsageHistoryData.addAppUsage({
@@ -248,6 +274,10 @@ Item {
if (appData.windowCount === 0) {
if (!appData.appId)
return;
if (appData.isCoreApp && appData.coreAppData) {
AppSearchService.executeCoreApp(appData.coreAppData);
return;
}
const groupedEntry = cachedDesktopEntry;
if (groupedEntry) {
AppUsageHistoryData.addAppUsage({
@@ -374,6 +404,19 @@ Item {
z: -1
}
AppIconRenderer {
id: coreIcon
anchors.centerIn: parent
iconSize: actualIconSize
iconValue: appData && appData.isCoreApp && appData.coreAppData ? (appData.coreAppData.icon || "") : ""
colorOverride: effectiveCoreIconColor
brightnessOverride: effectiveCoreIconBrightness
contrastOverride: effectiveCoreIconContrast
fallbackText: "?"
visible: iconValue !== ""
}
IconImage {
id: iconImg
@@ -383,12 +426,15 @@ Item {
if (!appData || appData.appId === "__SEPARATOR__") {
return "";
}
if (appData.isCoreApp && appData.coreAppData) {
return "";
}
return Paths.getAppIcon(appData.appId, cachedDesktopEntry);
}
mipmap: true
smooth: true
asynchronous: true
visible: status === Image.Ready
visible: status === Image.Ready && !coreIcon.visible
layer.enabled: appData && appData.appId === "org.quickshell"
layer.smooth: true
layer.mipmap: true
@@ -403,7 +449,7 @@ Item {
width: actualIconSize
height: actualIconSize
anchors.centerIn: parent
visible: iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId)
visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId)
color: Theme.surfaceLight
radius: Theme.cornerRadius
border.width: 1
@@ -416,7 +462,12 @@ Item {
return "?";
}
const appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
let appName;
if (appData.isCoreApp && appData.coreAppData) {
appName = appData.coreAppData.name || appData.appId;
} else {
appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
}
return appName.charAt(0).toUpperCase();
}
font.pixelSize: Math.max(8, parent.width * 0.35)
@@ -430,7 +481,7 @@ Item {
size: actualIconSize
name: "sports_esports"
color: Theme.surfaceText
visible: iconImg.status !== Image.Ready && appData && appData.appId && Paths.isSteamApp(appData.appId)
visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && Paths.isSteamApp(appData.appId)
}
Loader {

View File

@@ -91,6 +91,34 @@ Item {
return false;
}
function getCoreAppData(appId) {
if (typeof AppSearchService === "undefined")
return null;
const coreApps = AppSearchService.coreApps || [];
for (let i = 0; i < coreApps.length; i++) {
const app = coreApps[i];
if (app.builtInPluginId === appId) {
return app;
}
}
return null;
}
function getCoreAppDataByTitle(windowTitle) {
if (typeof AppSearchService === "undefined" || !windowTitle)
return null;
const coreApps = AppSearchService.coreApps || [];
for (let i = 0; i < coreApps.length; i++) {
const app = coreApps[i];
if (app.name === windowTitle) {
return app;
}
}
return null;
}
function insertLauncher(targetArray) {
if (!SettingsData.dockLauncherEnabled)
return;
@@ -119,21 +147,35 @@ Item {
pinnedApps.forEach(rawAppId => {
const appId = Paths.moddedAppId(rawAppId);
const coreAppData = getCoreAppData(appId);
appGroups.set(appId, {
appId: appId,
isPinned: true,
windows: []
windows: [],
isCoreApp: coreAppData !== null,
coreAppData: coreAppData
});
});
sortedToplevels.forEach((toplevel, index) => {
const rawAppId = toplevel.appId || "unknown";
const appId = Paths.moddedAppId(rawAppId);
let appId = Paths.moddedAppId(rawAppId);
let coreAppData = null;
if (rawAppId === "org.quickshell") {
coreAppData = getCoreAppDataByTitle(toplevel.title);
if (coreAppData) {
appId = coreAppData.builtInPluginId;
}
}
if (!appGroups.has(appId)) {
appGroups.set(appId, {
appId: appId,
isPinned: false,
windows: []
windows: [],
isCoreApp: coreAppData !== null,
coreAppData: coreAppData
});
}
@@ -157,7 +199,9 @@ Item {
isPinned: group.isPinned,
isRunning: group.windows.length > 0,
windowCount: group.windows.length,
allWindows: group.windows
allWindows: group.windows,
isCoreApp: group.isCoreApp || false,
coreAppData: group.coreAppData || null
};
if (group.isPinned) {
@@ -187,13 +231,16 @@ Item {
} else {
pinnedApps.forEach(rawAppId => {
const appId = Paths.moddedAppId(rawAppId);
const coreAppData = getCoreAppData(appId);
items.push({
uniqueKey: "pinned_" + appId,
type: "pinned",
appId: appId,
toplevel: null,
isPinned: true,
isRunning: false
isRunning: false,
isCoreApp: coreAppData !== null,
coreAppData: coreAppData
});
});
@@ -224,13 +271,31 @@ Item {
}
}
const rawAppId = toplevel.appId || "unknown";
const moddedAppId = Paths.moddedAppId(rawAppId);
// Check if this is a core app window (e.g., Settings modal with appId "org.quickshell")
let coreAppData = null;
let isCoreApp = false;
if (rawAppId === "org.quickshell") {
coreAppData = getCoreAppDataByTitle(toplevel.title);
if (coreAppData) {
isCoreApp = true;
}
}
const finalAppId = isCoreApp ? coreAppData.builtInPluginId : moddedAppId;
const isPinned = pinnedApps.indexOf(finalAppId) !== -1;
items.push({
uniqueKey: uniqueKey,
type: "window",
appId: Paths.moddedAppId(toplevel.appId),
appId: finalAppId,
toplevel: toplevel,
isPinned: false,
isRunning: true
isPinned: isPinned,
isRunning: true,
isCoreApp: isCoreApp,
coreAppData: coreAppData
});
});
}

View File

@@ -11,6 +11,10 @@ Item {
required property int iconSize
property string fallbackText: "A"
property color iconColor: Theme.surfaceText
property color colorOverride: "transparent"
property real brightnessOverride: 0.0
property real contrastOverride: 0.0
property real saturationOverride: 0.0
property color fallbackBackgroundColor: Theme.surfaceLight
property color fallbackTextColor: Theme.primary
property real materialIconSizeAdjustment: Theme.spacingM
@@ -27,6 +31,7 @@ Item {
readonly property bool isSvgCorner: iconValue.startsWith("svg+corner:")
readonly property bool isSvg: !isSvgCorner && iconValue.startsWith("svg:")
readonly property bool isImage: iconValue.startsWith("image:")
readonly property bool hasColorOverride: colorOverride.a > 0
readonly property string materialName: isMaterial ? iconValue.substring(9) : ""
readonly property string unicodeChar: isUnicode ? iconValue.substring(8) : ""
readonly property string imagePath: isImage ? iconValue.substring(6) : ""
@@ -48,7 +53,7 @@ Item {
anchors.centerIn: parent
name: root.materialName
size: root.iconSize - root.materialIconSizeAdjustment
color: root.iconColor
color: root.hasColorOverride ? root.colorOverride : root.iconColor
visible: root.isMaterial
}
@@ -56,7 +61,7 @@ Item {
anchors.centerIn: parent
text: root.unicodeChar
font.pixelSize: root.iconSize * root.unicodeIconScale
color: root.iconColor
color: root.hasColorOverride ? root.colorOverride : root.iconColor
visible: root.isUnicode
}
@@ -65,6 +70,10 @@ Item {
source: root.svgSource
size: root.iconSize
cornerIcon: root.svgCornerIcon
colorOverride: root.colorOverride
brightnessOverride: root.brightnessOverride
contrastOverride: root.contrastOverride
saturationOverride: root.saturationOverride
visible: root.isSvg || root.isSvgCorner
}