summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2025-08-17 15:36:54 +0800
committerlittleblack111 <littleblack11111@gmail.com>2025-08-19 20:15:21 +0800
commit17b0230ea1fb6cb36b75ef4544fd09222d689e81 (patch)
treed767df4546bb40442a704c6c6bfb659f17155c99
parent25ff04a807bb30050ea1a5e34f0ff3dfc7d3f0f3 (diff)
feat(Clip): preview
-rw-r--r--launcher/components/Clip.qml149
-rw-r--r--services/Clip.qml46
2 files changed, 135 insertions, 60 deletions
diff --git a/launcher/components/Clip.qml b/launcher/components/Clip.qml
index 3217646..23e48a9 100644
--- a/launcher/components/Clip.qml
+++ b/launcher/components/Clip.qml
@@ -73,70 +73,111 @@ IComponent {
width: parent.width
height: Math.min(listView.contentHeight + titleBar.height, Launcher.widgetHeight * 1.5)
- ListView {
- id: listView
+ RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
- clip: true
- model: clipHist
- spacing: 0
-
- delegate: Item {
- required property var modelData
- required property int index
- width: item.implicitWidth + Launcher.innerMargin * 4
- height: item.height + Launcher.innerMargin * 4
-
- Row {
- id: item
- anchors.left: parent.left
- anchors.top: parent.top
- anchors.margins: Launcher.innerMargin * 2
- spacing: Launcher.innerMargin * 2
-
- IconImage {
- source: modelData?.appIcon
- implicitSize: parent.height
- }
-
- Column {
- Loader {
- sourceComponent: modelData?.type === "image" ? img : text
- readonly property Component text: IText {
- text: modelData?.data || ""
- font.pixelSize: Style.font.size.largerr
- }
- readonly property Component img: Image {
- source: modelData?.data || ""
- }
+ ListView {
+ id: listView
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ clip: true
+ model: clipHist
+ spacing: 0
+
+ delegate: Item {
+ required property var modelData
+ required property int index
+ width: item.implicitWidth + Launcher.innerMargin * 4
+ height: item.height + Launcher.innerMargin * 4
+
+ Row {
+ id: item
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.margins: Launcher.innerMargin * 2
+ spacing: Launcher.innerMargin * 2
+
+ IconImage {
+ source: modelData?.appIcon
+ implicitSize: parent.height
}
- Row {
- spacing: Launcher.innerMargin
- IText {
- text: modelData.type
- color: Colors.foreground3
- font.pixelSize: Style.font.size.normal
+
+ Column {
+ Loader {
+ sourceComponent: modelData?.type === "image" ? img : text
+ readonly property Component text: IText {
+ text: modelData?.data || ""
+ font.pixelSize: Style.font.size.largerr
+ }
+ readonly property Component img: Image {
+ source: modelData?.data || ""
+ }
}
- IText {
- text: TimeDate.sinceWhen(modelData?.timestamp) || ""
- color: Colors.foreground3
- font.pixelSize: Style.font.size.normal
+ Row {
+ spacing: Launcher.innerMargin
+ property string sinceWhen: TimeDate.sinceWhen(modelData?.timestamp) || ""
+ IText {
+ text: modelData.type
+ color: Colors.foreground3
+ font.pixelSize: Style.font.size.normal
+ }
+ IText {
+ visible: parent.sinceWhen
+ text: 'ยท'
+ color: Colors.foreground3
+ font.pixelSize: Style.font.size.normal
+ }
+ IText {
+ text: parent.sinceWhen || ""
+ color: Colors.foreground3
+ font.pixelSize: Style.font.size.normal
+ }
}
}
}
- }
- MouseArea {
- anchors.fill: parent
- hoverEnabled: true
- onPositionChanged: {
- root.selectedIndex = index;
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onPositionChanged: {
+ root.selectedIndex = index;
+ }
+ onExited: {
+ root.selectedIndex = 0;
+ }
+ onPressed: {
+ root.exec();
+ }
}
- onExited: {
- root.selectedIndex = 0;
+ }
+ }
+ Flickable {
+ id: preview
+ clip: true
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ contentWidth: loader.item.width
+ contentHeight: loader.item.height
+ flickableDirection: Flickable.VerticalFlick
+ boundsBehavior: Flickable.StopAtBounds
+
+ Loader {
+ id: loader
+ sourceComponent: clipHist[selectedIndex]?.type === "image" ? img : text
+ property Component text: TextEdit {
+ id: textEdit
+ width: preview.width
+ color: Colors.foreground1
+ selectionColor: Colors.background3
+ text: clipHist[selectedIndex]?.decoded
}
- onPressed: {
- root.exec();
+ property Component img: Image {
+ id: image
+ width: preview.width
+ height: preview.height
+ source: clipHist[selectedIndex]?.image || ""
+ fillMode: Image.PreserveAspectFit
}
}
}
diff --git a/services/Clip.qml b/services/Clip.qml
index 4b289a0..734e2f2 100644
--- a/services/Clip.qml
+++ b/services/Clip.qml
@@ -18,8 +18,8 @@ Searchable {
property list<string> _clipHist: []
property list<string> _clipImg: []
property list<string> _clipImgIds: _clipImg.map(p => p.split("/").pop().split(".").shift())
-
property var _clipMetadata: ({})
+ property var _clipDecoded: ({})
function getType(text: string): string {
if (!text)
@@ -42,7 +42,7 @@ Searchable {
return map;
}, {});
- return _clipHist.filter(raw => raw).map(raw => {
+ return _clipHist.filter(raw => raw).map((raw, idx) => {
const tab = raw.indexOf("\t");
let idNum = -1;
let payload = raw;
@@ -89,9 +89,6 @@ Searchable {
}
root._clipMetadata = meta;
}
- // fileView.onAdapterUpdated: {
- // root._clipMetadata = adapter.metadata;
- // }
}
on_ClipMetadataChanged: {
@@ -112,6 +109,7 @@ Searchable {
function _update() {
clipProc.running = true;
+ clipDecodeProc.running = true;
imgProc.running = true;
}
@@ -130,7 +128,7 @@ Searchable {
const idStr = firstLine.slice(0, tab);
const n = parseInt(idStr, 10);
if (!Number.isNaN(n)) {
- var newMetadata = {};
+ let newMetadata = {};
for (var k in _clipMetadata) {
if (_clipMetadata.hasOwnProperty(k))
newMetadata[k] = _clipMetadata[k];
@@ -173,6 +171,42 @@ Searchable {
}
Process {
+ id: clipDecodeProc
+ property var tmp: ({})
+ property int index: 0
+ running: true
+ command: ["sh", "-c", 'cliphist list | while IFS= read -r line; do\n' + ' cliphist decode "$line"; ' + 'printf "THIS IS A SEPERATOR 123 -----";\n' + 'done']
+ onStarted: {
+ clipDecodeProc.tmp = [];
+ clipDecodeProc.index = 0;
+ }
+ onExited: {
+ if (clipDecodeProc.tmp)
+ root._clipDecoded = clipDecodeProc.tmp;
+ }
+ stdout: SplitParser {
+ onRead: data => {
+ data = data += '\n';
+ if (data.includes("THIS IS A SEPERATOR 123 -----")) {
+ const split = data.split("THIS IS A SEPERATOR 123 -----");
+ const first = split[0] || "";
+ const second = split[1] || "";
+ if (first)
+ clipDecodeProc.tmp[clipDecodeProc.index] += first;
+ clipDecodeProc.index++;
+ if (second)
+ clipDecodeProc.tmp[clipDecodeProc.index] = second;
+ return;
+ }
+ if (!clipDecodeProc.tmp[clipDecodeProc.index])
+ clipDecodeProc.tmp[clipDecodeProc.index] = data;
+ else
+ clipDecodeProc.tmp[clipDecodeProc.index] += data;
+ }
+ }
+ }
+
+ Process {
id: imgProc
running: true
command: ["sh", Quickshell.shellDir + "/utils/cliphist-img.sh"]