mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-08 04:09:15 -04:00
feat(Clipboard): Implement clipboard/settings search functionality in DMS Launcher
This commit is contained in:
@@ -76,6 +76,13 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "clipboard":
|
||||
if (selectedItem?.actions) {
|
||||
for (var i = 0; i < selectedItem.actions.length; i++) {
|
||||
result.push(selectedItem.actions[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
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)
|
||||
|
||||
onActiveChanged: {
|
||||
if (!active) {
|
||||
if (active) {
|
||||
if (clipboardSearchEnabledInAll())
|
||||
ClipboardService.ensureLauncherHistory();
|
||||
} else {
|
||||
SessionData.addLauncherHistory(searchQuery);
|
||||
|
||||
sections = [];
|
||||
@@ -69,6 +72,28 @@ Item {
|
||||
AppSearchService.invalidateLauncherCache();
|
||||
_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 {
|
||||
@@ -124,6 +149,18 @@ Item {
|
||||
function pasteSelected() {
|
||||
if (!selectedItem)
|
||||
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) {
|
||||
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
|
||||
return;
|
||||
@@ -155,6 +192,20 @@ Item {
|
||||
priority: 2,
|
||||
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",
|
||||
title: I18n.tr("Browse"),
|
||||
@@ -352,6 +403,9 @@ Item {
|
||||
searchQuery = query;
|
||||
searchDebounce.restart();
|
||||
|
||||
if (searchMode === "all" && clipboardSearchEnabledInAll() && query.length >= 2)
|
||||
ClipboardService.ensureLauncherHistory();
|
||||
|
||||
var filesInAll = searchMode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll);
|
||||
if (searchMode !== "plugins" && (searchMode === "files" || query.startsWith("/") || filesInAll) && query.length > 0) {
|
||||
fileSearchDebounce.restart();
|
||||
@@ -370,6 +424,8 @@ Item {
|
||||
searchMode = mode;
|
||||
modeChanged(mode);
|
||||
performSearch();
|
||||
if (mode === "all" && clipboardSearchEnabledInAll() && searchQuery.length >= 2)
|
||||
ClipboardService.ensureLauncherHistory();
|
||||
var filesInAll = mode === "all" && (SettingsData.dankLauncherV2IncludeFilesInAll || SettingsData.dankLauncherV2IncludeFoldersInAll) && searchQuery.length > 0;
|
||||
if (mode === "files" || filesInAll) {
|
||||
fileSearchDebounce.restart();
|
||||
@@ -612,7 +668,7 @@ Item {
|
||||
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));
|
||||
allItems.push(transformBuiltInSearchItem(builtInItems[j], triggerMatch.pluginId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,7 +804,7 @@ Item {
|
||||
|
||||
var builtInItems = AppSearchService.getBuiltInLauncherItems(pluginFilter, searchQuery);
|
||||
for (var j = 0; j < builtInItems.length; j++) {
|
||||
allItems.push(transformBuiltInLauncherItem(builtInItems[j], pluginFilter));
|
||||
allItems.push(transformBuiltInSearchItem(builtInItems[j], pluginFilter));
|
||||
}
|
||||
} else {
|
||||
var emptyTriggerPlugins = getEmptyTriggerPlugins();
|
||||
@@ -764,7 +820,7 @@ Item {
|
||||
var pluginId = builtInLauncherPlugins[i];
|
||||
var blItems = AppSearchService.getBuiltInLauncherItems(pluginId, searchQuery);
|
||||
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") {
|
||||
appendSharedAllResults(allItems, searchQuery);
|
||||
if (searchQuery && searchQuery.length >= 2) {
|
||||
_pluginPhasePending = true;
|
||||
_phase1Items = allItems.slice();
|
||||
@@ -814,7 +871,7 @@ Item {
|
||||
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));
|
||||
allItems.push(transformBuiltInSearchItem(blItems[j], plugin.id));
|
||||
} else {
|
||||
var pItems = getPluginItems(plugin.id, searchQuery);
|
||||
for (var j = 0; j < pItems.length; j++)
|
||||
@@ -883,11 +940,13 @@ Item {
|
||||
if (currentVersion !== _searchVersion)
|
||||
return;
|
||||
var plugin = allPluginsOrdered[i];
|
||||
if (plugin.isBuiltIn && (plugin.id === "dms_settings_search" || plugin.id === "dms_clipboard_search"))
|
||||
continue;
|
||||
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);
|
||||
var item = transformBuiltInSearchItem(blItems[j], plugin.id);
|
||||
item._preScored = 900 - j;
|
||||
allItems.push(item);
|
||||
}
|
||||
@@ -1110,10 +1169,56 @@ Item {
|
||||
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) {
|
||||
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) {
|
||||
if (!query || query.length === 0)
|
||||
return {
|
||||
@@ -1308,7 +1413,9 @@ Item {
|
||||
}
|
||||
|
||||
function buildDynamicSectionDefs(items) {
|
||||
var baseDefs = sectionDefinitions.slice();
|
||||
var baseDefs = sectionDefinitions.map(function (def) {
|
||||
return Object.assign({}, def);
|
||||
});
|
||||
var pluginSections = {};
|
||||
var order = SettingsData.launcherPluginOrder || [];
|
||||
var orderMap = {};
|
||||
@@ -1316,6 +1423,12 @@ Item {
|
||||
orderMap[order[k]] = k;
|
||||
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++) {
|
||||
var section = items[i].section;
|
||||
if (!section || !section.startsWith("plugin_"))
|
||||
@@ -1768,6 +1881,20 @@ Item {
|
||||
AppSearchService.executePluginItem(item.data, item.pluginId);
|
||||
}
|
||||
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":
|
||||
openFile(item.data?.path);
|
||||
break;
|
||||
@@ -1803,6 +1930,16 @@ Item {
|
||||
case "execute":
|
||||
executeItem(item);
|
||||
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":
|
||||
if (item.type === "app" && item.data) {
|
||||
launchAppWithNvidia(item.data);
|
||||
|
||||
@@ -94,17 +94,19 @@ function transformBuiltInLauncherItem(item, pluginId, openLabel) {
|
||||
|
||||
return {
|
||||
id: item.action || "",
|
||||
type: "plugin",
|
||||
type: item.type || "plugin",
|
||||
name: item.name || "",
|
||||
subtitle: item.comment || "",
|
||||
icon: icon,
|
||||
iconType: iconType,
|
||||
section: "plugin_" + pluginId,
|
||||
data: item,
|
||||
section: item.section || ("plugin_" + pluginId),
|
||||
data: item.data || item,
|
||||
pluginId: pluginId,
|
||||
isBuiltInLauncher: true,
|
||||
keywords: item.keywords || [],
|
||||
actions: [],
|
||||
source: item.source || "",
|
||||
badgeLabel: item.badgeLabel || "",
|
||||
primaryAction: {
|
||||
name: openLabel,
|
||||
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) {
|
||||
var filename = file.path ? file.path.split("/").pop() : "";
|
||||
var dirname = file.path ? file.path.substring(0, file.path.lastIndexOf("/")) : "";
|
||||
|
||||
@@ -32,6 +32,8 @@ Popup {
|
||||
var actions = instance.getContextMenuActions(spotlightItem.data);
|
||||
return Array.isArray(actions) && actions.length > 0;
|
||||
}
|
||||
if (spotlightItem.actions && spotlightItem.actions.length > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,6 +82,13 @@ Popup {
|
||||
hide();
|
||||
}
|
||||
|
||||
function executeLauncherAction(actionData) {
|
||||
if (!controller || !item || !actionData)
|
||||
return;
|
||||
controller.executeAction(item, actionData);
|
||||
hide();
|
||||
}
|
||||
|
||||
readonly property var menuItems: {
|
||||
var items = [];
|
||||
|
||||
@@ -97,6 +106,19 @@ Popup {
|
||||
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") {
|
||||
items.push({
|
||||
type: "item",
|
||||
@@ -293,6 +315,8 @@ Popup {
|
||||
menuItem.action();
|
||||
else if (menuItem.pluginAction)
|
||||
executePluginAction(menuItem.pluginAction);
|
||||
else if (menuItem.launcherActionData)
|
||||
executeLauncherAction(menuItem.launcherActionData);
|
||||
else if (menuItem.actionData)
|
||||
executeDesktopAction(menuItem.actionData);
|
||||
return;
|
||||
@@ -500,6 +524,8 @@ Popup {
|
||||
menuItem.action();
|
||||
else if (menuItem.pluginAction)
|
||||
root.executePluginAction(menuItem.pluginAction);
|
||||
else if (menuItem.launcherActionData)
|
||||
root.executeLauncherAction(menuItem.launcherActionData);
|
||||
else if (menuItem.actionData)
|
||||
root.executeDesktopAction(menuItem.actionData);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ Rectangle {
|
||||
return item.icon || "";
|
||||
}
|
||||
}
|
||||
readonly property bool hasClipboardPreview: item?.type === "clipboard" && item?.data?.isImage === true && (item?.data?.mimeType ?? "").startsWith("image/")
|
||||
|
||||
width: parent?.width ?? 200
|
||||
height: 52
|
||||
@@ -154,6 +155,14 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
ClipboardLauncherPreview {
|
||||
width: root.hasClipboardPreview ? 56 : 0
|
||||
height: 36
|
||||
visible: root.hasClipboardPreview
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
entry: root.item?.data ?? null
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: allModeToggle
|
||||
visible: root.item?.type === "plugin_browse"
|
||||
@@ -208,9 +217,15 @@ Rectangle {
|
||||
text: {
|
||||
if (!root.item)
|
||||
return "";
|
||||
if ((root.item.badgeLabel ?? "").length > 0)
|
||||
return root.item.badgeLabel;
|
||||
switch (root.item.type) {
|
||||
case "plugin":
|
||||
return I18n.tr("Plugin");
|
||||
case "setting":
|
||||
return I18n.tr("Setting");
|
||||
case "clipboard":
|
||||
return I18n.tr("Clipboard");
|
||||
case "file":
|
||||
return root.item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
||||
default:
|
||||
|
||||
@@ -10,6 +10,8 @@ const Weights = {
|
||||
typeBonus: {
|
||||
app: 1000,
|
||||
plugin: 900,
|
||||
setting: 850,
|
||||
clipboard: 825,
|
||||
file: 800,
|
||||
action: 600
|
||||
}
|
||||
|
||||
@@ -48,17 +48,24 @@ Rectangle {
|
||||
return "file://" + 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 string typeLabel: {
|
||||
if (!item)
|
||||
return "";
|
||||
if ((item.badgeLabel ?? "").length > 0)
|
||||
return item.badgeLabel;
|
||||
switch (item.type) {
|
||||
case "plugin_browse":
|
||||
return I18n.tr("Browse");
|
||||
case "plugin":
|
||||
return I18n.tr("Plugin");
|
||||
case "setting":
|
||||
return I18n.tr("Setting");
|
||||
case "clipboard":
|
||||
return I18n.tr("Clipboard");
|
||||
case "file":
|
||||
return item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
|
||||
default:
|
||||
@@ -278,7 +285,7 @@ Rectangle {
|
||||
source: root.previewSource
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
visible: !root.previewAnimated
|
||||
visible: !root.hasClipboardPreview && !root.previewAnimated
|
||||
}
|
||||
|
||||
AnimatedImage {
|
||||
@@ -286,7 +293,13 @@ Rectangle {
|
||||
source: root.previewSource
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
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
|
||||
|
||||
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 {
|
||||
id: pluginDelegate
|
||||
|
||||
@@ -211,11 +211,21 @@ Singleton {
|
||||
},
|
||||
"dms_settings_search": {
|
||||
id: "dms_settings_search",
|
||||
name: I18n.tr("Settings", "settings window title"),
|
||||
name: I18n.tr("Settings Search"),
|
||||
cornerIcon: "search",
|
||||
comment: "DMS",
|
||||
comment: I18n.tr("DMS Settings"),
|
||||
defaultTrigger: "?",
|
||||
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) {
|
||||
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")
|
||||
return [];
|
||||
|
||||
@@ -295,10 +315,15 @@ Singleton {
|
||||
const r = results[i];
|
||||
items.push({
|
||||
name: r.label,
|
||||
type: "setting",
|
||||
section: "settings",
|
||||
icon: "material:" + r.icon,
|
||||
comment: r.category,
|
||||
comment: r.description || r.category,
|
||||
action: "settings_nav:" + r.tabIndex + ":" + r.section,
|
||||
categories: ["Settings"],
|
||||
keywords: r.keywords || [],
|
||||
source: I18n.tr("Settings", "settings window title"),
|
||||
badgeLabel: I18n.tr("Setting"),
|
||||
isCore: true,
|
||||
isBuiltInLauncher: true,
|
||||
builtInPluginId: pluginId
|
||||
|
||||
@@ -26,6 +26,7 @@ Singleton {
|
||||
property int selectedIndex: 0
|
||||
property bool keyboardNavigationActive: false
|
||||
property int refCount: 0
|
||||
property real _launcherLastRefresh: 0
|
||||
|
||||
signal historyCopied
|
||||
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() {
|
||||
searchText = "";
|
||||
selectedIndex = 0;
|
||||
|
||||
Reference in New Issue
Block a user