|
|
|
@ -1,47 +1,52 @@ |
|
|
|
|
#include <QFile> |
|
|
|
|
#include <QLabel> |
|
|
|
|
#include <QVBoxLayout> |
|
|
|
|
#include <QHBoxLayout> |
|
|
|
|
#include <QJsonObject> |
|
|
|
|
#include <QJsonDocument> |
|
|
|
|
#include <QDebug> |
|
|
|
|
|
|
|
|
|
#include "offroad_alerts.hpp" |
|
|
|
|
#include "common/params.h" |
|
|
|
|
#include "selfdrive/hardware/hw.h" |
|
|
|
|
|
|
|
|
|
void cleanStackedWidget(QStackedWidget* swidget) { |
|
|
|
|
while(swidget->count() > 0) { |
|
|
|
|
QWidget *w = swidget->widget(0); |
|
|
|
|
swidget->removeWidget(w); |
|
|
|
|
w->deleteLater(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#include "selfdrive/common/util.h" |
|
|
|
|
|
|
|
|
|
OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { |
|
|
|
|
QVBoxLayout *main_layout = new QVBoxLayout(); |
|
|
|
|
main_layout->setMargin(25); |
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(); |
|
|
|
|
layout->setMargin(50); |
|
|
|
|
|
|
|
|
|
// setup labels for each alert
|
|
|
|
|
QString json = QString::fromStdString(util::read_file("../controls/lib/alerts_offroad.json")); |
|
|
|
|
QJsonObject obj = QJsonDocument::fromJson(json.toUtf8()).object(); |
|
|
|
|
for (auto &k : obj.keys()) { |
|
|
|
|
QLabel *l = new QLabel(this); |
|
|
|
|
alerts[k.toStdString()] = l; |
|
|
|
|
int severity = obj[k].toObject()["severity"].toInt(); |
|
|
|
|
|
|
|
|
|
l->setMargin(60); |
|
|
|
|
l->setWordWrap(true); |
|
|
|
|
l->setStyleSheet("background-color: " + QString(severity ? "#E22C2C" : "#292929")); |
|
|
|
|
l->setVisible(false); |
|
|
|
|
layout->addWidget(l); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
alerts_stack = new QStackedWidget(); |
|
|
|
|
main_layout->addWidget(alerts_stack, 1); |
|
|
|
|
// release notes
|
|
|
|
|
releaseNotes.setVisible(false); |
|
|
|
|
releaseNotes.setStyleSheet("font-size: 48px;"); |
|
|
|
|
layout->addWidget(&releaseNotes); |
|
|
|
|
|
|
|
|
|
// bottom footer
|
|
|
|
|
// bottom footer, dismiss + reboot buttons
|
|
|
|
|
QHBoxLayout *footer_layout = new QHBoxLayout(); |
|
|
|
|
main_layout->addLayout(footer_layout); |
|
|
|
|
layout->addLayout(footer_layout); |
|
|
|
|
|
|
|
|
|
QPushButton *dismiss_btn = new QPushButton("Dismiss"); |
|
|
|
|
dismiss_btn->setFixedSize(400, 125); |
|
|
|
|
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignLeft); |
|
|
|
|
|
|
|
|
|
reboot_btn = new QPushButton("Reboot and Update"); |
|
|
|
|
reboot_btn->setFixedSize(600, 125); |
|
|
|
|
reboot_btn->setVisible(false); |
|
|
|
|
footer_layout->addWidget(reboot_btn, 0, Qt::AlignRight); |
|
|
|
|
|
|
|
|
|
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); |
|
|
|
|
QObject::connect(dismiss_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); |
|
|
|
|
QObject::connect(reboot_btn, &QPushButton::released, [=]() { Hardware::reboot(); }); |
|
|
|
|
|
|
|
|
|
setLayout(main_layout); |
|
|
|
|
rebootBtn.setText("Reboot and Update"); |
|
|
|
|
rebootBtn.setFixedSize(600, 125); |
|
|
|
|
rebootBtn.setVisible(false); |
|
|
|
|
footer_layout->addWidget(&rebootBtn, 0, Qt::AlignBottom | Qt::AlignRight); |
|
|
|
|
QObject::connect(&rebootBtn, &QPushButton::released, [=]() { Hardware::reboot(); }); |
|
|
|
|
|
|
|
|
|
setLayout(layout); |
|
|
|
|
setStyleSheet(R"( |
|
|
|
|
* { |
|
|
|
|
font-size: 48px; |
|
|
|
@ -58,54 +63,33 @@ OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) { |
|
|
|
|
background-color: white; |
|
|
|
|
} |
|
|
|
|
)"); |
|
|
|
|
main_layout->setMargin(50); |
|
|
|
|
|
|
|
|
|
QFile inFile("../controls/lib/alerts_offroad.json"); |
|
|
|
|
bool ret = inFile.open(QIODevice::ReadOnly | QIODevice::Text); |
|
|
|
|
assert(ret); |
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(inFile.readAll()); |
|
|
|
|
assert(!doc.isNull()); |
|
|
|
|
alert_keys = doc.object().keys(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OffroadAlert::refresh() { |
|
|
|
|
parse_alerts(); |
|
|
|
|
cleanStackedWidget(alerts_stack); |
|
|
|
|
|
|
|
|
|
updateAvailable = Params().read_db_bool("UpdateAvailable"); |
|
|
|
|
reboot_btn->setVisible(updateAvailable); |
|
|
|
|
updateAlerts(); |
|
|
|
|
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout; |
|
|
|
|
layout->setSpacing(20); |
|
|
|
|
rebootBtn.setVisible(updateAvailable); |
|
|
|
|
releaseNotes.setVisible(updateAvailable); |
|
|
|
|
releaseNotes.setText(QString::fromStdString(params.get("ReleaseNotes"))); |
|
|
|
|
|
|
|
|
|
if (updateAvailable) { |
|
|
|
|
QLabel *body = new QLabel(QString::fromStdString(Params().get("ReleaseNotes"))); |
|
|
|
|
body->setStyleSheet(R"(font-size: 48px;)"); |
|
|
|
|
layout->addWidget(body, 0, Qt::AlignLeft | Qt::AlignTop); |
|
|
|
|
} else { |
|
|
|
|
for (const auto &alert : alerts) { |
|
|
|
|
QLabel *l = new QLabel(alert.text); |
|
|
|
|
l->setMargin(60); |
|
|
|
|
l->setWordWrap(true); |
|
|
|
|
l->setStyleSheet("background-color: " + QString(alert.severity ? "#E22C2C" : "#292929")); |
|
|
|
|
layout->addWidget(l, 0, Qt::AlignTop); |
|
|
|
|
} |
|
|
|
|
for (const auto& [k, label] : alerts) { |
|
|
|
|
label->setVisible(!updateAvailable && !label->text().isEmpty()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QWidget *w = new QWidget(); |
|
|
|
|
w->setLayout(layout); |
|
|
|
|
alerts_stack->addWidget(w); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void OffroadAlert::parse_alerts() { |
|
|
|
|
alerts.clear(); |
|
|
|
|
for (const QString &key : alert_keys) { |
|
|
|
|
std::vector<char> bytes = Params().read_db_bytes(key.toStdString().c_str()); |
|
|
|
|
void OffroadAlert::updateAlerts() { |
|
|
|
|
alertCount = 0; |
|
|
|
|
updateAvailable = params.read_db_bool("UpdateAvailable"); |
|
|
|
|
for (const auto& [key, label] : alerts) { |
|
|
|
|
auto bytes = params.read_db_bytes(key.c_str()); |
|
|
|
|
if (bytes.size()) { |
|
|
|
|
QJsonDocument doc_par = QJsonDocument::fromJson(QByteArray(bytes.data(), bytes.size())); |
|
|
|
|
QJsonObject obj = doc_par.object(); |
|
|
|
|
Alert alert = {obj.value("text").toString(), obj.value("severity").toInt()}; |
|
|
|
|
alerts.push_back(alert); |
|
|
|
|
label->setText(obj.value("text").toString()); |
|
|
|
|
alertCount++; |
|
|
|
|
} else { |
|
|
|
|
label->setText(""); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|