0.7.0: assenza con date, conto alla rovescia del boost, catalogo rifatto

- AwayDialog.qml: popup con inizio e fine (Dialog, ValueButton,
  DatePickerDialog: componenti e proprieta' verificati nella guida Silica
  dell'SDK). Il tasto Assenza apre il popup invece di mandare il comando;
- conto alla rovescia 30:00 -> 00:00 in Home e in copertina, con i secondi
  dell'impianto (AiraJson::countdown + timer che si riallinea a ogni lettura);
- commandPayload accetta campi extra (start/end);
- catalogo: lupdate leggeva solo i C++ e marcava 151 voci QML come obsolete.
  Ora src e qml espliciti: 197 stringhe, 0 non tradotte;
- versione 0.7.0 (spec, main.cpp), PROTOCOL, README/PIANO, post per il forum.
This commit is contained in:
Carlo
2026-10-11 12:05:59 +02:00
parent 6ef6f5bfd8
commit d2cb9d692f
17 changed files with 481 additions and 80 deletions
+51 -2
View File
@@ -53,6 +53,14 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
m_refreshTimer->start();
});
// Un secondo alla volta mentre il boost e' in corso: i secondi veri li da'
// il bridge a ogni rilettura (ogni 30 s), qui si scorre in mezzo.
m_boostActive = false;
m_boostRemaining = 0;
m_boostTimer = new QTimer(this);
m_boostTimer->setInterval(1000);
connect(m_boostTimer, &QTimer::timeout, this, &ApiClient::tickBoost);
if (m_settings) {
// La UI deve riflettere subito il passaggio da "non configurato" a
// "configurato" quando si salvano indirizzo o token.
@@ -186,6 +194,7 @@ void ApiClient::refresh()
return;
}
m_summary = summary;
setBoostFromSummary(summary);
if (m_stale) {
m_stale = false;
emit staleChanged();
@@ -295,14 +304,14 @@ void ApiClient::refreshStats()
});
}
void ApiClient::sendCommand(const QString &id, const QVariant &value)
void ApiClient::sendCommand(const QString &id, const QVariant &value, const QVariantMap &extra)
{
if (!configured()) {
emit commandFinished(false, tr("Set the bridge address and token"));
return;
}
const QByteArray payload = AiraJson::commandPayload(id, value);
const QByteArray payload = AiraJson::commandPayload(id, value, extra);
qDebug() << "[api] comando:" << id; // mai i valori: qui potrebbe passare altro
QNetworkReply *reply = send("POST", QStringLiteral("/command"), payload, 30);
@@ -332,3 +341,43 @@ void ApiClient::sendCommand(const QString &id, const QVariant &value)
refresh(); // i valori letti cambiano: rileggo
});
}
QString ApiClient::boostCountdown() const
{
return AiraJson::countdown(m_boostRemaining);
}
// I secondi veri arrivano dal riassunto: il bridge li ricava dalla FINE del
// boost letta dall'impianto. Il timer li fa solo scorrere fra una lettura e
// l'altra, cosi' il conto non riparte da capo quando si riapre la app (e non
// sbaglia se il boost e' stato avviato da un'altra parte).
void ApiClient::setBoostFromSummary(const QVariantMap &summary)
{
const int restanti = summary.value(QStringLiteral("boost_remaining_seconds")).toInt();
const bool attivo = restanti > 0;
if (!attivo && !m_boostActive && m_boostRemaining == 0) {
m_boostTimer->stop(); // niente da mostrare: non disturbo
return;
}
m_boostRemaining = restanti;
m_boostActive = attivo;
if (attivo)
m_boostTimer->start();
else
m_boostTimer->stop();
emit boostChanged();
}
void ApiClient::tickBoost()
{
if (m_boostRemaining > 0)
--m_boostRemaining;
if (m_boostRemaining <= 0) {
m_boostRemaining = 0;
m_boostActive = false;
m_boostTimer->stop(); // arrivato a 00:00
}
emit boostChanged();
}