mirror of https://github.com/commaai/openpilot.git
offroad home style (#19593)
* make drive stats look nicer
* offroad alerts style
* rest of alerts
* move that
* fix up colors
Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: ce48d3c91e
This commit is contained in:
parent
30adcbc95e
commit
7dd876805f
|
@ -44,7 +44,7 @@ OffroadHome::OffroadHome(QWidget *parent) : QWidget(parent) {
|
|||
main_layout->addWidget(alert_notification, 0, Qt::AlignTop | Qt::AlignRight);
|
||||
|
||||
// main content
|
||||
main_layout->addSpacing(100);
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
|
||||
DriveStats *drive = new DriveStats;
|
||||
|
|
|
@ -64,7 +64,7 @@ QWidget * toggles_panel() {
|
|||
toggles_list->setSpacing(25);
|
||||
|
||||
toggles_list->addWidget(new ParamsToggle("OpenpilotEnabledToggle",
|
||||
"Enable Openpilot",
|
||||
"Enable openpilot",
|
||||
"Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.",
|
||||
"../assets/offroad/icon_openpilot.png"
|
||||
));
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include <QDebug>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
@ -19,7 +18,9 @@
|
|||
#include "drive_stats.hpp"
|
||||
#include "common/params.h"
|
||||
#include "common/utilpp.h"
|
||||
double MILE_TO_KM = 1.60934;
|
||||
|
||||
|
||||
constexpr double MILE_TO_KM = 1.60934;
|
||||
|
||||
|
||||
#if defined(QCOM) || defined(QCOM2)
|
||||
|
@ -28,7 +29,8 @@ const std::string private_key_path = "/persist/comma/id_rsa";
|
|||
const std::string private_key_path = util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa");
|
||||
#endif
|
||||
|
||||
QByteArray rsa_sign(QByteArray data){
|
||||
|
||||
QByteArray rsa_sign(QByteArray data) {
|
||||
auto file = QFile(private_key_path.c_str());
|
||||
bool r = file.open(QIODevice::ReadOnly);
|
||||
assert(r);
|
||||
|
@ -56,7 +58,7 @@ QByteArray rsa_sign(QByteArray data){
|
|||
return sig;
|
||||
}
|
||||
|
||||
QString create_jwt(QString dongle_id, int expiry=3600){
|
||||
QString create_jwt(QString dongle_id, int expiry=3600) {
|
||||
QJsonObject header;
|
||||
header.insert("alg", "RS256");
|
||||
header.insert("typ", "JWT");
|
||||
|
@ -81,24 +83,27 @@ QString create_jwt(QString dongle_id, int expiry=3600){
|
|||
return jwt;
|
||||
}
|
||||
|
||||
QString bold(QString s) {
|
||||
return "<b>" + s + "</b>";
|
||||
}
|
||||
|
||||
QWidget *widget(QLayout *l){
|
||||
QWidget *q = new QWidget();
|
||||
q->setLayout(l);
|
||||
return q;
|
||||
}
|
||||
|
||||
QWidget *build_stat(QString name, int stat){
|
||||
QLayout *build_stat(QString name, int stat) {
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(new QLabel(bold(QString("%1").arg(stat))), 1, Qt::AlignCenter);
|
||||
layout->addWidget(new QLabel(name),1, Qt::AlignCenter);
|
||||
return widget(layout);
|
||||
|
||||
QLabel *metric = new QLabel(QString("%1").arg(stat));
|
||||
metric->setStyleSheet(R"(
|
||||
font-size: 72px;
|
||||
font-weight: 700;
|
||||
)");
|
||||
layout->addWidget(metric, 0, Qt::AlignLeft);
|
||||
|
||||
QLabel *label = new QLabel(name);
|
||||
label->setStyleSheet(R"(
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
)");
|
||||
layout->addWidget(label, 0, Qt::AlignLeft);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
void DriveStats::replyFinished(QNetworkReply *l){
|
||||
void DriveStats::replyFinished(QNetworkReply *l) {
|
||||
QString answer = l->readAll();
|
||||
answer.chop(1);
|
||||
|
||||
|
@ -116,47 +121,27 @@ void DriveStats::replyFinished(QNetworkReply *l){
|
|||
QGridLayout *gl = new QGridLayout();
|
||||
|
||||
int all_distance = all["distance"].toDouble()*(metric ? MILE_TO_KM : 1);
|
||||
gl->addWidget(new QLabel(bold("ALL TIME")), 0, 0, 1, 3);
|
||||
gl->addWidget(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1);
|
||||
gl->addWidget(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1);
|
||||
gl->addWidget(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1);
|
||||
|
||||
QFrame *lineA = new QFrame;
|
||||
lineA->setFrameShape(QFrame::HLine);
|
||||
lineA->setFrameShadow(QFrame::Sunken);
|
||||
lineA->setProperty("class", "line");
|
||||
gl->addWidget(lineA, 5, 0, 1, 3);
|
||||
gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3);
|
||||
gl->addLayout(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1);
|
||||
gl->addLayout(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1);
|
||||
gl->addLayout(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1);
|
||||
|
||||
int week_distance = week["distance"].toDouble()*(metric ? MILE_TO_KM : 1);
|
||||
gl->addWidget(new QLabel(bold("PAST WEEK")), 6, 0, 1, 3);
|
||||
gl->addWidget(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1);
|
||||
gl->addWidget(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1);
|
||||
gl->addWidget(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1);
|
||||
gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3);
|
||||
gl->addLayout(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1);
|
||||
gl->addLayout(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1);
|
||||
gl->addLayout(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1);
|
||||
|
||||
f->setLayout(gl);
|
||||
f->setStyleSheet(R"(
|
||||
[class="line"] {
|
||||
border: 2px solid white;
|
||||
}
|
||||
[class="outside"] {
|
||||
border-radius: 20px;
|
||||
border: 2px solid white;
|
||||
padding: 10px;
|
||||
}
|
||||
setLayout(gl);
|
||||
setStyleSheet(R"(
|
||||
QLabel {
|
||||
font-size: 70px;
|
||||
font-weight: 200;
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
}
|
||||
)");
|
||||
|
||||
}
|
||||
DriveStats::DriveStats(QWidget *parent) : QWidget(parent) {
|
||||
f = new QFrame;
|
||||
f->setProperty("class", "outside");
|
||||
QVBoxLayout *v = new QVBoxLayout;
|
||||
v->addWidget(f);
|
||||
setLayout(v);
|
||||
|
||||
DriveStats::DriveStats(QWidget *parent) : QWidget(parent) {
|
||||
QString dongle_id = QString::fromStdString(Params().get("DongleId"));
|
||||
QString token = create_jwt(dongle_id);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QWidget>
|
||||
#include <QNetworkReply>
|
||||
|
||||
|
@ -12,6 +11,5 @@ public:
|
|||
explicit DriveStats(QWidget *parent = 0);
|
||||
|
||||
private:
|
||||
QFrame *f;
|
||||
void replyFinished(QNetworkReply *l);
|
||||
};
|
||||
|
|
|
@ -1,130 +1,110 @@
|
|||
#include <QLabel>
|
||||
#include <QFile>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QDebug>
|
||||
|
||||
#include "offroad_alerts.hpp"
|
||||
|
||||
#include "common/params.h"
|
||||
|
||||
|
||||
void cleanLayout(QLayout* layout) {
|
||||
while (QLayoutItem* item = layout->takeAt(0)) {
|
||||
if (QWidget* widget = item->widget()) {
|
||||
widget->deleteLater();
|
||||
}
|
||||
if (QLayout* childLayout = item->layout()) {
|
||||
cleanLayout(childLayout);
|
||||
}
|
||||
delete item;
|
||||
void cleanStackedWidget(QStackedWidget* swidget) {
|
||||
while(swidget->count() > 0) {
|
||||
QWidget *w = swidget->widget(0);
|
||||
swidget->removeWidget(w);
|
||||
w->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QString vectorToQString(std::vector<char> v) {
|
||||
return QString::fromStdString(std::string(v.begin(), v.end()));
|
||||
}
|
||||
|
||||
OffroadAlert::OffroadAlert(QWidget* parent) {
|
||||
vlayout = new QVBoxLayout;
|
||||
refresh();
|
||||
setLayout(vlayout);
|
||||
QVBoxLayout *main_layout = new QVBoxLayout();
|
||||
main_layout->setMargin(25);
|
||||
|
||||
alerts_stack = new QStackedWidget();
|
||||
main_layout->addWidget(alerts_stack, 1);
|
||||
|
||||
// bottom footer
|
||||
QVBoxLayout *footer_layout = new QVBoxLayout();
|
||||
main_layout->addLayout(footer_layout);
|
||||
|
||||
QPushButton *dismiss_btn = new QPushButton("Dismiss");
|
||||
dismiss_btn->setFixedSize(453, 125);
|
||||
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignLeft);
|
||||
QObject::connect(dismiss_btn, SIGNAL(released()), this, SIGNAL(closeAlerts()));
|
||||
|
||||
setLayout(main_layout);
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
QFrame {
|
||||
border-radius: 30px;
|
||||
background-color: #393939;
|
||||
}
|
||||
QPushButton {
|
||||
color: black;
|
||||
font-size: 40px;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
background-color: white;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void OffroadAlert::refresh() {
|
||||
cleanLayout(vlayout);
|
||||
parse_alerts();
|
||||
cleanStackedWidget(alerts_stack);
|
||||
|
||||
updateAvailable = false;
|
||||
std::vector<char> bytes = Params().read_db_bytes("UpdateAvailable");
|
||||
if (bytes.size() && bytes[0] == '1') {
|
||||
updateAvailable = true;
|
||||
}
|
||||
updateAvailable = bytes.size() && bytes[0] == '1';
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
|
||||
if (updateAvailable) {
|
||||
// If there is an update available, don't show alerts
|
||||
alerts.clear();
|
||||
|
||||
QFrame *f = new QFrame();
|
||||
|
||||
QVBoxLayout *update_layout = new QVBoxLayout;
|
||||
update_layout->setMargin(10);
|
||||
update_layout->setSpacing(20);
|
||||
|
||||
QLabel *title = new QLabel("Update available");
|
||||
QLabel *title = new QLabel("Update Available");
|
||||
title->setStyleSheet(R"(
|
||||
font-size: 55px;
|
||||
font-weight: bold;
|
||||
font-size: 72px;
|
||||
font-weight: 700;
|
||||
)");
|
||||
update_layout->addWidget(title, 0, Qt::AlignTop);
|
||||
layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
QString release_notes = QString::fromStdString(Params().get("ReleaseNotes"));
|
||||
QLabel *notes_label = new QLabel(release_notes);
|
||||
notes_label->setStyleSheet(R"(font-size: 40px;)");
|
||||
notes_label->setWordWrap(true);
|
||||
update_layout->addWidget(notes_label, 1, Qt::AlignTop);
|
||||
|
||||
QPushButton *update_button = new QPushButton("Reboot and Update");
|
||||
update_layout->addWidget(update_button);
|
||||
#ifdef __aarch64__
|
||||
QObject::connect(update_button, &QPushButton::released, [=]() {std::system("sudo reboot");});
|
||||
#endif
|
||||
|
||||
f->setLayout(update_layout);
|
||||
f->setStyleSheet(R"(
|
||||
.QFrame{
|
||||
border-radius: 20px;
|
||||
border: 2px solid white;
|
||||
background-color: #114267;
|
||||
}
|
||||
QPushButton {
|
||||
padding: 20px;
|
||||
font-size: 35px;
|
||||
color: white;
|
||||
background-color: blue;
|
||||
}
|
||||
QLabel *body = new QLabel(release_notes);
|
||||
body->setStyleSheet(R"(
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
)");
|
||||
|
||||
vlayout->addWidget(f);
|
||||
vlayout->addSpacing(60);
|
||||
layout->addWidget(body, 1, Qt::AlignLeft | Qt::AlignTop);
|
||||
} else {
|
||||
vlayout->addSpacing(60);
|
||||
|
||||
// TODO: paginate the alerts
|
||||
for (const auto &alert : alerts) {
|
||||
QLabel *l = new QLabel(alert.text);
|
||||
l->setWordWrap(true);
|
||||
l->setMargin(60);
|
||||
|
||||
QString style = R"(
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
border-radius: 30px;
|
||||
border: 2px solid;
|
||||
border-color: white;
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
)";
|
||||
style.append("background-color: " + QString(alert.severity ? "#971b1c" : "#114267"));
|
||||
|
||||
style.append("background-color: " + QString(alert.severity ? "#E22C2C" : "#292929"));
|
||||
l->setStyleSheet(style);
|
||||
vlayout->addWidget(l);
|
||||
vlayout->addSpacing(20);
|
||||
|
||||
layout->addWidget(l, 0, Qt::AlignTop);
|
||||
}
|
||||
layout->setSpacing(20);
|
||||
}
|
||||
|
||||
QPushButton *hide_btn = new QPushButton(updateAvailable ? "Later" : "Hide alerts");
|
||||
hide_btn->setStyleSheet(R"(
|
||||
padding: 20px;
|
||||
font-size: 35px;
|
||||
color: white;
|
||||
background-color: blue;
|
||||
)");
|
||||
vlayout->addWidget(hide_btn);
|
||||
QObject::connect(hide_btn, SIGNAL(released()), this, SIGNAL(closeAlerts()));
|
||||
QWidget *w = new QWidget();
|
||||
w->setLayout(layout);
|
||||
alerts_stack->addWidget(w);
|
||||
}
|
||||
|
||||
void OffroadAlert::parse_alerts() {
|
||||
alerts.clear();
|
||||
// We launch in selfdrive/ui
|
||||
|
||||
// TODO: only read this once
|
||||
QFile inFile("../controls/lib/alerts_offroad.json");
|
||||
inFile.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
QByteArray data = inFile.readAll();
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFrame>
|
||||
#include <QStackedWidget>
|
||||
|
||||
struct Alert {
|
||||
QString text;
|
||||
int severity;
|
||||
};
|
||||
|
||||
class OffroadAlert : public QWidget {
|
||||
class OffroadAlert : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -17,8 +17,7 @@ public:
|
|||
bool updateAvailable;
|
||||
|
||||
private:
|
||||
QVBoxLayout *vlayout;
|
||||
|
||||
QStackedWidget *alerts_stack;
|
||||
void parse_alerts();
|
||||
|
||||
signals:
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
#include "sidebar.hpp"
|
||||
|
||||
static void ui_draw_sidebar_background(UIState *s) {
|
||||
ui_draw_rect(s->vg, 0, 0, sbr_w, s->fb_h, COLOR_BLACK_ALPHA(85));
|
||||
#ifdef QCOM
|
||||
const NVGcolor color = COLOR_BLACK_ALPHA(85);
|
||||
#else
|
||||
const NVGcolor color = nvgRGBA(0x39, 0x39, 0x39, 0xff);
|
||||
#endif
|
||||
ui_draw_rect(s->vg, 0, 0, sbr_w, s->fb_h, color);
|
||||
}
|
||||
|
||||
static void ui_draw_sidebar_settings_button(UIState *s) {
|
||||
|
|
|
@ -18,7 +18,10 @@ if __name__ == "__main__":
|
|||
while True:
|
||||
print("setting alert update")
|
||||
params.put("UpdateAvailable", "1")
|
||||
params.put("ReleaseNotes", "this is a new version")
|
||||
r = open(os.path.join(BASEDIR, "RELEASES.md"), "r").read()
|
||||
r = r[:r.find('\n\n')] # Slice latest release notes
|
||||
params.put("ReleaseNotes", r + "\n")
|
||||
|
||||
time.sleep(t)
|
||||
params.put("UpdateAvailable", "0")
|
||||
|
||||
|
|
|
@ -74,7 +74,11 @@ typedef enum UIStatus {
|
|||
} UIStatus;
|
||||
|
||||
static std::map<UIStatus, NVGcolor> bg_colors = {
|
||||
#ifdef QCOM
|
||||
{STATUS_OFFROAD, nvgRGBA(0x07, 0x23, 0x39, 0xf1)},
|
||||
#else
|
||||
{STATUS_OFFROAD, nvgRGBA(0x0, 0x0, 0x0, 0xff)},
|
||||
#endif
|
||||
{STATUS_DISENGAGED, nvgRGBA(0x17, 0x33, 0x49, 0xc8)},
|
||||
{STATUS_ENGAGED, nvgRGBA(0x17, 0x86, 0x44, 0xf1)},
|
||||
{STATUS_WARNING, nvgRGBA(0xDA, 0x6F, 0x25, 0xf1)},
|
||||
|
|
Loading…
Reference in New Issue