This repository has been archived on 2026-08-16. You can view files and clone it, but cannot push or open issues or pull requests.
ollie-kde/gui/main.qml

176 lines
5.2 KiB
QML

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
ApplicationWindow {
id: root
visible: true
width: 1000
height: 600
title: "Ollie"
// Chat tail buffer — only keep last 8KB for display
property string chatTail: ""
readonly property int maxTail: 8192
Component.onCompleted: {
// Load initial log content
var log = ollie.readLog()
if (log.length > maxTail)
log = log.slice(-maxTail)
chatTail = log
}
Connections {
target: ollie
function onChatReceived(text) {
chatTail += text
if (chatTail.length > maxTail * 2) {
chatTail = chatTail.slice(-maxTail)
}
}
function onActiveSessionIdChanged() {
chatTail = ""
var log = ollie.readLog()
if (log.length > maxTail)
log = log.slice(-maxTail)
chatTail = log
}
function onStreamingDone() {
// Session was killed
chatTail += "\n[session ended]\n"
}
}
SplitView {
anchors.fill: parent
// Left pane: session list
ColumnLayout {
SplitView.preferredWidth: 200
SplitView.minimumWidth: 120
spacing: 0
ToolBar {
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
Label { text: "Sessions"; Layout.fillWidth: true; font.bold: true; leftPadding: 8 }
ToolButton {
text: "↻"
onClicked: ollie.refreshSessions()
}
}
}
ListView {
id: sessionList
Layout.fillWidth: true
Layout.fillHeight: true
model: ollie.sessions
clip: true
delegate: ItemDelegate {
width: sessionList.width
text: modelData.id || ""
highlighted: (modelData.id === ollie.activeSessionId)
onClicked: ollie.activeSessionId = modelData.id
Rectangle {
width: 8; height: 8; radius: 4
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
color: {
var s = modelData.state || "idle"
if (s === "idle") return "#4caf50"
if (s.startsWith("calling")) return "#ff9800"
return "#2196f3"
}
}
}
}
}
// Right pane: chat + input
ColumnLayout {
spacing: 0
// Header
RowLayout {
Layout.fillWidth: true
Layout.margins: 6
spacing: 8
Rectangle {
width: 10; height: 10; radius: 5
color: {
if (ollie.activeState === "idle") return "#4caf50"
if (ollie.activeState.startsWith("calling")) return "#ff9800"
return "#2196f3"
}
}
Label {
text: ollie.activeState
opacity: 0.7
font.pixelSize: 11
}
Item { Layout.fillWidth: true }
ToolButton {
text: "Stop"
onClicked: ollie.interrupt()
}
}
Rectangle { Layout.fillWidth: true; height: 1; color: palette.mid }
// Chat display — streaming text, last 8KB
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
TextArea {
id: chatArea
readOnly: true
wrapMode: TextEdit.NoWrap
text: root.chatTail
font.family: "monospace"
font.pixelSize: 12
onTextChanged: cursorPosition = text.length
}
}
Rectangle { Layout.fillWidth: true; height: 1; color: palette.mid }
// Input
RowLayout {
Layout.fillWidth: true
Layout.margins: 6
spacing: 4
TextField {
id: promptInput
Layout.fillWidth: true
placeholderText: ollie.activeSessionId ? "Message..." : "No session"
enabled: ollie.activeSessionId !== ""
onAccepted: {
if (text.trim() !== "") {
ollie.submit(text.trim())
text = ""
}
}
}
Button {
text: "Send"
enabled: promptInput.text.trim() !== "" && ollie.activeSessionId !== ""
onClicked: promptInput.accepted()
}
}
}
}
}