diff options
| author | Nippy <nippy@rp1.hu> | 2026-05-08 19:50:49 +0200 |
|---|---|---|
| committer | Nippy <nippy@rp1.hu> | 2026-05-08 19:50:49 +0200 |
| commit | 3462bcc46ecf74f576ea4397f16492c16bd75b10 (patch) | |
| tree | c5ab7aef4498647e057bda8d49c11e5f9dda74c9 /raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml | |
| parent | 56616f693b4f263cbf0d47da43b67424efa6022d (diff) | |
| download | RaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.tar.gz RaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.zip | |
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml')
| -rw-r--r-- | raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml | 1894 |
1 files changed, 1894 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml b/raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml new file mode 100644 index 0000000..67cb606 --- /dev/null +++ b/raveos-hyprland-theme/theme-data/dms/Modals/DankLauncherV2/Controller.qml @@ -0,0 +1,1894 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import qs.Common +import qs.Services +import "Scorer.js" as Scorer +import "ControllerUtils.js" as Utils +import "NavigationHelpers.js" as Nav +import "ItemTransformers.js" as Transform + +Item { + id: root + + property string searchQuery: "" + property string searchMode: "all" + property string previousSearchMode: "all" + property bool autoSwitchedToFiles: false + property bool isFileSearching: false + property var sections: [] + property var flatModel: [] + property int selectedFlatIndex: 0 + property var selectedItem: null + property bool isSearching: false + property string activePluginId: "" + property var collapsedSections: ({}) + property bool keyboardNavigationActive: false + property bool active: false + property var _modeSectionsCache: ({}) + property bool _queryDrivenSearch: false + property bool _diskCacheConsumed: false + property var sectionViewModes: ({}) + property var pluginViewPreferences: ({}) + property int gridColumns: SettingsData.appLauncherGridColumns + property int viewModeVersion: 0 + property string viewModeContext: "spotlight" + + signal itemExecuted + signal searchCompleted + signal modeChanged(string mode) + signal queryChanged(string query) + signal viewModeChanged(string sectionId, string mode) + signal searchQueryRequested(string query) + + onActiveChanged: { + if (!active) { + SessionData.addLauncherHistory(searchQuery); + + sections = []; + flatModel = []; + selectedItem = null; + _clearModeCache(); + } + } + + onSearchModeChanged: { + if (searchMode === "apps") { + _loadAppCategories(); + } else { + appCategory = ""; + appCategories = []; + } + } + + Connections { + target: SettingsData + function onSortAppsAlphabeticallyChanged() { + AppSearchService.invalidateLauncherCache(); + _clearModeCache(); + } + } + + Connections { + target: AppSearchService + function onCacheVersionChanged() { + if (!active) + return; + _clearModeCache(); + if (searchMode === "apps") { + _loadAppCategories(); + performSearch(); + } else if (!searchQuery && searchMode === "all") { + performSearch(); + } + } + } + + Connections { + target: PluginService + function onRequestLauncherUpdate(pluginId) { + if (!active) + return; + if (activePluginId === pluginId) { + if (activePluginCategories.length <= 1) + loadPluginCategories(pluginId); + performSearch(); + return; + } + if (searchQuery) + performSearch(); + } + } + + Process { + id: wtypeProcess + command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"] + running: false + } + + Process { + id: copyProcess + running: false + onExited: pasteTimer.start() + } + + Timer { + id: pasteTimer + interval: 200 + repeat: false + onTriggered: wtypeProcess.running = true + } + + function pasteSelected() { + if (!selectedItem) + return; + if (!SessionService.wtypeAvailable) { + ToastService.showError("wtype not available - install wtype for paste support"); + return; + } + + const pluginId = selectedItem.pluginId; + if (!pluginId) + return; + const pasteArgs = AppSearchService.getPluginPasteArgs(pluginId, selectedItem.data); + if (!pasteArgs) + return; + copyProcess.command = pasteArgs; + copyProcess.running = true; + itemExecuted(); + } + + readonly property var sectionDefinitions: [ + { + id: "favorites", + title: I18n.tr("Pinned"), + icon: "push_pin", + priority: 1, + defaultViewMode: "list" + }, + { + id: "apps", + title: I18n.tr("Applications"), + icon: "apps", + priority: 2, + defaultViewMode: "list" + }, + { + id: "browse_plugins", + title: I18n.tr("Browse"), + icon: "category", + priority: 2.5, + defaultViewMode: "grid" + }, + { + id: "files", + title: I18n.tr("Files"), + icon: "folder", + priority: 4, + defaultViewMode: "list" + }, + { + id: "fallback", + title: I18n.tr("Commands"), + icon: "terminal", + priority: 5, + defaultViewMode: "list" + } + ] + + property int historyIndex: -1 + property string typingBackup: "" + + function navigateHistory(direction) { + let history = SessionData.launcherQueryHistory; + if (history.length === 0) + return; + + if (historyIndex === -1) + typingBackup = searchQuery; + + let nextIndex = historyIndex + (direction === "up" ? 1 : -1); + if (nextIndex >= history.length) + nextIndex = history.length - 1; + if (nextIndex < -1) + nextIndex = -1; + + if (nextIndex === historyIndex) + return; + historyIndex = nextIndex; + + let targetText = (historyIndex === -1) ? typingBackup : history[historyIndex]; + + setSearchQuery(targetText); + searchQueryRequested(targetText); + } + + property string fileSearchType: "all" + property string fileSearchExt: "" + property string fileSearchFolder: "" + property string fileSearchSort: "score" + + property string pluginFilter: "" + property string activePluginName: "" + property var activePluginCategories: [] + property string activePluginCategory: "" + property string appCategory: "" + property var appCategories: [] + + function getSectionViewMode(sectionId) { + if (sectionId === "browse_plugins") + return "list"; + if (pluginViewPreferences[sectionId]?.enforced) + return pluginViewPreferences[sectionId].mode; + if (sectionViewModes[sectionId]) + return sectionViewModes[sectionId]; + + var savedModes = viewModeContext === "appDrawer" ? (SettingsData.appDrawerSectionViewModes || {}) : (SettingsData.spotlightSectionViewModes || {}); + if (savedModes[sectionId]) + return savedModes[sectionId]; + + for (var i = 0; i < sectionDefinitions.length; i++) { + if (sectionDefinitions[i].id === sectionId) + return sectionDefinitions[i].defaultViewMode || "list"; + } + + if (pluginViewPreferences[sectionId]?.mode) + return pluginViewPreferences[sectionId].mode; + + return "list"; + } + + function setSectionViewMode(sectionId, mode) { + if (sectionId === "browse_plugins") + return; + if (pluginViewPreferences[sectionId]?.enforced) + return; + sectionViewModes = Object.assign({}, sectionViewModes, { + [sectionId]: mode + }); + viewModeVersion++; + if (viewModeContext === "appDrawer") { + var savedModes = Object.assign({}, SettingsData.appDrawerSectionViewModes || {}, { + [sectionId]: mode + }); + SettingsData.appDrawerSectionViewModes = savedModes; + } else { + var savedModes = Object.assign({}, SettingsData.spotlightSectionViewModes || {}, { + [sectionId]: mode + }); + SettingsData.spotlightSectionViewModes = savedModes; + } + viewModeChanged(sectionId, mode); + } + + function canChangeSectionViewMode(sectionId) { + if (sectionId === "browse_plugins") + return false; + return !pluginViewPreferences[sectionId]?.enforced; + } + + function canCollapseSection(sectionId) { + return searchMode === "all"; + } + + function setPluginViewPreference(pluginId, mode, enforced) { + var prefs = Object.assign({}, pluginViewPreferences); + prefs[pluginId] = { + mode: mode, + enforced: enforced || false + }; + pluginViewPreferences = prefs; + } + + function applyActivePluginViewPreference(pluginId, isBuiltIn) { + var sectionId = "plugin_" + pluginId; + var pref = null; + if (isBuiltIn) { + var builtIn = AppSearchService.builtInPlugins[pluginId]; + if (builtIn && builtIn.viewMode) { + pref = { + mode: builtIn.viewMode, + enforced: builtIn.viewModeEnforced === true + }; + } + } else { + pref = PluginService.getPluginViewPreference(pluginId); + } + + if (pref && pref.mode) { + setPluginViewPreference(sectionId, pref.mode, pref.enforced); + } else { + var prefs = Object.assign({}, pluginViewPreferences); + delete prefs[sectionId]; + pluginViewPreferences = prefs; + } + } + + function clearActivePluginViewPreference() { + var prefs = {}; + for (var key in pluginViewPreferences) { + if (!key.startsWith("plugin_")) { + prefs[key] = pluginViewPreferences[key]; + } + } + pluginViewPreferences = prefs; + } + + property int _searchVersion: 0 + property bool _pluginPhasePending: false + property bool _pluginPhaseForceFirst: false + property var _phase1Items: [] + + Timer { + id: searchDebounce + interval: 60 + onTriggered: root.performSearch() + } + + Timer { + id: pluginPhaseTimer + interval: 1 + onTriggered: root._performPluginPhase() + } + + Timer { + id: fileSearchDebounce + interval: 200 + onTriggered: root.performFileSearch() + } + + function getOrTransformApp(app) { + return AppSearchService.getOrTransformApp(app, transformApp); + } + + function setSearchQuery(query) { + _searchVersion++; + _queryDrivenSearch = true; + _pluginPhasePending = false; + _phase1Items = []; + pluginPhaseTimer.stop(); + searchQuery = query; + searchDebounce.restart(); + + var filesInAll = searchMode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll); + if (searchMode !== "plugins" && (searchMode === "files" || query.startsWith("/") || filesInAll) && query.length > 0) { + fileSearchDebounce.restart(); + } + } + + function setMode(mode, isAutoSwitch) { + if (searchMode === mode) + return; + if (isAutoSwitch) { + previousSearchMode = searchMode; + autoSwitchedToFiles = true; + } else { + autoSwitchedToFiles = false; + } + searchMode = mode; + modeChanged(mode); + performSearch(); + var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0; + if (mode === "files" || filesInAll) { + fileSearchDebounce.restart(); + } + } + + function restorePreviousMode() { + if (!autoSwitchedToFiles) + return; + autoSwitchedToFiles = false; + searchMode = previousSearchMode; + modeChanged(previousSearchMode); + performSearch(); + } + + function cycleMode(reverse = false) { + var modes = ["all", "apps", "files", "plugins"]; + var currentIndex = modes.indexOf(searchMode); + if (!reverse) + var nextIndex = (currentIndex + 1) % modes.length; + else + var nextIndex = (currentIndex - 1 + modes.length) % modes.length; + setMode(modes[nextIndex]); + } + + function reset() { + searchQuery = ""; + searchMode = "all"; + previousSearchMode = "all"; + autoSwitchedToFiles = false; + isFileSearching = false; + fileSearchType = "all"; + fileSearchExt = ""; + fileSearchFolder = ""; + fileSearchSort = "score"; + sections = []; + flatModel = []; + selectedFlatIndex = 0; + selectedItem = null; + isSearching = false; + activePluginId = ""; + activePluginName = ""; + activePluginCategories = []; + activePluginCategory = ""; + appCategory = ""; + appCategories = []; + pluginFilter = ""; + collapsedSections = {}; + _clearModeCache(); + _queryDrivenSearch = false; + _pluginPhasePending = false; + _pluginPhaseForceFirst = false; + _phase1Items = []; + pluginPhaseTimer.stop(); + } + + function loadPluginCategories(pluginId) { + if (!pluginId) { + if (activePluginCategories.length > 0) { + activePluginCategories = []; + activePluginCategory = ""; + } + return; + } + + const categories = AppSearchService.getPluginLauncherCategories(pluginId); + if (categories.length === activePluginCategories.length) { + let same = true; + for (let i = 0; i < categories.length; i++) { + if (categories[i].id !== activePluginCategories[i]?.id) { + same = false; + break; + } + } + if (same) + return; + } + activePluginCategories = categories; + activePluginCategory = ""; + AppSearchService.setPluginLauncherCategory(pluginId, ""); + } + + function setActivePluginCategory(categoryId) { + if (activePluginCategory === categoryId) + return; + activePluginCategory = categoryId; + AppSearchService.setPluginLauncherCategory(activePluginId, categoryId); + performSearch(); + } + + function setAppCategory(category) { + if (appCategory === category) + return; + appCategory = category; + _queryDrivenSearch = true; + _clearModeCache(); + performSearch(); + } + + function _loadAppCategories() { + appCategories = AppSearchService.getAllCategories(); + } + + function setFileSearchType(type) { + if (fileSearchType === type) + return; + fileSearchType = type; + performFileSearch(); + } + + function setFileSearchExt(ext) { + if (fileSearchExt === ext) + return; + fileSearchExt = ext; + performFileSearch(); + } + + function setFileSearchFolder(folder) { + if (fileSearchFolder === folder) + return; + fileSearchFolder = folder; + performFileSearch(); + } + + function setFileSearchSort(sort) { + if (fileSearchSort === sort) + return; + fileSearchSort = sort; + performFileSearch(); + } + + function clearPluginFilter() { + if (pluginFilter) { + pluginFilter = ""; + performSearch(); + return true; + } + return false; + } + + function preserveSelectionAfterUpdate(forceFirst) { + if (forceFirst) + return function () { + return getFirstItemIndex(); + }; + var previousSelectedId = selectedItem?.id || ""; + return function (newFlatModel) { + if (!previousSelectedId) + return getFirstItemIndex(); + for (var i = 0; i < newFlatModel.length; i++) { + if (!newFlatModel[i].isHeader && newFlatModel[i].item?.id === previousSelectedId) + return i; + } + return getFirstItemIndex(); + }; + } + + function performSearch() { + queryChanged(searchQuery); + + var currentVersion = _searchVersion; + isSearching = true; + var shouldResetSelection = _queryDrivenSearch; + _queryDrivenSearch = false; + var restoreSelection = preserveSelectionAfterUpdate(shouldResetSelection); + + var cachedSections = AppSearchService.getCachedDefaultSections(); + if (!cachedSections && !_diskCacheConsumed && !searchQuery && searchMode === "all" && !pluginFilter) { + _diskCacheConsumed = true; + var diskSections = _loadDiskCache(); + if (diskSections) { + activePluginId = ""; + activePluginName = ""; + activePluginCategories = []; + activePluginCategory = ""; + clearActivePluginViewPreference(); + for (var i = 0; i < diskSections.length; i++) { + if (collapsedSections[diskSections[i].id] !== undefined) + diskSections[i].collapsed = collapsedSections[diskSections[i].id]; + } + _applyHighlights(diskSections, ""); + flatModel = Scorer.flattenSections(diskSections); + sections = diskSections; + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + isSearching = false; + searchCompleted(); + return; + } + } + + if (cachedSections && !searchQuery && searchMode === "all" && !pluginFilter) { + activePluginId = ""; + activePluginName = ""; + activePluginCategories = []; + activePluginCategory = ""; + clearActivePluginViewPreference(); + var modeCache = _getCachedModeData("all"); + if (modeCache) { + _applyHighlights(modeCache.sections, ""); + sections = modeCache.sections; + flatModel = modeCache.flatModel; + } else { + var newSections = cachedSections.map(function (s) { + var copy = Object.assign({}, s, { + items: s.items ? s.items.slice() : [] + }); + if (collapsedSections[s.id] !== undefined) + copy.collapsed = collapsedSections[s.id]; + return copy; + }); + _applyHighlights(newSections, ""); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + _setCachedModeData("all", sections, flatModel); + } + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + isSearching = false; + searchCompleted(); + return; + } + + var allItems = []; + + var triggerMatch = detectTrigger(searchQuery); + if (triggerMatch.pluginId) { + var pluginChanged = activePluginId !== triggerMatch.pluginId; + activePluginId = triggerMatch.pluginId; + activePluginName = getPluginName(triggerMatch.pluginId, triggerMatch.isBuiltIn); + applyActivePluginViewPreference(triggerMatch.pluginId, triggerMatch.isBuiltIn); + + if (pluginChanged && !triggerMatch.isBuiltIn) + loadPluginCategories(triggerMatch.pluginId); + + var pluginItems = getPluginItems(triggerMatch.pluginId, triggerMatch.query); + for (var k = 0; k < pluginItems.length; k++) + allItems.push(pluginItems[k]); + + if (triggerMatch.isBuiltIn) { + var builtInItems = AppSearchService.getBuiltInLauncherItems(triggerMatch.pluginId, triggerMatch.query); + for (var j = 0; j < builtInItems.length; j++) { + allItems.push(transformBuiltInLauncherItem(builtInItems[j], triggerMatch.pluginId)); + } + } + + var dynamicDefs = buildDynamicSectionDefs(allItems); + var scoredItems = Scorer.scoreItems(allItems, triggerMatch.query, getFrecencyForItem); + var sortAlpha = !triggerMatch.query && SettingsData.sortAppsAlphabetically; + var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, 500); + + for (var sid in collapsedSections) { + for (var i = 0; i < newSections.length; i++) { + if (newSections[i].id === sid) { + newSections[i].collapsed = collapsedSections[sid]; + } + } + } + + _applyHighlights(newSections, triggerMatch.query); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + + isSearching = false; + searchCompleted(); + return; + } + + activePluginId = ""; + activePluginName = ""; + activePluginCategories = []; + activePluginCategory = ""; + clearActivePluginViewPreference(); + + if (searchMode === "files") { + var fileQuery = searchQuery.startsWith("/") ? searchQuery.substring(1).trim() : searchQuery.trim(); + isFileSearching = fileQuery.length >= 2 && DSearchService.dsearchAvailable; + sections = []; + flatModel = []; + selectedFlatIndex = 0; + selectedItem = null; + isSearching = false; + searchCompleted(); + return; + } + + if (searchMode === "apps") { + var isCategoryFiltered = appCategory && appCategory !== I18n.tr("All"); + var cachedSections = AppSearchService.getCachedDefaultSections(); + if (cachedSections && !searchQuery && !isCategoryFiltered) { + var modeCache = _getCachedModeData("apps"); + if (modeCache) { + _applyHighlights(modeCache.sections, ""); + sections = modeCache.sections; + flatModel = modeCache.flatModel; + } else { + var appSectionIds = ["favorites", "apps"]; + var newSections = cachedSections.filter(function (s) { + return appSectionIds.indexOf(s.id) !== -1; + }).map(function (s) { + var copy = Object.assign({}, s, { + items: s.items ? s.items.slice() : [] + }); + if (collapsedSections[s.id] !== undefined) + copy.collapsed = collapsedSections[s.id]; + return copy; + }); + _applyHighlights(newSections, ""); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + _setCachedModeData("apps", sections, flatModel); + } + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + isSearching = false; + searchCompleted(); + return; + } + + if (isCategoryFiltered) { + var rawApps = AppSearchService.getAppsInCategory(appCategory); + for (var i = 0; i < rawApps.length; i++) { + allItems.push(getOrTransformApp(rawApps[i])); + } + // Also include core apps (DMS Settings etc.) that match this category + var allCoreApps = AppSearchService.getCoreApps(""); + for (var i = 0; i < allCoreApps.length; i++) { + var coreAppCats = AppSearchService.getCategoriesForApp(allCoreApps[i]); + if (coreAppCats.indexOf(appCategory) !== -1) + allItems.push(transformCoreApp(allCoreApps[i])); + } + } else { + var apps = searchApps(searchQuery); + for (var i = 0; i < apps.length; i++) { + allItems.push(apps[i]); + } + } + + var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); + var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; + var newSections = Scorer.groupBySection(scoredItems, sectionDefinitions, sortAlpha, searchQuery ? 50 : 500); + + for (var sid in collapsedSections) { + for (var i = 0; i < newSections.length; i++) { + if (newSections[i].id === sid) { + newSections[i].collapsed = collapsedSections[sid]; + } + } + } + + _applyHighlights(newSections, searchQuery); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + + isSearching = false; + searchCompleted(); + return; + } + + if (searchMode === "plugins") { + if (!searchQuery && !pluginFilter) { + var browseItems = getPluginBrowseItems(); + for (var k = 0; k < browseItems.length; k++) + allItems.push(browseItems[k]); + } else if (pluginFilter) { + var isBuiltInFilter = !!AppSearchService.builtInPlugins[pluginFilter]; + applyActivePluginViewPreference(pluginFilter, isBuiltInFilter); + + var filterItems = getPluginItems(pluginFilter, searchQuery); + for (var k = 0; k < filterItems.length; k++) + allItems.push(filterItems[k]); + + var builtInItems = AppSearchService.getBuiltInLauncherItems(pluginFilter, searchQuery); + for (var j = 0; j < builtInItems.length; j++) { + allItems.push(transformBuiltInLauncherItem(builtInItems[j], pluginFilter)); + } + } else { + var emptyTriggerPlugins = getEmptyTriggerPlugins(); + for (var i = 0; i < emptyTriggerPlugins.length; i++) { + var pluginId = emptyTriggerPlugins[i]; + var pItems = getPluginItems(pluginId, searchQuery); + for (var k = 0; k < pItems.length; k++) + allItems.push(pItems[k]); + } + + var builtInLauncherPlugins = getBuiltInEmptyTriggerLaunchers(); + for (var i = 0; i < builtInLauncherPlugins.length; i++) { + var pluginId = builtInLauncherPlugins[i]; + var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery); + for (var j = 0; j < blItems.length; j++) { + allItems.push(transformBuiltInLauncherItem(blItems[j], pluginId)); + } + } + } + + var dynamicDefs = buildDynamicSectionDefs(allItems); + var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); + var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; + var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, 500); + + for (var sid in collapsedSections) { + for (var i = 0; i < newSections.length; i++) { + if (newSections[i].id === sid) { + newSections[i].collapsed = collapsedSections[sid]; + } + } + } + + _applyHighlights(newSections, searchQuery); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + + isSearching = false; + searchCompleted(); + return; + } + + var apps = searchApps(searchQuery); + for (var i = 0; i < apps.length; i++) { + allItems.push(apps[i]); + } + + if (searchMode === "all") { + if (searchQuery && searchQuery.length >= 2) { + _pluginPhasePending = true; + _phase1Items = allItems.slice(); + _pluginPhaseForceFirst = shouldResetSelection; + pluginPhaseTimer.restart(); + isSearching = true; + searchCompleted(); + return; + } else if (!searchQuery) { + var emptyTriggerOrdered = getEmptyTriggerPluginsOrdered(); + for (var i = 0; i < emptyTriggerOrdered.length; i++) { + var plugin = emptyTriggerOrdered[i]; + if (plugin.isBuiltIn) { + var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery); + for (var j = 0; j < blItems.length; j++) + allItems.push(transformBuiltInLauncherItem(blItems[j], plugin.id)); + } else { + var pItems = getPluginItems(plugin.id, searchQuery); + for (var j = 0; j < pItems.length; j++) + allItems.push(pItems[j]); + } + } + + var browseItems = getPluginBrowseItems(); + for (var i = 0; i < browseItems.length; i++) + allItems.push(browseItems[i]); + } + } + + var dynamicDefs = buildDynamicSectionDefs(allItems); + + if (currentVersion !== _searchVersion) { + isSearching = false; + return; + } + + var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); + var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically; + var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, searchQuery ? 50 : 500); + + if (currentVersion !== _searchVersion) { + isSearching = false; + return; + } + + for (var i = 0; i < newSections.length; i++) { + var sid = newSections[i].id; + if (collapsedSections[sid] !== undefined) { + newSections[i].collapsed = collapsedSections[sid]; + } + } + + _applyHighlights(newSections, searchQuery); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + + if (!AppSearchService.isCacheValid() && !searchQuery && searchMode === "all" && !pluginFilter) { + AppSearchService.setCachedDefaultSections(sections, flatModel); + _saveDiskCache(sections); + } + + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + + isSearching = _pluginPhasePending; + searchCompleted(); + } + + function _performPluginPhase() { + _pluginPhasePending = false; + if (!searchQuery || searchQuery.length < 2 || searchMode !== "all") + return; + + var currentVersion = _searchVersion; + var restoreSelection = preserveSelectionAfterUpdate(_pluginPhaseForceFirst); + var allItems = _phase1Items; + _phase1Items = []; + + var allPluginsOrdered = getAllVisiblePluginsOrdered(); + var maxPerPlugin = 10; + for (var i = 0; i < allPluginsOrdered.length; i++) { + if (currentVersion !== _searchVersion) + return; + var plugin = allPluginsOrdered[i]; + if (plugin.isBuiltIn) { + var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery); + var blLimit = Math.min(blItems.length, maxPerPlugin); + for (var j = 0; j < blLimit; j++) { + var item = transformBuiltInLauncherItem(blItems[j], plugin.id); + item._preScored = 900 - j; + allItems.push(item); + } + } else { + var pItems = getPluginItems(plugin.id, searchQuery, maxPerPlugin); + for (var j = 0; j < pItems.length; j++) { + pItems[j]._preScored = 900 - j; + allItems.push(pItems[j]); + } + } + } + + if (currentVersion !== _searchVersion) + return; + + var dynamicDefs = buildDynamicSectionDefs(allItems); + var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); + var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, false, 50); + + if (currentVersion !== _searchVersion) + return; + + for (var i = 0; i < newSections.length; i++) { + var sid = newSections[i].id; + if (collapsedSections[sid] !== undefined) + newSections[i].collapsed = collapsedSections[sid]; + } + + _applyHighlights(newSections, searchQuery); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + selectedFlatIndex = restoreSelection(flatModel); + updateSelectedItem(); + isSearching = false; + searchCompleted(); + } + + function performFileSearch() { + if (!DSearchService.dsearchAvailable) + return; + var fileQuery = ""; + var effectiveType = fileSearchType || "all"; + var includeFiles = SettingsData.dankLauncherV2IncludeFilesInAll; + var includeFolders = SettingsData.dankLauncherV2IncludeFoldersInAll; + + if (searchQuery.startsWith("/")) { + fileQuery = searchQuery.substring(1).trim(); + } else if (searchMode === "files") { + fileQuery = searchQuery.trim(); + } else if (searchMode === "all" && (includeFiles || includeFolders)) { + fileQuery = searchQuery.trim(); + if (includeFiles && !includeFolders) + effectiveType = "file"; + else if (!includeFiles && includeFolders) + effectiveType = "dir"; + else + effectiveType = "all"; + } else { + return; + } + + if (fileQuery.length < 2) { + isFileSearching = false; + return; + } + + isFileSearching = true; + + var splitBothTypes = searchMode === "all" && includeFiles && includeFolders && DSearchService.supportsTypeFilter; + var queryTypes = splitBothTypes ? ["file", "dir"] : [effectiveType]; + var pending = queryTypes.length; + var aggregatedItems = []; + + for (var t = 0; t < queryTypes.length; t++) { + var queryType = queryTypes[t]; + var params = { + limit: 20, + fuzzy: true, + sort: fileSearchSort || "score", + desc: true + }; + + if (DSearchService.supportsTypeFilter) { + params.type = (queryType && queryType !== "all") ? queryType : "all"; + } + if (fileSearchExt) { + params.ext = fileSearchExt; + } + if (fileSearchFolder) { + params.folder = fileSearchFolder; + } + + DSearchService.search(fileQuery, params, function (response) { + pending--; + if (!response.error) { + var hits = response.result?.hits || []; + for (var i = 0; i < hits.length; i++) { + var hit = hits[i]; + var docTypes = hit.locations?.doc_type; + var isDir = docTypes ? !!docTypes["dir"] : false; + aggregatedItems.push(transformFileResult({ + path: hit.id || "", + score: hit.score || 0, + is_dir: isDir + })); + } + } + if (pending > 0) + return; + + isFileSearching = false; + _applyFileSearchResults(aggregatedItems, effectiveType); + }); + } + } + + function _applyFileSearchResults(fileItems, effectiveType) { + var fileSections = []; + var showType = effectiveType; + var order = SettingsData.launcherPluginOrder || []; + var filesOrderIdx = order.indexOf("__files"); + var foldersOrderIdx = order.indexOf("__folders"); + var filesPriority = filesOrderIdx !== -1 ? 2.6 + filesOrderIdx * 0.01 : 4; + var foldersPriority = foldersOrderIdx !== -1 ? 2.6 + foldersOrderIdx * 0.01 : 4.1; + + if (showType === "all" && DSearchService.supportsTypeFilter) { + var onlyFiles = []; + var onlyDirs = []; + for (var j = 0; j < fileItems.length; j++) { + if (fileItems[j].data?.is_dir) + onlyDirs.push(fileItems[j]); + else + onlyFiles.push(fileItems[j]); + } + if (onlyFiles.length > 0) { + fileSections.push({ + id: "files", + title: I18n.tr("Files"), + icon: "insert_drive_file", + priority: filesPriority, + items: onlyFiles, + collapsed: collapsedSections["files"] || false, + flatStartIndex: 0 + }); + } + if (onlyDirs.length > 0) { + fileSections.push({ + id: "folders", + title: I18n.tr("Folders"), + icon: "folder", + priority: foldersPriority, + items: onlyDirs, + collapsed: collapsedSections["folders"] || false, + flatStartIndex: 0 + }); + } + } else { + var filesIcon = showType === "dir" ? "folder" : showType === "file" ? "insert_drive_file" : "folder"; + var filesTitle = showType === "dir" ? I18n.tr("Folders") : I18n.tr("Files"); + var singlePriority = showType === "dir" ? foldersPriority : filesPriority; + if (fileItems.length > 0) { + fileSections.push({ + id: "files", + title: filesTitle, + icon: filesIcon, + priority: singlePriority, + items: fileItems, + collapsed: collapsedSections["files"] || false, + flatStartIndex: 0 + }); + } + } + + var newSections; + if (searchMode === "files") { + newSections = fileSections; + } else { + var existingNonFile = sections.filter(function (s) { + return s.id !== "files" && s.id !== "folders"; + }); + newSections = existingNonFile.concat(fileSections); + } + newSections.sort(function (a, b) { + return a.priority - b.priority; + }); + _applyHighlights(newSections, searchQuery); + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + selectedFlatIndex = getFirstItemIndex(); + updateSelectedItem(); + } + + function searchApps(query) { + var apps = AppSearchService.searchApplications(query); + var items = []; + + for (var i = 0; i < apps.length; i++) { + items.push(getOrTransformApp(apps[i])); + } + + var coreApps = AppSearchService.getCoreApps(query); + for (var i = 0; i < coreApps.length; i++) { + items.push(transformCoreApp(coreApps[i])); + } + + return items; + } + + function transformApp(app) { + var appId = app.id || app.execString || app.exec || ""; + var override = SessionData.getAppOverride(appId); + return Transform.transformApp(app, override, [], I18n.tr("Launch")); + } + + function transformCoreApp(app) { + return Transform.transformCoreApp(app, I18n.tr("Open")); + } + + function transformBuiltInLauncherItem(item, pluginId) { + return Transform.transformBuiltInLauncherItem(item, pluginId, I18n.tr("Open")); + } + + function transformFileResult(file) { + return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"), I18n.tr("Open in terminal")); + } + + function detectTrigger(query) { + if (!query || query.length === 0) + return { + pluginId: null, + query: query + }; + + var pluginTriggers = PluginService.getAllPluginTriggers(); + for (var trigger in pluginTriggers) { + if (trigger && query.startsWith(trigger)) { + return { + pluginId: pluginTriggers[trigger], + query: query.substring(trigger.length).trim() + }; + } + } + + var builtInTriggers = AppSearchService.getBuiltInLauncherTriggers(); + for (var trigger in builtInTriggers) { + if (trigger && query.startsWith(trigger)) { + return { + pluginId: builtInTriggers[trigger], + query: query.substring(trigger.length).trim(), + isBuiltIn: true + }; + } + } + + return { + pluginId: null, + query: query + }; + } + + function getEmptyTriggerPlugins() { + var plugins = PluginService.getPluginsWithEmptyTrigger(); + var visible = plugins.filter(function (pluginId) { + return SettingsData.getPluginAllowWithoutTrigger(pluginId); + }); + return sortPluginIdsByOrder(visible); + } + + function getAllLauncherPluginIds() { + var launchers = PluginService.getLauncherPlugins(); + return Object.keys(launchers); + } + + function getVisibleLauncherPluginIds() { + var launchers = PluginService.getLauncherPlugins(); + var visible = Object.keys(launchers).filter(function (pluginId) { + return SettingsData.getPluginAllowWithoutTrigger(pluginId); + }); + return sortPluginIdsByOrder(visible); + } + + function getAllBuiltInLauncherIds() { + var launchers = AppSearchService.getBuiltInLauncherPlugins(); + return Object.keys(launchers); + } + + function getVisibleBuiltInLauncherIds() { + var launchers = AppSearchService.getBuiltInLauncherPlugins(); + var visible = Object.keys(launchers).filter(function (pluginId) { + return SettingsData.getPluginAllowWithoutTrigger(pluginId); + }); + return sortPluginIdsByOrder(visible); + } + + function sortPluginIdsByOrder(pluginIds) { + return Utils.sortPluginIdsByOrder(pluginIds, SettingsData.launcherPluginOrder || []); + } + + function getAllVisiblePluginsOrdered() { + var thirdPartyLaunchers = PluginService.getLauncherPlugins() || {}; + var builtInLaunchers = AppSearchService.getBuiltInLauncherPlugins() || {}; + var all = []; + for (var id in thirdPartyLaunchers) { + if (SettingsData.getPluginAllowWithoutTrigger(id)) + all.push({ + id: id, + isBuiltIn: false + }); + } + for (var id in builtInLaunchers) { + if (SettingsData.getPluginAllowWithoutTrigger(id)) + all.push({ + id: id, + isBuiltIn: true + }); + } + return Utils.sortPluginsOrdered(all, SettingsData.launcherPluginOrder || []); + } + + function getEmptyTriggerPluginsOrdered() { + var thirdParty = PluginService.getPluginsWithEmptyTrigger() || []; + var builtIn = AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger() || []; + var all = []; + for (var i = 0; i < thirdParty.length; i++) { + var id = thirdParty[i]; + if (SettingsData.getPluginAllowWithoutTrigger(id)) + all.push({ + id: id, + isBuiltIn: false + }); + } + for (var i = 0; i < builtIn.length; i++) { + var id = builtIn[i]; + if (SettingsData.getPluginAllowWithoutTrigger(id)) + all.push({ + id: id, + isBuiltIn: true + }); + } + return Utils.sortPluginsOrdered(all, SettingsData.launcherPluginOrder || []); + } + + function getPluginBrowseItems() { + var items = []; + var browseLabel = I18n.tr("Browse"); + var triggerLabel = I18n.tr("Trigger: %1"); + var noTriggerLabel = I18n.tr("No trigger"); + + var launchers = PluginService.getLauncherPlugins(); + for (var pluginId in launchers) { + var trigger = PluginService.getPluginTrigger(pluginId); + var isAllowed = SettingsData.getPluginAllowWithoutTrigger(pluginId); + items.push(Transform.createPluginBrowseItem(pluginId, launchers[pluginId], trigger, false, isAllowed, browseLabel, triggerLabel, noTriggerLabel)); + } + + var builtInLaunchers = AppSearchService.getBuiltInLauncherPlugins(); + for (var pluginId in builtInLaunchers) { + var trigger = AppSearchService.getBuiltInPluginTrigger(pluginId); + var isAllowed = SettingsData.getPluginAllowWithoutTrigger(pluginId); + items.push(Transform.createPluginBrowseItem(pluginId, builtInLaunchers[pluginId], trigger, true, isAllowed, browseLabel, triggerLabel, noTriggerLabel)); + } + + return items; + } + + function getBuiltInEmptyTriggerLaunchers() { + var plugins = AppSearchService.getBuiltInLauncherPluginsWithEmptyTrigger(); + var visible = plugins.filter(function (pluginId) { + return SettingsData.getPluginAllowWithoutTrigger(pluginId); + }); + return sortPluginIdsByOrder(visible); + } + + function getPluginItems(pluginId, query, limit) { + var items = AppSearchService.getPluginItemsForPlugin(pluginId, query); + var count = limit > 0 && limit < items.length ? limit : items.length; + var transformed = []; + + for (var i = 0; i < count; i++) { + transformed.push(transformPluginItem(items[i], pluginId)); + } + + return transformed; + } + + function getPluginName(pluginId, isBuiltIn) { + if (isBuiltIn) { + var plugin = AppSearchService.builtInPlugins[pluginId]; + return plugin ? plugin.name : pluginId; + } + var launchers = PluginService.getLauncherPlugins(); + if (launchers[pluginId]) { + return launchers[pluginId].name || pluginId; + } + return pluginId; + } + + function getPluginMetadata(pluginId) { + var builtIn = AppSearchService.builtInPlugins[pluginId]; + if (builtIn) { + return { + name: builtIn.name || pluginId, + icon: builtIn.cornerIcon || "extension" + }; + } + var launchers = PluginService.getLauncherPlugins(); + if (launchers[pluginId]) { + var rawIcon = launchers[pluginId].icon || "extension"; + return { + name: launchers[pluginId].name || pluginId, + icon: Utils.stripIconPrefix(rawIcon) + }; + } + return { + name: pluginId, + icon: "extension" + }; + } + + function buildDynamicSectionDefs(items) { + var baseDefs = sectionDefinitions.slice(); + var pluginSections = {}; + var order = SettingsData.launcherPluginOrder || []; + var orderMap = {}; + for (var k = 0; k < order.length; k++) + orderMap[order[k]] = k; + var unorderedPriority = 2.6 + order.length * 0.01; + + for (var i = 0; i < items.length; i++) { + var section = items[i].section; + if (!section || !section.startsWith("plugin_")) + continue; + if (pluginSections[section]) + continue; + var pluginId = section.substring(7); + var meta = getPluginMetadata(pluginId); + var viewPref = getPluginViewPref(pluginId); + var orderIdx = orderMap[pluginId]; + var priority; + if (orderIdx !== undefined) { + priority = 2.6 + orderIdx * 0.01; + } else { + priority = unorderedPriority; + unorderedPriority += 0.01; + } + + pluginSections[section] = { + id: section, + title: meta.name, + icon: meta.icon, + priority: priority, + defaultViewMode: viewPref.mode || "list" + }; + + if (viewPref.mode) + setPluginViewPreference(section, viewPref.mode, viewPref.enforced); + } + + for (var sectionId in pluginSections) { + baseDefs.push(pluginSections[sectionId]); + } + + baseDefs.sort(function (a, b) { + return a.priority - b.priority; + }); + return baseDefs; + } + + function getPluginViewPref(pluginId) { + var builtIn = AppSearchService.builtInPlugins[pluginId]; + if (builtIn && builtIn.viewMode) { + return { + mode: builtIn.viewMode, + enforced: builtIn.viewModeEnforced === true + }; + } + + var pref = PluginService.getPluginViewPreference(pluginId); + if (pref && pref.mode) { + return pref; + } + + return { + mode: "list", + enforced: false + }; + } + + function transformPluginItem(item, pluginId) { + return Transform.transformPluginItem(item, pluginId, I18n.tr("Select")); + } + + function getFrecencyForItem(item) { + if (item.type !== "app") + return null; + + var appId = item.id; + var usageRanking = AppUsageHistoryData.appUsageRanking || {}; + + var idVariants = [appId, appId.replace(".desktop", "")]; + var usageData = null; + + for (var i = 0; i < idVariants.length; i++) { + if (usageRanking[idVariants[i]]) { + usageData = usageRanking[idVariants[i]]; + break; + } + } + + return { + usageCount: usageData?.usageCount || 0 + }; + } + + function getFirstItemIndex() { + return Nav.getFirstItemIndex(flatModel); + } + + function _getCachedModeData(mode) { + return _modeSectionsCache[mode] || null; + } + + function _setCachedModeData(mode, sectionsData, flatModelData) { + var cache = Object.assign({}, _modeSectionsCache); + cache[mode] = { + sections: sectionsData, + flatModel: flatModelData + }; + _modeSectionsCache = cache; + } + + function _clearModeCache() { + _modeSectionsCache = {}; + } + + function _saveDiskCache(sectionsData) { + var serializable = []; + for (var i = 0; i < sectionsData.length; i++) { + var s = sectionsData[i]; + var items = []; + var srcItems = s.items || []; + for (var j = 0; j < srcItems.length; j++) { + var it = srcItems[j]; + items.push({ + id: it.id, + type: it.type, + name: it.name || "", + subtitle: it.subtitle || "", + icon: it.icon || "", + iconType: it.iconType || "image", + iconFull: it.iconFull || "", + section: it.section || "", + isCore: it.isCore || false, + isBuiltInLauncher: it.isBuiltInLauncher || false, + pluginId: it.pluginId || "" + }); + } + serializable.push({ + id: s.id, + title: s.title || "", + icon: s.icon || "", + priority: s.priority || 0, + items: items + }); + } + CacheData.saveLauncherCache(serializable); + } + + function _actionsFromDesktopEntry(appId) { + if (!appId) + return []; + var entry = DesktopEntries.heuristicLookup(appId); + if (!entry || !entry.actions || entry.actions.length === 0) + return []; + var result = []; + for (var i = 0; i < entry.actions.length; i++) { + result.push({ + name: entry.actions[i].name, + icon: "play_arrow", + actionData: entry.actions[i] + }); + } + return result; + } + + function _loadDiskCache() { + var cached = CacheData.loadLauncherCache(); + if (!cached || !Array.isArray(cached) || cached.length === 0) + return null; + + var sectionsData = []; + for (var i = 0; i < cached.length; i++) { + var s = cached[i]; + var items = []; + var srcItems = s.items || []; + for (var j = 0; j < srcItems.length; j++) { + var it = srcItems[j]; + items.push({ + id: it.id || "", + type: it.type || "app", + name: it.name || "", + subtitle: it.subtitle || "", + icon: it.icon || "", + iconType: it.iconType || "image", + iconFull: it.iconFull || "", + section: it.section || "", + isCore: it.isCore || false, + isBuiltInLauncher: it.isBuiltInLauncher || false, + pluginId: it.pluginId || "", + data: { + id: it.id + }, + actions: _actionsFromDesktopEntry(it.id), + primaryAction: it.type === "app" && !it.isCore ? { + name: I18n.tr("Launch"), + icon: "open_in_new", + action: "launch" + } : null, + _diskCached: true, + _hName: "", + _hSub: "", + _hRich: false, + _preScored: undefined + }); + } + sectionsData.push({ + id: s.id || "", + title: s.title || "", + icon: s.icon || "", + priority: s.priority || 0, + items: items, + collapsed: false, + flatStartIndex: 0 + }); + } + return sectionsData; + } + + function updateSelectedItem() { + if (selectedFlatIndex >= 0 && selectedFlatIndex < flatModel.length) { + var entry = flatModel[selectedFlatIndex]; + selectedItem = entry.isHeader ? null : entry.item; + } else { + selectedItem = null; + } + } + + function _applyHighlights(sectionsData, query) { + if (!query || query.length === 0) { + for (var i = 0; i < sectionsData.length; i++) { + var items = sectionsData[i].items; + for (var j = 0; j < items.length; j++) { + var item = items[j]; + item._hName = item.name || ""; + item._hSub = item.subtitle || ""; + item._hRich = false; + } + } + return; + } + + var highlightColor = Theme.primary; + var nameColor = Theme.surfaceText; + var subColor = Theme.surfaceVariantText; + var lowerQuery = query.toLowerCase(); + + for (var i = 0; i < sectionsData.length; i++) { + var items = sectionsData[i].items; + for (var j = 0; j < items.length; j++) { + var item = items[j]; + item._hName = _highlightField(item.name || "", lowerQuery, query.length, nameColor, highlightColor); + item._hSub = _highlightField(item.subtitle || "", lowerQuery, query.length, subColor, highlightColor); + item._hRich = true; + } + } + } + + function _highlightField(text, lowerQuery, queryLen, baseColor, highlightColor) { + if (!text) + return ""; + var idx = text.toLowerCase().indexOf(lowerQuery); + if (idx === -1) + return text; + var before = text.substring(0, idx); + var match = text.substring(idx, idx + queryLen); + var after = text.substring(idx + queryLen); + return '<span style="color:' + baseColor + '">' + before + '</span><span style="color:' + highlightColor + '; font-weight:600">' + match + '</span><span style="color:' + baseColor + '">' + after + '</span>'; + } + + function getCurrentSectionViewMode() { + if (selectedFlatIndex < 0 || selectedFlatIndex >= flatModel.length) + return "list"; + var entry = flatModel[selectedFlatIndex]; + if (!entry || entry.isHeader) + return "list"; + return getSectionViewMode(entry.sectionId); + } + + function getGridColumns(sectionId) { + return Nav.getGridColumns(getSectionViewMode(sectionId), gridColumns); + } + + function _cancelPendingSelectionReset() { + _queryDrivenSearch = false; + _pluginPhaseForceFirst = false; + } + + function selectNext() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculateNextIndex(flatModel, selectedFlatIndex, null, null, gridColumns, getSectionViewMode); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectPrevious() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculatePrevIndex(flatModel, selectedFlatIndex, null, null, gridColumns, getSectionViewMode); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectRight() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculateRightIndex(flatModel, selectedFlatIndex, getSectionViewMode); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectLeft() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculateLeftIndex(flatModel, selectedFlatIndex, getSectionViewMode); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectNextSection() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculateNextSectionIndex(flatModel, selectedFlatIndex); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectPreviousSection() { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculatePrevSectionIndex(flatModel, selectedFlatIndex); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectPageDown(visibleItems) { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculatePageDownIndex(flatModel, selectedFlatIndex, visibleItems); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectPageUp(visibleItems) { + keyboardNavigationActive = true; + _cancelPendingSelectionReset(); + var newIndex = Nav.calculatePageUpIndex(flatModel, selectedFlatIndex, visibleItems); + if (newIndex !== selectedFlatIndex) { + selectedFlatIndex = newIndex; + updateSelectedItem(); + } + } + + function selectIndex(index) { + keyboardNavigationActive = false; + if (index >= 0 && index < flatModel.length && !flatModel[index].isHeader) { + selectedFlatIndex = index; + updateSelectedItem(); + } + } + + function toggleSection(sectionId) { + _clearModeCache(); + var newCollapsed = Object.assign({}, collapsedSections); + var currentState = newCollapsed[sectionId]; + + if (currentState === undefined) { + for (var i = 0; i < sections.length; i++) { + if (sections[i].id === sectionId) { + currentState = sections[i].collapsed || false; + break; + } + } + } + + newCollapsed[sectionId] = !currentState; + collapsedSections = newCollapsed; + + var newSections = sections.slice(); + for (var i = 0; i < newSections.length; i++) { + if (newSections[i].id === sectionId) { + newSections[i] = Object.assign({}, newSections[i], { + collapsed: newCollapsed[sectionId] + }); + } + } + flatModel = Scorer.flattenSections(newSections); + sections = newSections; + + if (selectedFlatIndex >= flatModel.length) { + selectedFlatIndex = getFirstItemIndex(); + } + updateSelectedItem(); + } + + function executeSelected() { + if (searchDebounce.running) { + searchDebounce.stop(); + performSearch(); + } + if (!selectedItem) + return; + executeItem(selectedItem); + } + + function executeItem(item) { + if (!item) + return; + + SessionData.addLauncherHistory(searchQuery); + + if (item.type === "plugin_browse") { + var browsePluginId = item.data?.pluginId; + if (!browsePluginId) + return; + var browseTrigger = item.data.isBuiltIn ? AppSearchService.getBuiltInPluginTrigger(browsePluginId) : PluginService.getPluginTrigger(browsePluginId); + + if (browseTrigger && browseTrigger.length > 0) { + searchQueryRequested(browseTrigger); + } else { + setMode("plugins"); + pluginFilter = browsePluginId; + performSearch(); + } + return; + } + + switch (item.type) { + case "app": + if (item.isCore) { + AppSearchService.executeCoreApp(item.data); + } else if (item.data?.isAction) { + launchAppAction(item.data); + } else { + launchApp(item.data); + } + break; + case "plugin": + if (item.isBuiltInLauncher) { + AppSearchService.executeBuiltInLauncherItem(item.data); + } else { + AppSearchService.executePluginItem(item.data, item.pluginId); + } + break; + case "file": + openFile(item.data?.path); + break; + default: + return; + } + + itemExecuted(); + } + + function executeAction(item, action) { + if (!item || !action) + return; + switch (action.action) { + case "launch": + executeItem(item); + break; + case "open": + openFile(item.data.path); + break; + case "open_folder": + openFolder(item.data.path); + break; + case "copy_path": + copyToClipboard(item.data.path); + break; + case "open_terminal": + openTerminal(item.data.path); + break; + case "copy": + copyToClipboard(item.name); + break; + case "execute": + executeItem(item); + break; + case "launch_dgpu": + if (item.type === "app" && item.data) { + launchAppWithNvidia(item.data); + } + break; + case "toggle_all_visibility": + if (item.type === "plugin_browse" && item.data?.pluginId) { + var pluginId = item.data.pluginId; + var currentState = SettingsData.getPluginAllowWithoutTrigger(pluginId); + SettingsData.setPluginAllowWithoutTrigger(pluginId, !currentState); + performSearch(); + } + return; + default: + if (item.type === "app" && action.actionData) { + launchAppAction({ + parentApp: item.data, + actionData: action.actionData + }); + } + } + + itemExecuted(); + } + + function _resolveDesktopEntry(app) { + if (!app) + return null; + if (app.command) + return app; + var id = app.id || app.execString || app.exec || ""; + if (!id) + return null; + return DesktopEntries.heuristicLookup(id); + } + + function launchApp(app) { + var entry = _resolveDesktopEntry(app); + if (!entry) + return; + SessionService.launchDesktopEntry(entry); + AppUsageHistoryData.addAppUsage(entry); + } + + function launchAppWithNvidia(app) { + var entry = _resolveDesktopEntry(app); + if (!entry) + return; + SessionService.launchDesktopEntry(entry, true); + AppUsageHistoryData.addAppUsage(entry); + } + + function launchAppAction(actionItem) { + if (!actionItem || !actionItem.actionData) + return; + var entry = _resolveDesktopEntry(actionItem.parentApp); + if (!entry) + return; + SessionService.launchDesktopAction(entry, actionItem.actionData); + AppUsageHistoryData.addAppUsage(entry); + } + + function openFile(path) { + if (!path) + return; + Qt.openUrlExternally("file://" + path); + } + + function openFolder(path) { + if (!path) + return; + var folder = path.substring(0, path.lastIndexOf("/")); + Qt.openUrlExternally("file://" + folder); + } + + function openTerminal(path) { + if (!path) + return; + var terminal = Quickshell.env("TERMINAL") || "xterm"; + Quickshell.execDetached({ + command: [terminal], + workingDirectory: path + }); + } + + function copyToClipboard(text) { + if (!text) + return; + Quickshell.execDetached(["dms", "cl", "copy", text]); + } +} |