Launcher: clipboard, prevent unecessary refresh while browsing

This commit is contained in:
LemmyCook 2025-09-03 10:25:44 -04:00
parent 20b29f98a7
commit 7b2d490ba7
6 changed files with 91 additions and 37 deletions

View file

@ -11,8 +11,18 @@ NPanel {
id: root
// Panel configuration
panelWidth: Math.min(700 * scaling, screen?.width * 0.75)
panelHeight: Math.min(600 * scaling, screen?.height * 0.8)
panelWidth: {
var w = Math.round(Math.max(screen?.width * 0.3, 500) * scaling)
w = Math.min(w, screen?.width - Style.marginL * 2)
return w
}
panelHeight: {
var h = Math.round(Math.max(screen?.height * 0.5, 600) * scaling)
h = Math.min(h, screen?.height - Style.barHeight * scaling - Style.marginL * 2)
return h
}
panelKeyboardFocus: true
panelBackgroundColor: Qt.rgba(Color.mSurface.r, Color.mSurface.g, Color.mSurface.b,
Settings.data.appLauncher.backgroundOpacity)
@ -246,7 +256,7 @@ NPanel {
id: entry
property bool isSelected: mouseArea.containsMouse || (index === selectedIndex)
property int badgeSize: Style.baseWidgetSize * 1.75 * scaling
property int badgeSize: Style.baseWidgetSize * 1.6 * scaling
// Property to reliably track the current item's ID.
// This changes whenever the delegate is recycled for a new item.

View file

@ -5,7 +5,7 @@ import qs.Commons
import qs.Services
import "../../../Helpers/FuzzySort.js" as Fuzzysort
QtObject {
Item {
property var launcher: null
property string name: "Applications"
property bool handleSearch: true

View file

@ -2,7 +2,7 @@ import QtQuick
import qs.Services
import "../../../Helpers/AdvancedMath.js" as AdvancedMath
QtObject {
Item {
property var launcher: null
property string name: "Calculator"

View file

@ -3,7 +3,7 @@ import Quickshell
import qs.Commons
import qs.Services
QtObject {
Item {
id: root
// Plugin metadata
@ -13,27 +13,48 @@ QtObject {
// Plugin capabilities
property bool handleSearch: false // Don't handle regular search
// Internal state
property bool isWaitingForData: false
property bool gotResults: false
property string lastSearchText: ""
// Listen for clipboard data updates
// Connections {
// target: ClipboardService
// function onListCompleted() {
// // Only refresh if the clipboard plugin is active
// if (launcher && launcher.activePlugin === root) {
// launcher.updateResults()
// }
// }
// }
Connections {
target: ClipboardService
function onListCompleted() {
if (gotResults) {
// Do not update results after the first fetch.
// This will avoid the list resetting every 2seconds when the service updates.
return
}
// Refresh results if we're waiting for data or if clipboard plugin is active
if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
isWaitingForData = false
gotResults = true
if (launcher) {
launcher.updateResults()
}
}
}
}
// Initialize plugin
function init() {
Logger.log("ClipboardPlugin", "Initialized")
// Pre-load clipboard data if service is active
if (ClipboardService.active) {
ClipboardService.list(100)
}
}
// Called when launcher opens
function onOpened() {
// Refresh clipboard history when launcher opens
if (ClipboardService.active) {
isWaitingForData = true
ClipboardService.list(100)
}
}
// Check if this plugin handles the command
function handleCommand(searchText) {
@ -45,7 +66,7 @@ QtObject {
return [{
"name": ">clip",
"description": "Search clipboard history",
"icon": "content_paste",
"icon": "text-x-generic",
"isImage": false,
"onActivate": function () {
launcher.setSearchText(">clip ")
@ -53,7 +74,7 @@ QtObject {
}, {
"name": ">clip clear",
"description": "Clear all clipboard history",
"icon": "delete_sweep",
"icon": "text-x-generic",
"isImage": false,
"onActivate": function () {
ClipboardService.wipeAll()
@ -68,15 +89,28 @@ QtObject {
return []
}
lastSearchText = searchText
const results = []
const query = searchText.slice(5).trim()
// Check if clipboard service is not active
if (!ClipboardService.active) {
return [{
"name": "Clipboard History Disabled",
"description": "Enable clipboard history in settings or install cliphist",
"icon": "view-refresh",
"isImage": false,
"onActivate": function () {}
}]
}
// Special command: clear
if (query === "clear") {
return [{
"name": "Clear Clipboard History",
"description": "Remove all items from clipboard history",
"icon": "delete_sweep",
"isImage": false,
"onActivate": function () {
ClipboardService.wipeAll()
launcher.close()
@ -84,8 +118,24 @@ QtObject {
}]
}
// Show loading state if data isn't ready yet
if (ClipboardService.loading) {
// Show loading state if data is being loaded
if (ClipboardService.loading || isWaitingForData) {
return [{
"name": "Loading clipboard history...",
"description": "Please wait",
"icon": "view-refresh",
"isImage": false,
"onActivate": function () {}
}]
}
// Get clipboard items
const items = ClipboardService.items || []
// If no items and we haven't tried loading yet, trigger a load
if (items.length === 0 && !ClipboardService.loading) {
isWaitingForData = true
ClipboardService.list(100)
return [{
"name": "Loading clipboard history...",
"description": "Please wait",
@ -98,10 +148,6 @@ QtObject {
// Search clipboard items
const searchTerm = query.toLowerCase()
// Force dependency update
const _rev = ClipboardService.revision
const items = ClipboardService.items || []
// Filter and format results
items.forEach(function (item) {
const preview = (item.preview || "").toLowerCase()
@ -140,7 +186,7 @@ QtObject {
})
}
Logger.log("ClipboardPlugin", `Returning ${results.length} results`)
//Logger.log("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
return results
}

View file

@ -10,10 +10,9 @@ Singleton {
id: root
// Public API
property var items: [] // [{id, preview, mime, isImage}]
property bool active: Settings.isLoaded && Settings.data.appLauncher.enableClipboardHistory && cliphistAvailable
property bool loading: false
// Active only when feature is enabled, settings have finished initial load, and cliphist is available
property bool active: Settings.data.appLauncher.enableClipboardHistory && Settings.isLoaded && cliphistAvailable
property var items: [] // [{id, preview, mime, isImage}]
// Check if cliphist is available on the system
property bool cliphistAvailable: false
@ -39,7 +38,7 @@ Singleton {
property string _b64CurrentMime: ""
property string _b64CurrentId: ""
signal listCompleted()
signal listCompleted
// Check if cliphist is available
Component.onCompleted: {
@ -82,7 +81,7 @@ Singleton {
// Start/stop watchers when enabled changes
onActiveChanged: {
if (root.active && root.cliphistAvailable) {
if (root.active) {
startWatchers()
} else {
stopWatchers()
@ -96,7 +95,7 @@ Singleton {
Timer {
interval: 5000
repeat: true
running: root.active && root.cliphistAvailable
running: root.active
onTriggered: list()
}
@ -185,9 +184,9 @@ Singleton {
const url = `data:${root._b64CurrentMime};base64,${b64}`
try {
root._b64CurrentCb(url)
} finally {
} catch (e) {
/* noop */ }
}
}
if (root._b64CurrentId !== "") {
root.imageDataById[root._b64CurrentId] = `data:${root._b64CurrentMime};base64,${b64}`
@ -321,6 +320,7 @@ Singleton {
return
}
Quickshell.execDetached(["cliphist", "delete", id])
revision++
Qt.callLater(() => list())
}
@ -330,9 +330,7 @@ Singleton {
}
Quickshell.execDetached(["cliphist", "wipe"])
revision++
Qt.callLater(() => list())
}
}

View file

@ -7,7 +7,7 @@ import qs.Commons
import qs.Services
import Quickshell.Services.Notifications
QtObject {
Singleton {
id: root
// Notification server instance