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

launcher v2: meta improvements

- Allow disabling each plugin from "all" mode
- add IPCs for toggling specific modes
- niri: overview respect size & default to apps mode
- fix unicode icon handling
This commit is contained in:
bbedward
2026-01-21 11:38:48 -05:00
parent eebb4827c4
commit 3922070488
11 changed files with 312 additions and 15 deletions

View File

@@ -79,6 +79,23 @@ Singleton {
saveSettings();
}
property var launcherPluginVisibility: ({})
function getPluginAllowWithoutTrigger(pluginId) {
if (!launcherPluginVisibility[pluginId])
return true;
return launcherPluginVisibility[pluginId].allowWithoutTrigger !== false;
}
function setPluginAllowWithoutTrigger(pluginId, allow) {
const updated = JSON.parse(JSON.stringify(launcherPluginVisibility));
if (!updated[pluginId])
updated[pluginId] = {};
updated[pluginId].allowWithoutTrigger = allow;
launcherPluginVisibility = updated;
saveSettings();
}
property alias dankBarLeftWidgetsModel: leftWidgetsModel
property alias dankBarCenterWidgetsModel: centerWidgetsModel
property alias dankBarRightWidgetsModel: rightWidgetsModel

View File

@@ -415,7 +415,8 @@ var SPEC = {
desktopWidgetGroups: { def: [] },
builtInPluginSettings: { def: {} }
builtInPluginSettings: { def: {} },
launcherPluginVisibility: { def: {} }
};
function getValidKeys() {

View File

@@ -1041,6 +1041,20 @@ Item {
return "LAUNCHER_TOGGLE_SUCCESS";
}
function openWith(mode: string): string {
if (!mode)
return "LAUNCHER_OPEN_FAILED: No mode specified";
PopoutService.openSpotlightV2WithMode(mode);
return `LAUNCHER_OPEN_SUCCESS: ${mode}`;
}
function toggleWith(mode: string): string {
if (!mode)
return "LAUNCHER_TOGGLE_FAILED: No mode specified";
PopoutService.toggleSpotlightV2WithMode(mode);
return `LAUNCHER_TOGGLE_SUCCESS: ${mode}`;
}
function openQuery(query: string): string {
PopoutService.openSpotlightV2WithQuery(query);
return "LAUNCHER_OPEN_QUERY_SUCCESS";

View File

@@ -431,14 +431,14 @@ Item {
if (searchMode === "all") {
if (searchQuery) {
var allPluginIds = getAllLauncherPluginIds();
var allPluginIds = getVisibleLauncherPluginIds();
for (var i = 0; i < allPluginIds.length; i++) {
var pluginId = allPluginIds[i];
var pItems = getPluginItems(pluginId, searchQuery);
allItems = allItems.concat(pItems);
}
var allBuiltInIds = getAllBuiltInLauncherIds();
var allBuiltInIds = getVisibleBuiltInLauncherIds();
for (var i = 0; i < allBuiltInIds.length; i++) {
var pluginId = allBuiltInIds[i];
var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery);
@@ -858,7 +858,10 @@ Item {
}
function getEmptyTriggerPlugins() {
return PluginService.getPluginsWithEmptyTrigger();
var plugins = PluginService.getPluginsWithEmptyTrigger();
return plugins.filter(function (pluginId) {
return SettingsData.getPluginAllowWithoutTrigger(pluginId);
});
}
function getAllLauncherPluginIds() {
@@ -866,11 +869,25 @@ Item {
return Object.keys(launchers);
}
function getVisibleLauncherPluginIds() {
var launchers = PluginService.getLauncherPlugins();
return Object.keys(launchers).filter(function (pluginId) {
return SettingsData.getPluginAllowWithoutTrigger(pluginId);
});
}
function getAllBuiltInLauncherIds() {
var launchers = AppSearchService.getBuiltInLauncherPlugins();
return Object.keys(launchers);
}
function getVisibleBuiltInLauncherIds() {
var launchers = AppSearchService.getBuiltInLauncherPlugins();
return Object.keys(launchers).filter(function (pluginId) {
return SettingsData.getPluginAllowWithoutTrigger(pluginId);
});
}
function getPluginBrowseItems() {
var items = [];
@@ -930,7 +947,10 @@ Item {
}
function getBuiltInEmptyTriggerLaunchers() {
return AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger();
var plugins = AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger();
return plugins.filter(function (pluginId) {
return SettingsData.getPluginAllowWithoutTrigger(pluginId);
});
}
function getPluginItems(pluginId, query) {
@@ -947,12 +967,14 @@ Item {
function detectIconType(iconName) {
if (!iconName)
return "material";
if (iconName.indexOf("/") >= 0 || iconName.indexOf(".") >= 0)
return "image";
if (iconName.startsWith("unicode:"))
return "unicode";
if (iconName.startsWith("material:"))
return "material";
if (iconName.startsWith("image:"))
return "image";
if (iconName.indexOf("/") >= 0 || iconName.indexOf(".") >= 0)
return "image";
if (/^[a-z]+-[a-z]/.test(iconName.toLowerCase()))
return "image";
return "material";
@@ -961,6 +983,8 @@ Item {
function stripIconPrefix(iconName) {
if (!iconName)
return "extension";
if (iconName.startsWith("unicode:"))
return iconName.substring(8);
if (iconName.startsWith("material:"))
return iconName.substring(9);
if (iconName.startsWith("image:"))

View File

@@ -53,7 +53,7 @@ Item {
signal dialogClosed
function _initializeAndShow(query) {
function _initializeAndShow(query, mode) {
contentVisible = true;
spotlightContent.searchField.forceActiveFocus();
@@ -61,7 +61,8 @@ Item {
spotlightContent.searchField.text = query;
}
if (spotlightContent.controller) {
spotlightContent.controller.searchMode = "all";
var targetMode = mode || "all";
spotlightContent.controller.searchMode = targetMode;
spotlightContent.controller.activePluginId = "";
spotlightContent.controller.activePluginName = "";
spotlightContent.controller.pluginFilter = "";
@@ -136,6 +137,32 @@ Item {
spotlightOpen ? hide() : show();
}
function showWithMode(mode) {
closeCleanupTimer.stop();
isClosing = false;
openedFromOverview = false;
var focusedScreen = CompositorService.getFocusedScreen();
if (focusedScreen)
launcherWindow.screen = focusedScreen;
spotlightOpen = true;
keyboardActive = true;
ModalManager.openModal(root);
if (useHyprlandFocusGrab)
focusGrab.active = true;
_initializeAndShow("", mode);
}
function toggleWithMode(mode) {
if (spotlightOpen) {
hide();
} else {
showWithMode(mode);
}
}
Timer {
id: closeCleanupTimer
interval: Theme.expressiveDurations.expressiveFastSpatial + 50

View File

@@ -52,6 +52,14 @@ Rectangle {
color: root.isSelected ? Theme.primary : Theme.surfaceText
}
StyledText {
anchors.centerIn: parent
visible: root.item?.iconType === "unicode"
text: root.item?.icon ?? ""
font.pixelSize: parent.iconSize * 0.7
color: root.isSelected ? Theme.primary : Theme.surfaceText
}
Item {
anchors.fill: parent
visible: root.item?.iconType === "composite"

View File

@@ -52,6 +52,14 @@ Rectangle {
color: Theme.surfaceText
}
StyledText {
anchors.centerIn: parent
visible: root.item?.iconType === "unicode"
text: root.item?.icon ?? ""
font.pixelSize: 24
color: Theme.surfaceText
}
Item {
anchors.fill: parent
visible: root.item?.iconType === "composite"

View File

@@ -76,12 +76,20 @@ Rectangle {
DankIcon {
anchors.centerIn: parent
visible: !root.useImage && !root.useIconProvider
visible: !root.useImage && !root.useIconProvider && root.item?.iconType !== "unicode"
name: root.item?.icon ?? "image"
size: Math.min(parent.width, parent.height) * 0.4
color: Theme.surfaceVariantText
}
StyledText {
anchors.centerIn: parent
visible: root.item?.iconType === "unicode"
text: root.item?.icon ?? ""
font.pixelSize: Math.min(parent.width, parent.height) * 0.4
color: Theme.surfaceVariantText
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right

View File

@@ -572,6 +572,160 @@ Item {
}
}
SettingsCard {
id: pluginVisibilityCard
width: parent.width
iconName: "filter_list"
title: I18n.tr("Plugin Visibility")
settingKey: "pluginVisibility"
property var allLauncherPlugins: {
SettingsData.launcherPluginVisibility;
var plugins = [];
var builtIn = AppSearchService.getBuiltInLauncherPlugins() || {};
for (var pluginId in builtIn) {
var plugin = builtIn[pluginId];
plugins.push({
id: pluginId,
name: plugin.name || pluginId,
icon: plugin.cornerIcon || "extension",
iconType: "material",
isBuiltIn: true,
trigger: AppSearchService.getBuiltInPluginTrigger(pluginId) || ""
});
}
var thirdParty = PluginService.getLauncherPlugins() || {};
for (var pluginId in thirdParty) {
var plugin = thirdParty[pluginId];
var rawIcon = plugin.icon || "extension";
plugins.push({
id: pluginId,
name: plugin.name || pluginId,
icon: rawIcon.startsWith("material:") ? rawIcon.substring(9) : rawIcon.startsWith("unicode:") ? rawIcon.substring(8) : rawIcon,
iconType: rawIcon.startsWith("unicode:") ? "unicode" : "material",
isBuiltIn: false,
trigger: PluginService.getPluginTrigger(pluginId) || ""
});
}
return plugins.sort((a, b) => a.name.localeCompare(b.name));
}
StyledText {
width: parent.width
text: I18n.tr("Control which plugins appear in 'All' mode without requiring a trigger prefix. Disabled plugins will only show when using their trigger.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
Column {
width: parent.width
spacing: Theme.spacingS
Repeater {
model: pluginVisibilityCard.allLauncherPlugins
delegate: Rectangle {
id: visibilityDelegate
required property var modelData
required property int index
width: parent.width
height: 52
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3)
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
Item {
width: Theme.iconSize
height: Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
visible: visibilityDelegate.modelData.iconType !== "unicode"
name: visibilityDelegate.modelData.icon
size: Theme.iconSize
color: Theme.primary
}
StyledText {
anchors.centerIn: parent
visible: visibilityDelegate.modelData.iconType === "unicode"
text: visibilityDelegate.modelData.icon
font.pixelSize: Theme.iconSize
color: Theme.primary
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Row {
spacing: Theme.spacingS
StyledText {
text: visibilityDelegate.modelData.name
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
Rectangle {
visible: visibilityDelegate.modelData.isBuiltIn
width: dmsLabel.implicitWidth + Theme.spacingS
height: 16
radius: 8
color: Theme.primaryContainer
anchors.verticalCenter: parent.verticalCenter
StyledText {
id: dmsLabel
anchors.centerIn: parent
text: "DMS"
font.pixelSize: Theme.fontSizeSmall - 2
color: Theme.primaryText
}
}
}
StyledText {
text: visibilityDelegate.modelData.trigger ? I18n.tr("Trigger: %1").arg(visibilityDelegate.modelData.trigger) : I18n.tr("No trigger")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
DankToggle {
id: visibilityToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.getPluginAllowWithoutTrigger(visibilityDelegate.modelData.id)
onToggled: function (isChecked) {
SettingsData.setPluginAllowWithoutTrigger(visibilityDelegate.modelData.id, isChecked);
}
}
}
}
StyledText {
width: parent.width
text: I18n.tr("No launcher plugins installed.")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter
visible: pluginVisibilityCard.allLauncherPlugins.length === 0
}
}
}
SettingsCard {
width: parent.width
iconName: "search"

View File

@@ -122,8 +122,10 @@ Scope {
onShouldShowSpotlightChanged: {
if (shouldShowSpotlight) {
if (launcherContent?.controller)
if (launcherContent?.controller) {
launcherContent.controller.searchMode = "apps";
launcherContent.controller.performSearch();
}
return;
}
if (!isActiveScreen)
@@ -198,8 +200,11 @@ Scope {
id: spotlightContainer
x: Theme.snap((parent.width - width) / 2, overlayWindow.dpr)
y: Theme.snap((parent.height - height) / 2, overlayWindow.dpr)
width: Theme.px(500, overlayWindow.dpr)
height: Theme.px(600, overlayWindow.dpr)
readonly property int baseWidth: SettingsData.dankLauncherV2Size === "medium" ? 720 : SettingsData.dankLauncherV2Size === "large" ? 860 : 620
readonly property int baseHeight: SettingsData.dankLauncherV2Size === "medium" ? 720 : SettingsData.dankLauncherV2Size === "large" ? 860 : 600
width: Math.min(baseWidth, overlayWindow.screen.width - 100)
height: Math.min(baseHeight, overlayWindow.screen.height - 100)
readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen
@@ -252,7 +257,7 @@ Scope {
property bool isClosing: niriOverviewScope.isClosing
function hide() {
if (niriOverviewScope.searchActive) {
niriOverviewScope.hideAndReleaseKeyboard();
niriOverviewScope.hideSpotlight();
return;
}
NiriService.toggleOverview();

View File

@@ -366,6 +366,7 @@ Singleton {
property bool _spotlightV2WantsOpen: false
property bool _spotlightV2WantsToggle: false
property string _spotlightV2PendingQuery: ""
property string _spotlightV2PendingMode: ""
function openSpotlightV2() {
if (spotlightV2Modal) {
@@ -388,6 +389,17 @@ Singleton {
}
}
function openSpotlightV2WithMode(mode: string) {
if (spotlightV2Modal) {
spotlightV2Modal.showWithMode(mode);
} else if (spotlightV2ModalLoader) {
_spotlightV2PendingMode = mode;
_spotlightV2WantsOpen = true;
_spotlightV2WantsToggle = false;
spotlightV2ModalLoader.active = true;
}
}
function closeSpotlightV2() {
spotlightV2Modal?.hide();
}
@@ -402,12 +414,26 @@ Singleton {
}
}
function toggleSpotlightV2WithMode(mode: string) {
if (spotlightV2Modal) {
spotlightV2Modal.toggleWithMode(mode);
} else if (spotlightV2ModalLoader) {
_spotlightV2PendingMode = mode;
_spotlightV2WantsToggle = true;
_spotlightV2WantsOpen = false;
spotlightV2ModalLoader.active = true;
}
}
function _onSpotlightV2ModalLoaded() {
if (_spotlightV2WantsOpen) {
_spotlightV2WantsOpen = false;
if (_spotlightV2PendingQuery) {
spotlightV2Modal?.showWithQuery(_spotlightV2PendingQuery);
_spotlightV2PendingQuery = "";
} else if (_spotlightV2PendingMode) {
spotlightV2Modal?.showWithMode(_spotlightV2PendingMode);
_spotlightV2PendingMode = "";
} else {
spotlightV2Modal?.show();
}
@@ -415,7 +441,12 @@ Singleton {
}
if (_spotlightV2WantsToggle) {
_spotlightV2WantsToggle = false;
spotlightV2Modal?.toggle();
if (_spotlightV2PendingMode) {
spotlightV2Modal?.toggleWithMode(_spotlightV2PendingMode);
_spotlightV2PendingMode = "";
} else {
spotlightV2Modal?.toggle();
}
}
}