- ApiClient HTTP/SSE: login, sessioni, chat/start, stream SSE, transcribe, tts - ChatModel: streaming live + risincronizzazione dallo stato del server - CookieJar persistente (0600, mai la password); Settings - Recorder OGG/Opus (fallback WAV/PCM, retry); Player TTS (QMediaPlayer) - UI Silica: splash, login, sessioni, chat (dettatura + read-aloud), settings, cover - Sailjail Internet;Audio;Microphone; icone; spec RPM; docs PROTOCOL/BUILD - tests/core_test: unit parser SSE + integrazione live (probe :8899)
116 lines
3.4 KiB
QML
116 lines
3.4 KiB
QML
import QtQuick 2.0
|
|
import Sailfish.Silica 1.0
|
|
|
|
// Lista delle sessioni della Web UI di Hermes (sidebar).
|
|
Page {
|
|
id: page
|
|
|
|
// true solo quando e' questa pagina a chiedere una nuova sessione:
|
|
// serve a distinguere la creazione dall'apertura di una sessione esistente.
|
|
property bool expectNewSession: false
|
|
|
|
SilicaListView {
|
|
id: list
|
|
anchors.fill: parent
|
|
model: api.sessions
|
|
spacing: Theme.paddingSmall
|
|
|
|
header: PageHeader { title: qsTr("Sessions") }
|
|
|
|
PullDownMenu {
|
|
MenuItem {
|
|
text: qsTr("New session")
|
|
onClicked: page.createSession()
|
|
}
|
|
MenuItem {
|
|
text: qsTr("Refresh")
|
|
onClicked: api.refreshSessions()
|
|
}
|
|
MenuItem {
|
|
text: qsTr("Settings")
|
|
onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"))
|
|
}
|
|
MenuItem {
|
|
text: qsTr("Sign out")
|
|
onClicked: api.logout()
|
|
}
|
|
}
|
|
|
|
delegate: ListItem {
|
|
id: item
|
|
contentHeight: col.height + Theme.paddingMedium
|
|
|
|
Column {
|
|
id: col
|
|
x: Theme.horizontalPageMargin
|
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: Theme.paddingSmall / 2
|
|
|
|
Label {
|
|
width: parent.width
|
|
truncationMode: TruncationMode.Fade
|
|
color: item.highlighted ? Theme.highlightColor : Theme.primaryColor
|
|
text: ("" + model.title).length > 0 ? model.title : model.session_id
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
text: page.describe(model)
|
|
}
|
|
}
|
|
|
|
onClicked: page.openSession(model.session_id)
|
|
}
|
|
|
|
ViewPlaceholder {
|
|
enabled: api.sessions.length === 0 && !api.busy
|
|
text: qsTr("No sessions")
|
|
hintText: qsTr("Pull down to create a new session")
|
|
}
|
|
|
|
VerticalScrollDecorator {}
|
|
}
|
|
|
|
BusyIndicator {
|
|
anchors.centerIn: parent
|
|
size: BusyIndicatorSize.Large
|
|
running: api.busy
|
|
}
|
|
|
|
Connections {
|
|
target: api
|
|
onLoggedInChanged: {
|
|
if (!api.loggedIn)
|
|
pageStack.replace(Qt.resolvedUrl("LoginPage.qml"))
|
|
}
|
|
onSessionOpened: {
|
|
if (page.expectNewSession) {
|
|
page.expectNewSession = false
|
|
pageStack.push(Qt.resolvedUrl("ChatPage.qml"),
|
|
{ sessionId: api.session.session_id })
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: api.refreshSessions()
|
|
|
|
function openSession(id) {
|
|
expectNewSession = false
|
|
pageStack.push(Qt.resolvedUrl("ChatPage.qml"), { sessionId: id })
|
|
}
|
|
|
|
function createSession() {
|
|
expectNewSession = true
|
|
chat.newSession()
|
|
}
|
|
|
|
function describe(m) {
|
|
var n = m.message_count ? m.message_count : 0
|
|
var d = new Date((m.updated_at ? m.updated_at : 0) * 1000)
|
|
return n + qsTr(" messages") + " · " + Qt.formatDateTime(d, "dd/MM HH:mm")
|
|
}
|
|
}
|