diff --git a/Modules/Launcher/Launcher.qml b/Modules/Launcher/Launcher.qml index b26b38d..4c44ad6 100644 --- a/Modules/Launcher/Launcher.qml +++ b/Modules/Launcher/Launcher.qml @@ -231,9 +231,6 @@ NPanel { clip: true cacheBuffer: resultsList.height * 2 - //boundsBehavior: Flickable.StopAtBounds - // maximumFlickVelocity: 2500 - // flickDeceleration: 2000 onCurrentIndexChanged: { cancelFlick() if (currentIndex >= 0) { @@ -245,15 +242,26 @@ NPanel { policy: ScrollBar.AsNeeded } - // Replace the delegate in Launcher.qml's ListView with this enhanced version: delegate: Rectangle { id: entry property bool isSelected: mouseArea.containsMouse || (index === selectedIndex) - property int badgeSize: Style.baseWidgetSize * 1.75 * scaling + property int badgeSize: Style.baseWidgetSize * 1.75 * scaling + + // Property to reliably track the current item's ID. + // This changes whenever the delegate is recycled for a new item. + property var currentClipboardId: modelData.isImage ? modelData.clipboardId : "" + + // When this delegate is assigned a new image item, trigger the decode. + onCurrentClipboardIdChanged: { + // Check if it's a valid ID and if the data isn't already cached. + if (currentClipboardId && !CliphistService.getImageData(currentClipboardId)) { + CliphistService.decodeToDataUrl(currentClipboardId, modelData.mime, null) + } + } width: resultsList.width - Style.marginS * scaling - height: badgeSize + Style.marginM * 2 *scaling + height: badgeSize + Style.marginM * 2 * scaling radius: Style.radiusM * scaling color: entry.isSelected ? Color.mTertiary : Color.mSurface @@ -282,8 +290,19 @@ NPanel { id: imagePreview anchors.fill: parent anchors.margins: 2 * scaling - visible: modelData.isImage && modelData.imageSource - source: modelData.imageSource || "" + visible: modelData.isImage + + // This property creates a dependency on the service's revision counter + readonly property int _rev: CliphistService.revision + + // Fetches from the service's cache. + // The dependency on `_rev` ensures this binding is re-evaluated + // when the cache is updated by the service. + source: { + _rev + return CliphistService.getImageData(modelData.clipboardId) || "" + } + fillMode: Image.PreserveAspectFit smooth: true mipmap: true @@ -307,7 +326,6 @@ NPanel { // Error fallback onStatusChanged: { if (status === Image.Error) { - // Fall back to icon iconLoader.visible = true imagePreview.visible = false } @@ -319,7 +337,8 @@ NPanel { id: iconLoader anchors.fill: parent anchors.margins: Style.marginXS * scaling - visible: !modelData.isImage || !modelData.imageSource || imagePreview.status === Image.Error + + visible: !modelData.isImage || imagePreview.status === Image.Error active: visible sourceComponent: Component { @@ -391,23 +410,6 @@ NPanel { Layout.fillWidth: true visible: text !== "" } - - // // Show text preview for text items if space allows - // NText { - // visible: !modelData.isImage && modelData.fullText && modelData.fullText.length > 100 - // text: { - // if (!modelData.fullText) return "" - // const preview = modelData.fullText.substring(0, 150).replace(/\n/g, " ") - // return preview + (modelData.fullText.length > 150 ? "..." : "") - // } - // font.pointSize: Style.fontSizeXS * scaling - // color: entry.isSelected ? Color.mOnTertiary : Color.mOnSurfaceVariant - // opacity: 0.7 - // elide: Text.ElideRight - // maximumLineCount: 2 - // wrapMode: Text.WordWrap - // Layout.fillWidth: true - // } } } diff --git a/Modules/Launcher/Plugins/ClipboardPlugin.qml b/Modules/Launcher/Plugins/ClipboardPlugin.qml index d0e2269..8d51124 100644 --- a/Modules/Launcher/Plugins/ClipboardPlugin.qml +++ b/Modules/Launcher/Plugins/ClipboardPlugin.qml @@ -13,6 +13,17 @@ QtObject { // Plugin capabilities property bool handleSearch: false // Don't handle regular search + // Connections { + // target: CliphistService + // // Use the function syntax for on + // function onListCompleted() { + // // Only refresh if the clipboard plugin is active + // if (launcher && launcher.activePlugin === root) { + // launcher.updateResults() + // } + // } + // } + // Initialize plugin function init() { Logger.log("ClipboardPlugin", "Initialized") @@ -121,40 +132,22 @@ QtObject { return results } - // Helper: Format image clipboard entry with actual image data + // Helper: Format image clipboard entry function formatImageEntry(item) { const meta = parseImageMeta(item.preview) - // Get the actual image data/path from the clipboard service - // This assumes CliphistService provides either a path or base64 data - let imageData = null - - // Try to get image data from the service - // Method 1: If the service provides a file path - if (item.imagePath) { - imageData = "file://" + item.imagePath - } // Method 2: If the service provides base64 data - else if (item.imageData) { - imageData = ClipHistService.getImageData(item.id) - - // "data:" + (item.mime || "image/png") + ";base64," + item.imageData - } // Method 3: If we need to fetch it from the service - - // else if (item.id) { - // // Some clipboard services might require fetching the image separately - // // This would depend on your CliphistService implementation - // imageData = CliphistService.getImageData ? CliphistService.getImageData(item.id) : null - // } + // The launcher's delegate will now be responsible for fetching the image data. + // This function's role is to provide the necessary metadata for that request. return { "name": meta ? `Image ${meta.w}×${meta.h}` : "Image", "description": meta ? `${meta.fmt} • ${meta.size}` : item.mime || "Image data", "icon": "image", "isImage": true, - "imageSource": imageData, "imageWidth": meta ? meta.w : 0, "imageHeight": meta ? meta.h : 0, - "clipboardId"// Add clipboard item ID for potential async loading - : item.id + "clipboardId"// Provide the ID and mime type for the delegate to make an async request + : item.id, + "mime": item.mime } } @@ -185,7 +178,7 @@ QtObject { return { "name": title, "description": description, - "icon": "description", + "icon": "text-x-generic", "isImage": false } } diff --git a/Services/CliphistService.qml b/Services/CliphistService.qml index 60b9a34..e521369 100644 --- a/Services/CliphistService.qml +++ b/Services/CliphistService.qml @@ -39,6 +39,8 @@ Singleton { property string _b64CurrentMime: "" property string _b64CurrentId: "" + signal listCompleted() + // Check if cliphist is available Component.onCompleted: { checkCliphistAvailability() @@ -147,6 +149,9 @@ Singleton { }) items = parsed loading = false + + // Emit the signal for subscribers + root.listCompleted() } } @@ -285,10 +290,12 @@ Singleton { } function getImageData(id) { + if (id === undefined) { + return null + } return root.imageDataById[id] } - function _startNextB64() { if (root._b64Queue.length === 0 || !root.cliphistAvailable) return