139 lines
4 KiB
QML
139 lines
4 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Services
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property var history: []
|
|
property bool initialized: false
|
|
|
|
// Internal state
|
|
property bool _enabled: true
|
|
|
|
Timer {
|
|
interval: 1000
|
|
repeat: true
|
|
running: root._enabled
|
|
onTriggered: root.refresh()
|
|
}
|
|
|
|
// Detect current clipboard types (text/image)
|
|
Process {
|
|
id: typeProcess
|
|
property bool isLoading: false
|
|
property var currentTypes: []
|
|
|
|
onExited: (exitCode, exitStatus) => {
|
|
if (exitCode === 0) {
|
|
currentTypes = String(stdout.text).trim().split('\n').filter(t => t)
|
|
|
|
const imageType = currentTypes.find(t => t.startsWith('image/'))
|
|
if (imageType) {
|
|
imageProcess.mimeType = imageType
|
|
imageProcess.command = ["sh", "-c", `wl-paste -n -t "${imageType}" | base64 -w 0`]
|
|
imageProcess.running = true
|
|
} else {
|
|
textProcess.command = ["wl-paste", "-n", "--type", "text/plain"]
|
|
textProcess.running = true
|
|
}
|
|
} else {
|
|
typeProcess.isLoading = false
|
|
}
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
}
|
|
|
|
// Read image data
|
|
Process {
|
|
id: imageProcess
|
|
property string mimeType: ""
|
|
|
|
onExited: (exitCode, exitStatus) => {
|
|
if (exitCode === 0) {
|
|
const base64 = stdout.text.trim()
|
|
if (base64) {
|
|
const entry = {
|
|
type: 'image',
|
|
mimeType: mimeType,
|
|
data: `data:${mimeType};base64,${base64}`,
|
|
timestamp: new Date().getTime()
|
|
}
|
|
|
|
const exists = root.history.find(item => item.type === 'image' && item.data === entry.data)
|
|
if (!exists) {
|
|
root.history = [entry, ...root.history].slice(0, 20)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!textProcess.isLoading) {
|
|
root.initialized = true
|
|
}
|
|
typeProcess.isLoading = false
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
}
|
|
|
|
// Read text data
|
|
Process {
|
|
id: textProcess
|
|
property bool isLoading: false
|
|
|
|
onExited: (exitCode, exitStatus) => {
|
|
if (exitCode === 0) {
|
|
const content = String(stdout.text).trim()
|
|
if (content) {
|
|
const entry = {
|
|
type: 'text',
|
|
content: content,
|
|
timestamp: new Date().getTime()
|
|
}
|
|
|
|
const exists = root.history.find(item => {
|
|
if (item.type === 'text') {
|
|
return item.content === content
|
|
}
|
|
return item === content
|
|
})
|
|
|
|
if (!exists) {
|
|
const newHistory = root.history.map(item => {
|
|
if (typeof item === 'string') {
|
|
return {
|
|
type: 'text',
|
|
content: item,
|
|
timestamp: new Date().getTime()
|
|
}
|
|
}
|
|
return item
|
|
})
|
|
|
|
root.history = [entry, ...newHistory].slice(0, 20)
|
|
}
|
|
}
|
|
} else {
|
|
textProcess.isLoading = false
|
|
}
|
|
|
|
root.initialized = true
|
|
typeProcess.isLoading = false
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
}
|
|
|
|
function refresh() {
|
|
if (!typeProcess.isLoading && !textProcess.isLoading) {
|
|
typeProcess.isLoading = true
|
|
typeProcess.command = ["wl-paste", "-l"]
|
|
typeProcess.running = true
|
|
}
|
|
}
|
|
}
|
|
|