1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-08 04:09:15 -04:00

feat(Launcher/Spotlight): improve context keyboard navigation and mode persistence (#2467)

* feat(Spotlight): fix submenu keyboard navigation

* feat(Launcher/Spotlight): disable persisting last mode when changed by triggers

* feat(Launcher/Spotlight): add option to disable last mode being persisted

* fix(Launcher/Spotlight): fix context menu keys navigation

* fix(NiriOverviewOverlay): fix context menu keys navigation and position
This commit is contained in:
Lucas
2026-05-22 09:53:45 -03:00
committed by GitHub
parent ef5de19f6b
commit eea039f575
12 changed files with 120 additions and 48 deletions
+6
View File
@@ -1179,6 +1179,12 @@ Singleton {
saveSettings();
}
function getLauncherRestoreMode() {
if (!SettingsData.rememberLastMode)
return "all";
return launcherLastMode || "all";
}
function setLauncherLastFileSearchType(type) {
launcherLastFileSearchType = type;
saveSettings();
+1
View File
@@ -435,6 +435,7 @@ Singleton {
property int appLauncherGridColumns: 4
property bool spotlightCloseNiriOverview: true
property bool rememberLastQuery: false
property bool rememberLastMode: true
property var spotlightSectionViewModes: ({})
onSpotlightSectionViewModesChanged: saveSettings()
property var appDrawerSectionViewModes: ({})
@@ -203,6 +203,7 @@ var SPEC = {
appLauncherGridColumns: { def: 4 },
spotlightCloseNiriOverview: { def: true },
rememberLastQuery: { def: false },
rememberLastMode: { def: true },
spotlightSectionViewModes: { def: {} },
appDrawerSectionViewModes: { def: {} },
niriOverviewOverlayEnabled: { def: true },
@@ -39,7 +39,7 @@ Item {
signal itemExecuted
signal searchCompleted
signal modeChanged(string mode)
signal modeChanged(string mode, bool userInitiated)
signal queryChanged(string query)
signal viewModeChanged(string sectionId, string mode)
signal searchQueryRequested(string query)
@@ -440,7 +440,7 @@ Item {
}
}
function setMode(mode, isAutoSwitch, fileTypeOverride) {
function setMode(mode, isAutoSwitch, fileTypeOverride, notPersist) {
if (searchMode === mode) {
if (mode === "files" && fileTypeOverride !== undefined && fileSearchType !== fileTypeOverride) {
fileSearchType = fileTypeOverride;
@@ -458,7 +458,7 @@ Item {
if (mode === "files") {
fileSearchType = fileTypeOverride !== undefined ? fileTypeOverride : (SessionData.launcherLastFileSearchType || "all");
}
modeChanged(mode);
modeChanged(mode, !isAutoSwitch && notPersist !== true);
performSearch();
var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0;
if (mode === "files" || filesInAll) {
@@ -471,7 +471,7 @@ Item {
return;
autoSwitchedToFiles = false;
searchMode = previousSearchMode;
modeChanged(previousSearchMode);
modeChanged(previousSearchMode, false);
performSearch();
}
@@ -1897,7 +1897,7 @@ Item {
if (browseTrigger && browseTrigger.length > 0) {
searchQueryRequested(browseTrigger);
} else {
setMode("plugins");
setMode("plugins", false, undefined, true);
pluginFilter = browsePluginId;
performSearch();
}
@@ -396,7 +396,7 @@ Item {
spotlightContent.searchField.text = query;
}
if (spotlightContent.controller) {
var targetMode = mode || SessionData.launcherLastMode || "all";
var targetMode = mode || SessionData.getLauncherRestoreMode();
spotlightContent.controller.searchMode = targetMode;
spotlightContent.controller.activePluginId = "";
spotlightContent.controller.activePluginName = "";
@@ -539,8 +539,8 @@ Item {
Connections {
target: spotlightContent?.controller ?? null
function onModeChanged(mode) {
if (spotlightContent.controller.autoSwitchedToFiles)
function onModeChanged(mode, userInitiated) {
if (!userInitiated || !SettingsData.rememberLastMode)
return;
SessionData.setLauncherLastMode(mode);
}
@@ -928,8 +928,12 @@ Item {
}
}
Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event)
Keys.onEscapePressed: event => {
root.hide();
root.spotlightContent?.activeContextMenu?.handleKey(event);
if (!event.accepted)
root.hide();
event.accepted = true;
}
}
@@ -145,7 +145,7 @@ Item {
spotlightContent.closeTransientUi?.();
const targetQuery = query || (SettingsData.rememberLastQuery ? (SessionData.launcherLastQuery || "") : "");
const targetMode = mode || SessionData.launcherLastMode || "all";
const targetMode = mode || SessionData.getLauncherRestoreMode();
if (spotlightContent.searchField) {
spotlightContent.searchField.text = targetQuery;
@@ -489,8 +489,12 @@ Item {
}
}
Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event)
Keys.onEscapePressed: event => {
root.hide();
root.spotlightContent?.activeContextMenu?.handleKey(event);
if (!event.accepted)
root.hide();
event.accepted = true;
}
}
@@ -148,7 +148,7 @@ Item {
spotlightContent.searchField.text = targetQuery;
}
if (spotlightContent.controller) {
var targetMode = mode || SessionData.launcherLastMode || "all";
var targetMode = mode || SessionData.getLauncherRestoreMode();
spotlightContent.controller.searchMode = targetMode;
spotlightContent.controller.activePluginId = "";
spotlightContent.controller.activePluginName = "";
@@ -260,8 +260,8 @@ Item {
Connections {
target: spotlightContent?.controller ?? null
function onModeChanged(mode) {
if (spotlightContent.controller.autoSwitchedToFiles)
function onModeChanged(mode, userInitiated) {
if (!userInitiated || !SettingsData.rememberLastMode || (mode !== "all" && mode !== "apps"))
return;
SessionData.setLauncherLastMode(mode);
}
@@ -536,8 +536,12 @@ Item {
}
}
Keys.onPressed: event => root.spotlightContent?.activeContextMenu?.handleKey(event)
Keys.onEscapePressed: event => {
root.hide();
root.spotlightContent?.activeContextMenu?.handleKey(event);
if (!event.accepted)
root.hide();
event.accepted = true;
}
}
@@ -17,6 +17,7 @@ FocusScope {
property alias controller: controller
property alias resultsList: resultsList
property alias actionPanel: actionPanel
readonly property alias activeContextMenu: contextMenu
property bool editMode: false
property var editingApp: null
@@ -340,6 +340,31 @@ Item {
return count;
}
function handleKey(event) {
if (!openState)
return;
switch (event.key) {
case Qt.Key_Down:
selectNext();
event.accepted = true;
return;
case Qt.Key_Up:
selectPrevious();
event.accepted = true;
return;
case Qt.Key_Return:
case Qt.Key_Enter:
activateSelected();
event.accepted = true;
return;
case Qt.Key_Left:
case Qt.Key_Escape:
hide();
event.accepted = true;
return;
}
}
function selectNext() {
if (visibleItemCount > 0) {
keyboardNavigation = true;
@@ -12,6 +12,7 @@ FocusScope {
property var parentModal: null
property alias searchField: searchInput
property alias controller: searchController
readonly property alias activeContextMenu: contextMenu
readonly property bool _hasQuery: searchInput.text.length > 0
readonly property real _searchBarH: 56
@@ -239,8 +240,8 @@ FocusScope {
Connections {
target: searchController
function onModeChanged(mode) {
if (searchController.autoSwitchedToFiles)
function onModeChanged(mode, userInitiated) {
if (!userInitiated || !SettingsData.rememberLastMode)
return;
SessionData.setLauncherLastMode(mode);
}
@@ -1121,6 +1121,15 @@ Item {
onToggled: checked => SessionData.setSearchAppActions(checked)
}
SettingsToggleRow {
settingKey: "rememberLastMode"
tags: ["launcher", "remember", "last", "mode", "tab"]
text: I18n.tr("Remember Last Mode")
description: I18n.tr("Restore the last selected mode (tab) when the launcher is opened")
checked: SettingsData.rememberLastMode
onToggled: checked => SettingsData.set("rememberLastMode", checked)
}
SettingsToggleRow {
settingKey: "rememberLastQuery"
tags: ["launcher", "remember", "last", "search", "query"]
@@ -338,45 +338,61 @@ Scope {
border.width: 1
}
LauncherContent {
id: launcherContent
FocusScope {
anchors.fill: parent
anchors.margins: 0
focus: true
property var fakeParentModal: QtObject {
property bool spotlightOpen: spotlightContainer.visible
property bool isClosing: niriOverviewScope.isClosing
function hide() {
if (niriOverviewScope.searchActive) {
niriOverviewScope.hideSpotlight();
return;
Keys.onPressed: event => launcherContent.activeContextMenu?.handleKey(event)
Keys.onEscapePressed: event => {
launcherContent.activeContextMenu?.handleKey(event);
if (!event.accepted)
launcherContent.parentModal?.hide();
event.accepted = true;
}
LauncherContent {
id: launcherContent
anchors.fill: parent
anchors.margins: 0
property var fakeParentModal: QtObject {
property bool spotlightOpen: spotlightContainer.visible
property bool isClosing: niriOverviewScope.isClosing
property real alignedX: spotlightContainer.x
property real alignedY: spotlightContainer.y
function hide() {
if (niriOverviewScope.searchActive) {
niriOverviewScope.hideSpotlight();
return;
}
NiriService.toggleOverview();
}
NiriService.toggleOverview();
}
}
Connections {
target: launcherContent.searchField
function onTextChanged() {
if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive)
return;
niriOverviewScope.hideSpotlight();
Connections {
target: launcherContent.searchField
function onTextChanged() {
if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive)
return;
niriOverviewScope.hideSpotlight();
}
}
}
Component.onCompleted: {
parentModal = fakeParentModal;
}
Connections {
target: launcherContent.controller
function onItemExecuted() {
niriOverviewScope.releaseKeyboard = true;
Component.onCompleted: {
parentModal = fakeParentModal;
}
function onModeChanged(mode) {
if (launcherContent.controller.autoSwitchedToFiles)
return;
SessionData.setNiriOverviewLastMode(mode);
Connections {
target: launcherContent.controller
function onItemExecuted() {
niriOverviewScope.releaseKeyboard = true;
}
function onModeChanged(mode) {
if (launcherContent.controller.autoSwitchedToFiles)
return;
SessionData.setNiriOverviewLastMode(mode);
}
}
}
}