Files
Panama/config/dot/quickshell/modules/capture/IntelligenceResult.qml

409 lines
15 KiB
QML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Focused result sheet for local OCR and code recognition. It is intentionally
// a transient overlay: the user selects pixels, acts on the result, and leaves
// without creating another application window or workspace tile.
import Quickshell
import Quickshell.Wayland
import QtQuick
import qs.config
import qs.services
import qs.widgets
PanelWindow {
id: win
visible: ScreenIntelligence.visible
color: "transparent"
exclusiveZone: 0
anchors {
top: true
bottom: true
left: true
right: true
}
WlrLayershell.namespace: "qs-screen-intelligence"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
onVisibleChanged: {
if (visible)
keyboardScope.forceActiveFocus();
else
copied = false;
}
property bool copied: false
Timer {
id: copiedTimer
interval: 1500
onTriggered: win.copied = false
}
FocusScope {
id: keyboardScope
anchors.fill: parent
focus: true
Keys.onEscapePressed: event => {
ScreenIntelligence.close();
event.accepted = true;
}
Rectangle {
anchors.fill: parent
color: Theme.alpha(Theme.bgDark, 0.46)
border.width: 0
MouseArea {
anchors.fill: parent
onClicked: ScreenIntelligence.close()
}
}
Rectangle {
id: sheet
anchors.centerIn: parent
width: Math.min(parent.width - 80, 840)
height: Math.min(parent.height - 120, ScreenIntelligence.phase === "ready" ? 680 : 390)
radius: 24
color: Theme.alpha(Theme.bgPopover, 0.965)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.1)
clip: true
PrismEdge {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
inset: sheet.radius
}
MouseArea {
anchors.fill: parent
onClicked: mouse => mouse.accepted = true
}
Column {
id: heading
anchors.left: parent.left
anchors.right: closeButton.left
anchors.top: parent.top
anchors.leftMargin: 28
anchors.topMargin: 25
anchors.rightMargin: 18
spacing: 4
Text {
text: "Screen Intelligence"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeTitle
font.weight: Font.DemiBold
}
Text {
text: {
if (ScreenIntelligence.phase === "capturing")
return "Capturing the selected pixels";
if (ScreenIntelligence.phase === "reading")
return "Reading locally on this computer";
if (ScreenIntelligence.phase === "error")
return "Recognition needs attention";
return "Local text and code recognition";
}
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
}
Rectangle {
id: closeButton
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 20
anchors.rightMargin: 20
width: 34
height: 34
radius: 11
color: closeMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha) : "transparent"
Text {
anchors.centerIn: parent
text: "×"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: 20
}
MouseArea {
id: closeMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: ScreenIntelligence.close()
}
}
Item {
id: body
anchors.left: parent.left
anchors.right: parent.right
anchors.top: heading.bottom
anchors.bottom: actions.top
anchors.leftMargin: 28
anchors.rightMargin: 28
anchors.topMargin: 24
anchors.bottomMargin: 18
Column {
anchors.centerIn: parent
width: Math.min(parent.width, 520)
spacing: 13
visible: ScreenIntelligence.busy
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "󰗊"
color: Theme.accent
font.family: Theme.fontMono
font.pixelSize: 40
}
Text {
width: parent.width
text: ScreenIntelligence.phase === "capturing" ? "Capturing…" : "Reading text and codes…"
color: Theme.fg
horizontalAlignment: Text.AlignHCenter
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Text {
width: parent.width
text: "Pixels stay on this computer. No network request is being made."
color: Theme.fgDim
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
}
Column {
anchors.centerIn: parent
width: Math.min(parent.width, 560)
spacing: 14
visible: ScreenIntelligence.phase === "error"
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "󰅚"
color: Theme.warn
font.family: Theme.fontMono
font.pixelSize: 38
}
Text {
width: parent.width
text: ScreenIntelligence.error
color: Theme.fg
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
}
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
width: commandText.implicitWidth + 28
height: 38
radius: 10
visible: !ScreenIntelligence.ocrReady
color: Theme.alpha(Theme.fg, 0.07)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.08)
Text {
id: commandText
anchors.centerIn: parent
text: "sudo dnf install -y tesseract zbar"
color: Theme.fgDim
font.family: Theme.fontMono
font.pixelSize: Theme.fontSizeSmall
}
}
}
Column {
anchors.fill: parent
spacing: 12
visible: ScreenIntelligence.phase === "ready"
Rectangle {
width: parent.width
height: ScreenIntelligence.codeValue === "" ? 0 : 62
visible: ScreenIntelligence.codeValue !== ""
radius: 13
color: Theme.alpha(Theme.accent, 0.09)
border.width: 1
border.color: Theme.alpha(Theme.accent, 0.2)
Text {
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
text: "󰐲"
color: Theme.accent
font.family: Theme.fontMono
font.pixelSize: 22
}
Column {
anchors.left: parent.left
anchors.leftMargin: 52
anchors.right: codeAction.left
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Text { text: ScreenIntelligence.codeType || "Detected code"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSizeSmall; font.weight: Font.DemiBold }
Text { width: parent.width; text: ScreenIntelligence.codeValue; color: Theme.fgDim; elide: Text.ElideMiddle; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
}
ResultAction {
id: codeAction
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
label: ScreenIntelligence.primaryUrl !== "" ? "Open" : "Copy"
onClicked: {
if (ScreenIntelligence.primaryUrl !== "")
ScreenIntelligence.openDetected();
else
ScreenIntelligence.copyCode();
}
}
}
Rectangle {
width: parent.width
height: parent.height - (ScreenIntelligence.codeValue === "" ? 0 : 74)
radius: 14
color: Theme.alpha(Theme.bgDark, 0.72)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.075)
Text {
anchors.centerIn: parent
width: parent.width - 60
visible: ScreenIntelligence.text === "" && ScreenIntelligence.codeValue === ""
text: "No readable text or code was found. Try a tighter selection with larger, higher-contrast text."
color: Theme.fgDim
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
}
Flickable {
anchors.fill: parent
anchors.margins: 17
visible: ScreenIntelligence.text !== ""
clip: true
contentWidth: width
contentHeight: resultText.implicitHeight
boundsBehavior: Flickable.StopAtBounds
TextEdit {
id: resultText
width: parent.width
text: ScreenIntelligence.text
readOnly: true
selectByMouse: true
wrapMode: TextEdit.Wrap
color: Theme.fg
selectionColor: Theme.accent
selectedTextColor: Theme.bgDark
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
}
}
}
}
}
Row {
id: actions
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 28
anchors.bottomMargin: 24
spacing: 8
visible: ScreenIntelligence.phase === "ready" && (ScreenIntelligence.text !== "" || ScreenIntelligence.codeValue !== "")
ResultAction {
label: "Open link"
visible: ScreenIntelligence.primaryUrl !== "" && ScreenIntelligence.codeValue === ""
onClicked: ScreenIntelligence.openDetected()
}
ResultAction {
label: "Translate"
enabled: ScreenIntelligence.text !== ""
onClicked: ScreenIntelligence.translate()
}
ResultAction {
label: "Search"
enabled: ScreenIntelligence.text !== ""
onClicked: ScreenIntelligence.search()
}
ResultAction {
label: win.copied ? "Copied" : "Copy text"
primary: true
enabled: ScreenIntelligence.text !== ""
onClicked: {
ScreenIntelligence.copyText();
win.copied = true;
copiedTimer.restart();
}
}
}
}
}
component ResultAction: Rectangle {
id: action
property string label: ""
property bool primary: false
property bool enabled: true
signal clicked
implicitWidth: actionLabel.implicitWidth + 26
implicitHeight: 34
radius: 10
opacity: enabled ? 1 : 0.4
color: primary
? (actionMouse.containsMouse ? Theme.mix(Theme.accent, Theme.fg, 0.1) : Theme.accent)
: (actionMouse.containsMouse ? Theme.alpha(Theme.fg, 0.13) : Theme.alpha(Theme.fg, 0.075))
border.width: primary ? 0 : 1
border.color: Theme.alpha(Theme.fg, 0.08)
Text {
id: actionLabel
anchors.centerIn: parent
text: action.label
color: action.primary ? Theme.bgDark : Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
MouseArea {
id: actionMouse
anchors.fill: parent
enabled: action.enabled
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: action.clicked()
}
}
}