fix(sessions): lista vuota sul device — modello C++ con ruoli (v0.1.2)

Causa: su Qt 5.6 (kit Sailfish 5.1) una QVariantList di QVariantMap
usata come model non fa risolvere i campi nei delegate QML
(model.title/message_count/updated_at = undefined -> righe vuote), pur
con payload corretto dal server (verificato con cattura reale del 12/09).

- Nuovo src/sessionsmodel.{h,cpp}: QAbstractListModel con ruoli
  session_id/title/message_count/updated_at; api.sessions ora e' il
  modello, api.sessionsCount per lo stato "nessuna sessione"
- /api/sessions con sidebar_source=webui&exclude_hidden=1 (come la
  sidebar del browser: solo sessioni WebUI, niente CLI/cron/nascoste)
- SessionsPage: describe(message_count, updated_at) con parametri espliciti
- PROTOCOL.md: payload sessions verificato + nota del pitfall Qt 5.6
This commit is contained in:
2026-09-12 08:47:28 +02:00
parent 98139be96a
commit 479edb0f99
11 changed files with 157 additions and 30 deletions
+16 -3
View File
@@ -15,6 +15,7 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
: QObject(parent)
, m_settings(settings)
, m_jar(new CookieJar(this))
, m_sessionsModel(new SessionsModel(this))
, m_loggedIn(false)
, m_busy(false)
, m_streaming(false)
@@ -170,7 +171,7 @@ void ApiClient::logout()
});
m_jar->clear();
setLoggedIn(false);
m_sessions.clear();
m_sessionsModel->setSessions(QVariantList());
emit sessionsChanged();
m_session.clear();
emit sessionChanged();
@@ -181,7 +182,14 @@ void ApiClient::logout()
void ApiClient::refreshSessions()
{
setBusy(true);
QNetworkReply *reply = m_nam.get(jsonRequest(QStringLiteral("/api/sessions")));
// Stessi parametri della sidebar del WebUI: solo sessioni WebUI visibili
// (senza parametri arriverebbero anche le CLI/cron e le nascoste).
QUrl url = apiUrl(QStringLiteral("/api/sessions"));
QUrlQuery q;
q.addQueryItem(QStringLiteral("sidebar_source"), QStringLiteral("webui"));
q.addQueryItem(QStringLiteral("exclude_hidden"), QStringLiteral("1"));
url.setQuery(q);
QNetworkReply *reply = m_nam.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
reply->deleteLater();
setBusy(false);
@@ -192,11 +200,16 @@ void ApiClient::refreshSessions()
}
const QJsonObject obj = QJsonDocument::fromJson(body).object();
const QJsonArray arr = obj.value(QStringLiteral("sessions")).toArray();
m_sessions = arr.toVariantList();
m_sessionsModel->setSessions(arr.toVariantList());
emit sessionsChanged();
});
}
int ApiClient::sessionsCount() const
{
return m_sessionsModel->rowCount();
}
void ApiClient::openSession(const QString &id)
{
setLastError(QString());
+6 -3
View File
@@ -9,6 +9,7 @@
#include "cookiejar.h"
#include "settings.h"
#include "sessionsmodel.h"
#include "sseparser.h"
class QHttpMultiPart;
@@ -36,7 +37,8 @@ class ApiClient : public QObject
Q_PROPERTY(bool streaming READ streaming NOTIFY streamingChanged)
Q_PROPERTY(bool transcribing READ transcribing NOTIFY transcribingChanged)
Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
Q_PROPERTY(QVariantList sessions READ sessions NOTIFY sessionsChanged)
Q_PROPERTY(SessionsModel *sessions READ sessions NOTIFY sessionsChanged)
Q_PROPERTY(int sessionsCount READ sessionsCount NOTIFY sessionsChanged)
Q_PROPERTY(QVariantMap session READ session NOTIFY sessionChanged)
public:
@@ -47,7 +49,8 @@ public:
bool streaming() const { return m_streaming; }
bool transcribing() const { return m_transcribing; }
QString lastError() const { return m_lastError; }
QVariantList sessions() const { return m_sessions; }
SessionsModel *sessions() const { return m_sessionsModel; }
int sessionsCount() const;
QVariantMap session() const { return m_session; }
// Avvio: verifica lo stato auth (cookie persistito o auth disabilitata).
@@ -119,7 +122,7 @@ private:
bool m_transcribing;
QString m_lastError;
QVariantList m_sessions;
SessionsModel *m_sessionsModel;
QVariantMap m_session;
QString m_streamId;
+52
View File
@@ -0,0 +1,52 @@
#include "sessionsmodel.h"
#include <QVariantMap>
SessionsModel::SessionsModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int SessionsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_rows.size();
}
QVariant SessionsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_rows.size())
return QVariant();
const QVariantMap row = m_rows.at(index.row()).toMap();
switch (role) {
case SessionIdRole:
return row.value(QStringLiteral("session_id"));
case TitleRole:
return row.value(QStringLiteral("title"));
case MessageCountRole:
return row.value(QStringLiteral("message_count"));
case UpdatedAtRole:
return row.value(QStringLiteral("updated_at"));
default:
return QVariant();
}
}
QHash<int, QByteArray> SessionsModel::roleNames() const
{
QHash<int, QByteArray> names;
names[SessionIdRole] = "session_id";
names[TitleRole] = "title";
names[MessageCountRole] = "message_count";
names[UpdatedAtRole] = "updated_at";
return names;
}
void SessionsModel::setSessions(const QVariantList &sessions)
{
beginResetModel();
m_rows = sessions;
endResetModel();
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef SESSIONSMODEL_H
#define SESSIONSMODEL_H
#include <QAbstractListModel>
#include <QVariantList>
// Modello delle sessioni per la lista QML.
//
// Perché non una QVariantList di mappe: sul kit Sailfish 5.1 (Qt 5.6) i campi
// di una QVariantMap dentro una lista non si risolvono nei delegate
// (model.campo = undefined -> righe vuote, pur con dati corretti dal server).
// I ruoli di un QAbstractListModel sono il meccanismo supportato da sempre
// (stesso principio dei ListModel usati con successo negli altri progetti).
class SessionsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
SessionIdRole = Qt::UserRole + 1,
TitleRole,
MessageCountRole,
UpdatedAtRole,
};
explicit SessionsModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
// Sostituisce i dati (reset del modello: la lista QML si aggiorna).
void setSessions(const QVariantList &sessions);
private:
QVariantList m_rows;
};
#endif // SESSIONSMODEL_H