clipboard history: images

This commit is contained in:
end-4
2025-05-28 00:09:38 +02:00
parent f04d5f6202
commit 442ddc1a7b
6 changed files with 123 additions and 12 deletions
@@ -26,15 +26,16 @@ Singleton {
property string shellConfigName: "config.json"
property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}`
property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`)
property string notificationsPath: `${Directories.cache}/notifications/notifications.json`
property string generatedMaterialThemePath: `${Directories.state}/user/generated/colors.json`
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`)
property string cliphistDecode: FileUtils.trimFileProtocol(`${Directories.cache}/media/cliphist`)
// Cleanup on init
Component.onCompleted: {
Hyprland.dispatch(`exec mkdir -p ${Directories.shellConfig}`)
Hyprland.dispatch(`exec mkdir -p ${favicons}`)
Hyprland.dispatch(`exec rm -rf ${coverArt} && mkdir -p ${coverArt}`)
Hyprland.dispatch(`exec rm -rf '${booruPreviews}' && mkdir -p '${booruPreviews}'`)
Hyprland.dispatch(`exec mkdir -p '${favicons}'`)
Hyprland.dispatch(`exec rm -rf '${coverArt}'; mkdir -p '${coverArt}'`)
Hyprland.dispatch(`exec rm -rf '${booruPreviews}'; mkdir -p '${booruPreviews}'`)
Hyprland.dispatch(`exec mkdir -p '${booruDownloads}' && mkdir -p '${booruDownloadsNsfw}'`)
Hyprland.dispatch(`exec rm -rf ${latexOutput} && mkdir -p ${latexOutput}`)
Hyprland.dispatch(`exec rm -rf '${latexOutput}'; mkdir -p '${latexOutput}'`)
Hyprland.dispatch(`exec rm -rf '${cliphistDecode}'; mkdir -p '${cliphistDecode}'`)
}
}
@@ -0,0 +1,96 @@
import "root:/modules/common"
import "root:/modules/common/widgets"
import "root:/services"
import "root:/modules/common/functions/string_utils.js" as StringUtils
import "root:/modules/common/functions/file_utils.js" as FileUtils
import Qt5Compat.GraphicalEffects
import Qt.labs.platform
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
import Quickshell.Widgets
import Quickshell.Hyprland
Rectangle {
id: root
property string entry
property real maxWidth
property real maxHeight
property string imageDecodePath: Directories.cliphistDecode
property string imageDecodeFileName: `${entryNumber}`
property string imageDecodeFilePath: `${imageDecodePath}/${imageDecodeFileName}`
property string source
property int entryNumber: {
if (!root.entry) return 0
const match = root.entry.match(/^(\d+)\t/)
return match ? parseInt(match[1]) : 0
}
property int imageWidth: {
if (!root.entry) return 0
const match = root.entry.match(/(\d+)x(\d+)/)
return match ? parseInt(match[1]) : 0
}
property int imageHeight: {
if (!root.entry) return 0
const match = root.entry.match(/(\d+)x(\d+)/)
return match ? parseInt(match[2]) : 0
}
property real scale: {
return Math.min(
root.maxWidth / imageWidth,
root.maxHeight / imageHeight
)
}
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
implicitHeight: imageHeight * scale
implicitWidth: imageWidth * scale
Component.onCompleted: {
decodeImageProcess.running = true
}
Process {
id: decodeImageProcess
command: ["bash", "-c",
`[ -f ${imageDecodeFilePath} ] || echo '${StringUtils.shellSingleQuoteEscape(root.entry)}' | cliphist decode > '${imageDecodeFilePath}'`
]
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
root.source = imageDecodeFilePath
} else {
console.error("[CliphistImage] Failed to decode image for entry:", root.entry)
root.source = ""
}
}
}
Image {
id: image
anchors.fill: parent
source: Qt.resolvedUrl(root.source)
fillMode: Image.PreserveAspectFit
antialiasing: true
asynchronous: true
width: root.imageWidth * root.scale
height: root.imageHeight * root.scale
sourceSize.width: width
sourceSize.height: height
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: image.width
height: image.height
radius: root.radius
}
}
}
}