feat(profile): selezione del profilo di cui vedere le sessioni (v0.5.0)

- Impostazioni > Sessions: selettore "Profile" (elenco da /api/profiles;
  "(server active)" come prima voce = nessun cookie di profilo)
- ApiClient: fetchProfiles() + switchProfile(); lo switch usa
  /api/profile/switch (process_wide=False lato server: il cookie firmato
  hermes_profile scopa le richieste dell'app per-client; il profilo attivo
  globale del server non viene toccato); refresh automatico delle sessioni
- CookieJar::removeCookiesByName per l'opzione "(server active)"
- Il profilo scelto viene riapplicato automaticamente dopo il login
- i18n: nuove stringhe tradotte it/fr/de
This commit is contained in:
2026-09-12 22:46:27 +02:00
parent 22ccb49424
commit 7b8e5e1102
15 changed files with 421 additions and 104 deletions
+81
View File
@@ -8,6 +8,9 @@ Page {
// impostazioni (ttsVoices/ttsEngines) e il valore corrente è sempre
// incluso. loading evita di salvare durante il caricamento iniziale.
property bool loading: true
// Feedback del selettore profilo (mostrato sotto il ComboBox).
property string profileStatusText: ""
property bool profileStatusError: false
SilicaFlickable {
anchors.fill: parent
@@ -34,6 +37,34 @@ Page {
}
}
SectionHeader { text: qsTr("Sessions") }
ComboBox {
label: qsTr("Profile")
currentIndex: page.profileIndex()
// Stesso pattern dei selettori voce (Repeater, provato in tide).
menu: ContextMenu {
Repeater {
model: page.profileChoices().length
delegate: MenuItem {
text: page.profileChoices()[index]
onClicked: api.switchProfile(page.profileValue(index))
}
}
}
}
Label {
x: Theme.horizontalPageMargin
width: parent.width - 2 * Theme.horizontalPageMargin
font.pixelSize: Theme.fontSizeExtraSmall
color: page.profileStatusError ? Theme.highlightColor
: Theme.secondaryHighlightColor
wrapMode: Text.WordWrap
visible: text.length > 0
text: page.profileStatusText
}
SectionHeader { text: qsTr("Voice") }
ComboBox {
@@ -160,11 +191,60 @@ Page {
VerticalScrollDecorator {}
}
Connections {
target: api
onProfileSwitched: {
page.profileStatusError = false
page.profileStatusText = name.length > 0
? qsTr("Profile: %1").arg(name)
: qsTr("Server active profile")
statusClear.restart()
}
onProfileSwitchFailed: {
page.profileStatusError = true
page.profileStatusText = error
statusClear.restart()
}
}
Timer {
id: statusClear
interval: 4000
onTriggered: page.profileStatusText = ""
}
function signOut() {
api.logout()
pageStack.replace(Qt.resolvedUrl("LoginPage.qml"))
}
// Valori del selettore profilo: "" (attivo sul server) + profili del
// server (da /api/profiles); il valore corrente e' sempre incluso.
function profileChoices() {
var out = [qsTr("(server active)")]
var list = api.profiles
for (var i = 0; i < list.length; i++)
out.push(list[i])
var cur = appSettings.profile
if (cur.length > 0 && out.indexOf(cur) < 0)
out.push(cur)
return out
}
function profileValue(i) {
if (i <= 0)
return ""
return page.profileChoices()[i]
}
function profileIndex() {
var cur = appSettings.profile
if (cur.length === 0)
return 0
var i = page.profileChoices().indexOf(cur)
return i < 0 ? 0 : i
}
// Elenchi dei selettori: preset configurati + valore corrente (così resta
// selezionabile anche se non è tra i preset). Indice 0 = "(server default)".
function voiceChoices() {
@@ -204,5 +284,6 @@ Page {
voicesField.text = appSettings.ttsVoices.join(", ")
enginesField.text = appSettings.ttsEngines.join(", ")
page.loading = false
api.fetchProfiles()
}
}