diff options
Diffstat (limited to 'desktop/assistant/Card.qml')
| -rw-r--r-- | desktop/assistant/Card.qml | 85 |
1 files changed, 80 insertions, 5 deletions
diff --git a/desktop/assistant/Card.qml b/desktop/assistant/Card.qml index f63ce59..02ee476 100644 --- a/desktop/assistant/Card.qml +++ b/desktop/assistant/Card.qml @@ -9,10 +9,12 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +import Quickshell import QtQuick import ".." import "Files.js" as Files import "Presets.js" as Presets +import "Ops.js" as Ops // The card in its three states (Assistant.qml, mode): entry is the input // line alone; file adds the staged chips and what can be done with them; @@ -33,6 +35,8 @@ Rectangle { height: card.tall ? card.fullHeight : footer.height + 28 + (chips.visible ? chips.height + 10 : 0) + (asks.visible ? asks.height + 10 : 0) + + (dos.visible ? dos.height + 10 : 0) + + (status.visible ? status.height + 10 : 0) + (actions.visible ? actions.height + 10 : 0) Behavior on height { NumberAnimation { duration: 180; easing.type: Easing.OutCubic } } clip: true @@ -153,7 +157,8 @@ Rectangle { id: chips visible: card.canvas.staged.length > 0 anchors { - bottom: asks.visible ? asks.top : actions.visible ? actions.top : footer.top + bottom: asks.visible ? asks.top : dos.visible ? dos.top : status.visible ? status.top + : actions.visible ? actions.top : footer.top bottomMargin: 10 left: parent.left; right: parent.right; leftMargin: 14; rightMargin: 14 } @@ -198,15 +203,14 @@ Rectangle { // --- what to do with them (file) --- // Ask: canned questions matching the staged kinds (Presets.js). A click - // sends one; Shift+click puts it in the input to edit first. The Do row - // (local operations) is its own spec and lands here too. + // sends one; Shift+click puts it in the input to edit first. Flow { id: asks readonly property var offered: Presets.offered(Presets.list(Prefs.presets), card.canvas.staged) - visible: card.mode === "file" && offered.length > 0 + visible: card.mode === "file" && offered.length > 0 && !card.canvas.opRunning anchors { - bottom: actions.top; bottomMargin: 10 + bottom: dos.visible ? dos.top : status.visible ? status.top : actions.top; bottomMargin: 10 left: parent.left; right: parent.right; leftMargin: 14; rightMargin: 14 } spacing: 8 @@ -230,6 +234,77 @@ Rectangle { } } + // Do: local operations (Ops.js, run by fileops or the daemon's write). + // Compress… swaps the row for its formats. Hidden while one runs. + property bool compressing: false + Connections { target: card.canvas; function onStagedChanged() { card.compressing = false; } } + + Flow { + id: dos + readonly property var offered: card.compressing + ? Ops.COMPRESS.concat([{ label: "Back", op: "back" }]) + : Ops.offered(card.canvas.staged) + visible: card.mode === "file" && offered.length > 0 && !card.canvas.opRunning + anchors { + bottom: status.visible ? status.top : actions.top; bottomMargin: 10 + left: parent.left; right: parent.right; leftMargin: 14; rightMargin: 14 + } + spacing: 8 + + Repeater { + model: dos.offered + Button { + required property var modelData + text: modelData.label + // Local operations need no daemon; To .md does. + enabled: modelData.op !== "md" || card.canvas.connected + onClicked: { + if (modelData.op === "compress") card.compressing = true; + else if (modelData.op === "back") card.compressing = false; + else { card.compressing = false; card.canvas.runOp(modelData); } + } + } + } + } + + // What the operation is doing, or what it made. + Row { + id: status + readonly property var c: card.canvas + visible: card.mode === "file" && (c.opRunning || c.opError !== "" || c.opOut.length > 0) + anchors { bottom: actions.top; bottomMargin: 10; left: parent.left; leftMargin: 14 } + spacing: 10 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: status.c.opRunning + ? (status.c.opDaemon && status.c.opChars + ? `${status.c.opLabel}… ${(status.c.opChars / 1000).toFixed(1)}k characters` + : `Working on ${status.c.opLabel}…`) + : status.c.opError !== "" ? status.c.opError + : status.c.opOut.length === 1 ? `Saved ${status.c.opOut[0].slice(status.c.opOut[0].lastIndexOf("/") + 1)}` + : `Saved ${status.c.opOut.length} files` + color: status.c.opError !== "" && !status.c.opRunning ? Theme.red : Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + Button { + visible: status.c.opRunning + text: "Stop" + danger: true + onClicked: status.c.stopOp() + } + Button { + visible: !status.c.opRunning && status.c.opOut.length === 1 + text: "Open" + onClicked: Quickshell.execDetached(["xdg-open", status.c.opOut[0]]) + } + Button { + visible: !status.c.opRunning && status.c.opOut.length > 0 + text: "Folder" + onClicked: Quickshell.execDetached(["xdg-open", status.c.outDir]) + } + } + Row { id: actions visible: card.mode === "file" |
