feat: v0.1.0 — client Sailfish per hermes-webui con voce
- 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)
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user