Refactor AppLauncher, fix clipboardhistory, add persistent history (max 50 entries), add advanced math stuff
This commit is contained in:
parent
7ce8e51fa3
commit
044da17763
5 changed files with 690 additions and 263 deletions
|
|
@ -11,12 +11,40 @@ Singleton {
|
|||
|
||||
property var history: []
|
||||
property bool initialized: false
|
||||
property int maxHistory: 50 // Limit clipboard history entries
|
||||
|
||||
// Internal state
|
||||
property bool _enabled: true
|
||||
|
||||
// Cached history file path
|
||||
property string historyFile: Quickshell.env("NOCTALIA_CLIPBOARD_HISTORY_FILE")
|
||||
|| (Settings.cacheDir + "clipboard.json")
|
||||
|
||||
// Persisted storage for clipboard history
|
||||
property FileView historyFileView: FileView {
|
||||
id: historyFileView
|
||||
objectName: "clipboardHistoryFileView"
|
||||
path: historyFile
|
||||
watchChanges: false // We don't need to watch changes for clipboard
|
||||
onAdapterUpdated: writeAdapter()
|
||||
Component.onCompleted: reload()
|
||||
onLoaded: loadFromHistory()
|
||||
onLoadFailed: function (error) {
|
||||
// Create file on first use
|
||||
if (error.toString().includes("No such file") || error === 2) {
|
||||
writeAdapter()
|
||||
}
|
||||
}
|
||||
|
||||
JsonAdapter {
|
||||
id: historyAdapter
|
||||
property var history: []
|
||||
property double timestamp: 0
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
interval: 2000
|
||||
repeat: true
|
||||
running: root._enabled
|
||||
onTriggered: root.refresh()
|
||||
|
|
@ -32,14 +60,17 @@ Singleton {
|
|||
if (exitCode === 0) {
|
||||
currentTypes = String(stdout.text).trim().split('\n').filter(t => t)
|
||||
|
||||
// Always check for text first
|
||||
textProcess.command = ["wl-paste", "-n", "--type", "text/plain"]
|
||||
textProcess.isLoading = true
|
||||
textProcess.running = true
|
||||
|
||||
// Also check for images if available
|
||||
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
|
||||
|
|
@ -65,17 +96,31 @@ Singleton {
|
|||
"timestamp": new Date().getTime()
|
||||
}
|
||||
|
||||
// Check if this exact image already exists
|
||||
const exists = root.history.find(item => item.type === 'image' && item.data === entry.data)
|
||||
if (!exists) {
|
||||
root.history = [entry, ...root.history].slice(0, 20)
|
||||
// Normalize existing history and add the new image
|
||||
const normalizedHistory = root.history.map(item => {
|
||||
if (typeof item === 'string') {
|
||||
return {
|
||||
"type": 'text',
|
||||
"content": item,
|
||||
"timestamp": new Date().getTime() - 1000 // Make it slightly older
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
root.history = [entry, ...normalizedHistory].slice(0, maxHistory)
|
||||
saveHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always mark as initialized when done
|
||||
if (!textProcess.isLoading) {
|
||||
root.initialized = true
|
||||
typeProcess.isLoading = false
|
||||
}
|
||||
typeProcess.isLoading = false
|
||||
}
|
||||
|
||||
stdout: StdioCollector {}
|
||||
|
|
@ -87,15 +132,18 @@ Singleton {
|
|||
property bool isLoading: false
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
textProcess.isLoading = false
|
||||
|
||||
if (exitCode === 0) {
|
||||
const content = String(stdout.text).trim()
|
||||
if (content) {
|
||||
if (content && content.length > 0) {
|
||||
const entry = {
|
||||
"type": 'text',
|
||||
"content": content,
|
||||
"timestamp": new Date().getTime()
|
||||
}
|
||||
|
||||
// Check if this exact text content already exists
|
||||
const exists = root.history.find(item => {
|
||||
if (item.type === 'text') {
|
||||
return item.content === content
|
||||
|
|
@ -104,36 +152,75 @@ Singleton {
|
|||
})
|
||||
|
||||
if (!exists) {
|
||||
const newHistory = root.history.map(item => {
|
||||
if (typeof item === 'string') {
|
||||
return {
|
||||
"type": 'text',
|
||||
"content": item,
|
||||
"timestamp": new Date().getTime()
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
// Normalize existing history entries
|
||||
const normalizedHistory = root.history.map(item => {
|
||||
if (typeof item === 'string') {
|
||||
return {
|
||||
"type": 'text',
|
||||
"content": item,
|
||||
"timestamp": new Date().getTime() - 1000 // Make it slightly older
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
root.history = [entry, ...newHistory].slice(0, 20)
|
||||
root.history = [entry, ...normalizedHistory].slice(0, maxHistory)
|
||||
saveHistory()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
textProcess.isLoading = false
|
||||
}
|
||||
|
||||
// Mark as initialized and clean up loading states
|
||||
root.initialized = true
|
||||
typeProcess.isLoading = false
|
||||
if (!imageProcess.running) {
|
||||
typeProcess.isLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
stdout: StdioCollector {}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (!typeProcess.isLoading && !textProcess.isLoading) {
|
||||
if (!typeProcess.isLoading && !textProcess.isLoading && !imageProcess.running) {
|
||||
typeProcess.isLoading = true
|
||||
typeProcess.command = ["wl-paste", "-l"]
|
||||
typeProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromHistory() {
|
||||
// Populate in-memory history from cached file
|
||||
try {
|
||||
const items = historyAdapter.history || []
|
||||
root.history = items.slice(0, maxHistory) // Apply limit when loading
|
||||
Logger.log("Clipboard", "Loaded", root.history.length, "entries from cache")
|
||||
} catch (e) {
|
||||
Logger.error("Clipboard", "Failed to load history:", e)
|
||||
root.history = []
|
||||
}
|
||||
}
|
||||
|
||||
function saveHistory() {
|
||||
try {
|
||||
// Ensure we don't exceed the maximum history limit
|
||||
const limitedHistory = root.history.slice(0, maxHistory)
|
||||
|
||||
historyAdapter.history = limitedHistory
|
||||
historyAdapter.timestamp = Time.timestamp
|
||||
|
||||
// Ensure cache directory exists
|
||||
Quickshell.execDetached(["mkdir", "-p", Settings.cacheDir])
|
||||
|
||||
Qt.callLater(function () {
|
||||
historyFileView.writeAdapter()
|
||||
})
|
||||
} catch (e) {
|
||||
Logger.error("Clipboard", "Failed to save history:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
root.history = []
|
||||
saveHistory()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue