mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-13 14:36:32 -04:00
feat(Clipboard): Implement clipboard/settings search functionality in DMS Launcher
This commit is contained in:
@@ -76,6 +76,13 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "clipboard":
|
||||||
|
if (selectedItem?.actions) {
|
||||||
|
for (var i = 0; i < selectedItem.actions.length; i++) {
|
||||||
|
result.push(selectedItem.actions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var entry: null
|
||||||
|
property string cachedImageData: ""
|
||||||
|
property var _requestedEntryId: null
|
||||||
|
|
||||||
|
readonly property bool canLoadImage: !!entry?.isImage && (entry?.mimeType ?? "").startsWith("image/")
|
||||||
|
readonly property string sourceUrl: cachedImageData.length > 0 ? "data:" + (entry?.mimeType ?? "image/png") + ";base64," + cachedImageData : ""
|
||||||
|
|
||||||
|
radius: Math.max(6, Theme.cornerRadius - 2)
|
||||||
|
clip: true
|
||||||
|
color: Theme.surfaceContainerHigh
|
||||||
|
border.color: Theme.withAlpha(Theme.outline, 0.16)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
onEntryChanged: reloadPreview()
|
||||||
|
Component.onCompleted: reloadPreview()
|
||||||
|
|
||||||
|
function reloadPreview() {
|
||||||
|
cachedImageData = "";
|
||||||
|
if (!canLoadImage || !entry?.id) {
|
||||||
|
_requestedEntryId = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entryId = entry.id;
|
||||||
|
_requestedEntryId = entryId;
|
||||||
|
DMSService.sendRequest("clipboard.getEntry", {
|
||||||
|
"id": entryId
|
||||||
|
}, function (response) {
|
||||||
|
if (_requestedEntryId !== entryId)
|
||||||
|
return;
|
||||||
|
if (response.error)
|
||||||
|
return;
|
||||||
|
const data = response.result?.data ?? "";
|
||||||
|
if (data.length > 0)
|
||||||
|
cachedImageData = data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: previewImage
|
||||||
|
anchors.fill: parent
|
||||||
|
source: root.sourceUrl
|
||||||
|
asynchronous: true
|
||||||
|
cache: false
|
||||||
|
smooth: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
visible: status === Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "image"
|
||||||
|
size: Math.min(22, Math.max(16, root.height * 0.46))
|
||||||
|
color: Theme.primary
|
||||||
|
visible: previewImage.status !== Image.Ready
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,10 @@ Item {
|
|||||||
signal searchQueryRequested(string query)
|
signal searchQueryRequested(string query)
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (!active) {
|
if (active) {
|
||||||
|
if (clipboardSearchEnabledInAll())
|
||||||
|
ClipboardService.ensureLauncherHistory();
|
||||||
|
} else {
|
||||||
SessionData.addLauncherHistory(searchQuery);
|
SessionData.addLauncherHistory(searchQuery);
|
||||||
|
|
||||||
sections = [];
|
sections = [];
|
||||||
@@ -69,6 +72,28 @@ Item {
|
|||||||
AppSearchService.invalidateLauncherCache();
|
AppSearchService.invalidateLauncherCache();
|
||||||
_clearModeCache();
|
_clearModeCache();
|
||||||
}
|
}
|
||||||
|
function onLauncherPluginVisibilityChanged() {
|
||||||
|
AppSearchService.invalidateLauncherCache();
|
||||||
|
_clearModeCache();
|
||||||
|
if (active)
|
||||||
|
performSearch();
|
||||||
|
}
|
||||||
|
function onBuiltInPluginSettingsChanged() {
|
||||||
|
AppSearchService.invalidateLauncherCache();
|
||||||
|
_clearModeCache();
|
||||||
|
if (active)
|
||||||
|
performSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ClipboardService
|
||||||
|
function onInternalEntriesChanged() {
|
||||||
|
if (!active || !clipboardSearchEnabledInAll())
|
||||||
|
return;
|
||||||
|
if (searchMode === "all" && searchQuery.length >= 2)
|
||||||
|
performSearch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -124,6 +149,18 @@ Item {
|
|||||||
function pasteSelected() {
|
function pasteSelected() {
|
||||||
if (!selectedItem)
|
if (!selectedItem)
|
||||||
return;
|
return;
|
||||||
|
if (selectedItem.type === "clipboard") {
|
||||||
|
if (SettingsData.clipboardEnterToPaste) {
|
||||||
|
ClipboardService.copyEntry(selectedItem.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ClipboardService.pasteEntry(selectedItem.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!SessionService.wtypeAvailable) {
|
if (!SessionService.wtypeAvailable) {
|
||||||
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
|
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
|
||||||
return;
|
return;
|
||||||
@@ -155,6 +192,20 @@ Item {
|
|||||||
priority: 2,
|
priority: 2,
|
||||||
defaultViewMode: "list"
|
defaultViewMode: "list"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "settings",
|
||||||
|
title: I18n.tr("Settings", "settings window title"),
|
||||||
|
icon: "settings",
|
||||||
|
priority: 2.35,
|
||||||
|
defaultViewMode: "list"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "clipboard",
|
||||||
|
title: I18n.tr("Clipboard"),
|
||||||
|
icon: "content_paste",
|
||||||
|
priority: 2.45,
|
||||||
|
defaultViewMode: "list"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "browse_plugins",
|
id: "browse_plugins",
|
||||||
title: I18n.tr("Browse"),
|
title: I18n.tr("Browse"),
|
||||||
@@ -352,6 +403,9 @@ Item {
|
|||||||
searchQuery = query;
|
searchQuery = query;
|
||||||
searchDebounce.restart();
|
searchDebounce.restart();
|
||||||
|
|
||||||
|
if (searchMode === "all" && clipboardSearchEnabledInAll() && query.length >= 2)
|
||||||
|
ClipboardService.ensureLauncherHistory();
|
||||||
|
|
||||||
var filesInAll = searchMode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll);
|
var filesInAll = searchMode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll);
|
||||||
if (searchMode !== "plugins" && (searchMode === "files" || query.startsWith("/") || filesInAll) && query.length > 0) {
|
if (searchMode !== "plugins" && (searchMode === "files" || query.startsWith("/") || filesInAll) && query.length > 0) {
|
||||||
fileSearchDebounce.restart();
|
fileSearchDebounce.restart();
|
||||||
@@ -370,6 +424,8 @@ Item {
|
|||||||
searchMode = mode;
|
searchMode = mode;
|
||||||
modeChanged(mode);
|
modeChanged(mode);
|
||||||
performSearch();
|
performSearch();
|
||||||
|
if (mode === "all" && clipboardSearchEnabledInAll() && searchQuery.length >= 2)
|
||||||
|
ClipboardService.ensureLauncherHistory();
|
||||||
var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0;
|
var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0;
|
||||||
if (mode === "files" || filesInAll) {
|
if (mode === "files" || filesInAll) {
|
||||||
fileSearchDebounce.restart();
|
fileSearchDebounce.restart();
|
||||||
@@ -612,7 +668,7 @@ Item {
|
|||||||
if (triggerMatch.isBuiltIn) {
|
if (triggerMatch.isBuiltIn) {
|
||||||
var builtInItems = AppSearchService.getBuiltInLauncherItems(triggerMatch.pluginId, triggerMatch.query);
|
var builtInItems = AppSearchService.getBuiltInLauncherItems(triggerMatch.pluginId, triggerMatch.query);
|
||||||
for (var j = 0; j < builtInItems.length; j++) {
|
for (var j = 0; j < builtInItems.length; j++) {
|
||||||
allItems.push(transformBuiltInLauncherItem(builtInItems[j], triggerMatch.pluginId));
|
allItems.push(transformBuiltInSearchItem(builtInItems[j], triggerMatch.pluginId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,7 +804,7 @@ Item {
|
|||||||
|
|
||||||
var builtInItems = AppSearchService.getBuiltInLauncherItems(pluginFilter, searchQuery);
|
var builtInItems = AppSearchService.getBuiltInLauncherItems(pluginFilter, searchQuery);
|
||||||
for (var j = 0; j < builtInItems.length; j++) {
|
for (var j = 0; j < builtInItems.length; j++) {
|
||||||
allItems.push(transformBuiltInLauncherItem(builtInItems[j], pluginFilter));
|
allItems.push(transformBuiltInSearchItem(builtInItems[j], pluginFilter));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var emptyTriggerPlugins = getEmptyTriggerPlugins();
|
var emptyTriggerPlugins = getEmptyTriggerPlugins();
|
||||||
@@ -764,7 +820,7 @@ Item {
|
|||||||
var pluginId = builtInLauncherPlugins[i];
|
var pluginId = builtInLauncherPlugins[i];
|
||||||
var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery);
|
var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery);
|
||||||
for (var j = 0; j < blItems.length; j++) {
|
for (var j = 0; j < blItems.length; j++) {
|
||||||
allItems.push(transformBuiltInLauncherItem(blItems[j], pluginId));
|
allItems.push(transformBuiltInSearchItem(blItems[j], pluginId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -799,6 +855,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchMode === "all") {
|
if (searchMode === "all") {
|
||||||
|
appendSharedAllResults(allItems, searchQuery);
|
||||||
if (searchQuery && searchQuery.length >= 2) {
|
if (searchQuery && searchQuery.length >= 2) {
|
||||||
_pluginPhasePending = true;
|
_pluginPhasePending = true;
|
||||||
_phase1Items = allItems.slice();
|
_phase1Items = allItems.slice();
|
||||||
@@ -814,7 +871,7 @@ Item {
|
|||||||
if (plugin.isBuiltIn) {
|
if (plugin.isBuiltIn) {
|
||||||
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
|
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
|
||||||
for (var j = 0; j < blItems.length; j++)
|
for (var j = 0; j < blItems.length; j++)
|
||||||
allItems.push(transformBuiltInLauncherItem(blItems[j], plugin.id));
|
allItems.push(transformBuiltInSearchItem(blItems[j], plugin.id));
|
||||||
} else {
|
} else {
|
||||||
var pItems = getPluginItems(plugin.id, searchQuery);
|
var pItems = getPluginItems(plugin.id, searchQuery);
|
||||||
for (var j = 0; j < pItems.length; j++)
|
for (var j = 0; j < pItems.length; j++)
|
||||||
@@ -883,11 +940,13 @@ Item {
|
|||||||
if (currentVersion !== _searchVersion)
|
if (currentVersion !== _searchVersion)
|
||||||
return;
|
return;
|
||||||
var plugin = allPluginsOrdered[i];
|
var plugin = allPluginsOrdered[i];
|
||||||
|
if (plugin.isBuiltIn && (plugin.id === "dms_settings_search" || plugin.id === "dms_clipboard_search"))
|
||||||
|
continue;
|
||||||
if (plugin.isBuiltIn) {
|
if (plugin.isBuiltIn) {
|
||||||
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
|
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
|
||||||
var blLimit = Math.min(blItems.length, maxPerPlugin);
|
var blLimit = Math.min(blItems.length, maxPerPlugin);
|
||||||
for (var j = 0; j < blLimit; j++) {
|
for (var j = 0; j < blLimit; j++) {
|
||||||
var item = transformBuiltInLauncherItem(blItems[j], plugin.id);
|
var item = transformBuiltInSearchItem(blItems[j], plugin.id);
|
||||||
item._preScored = 900 - j;
|
item._preScored = 900 - j;
|
||||||
allItems.push(item);
|
allItems.push(item);
|
||||||
}
|
}
|
||||||
@@ -1110,10 +1169,56 @@ Item {
|
|||||||
return Transform.transformBuiltInLauncherItem(item, pluginId, I18n.tr("Open"));
|
return Transform.transformBuiltInLauncherItem(item, pluginId, I18n.tr("Open"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transformBuiltInSearchItem(item, pluginId) {
|
||||||
|
if (pluginId === "dms_clipboard_search" || item.type === "clipboard")
|
||||||
|
return transformClipboardEntry(item.data || item);
|
||||||
|
return transformBuiltInLauncherItem(item, pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
function transformFileResult(file) {
|
function transformFileResult(file) {
|
||||||
return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"), I18n.tr("Open in terminal"));
|
return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"), I18n.tr("Open in terminal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transformClipboardEntry(entry) {
|
||||||
|
var copyLabel = I18n.tr("Copy");
|
||||||
|
var pasteLabel = I18n.tr("Paste");
|
||||||
|
var primaryLabel = SettingsData.clipboardEnterToPaste ? pasteLabel : copyLabel;
|
||||||
|
var pasteHintLabel = SettingsData.clipboardEnterToPaste ? I18n.tr("Shift+Enter to copy") : I18n.tr("Shift+Enter to paste");
|
||||||
|
return Transform.transformClipboardItem(entry, copyLabel, pasteLabel, primaryLabel, I18n.tr("Image"), I18n.tr("Text"), I18n.tr("Pinned"), pasteHintLabel, "", I18n.tr("Clipboard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function builtInLauncherVisibleInAll(pluginId) {
|
||||||
|
return SettingsData.getBuiltInPluginSetting(pluginId, "enabled", true) && SettingsData.getPluginAllowWithoutTrigger(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clipboardSearchEnabledInAll() {
|
||||||
|
return builtInLauncherVisibleInAll("dms_clipboard_search") && ClipboardService.clipboardAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendSharedAllResults(allItems, query) {
|
||||||
|
if (!query || query.length < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (builtInLauncherVisibleInAll("dms_settings_search")) {
|
||||||
|
var settingsItems = AppSearchService.getBuiltInLauncherItems("dms_settings_search", query);
|
||||||
|
var settingsLimit = Math.min(settingsItems.length, 8);
|
||||||
|
for (var i = 0; i < settingsLimit; i++) {
|
||||||
|
settingsItems[i]._preScored = 890 - i;
|
||||||
|
allItems.push(transformBuiltInSearchItem(settingsItems[i], "dms_settings_search"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipboardSearchEnabledInAll()) {
|
||||||
|
ClipboardService.ensureLauncherHistory();
|
||||||
|
var clipboardItems = AppSearchService.getBuiltInLauncherItems("dms_clipboard_search", query);
|
||||||
|
var clipboardLimit = Math.min(clipboardItems.length, 8);
|
||||||
|
for (var j = 0; j < clipboardLimit; j++) {
|
||||||
|
clipboardItems[j]._preScored = 840 - j;
|
||||||
|
allItems.push(transformBuiltInSearchItem(clipboardItems[j], "dms_clipboard_search"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function detectTrigger(query) {
|
function detectTrigger(query) {
|
||||||
if (!query || query.length === 0)
|
if (!query || query.length === 0)
|
||||||
return {
|
return {
|
||||||
@@ -1308,7 +1413,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildDynamicSectionDefs(items) {
|
function buildDynamicSectionDefs(items) {
|
||||||
var baseDefs = sectionDefinitions.slice();
|
var baseDefs = sectionDefinitions.map(function (def) {
|
||||||
|
return Object.assign({}, def);
|
||||||
|
});
|
||||||
var pluginSections = {};
|
var pluginSections = {};
|
||||||
var order = SettingsData.launcherPluginOrder || [];
|
var order = SettingsData.launcherPluginOrder || [];
|
||||||
var orderMap = {};
|
var orderMap = {};
|
||||||
@@ -1316,6 +1423,12 @@ Item {
|
|||||||
orderMap[order[k]] = k;
|
orderMap[order[k]] = k;
|
||||||
var unorderedPriority = 2.6 + order.length * 0.01;
|
var unorderedPriority = 2.6 + order.length * 0.01;
|
||||||
|
|
||||||
|
for (var d = 0; d < baseDefs.length; d++) {
|
||||||
|
var virtualId = baseDefs[d].id === "settings" ? "dms_settings_search" : baseDefs[d].id === "clipboard" ? "dms_clipboard_search" : "";
|
||||||
|
if (virtualId && orderMap[virtualId] !== undefined)
|
||||||
|
baseDefs[d].priority = 2.6 + orderMap[virtualId] * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (var i = 0; i < items.length; i++) {
|
||||||
var section = items[i].section;
|
var section = items[i].section;
|
||||||
if (!section || !section.startsWith("plugin_"))
|
if (!section || !section.startsWith("plugin_"))
|
||||||
@@ -1768,6 +1881,20 @@ Item {
|
|||||||
AppSearchService.executePluginItem(item.data, item.pluginId);
|
AppSearchService.executePluginItem(item.data, item.pluginId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "setting":
|
||||||
|
AppSearchService.executeBuiltInLauncherItem(item.data);
|
||||||
|
break;
|
||||||
|
case "clipboard":
|
||||||
|
if (SettingsData.clipboardEnterToPaste) {
|
||||||
|
ClipboardService.pasteEntry(item.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ClipboardService.copyEntry(item.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
case "file":
|
case "file":
|
||||||
openFile(item.data?.path);
|
openFile(item.data?.path);
|
||||||
break;
|
break;
|
||||||
@@ -1803,6 +1930,16 @@ Item {
|
|||||||
case "execute":
|
case "execute":
|
||||||
executeItem(item);
|
executeItem(item);
|
||||||
break;
|
break;
|
||||||
|
case "clipboard_copy":
|
||||||
|
ClipboardService.copyEntry(item.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case "clipboard_paste":
|
||||||
|
ClipboardService.pasteEntry(item.data, function () {
|
||||||
|
root.itemExecuted();
|
||||||
|
});
|
||||||
|
return;
|
||||||
case "launch_dgpu":
|
case "launch_dgpu":
|
||||||
if (item.type === "app" && item.data) {
|
if (item.type === "app" && item.data) {
|
||||||
launchAppWithNvidia(item.data);
|
launchAppWithNvidia(item.data);
|
||||||
|
|||||||
@@ -94,17 +94,19 @@ function transformBuiltInLauncherItem(item, pluginId, openLabel) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.action || "",
|
id: item.action || "",
|
||||||
type: "plugin",
|
type: item.type || "plugin",
|
||||||
name: item.name || "",
|
name: item.name || "",
|
||||||
subtitle: item.comment || "",
|
subtitle: item.comment || "",
|
||||||
icon: icon,
|
icon: icon,
|
||||||
iconType: iconType,
|
iconType: iconType,
|
||||||
section: "plugin_" + pluginId,
|
section: item.section || ("plugin_" + pluginId),
|
||||||
data: item,
|
data: item.data || item,
|
||||||
pluginId: pluginId,
|
pluginId: pluginId,
|
||||||
isBuiltInLauncher: true,
|
isBuiltInLauncher: true,
|
||||||
keywords: item.keywords || [],
|
keywords: item.keywords || [],
|
||||||
actions: [],
|
actions: [],
|
||||||
|
source: item.source || "",
|
||||||
|
badgeLabel: item.badgeLabel || "",
|
||||||
primaryAction: {
|
primaryAction: {
|
||||||
name: openLabel,
|
name: openLabel,
|
||||||
icon: "open_in_new",
|
icon: "open_in_new",
|
||||||
@@ -117,6 +119,58 @@ function transformBuiltInLauncherItem(item, pluginId, openLabel) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transformClipboardItem(entry, copyLabel, pasteLabel, primaryLabel, imageLabel, textLabel, pinnedLabel, pasteHintLabel, copyHintLabel, clipboardLabel) {
|
||||||
|
var preview = (entry.preview || "").toString().replace(/\s+/g, " ").trim();
|
||||||
|
var isImage = entry.isImage || false;
|
||||||
|
var title = preview.length > 0 ? preview : imageLabel;
|
||||||
|
if (title.length > 140)
|
||||||
|
title = title.substring(0, 137) + "...";
|
||||||
|
|
||||||
|
var typeLabel = isImage ? imageLabel : textLabel;
|
||||||
|
var subtitle = typeLabel;
|
||||||
|
if (entry.pinned)
|
||||||
|
subtitle = pinnedLabel + " - " + subtitle;
|
||||||
|
if (pasteHintLabel)
|
||||||
|
subtitle += " - " + pasteHintLabel;
|
||||||
|
if (copyHintLabel)
|
||||||
|
subtitle += " - " + copyHintLabel;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: "clipboard_" + (entry.id || entry.hash || title),
|
||||||
|
type: "clipboard",
|
||||||
|
name: title,
|
||||||
|
subtitle: subtitle,
|
||||||
|
icon: isImage ? "image" : "content_paste",
|
||||||
|
iconType: "material",
|
||||||
|
section: "clipboard",
|
||||||
|
data: entry,
|
||||||
|
keywords: [preview, isImage ? "image" : "text", "clipboard"],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: copyLabel,
|
||||||
|
icon: "content_copy",
|
||||||
|
action: "clipboard_copy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: pasteLabel,
|
||||||
|
icon: "content_paste",
|
||||||
|
action: "clipboard_paste"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
source: clipboardLabel,
|
||||||
|
badgeLabel: clipboardLabel,
|
||||||
|
primaryAction: {
|
||||||
|
name: primaryLabel,
|
||||||
|
icon: primaryLabel === pasteLabel ? "content_paste" : "content_copy",
|
||||||
|
action: primaryLabel === pasteLabel ? "clipboard_paste" : "clipboard_copy"
|
||||||
|
},
|
||||||
|
_hName: "",
|
||||||
|
_hSub: "",
|
||||||
|
_hRich: false,
|
||||||
|
_preScored: entry._preScored
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function transformFileResult(file, openLabel, openFolderLabel, copyPathLabel, openTerminalLabel) {
|
function transformFileResult(file, openLabel, openFolderLabel, copyPathLabel, openTerminalLabel) {
|
||||||
var filename = file.path ? file.path.split("/").pop() : "";
|
var filename = file.path ? file.path.split("/").pop() : "";
|
||||||
var dirname = file.path ? file.path.substring(0, file.path.lastIndexOf("/")) : "";
|
var dirname = file.path ? file.path.substring(0, file.path.lastIndexOf("/")) : "";
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ Popup {
|
|||||||
var actions = instance.getContextMenuActions(spotlightItem.data);
|
var actions = instance.getContextMenuActions(spotlightItem.data);
|
||||||
return Array.isArray(actions) && actions.length > 0;
|
return Array.isArray(actions) && actions.length > 0;
|
||||||
}
|
}
|
||||||
|
if (spotlightItem.actions && spotlightItem.actions.length > 0)
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +82,13 @@ Popup {
|
|||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function executeLauncherAction(actionData) {
|
||||||
|
if (!controller || !item || !actionData)
|
||||||
|
return;
|
||||||
|
controller.executeAction(item, actionData);
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var menuItems: {
|
readonly property var menuItems: {
|
||||||
var items = [];
|
var items = [];
|
||||||
|
|
||||||
@@ -97,6 +106,19 @@ Popup {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item?.type !== "app" && item?.actions && item.actions.length > 0) {
|
||||||
|
for (var i = 0; i < item.actions.length; i++) {
|
||||||
|
var genericAct = item.actions[i];
|
||||||
|
items.push({
|
||||||
|
type: "item",
|
||||||
|
icon: genericAct.icon || "play_arrow",
|
||||||
|
text: genericAct.name || "",
|
||||||
|
launcherActionData: genericAct
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
if (item?.type === "app") {
|
if (item?.type === "app") {
|
||||||
items.push({
|
items.push({
|
||||||
type: "item",
|
type: "item",
|
||||||
@@ -293,6 +315,8 @@ Popup {
|
|||||||
menuItem.action();
|
menuItem.action();
|
||||||
else if (menuItem.pluginAction)
|
else if (menuItem.pluginAction)
|
||||||
executePluginAction(menuItem.pluginAction);
|
executePluginAction(menuItem.pluginAction);
|
||||||
|
else if (menuItem.launcherActionData)
|
||||||
|
executeLauncherAction(menuItem.launcherActionData);
|
||||||
else if (menuItem.actionData)
|
else if (menuItem.actionData)
|
||||||
executeDesktopAction(menuItem.actionData);
|
executeDesktopAction(menuItem.actionData);
|
||||||
return;
|
return;
|
||||||
@@ -500,6 +524,8 @@ Popup {
|
|||||||
menuItem.action();
|
menuItem.action();
|
||||||
else if (menuItem.pluginAction)
|
else if (menuItem.pluginAction)
|
||||||
root.executePluginAction(menuItem.pluginAction);
|
root.executePluginAction(menuItem.pluginAction);
|
||||||
|
else if (menuItem.launcherActionData)
|
||||||
|
root.executeLauncherAction(menuItem.launcherActionData);
|
||||||
else if (menuItem.actionData)
|
else if (menuItem.actionData)
|
||||||
root.executeDesktopAction(menuItem.actionData);
|
root.executeDesktopAction(menuItem.actionData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Rectangle {
|
|||||||
return item.icon || "";
|
return item.icon || "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
readonly property bool hasClipboardPreview: item?.type === "clipboard" && item?.data?.isImage === true && (item?.data?.mimeType ?? "").startsWith("image/")
|
||||||
|
|
||||||
width: parent?.width ?? 200
|
width: parent?.width ?? 200
|
||||||
height: 52
|
height: 52
|
||||||
@@ -154,6 +155,14 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
ClipboardLauncherPreview {
|
||||||
|
width: root.hasClipboardPreview ? 56 : 0
|
||||||
|
height: 36
|
||||||
|
visible: root.hasClipboardPreview
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
entry: root.item?.data ?? null
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: allModeToggle
|
id: allModeToggle
|
||||||
visible: root.item?.type === "plugin_browse"
|
visible: root.item?.type === "plugin_browse"
|
||||||
@@ -208,9 +217,15 @@ Rectangle {
|
|||||||
text: {
|
text: {
|
||||||
if (!root.item)
|
if (!root.item)
|
||||||
return "";
|
return "";
|
||||||
|
if ((root.item.badgeLabel ?? "").length > 0)
|
||||||
|
return root.item.badgeLabel;
|
||||||
switch (root.item.type) {
|
switch (root.item.type) {
|
||||||
case "plugin":
|
case "plugin":
|
||||||
return I18n.tr("Plugin");
|
return I18n.tr("Plugin");
|
||||||
|
case "setting":
|
||||||
|
return I18n.tr("Setting");
|
||||||
|
case "clipboard":
|
||||||
|
return I18n.tr("Clipboard");
|
||||||
case "file":
|
case "file":
|
||||||
return root.item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
return root.item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ const Weights = {
|
|||||||
typeBonus: {
|
typeBonus: {
|
||||||
app: 1000,
|
app: 1000,
|
||||||
plugin: 900,
|
plugin: 900,
|
||||||
|
setting: 850,
|
||||||
|
clipboard: 825,
|
||||||
file: 800,
|
file: 800,
|
||||||
action: 600
|
action: 600
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,17 +48,24 @@ Rectangle {
|
|||||||
return "file://" + raw;
|
return "file://" + raw;
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
readonly property bool hasMediaPreview: previewSource.length > 0
|
readonly property bool hasClipboardPreview: item?.type === "clipboard" && item?.data?.isImage === true && (item?.data?.mimeType ?? "").startsWith("image/")
|
||||||
|
readonly property bool hasMediaPreview: previewSource.length > 0 || hasClipboardPreview
|
||||||
readonly property bool previewAnimated: previewSource.toLowerCase().indexOf(".gif") >= 0
|
readonly property bool previewAnimated: previewSource.toLowerCase().indexOf(".gif") >= 0
|
||||||
|
|
||||||
readonly property string typeLabel: {
|
readonly property string typeLabel: {
|
||||||
if (!item)
|
if (!item)
|
||||||
return "";
|
return "";
|
||||||
|
if ((item.badgeLabel ?? "").length > 0)
|
||||||
|
return item.badgeLabel;
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case "plugin_browse":
|
case "plugin_browse":
|
||||||
return I18n.tr("Browse");
|
return I18n.tr("Browse");
|
||||||
case "plugin":
|
case "plugin":
|
||||||
return I18n.tr("Plugin");
|
return I18n.tr("Plugin");
|
||||||
|
case "setting":
|
||||||
|
return I18n.tr("Setting");
|
||||||
|
case "clipboard":
|
||||||
|
return I18n.tr("Clipboard");
|
||||||
case "file":
|
case "file":
|
||||||
return item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
return item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
||||||
default:
|
default:
|
||||||
@@ -278,7 +285,7 @@ Rectangle {
|
|||||||
source: root.previewSource
|
source: root.previewSource
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
visible: !root.previewAnimated
|
visible: !root.hasClipboardPreview && !root.previewAnimated
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedImage {
|
AnimatedImage {
|
||||||
@@ -286,7 +293,13 @@ Rectangle {
|
|||||||
source: root.previewSource
|
source: root.previewSource
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
playing: visible
|
playing: visible
|
||||||
visible: root.previewAnimated
|
visible: !root.hasClipboardPreview && root.previewAnimated
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardLauncherPreview {
|
||||||
|
anchors.fill: parent
|
||||||
|
entry: root.item?.data ?? null
|
||||||
|
visible: root.hasClipboardPreview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: ["dms_settings", "dms_notepad", "dms_sysmon", "dms_settings_search"]
|
model: ["dms_settings", "dms_notepad", "dms_sysmon", "dms_settings_search", "dms_clipboard_search"]
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
id: pluginDelegate
|
id: pluginDelegate
|
||||||
|
|||||||
@@ -211,11 +211,21 @@ Singleton {
|
|||||||
},
|
},
|
||||||
"dms_settings_search": {
|
"dms_settings_search": {
|
||||||
id: "dms_settings_search",
|
id: "dms_settings_search",
|
||||||
name: I18n.tr("Settings", "settings window title"),
|
name: I18n.tr("Settings Search"),
|
||||||
cornerIcon: "search",
|
cornerIcon: "search",
|
||||||
comment: "DMS",
|
comment: I18n.tr("DMS Settings"),
|
||||||
defaultTrigger: "?",
|
defaultTrigger: "?",
|
||||||
isLauncher: true
|
isLauncher: true
|
||||||
|
},
|
||||||
|
"dms_clipboard_search": {
|
||||||
|
id: "dms_clipboard_search",
|
||||||
|
name: I18n.tr("Clipboard"),
|
||||||
|
cornerIcon: "content_paste",
|
||||||
|
comment: "DMS",
|
||||||
|
defaultTrigger: "cb",
|
||||||
|
isLauncher: true,
|
||||||
|
viewMode: "list",
|
||||||
|
viewModeEnforced: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -285,6 +295,16 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBuiltInLauncherItems(pluginId, query) {
|
function getBuiltInLauncherItems(pluginId, query) {
|
||||||
|
if (pluginId === "dms_clipboard_search") {
|
||||||
|
ClipboardService.ensureLauncherHistory();
|
||||||
|
const trimmed = (query || "").toString().trim();
|
||||||
|
const entries = trimmed.length === 0 ? ClipboardService.getRecentLauncherEntries(20) : ClipboardService.getLauncherEntries(trimmed, 20, 1);
|
||||||
|
return entries.map(entry => ({
|
||||||
|
type: "clipboard",
|
||||||
|
data: entry
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (pluginId !== "dms_settings_search")
|
if (pluginId !== "dms_settings_search")
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
@@ -295,10 +315,15 @@ Singleton {
|
|||||||
const r = results[i];
|
const r = results[i];
|
||||||
items.push({
|
items.push({
|
||||||
name: r.label,
|
name: r.label,
|
||||||
|
type: "setting",
|
||||||
|
section: "settings",
|
||||||
icon: "material:" + r.icon,
|
icon: "material:" + r.icon,
|
||||||
comment: r.category,
|
comment: r.description || r.category,
|
||||||
action: "settings_nav:" + r.tabIndex + ":" + r.section,
|
action: "settings_nav:" + r.tabIndex + ":" + r.section,
|
||||||
categories: ["Settings"],
|
categories: ["Settings"],
|
||||||
|
keywords: r.keywords || [],
|
||||||
|
source: I18n.tr("Settings", "settings window title"),
|
||||||
|
badgeLabel: I18n.tr("Setting"),
|
||||||
isCore: true,
|
isCore: true,
|
||||||
isBuiltInLauncher: true,
|
isBuiltInLauncher: true,
|
||||||
builtInPluginId: pluginId
|
builtInPluginId: pluginId
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Singleton {
|
|||||||
property int selectedIndex: 0
|
property int selectedIndex: 0
|
||||||
property bool keyboardNavigationActive: false
|
property bool keyboardNavigationActive: false
|
||||||
property int refCount: 0
|
property int refCount: 0
|
||||||
|
property real _launcherLastRefresh: 0
|
||||||
|
|
||||||
signal historyCopied
|
signal historyCopied
|
||||||
signal historyCleared
|
signal historyCleared
|
||||||
@@ -90,6 +91,68 @@ Singleton {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureLauncherHistory() {
|
||||||
|
if (!clipboardAvailable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
if (internalEntries.length === 0 || now - _launcherLastRefresh > 5000) {
|
||||||
|
_launcherLastRefresh = now;
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLauncherEntries(query, limit, minLength) {
|
||||||
|
if (!clipboardAvailable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = (query || "").toString().trim();
|
||||||
|
const requiredLength = minLength !== undefined ? minLength : 2;
|
||||||
|
if (trimmed.length < requiredLength) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerQuery = trimmed.toLowerCase();
|
||||||
|
const maxItems = limit > 0 ? limit : 8;
|
||||||
|
const matches = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < internalEntries.length; i++) {
|
||||||
|
const entry = internalEntries[i];
|
||||||
|
const preview = getEntryPreview(entry).toString();
|
||||||
|
const typeText = entry.isImage ? "image picture screenshot clipboard" : "text clipboard";
|
||||||
|
const haystack = (preview + " " + typeText).toLowerCase();
|
||||||
|
if (haystack.indexOf(lowerQuery) === -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
matches.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
matches.sort((a, b) => {
|
||||||
|
if (a.pinned !== b.pinned)
|
||||||
|
return b.pinned ? 1 : -1;
|
||||||
|
return (b.id || 0) - (a.id || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return matches.slice(0, maxItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecentLauncherEntries(limit) {
|
||||||
|
if (!clipboardAvailable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxItems = limit > 0 ? limit : 20;
|
||||||
|
const entries = internalEntries.slice();
|
||||||
|
entries.sort((a, b) => {
|
||||||
|
if (a.pinned !== b.pinned)
|
||||||
|
return b.pinned ? 1 : -1;
|
||||||
|
return (b.id || 0) - (a.id || 0);
|
||||||
|
});
|
||||||
|
return entries.slice(0, maxItems);
|
||||||
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
searchText = "";
|
searchText = "";
|
||||||
selectedIndex = 0;
|
selectedIndex = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user