UI: fast startup (#20781)

* faster startup

* faster

* cleanup

Co-authored-by: Comma Device <device@comma.ai>
albatross
Adeeb Shihadeh 2021-05-04 10:05:23 -07:00 committed by GitHub
parent 9fb79024ef
commit ed3b6bd90c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 88 additions and 68 deletions

View File

@ -61,7 +61,6 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
}
}
// OffroadHome: the offroad home page
OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
@ -99,7 +98,6 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
statsAndSetup->addWidget(drive);
SetupWidget* setup = new SetupWidget;
//setup->setFixedSize(700, 700);
statsAndSetup->addWidget(setup);
QWidget* statsAndSetupWidget = new QWidget();
@ -117,7 +115,6 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
// set up refresh timer
timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, this, &OffroadHome::refresh);
refresh();
timer->start(10 * 1000);
setLayout(main_layout);
@ -131,6 +128,10 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
)");
}
void OffroadHome::showEvent(QShowEvent *event) {
refresh();
}
void OffroadHome::openAlerts() {
center_layout->setCurrentIndex(1);
}

View File

@ -18,6 +18,9 @@ class OffroadHome : public QFrame {
public:
explicit OffroadHome(QWidget* parent = 0);
protected:
void showEvent(QShowEvent *event) override;
private:
QTimer* timer;

View File

@ -1,9 +1,9 @@
#include <QLabel>
#include <QPainter>
#include <QVBoxLayout>
#include <QQuickWidget>
#include <QQmlContext>
#include <QDesktopWidget>
#include <QQmlContext>
#include <QQuickWidget>
#include "common/params.h"
#include "onboarding.h"
@ -50,7 +50,12 @@ void TrainingGuide::paintEvent(QPaintEvent *event) {
imageCorner = rect.topLeft();
}
TermsPage::TermsPage(QWidget *parent) : QFrame(parent){
void TermsPage::showEvent(QShowEvent *event) {
// late init, building QML widget takes 200ms
if (layout()) {
return;
}
QVBoxLayout *main_layout = new QVBoxLayout;
main_layout->setMargin(40);
main_layout->setSpacing(40);
@ -61,15 +66,17 @@ TermsPage::TermsPage(QWidget *parent) : QFrame(parent){
text->setAttribute(Qt::WA_AlwaysStackOnTop);
text->setClearColor(Qt::transparent);
text->rootContext()->setContextProperty("font_size", 55);
QString text_view = util::read_file("../assets/offroad/tc.html").c_str();
text->rootContext()->setContextProperty("text_view", text_view);
text->rootContext()->setContextProperty("font_size", 55);
text->setSource(QUrl::fromLocalFile("qt/offroad/text_view.qml"));
main_layout->addWidget(text);
QObject *obj = (QObject*)text->rootObject();
QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept()));
// TODO: add decline page
QHBoxLayout* buttons = new QHBoxLayout;
main_layout->addLayout(buttons);
@ -82,15 +89,11 @@ TermsPage::TermsPage(QWidget *parent) : QFrame(parent){
buttons->addWidget(accept_btn);
QObject::connect(accept_btn, &QPushButton::released, this, &TermsPage::acceptedTerms);
QObject *obj = (QObject*)text->rootObject();
QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept()));
setLayout(main_layout);
setStyleSheet(R"(
* {
font-size: 50px;
}
QPushButton {
padding: 50px;
font-size: 50px;
border-radius: 10px;
background-color: #292929;
}
@ -136,7 +139,6 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
});
addWidget(tr);
setStyleSheet(R"(
* {
color: white;

View File

@ -57,7 +57,10 @@ class TermsPage : public QFrame {
Q_OBJECT
public:
explicit TermsPage(QWidget *parent = 0);
explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {};
protected:
void showEvent(QShowEvent *event) override;
private:
QPushButton *accept_btn;

View File

@ -263,7 +263,13 @@ QWidget * network_panel(QWidget * parent) {
return w;
}
SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
void SettingsWindow::showEvent(QShowEvent *event) {
if (layout()) {
panel_widget->setCurrentIndex(0);
nav_btns->buttons()[0]->setChecked(true);
return;
}
// setup two main layouts
QVBoxLayout *sidebar_layout = new QVBoxLayout();
sidebar_layout->setMargin(0);
@ -366,9 +372,3 @@ void SettingsWindow::hideEvent(QHideEvent *event){
}
}
}
void SettingsWindow::showEvent(QShowEvent *event){
panel_widget->setCurrentIndex(0);
nav_btns->buttons()[0]->setChecked(true);
}

View File

@ -41,7 +41,7 @@ class SettingsWindow : public QFrame {
Q_OBJECT
public:
explicit SettingsWindow(QWidget *parent = 0);
explicit SettingsWindow(QWidget *parent = 0) : QFrame(parent) {};
protected:
void hideEvent(QHideEvent *event);

View File

@ -35,35 +35,35 @@ void DriveStats::parseResponse(const QString& response) {
labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60)));
};
bool metric = Params().getBool("IsMetric");
QJsonObject json = doc.object();
update(json["all"].toObject(), all_, metric);
update(json["week"].toObject(), week_, metric);
}
DriveStats::DriveStats(QWidget* parent) : QWidget(parent) {
setStyleSheet("QLabel {font-size: 48px; font-weight: 500;}");
metric = Params().getBool("IsMetric");
QString distance_unit = metric ? "KM" : "MILES";
auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const char* distance_unit) {
auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const QString &distance_unit) {
gl->addLayout(build_stat_layout(&labels.routes, "DRIVES"), row, 0, 3, 1);
gl->addLayout(build_stat_layout(&labels.distance, distance_unit), row, 1, 3, 1);
gl->addLayout(build_stat_layout(&labels.hours, "HOURS"), row, 2, 3, 1);
};
const char* distance_unit = Params().getBool("IsMetric") ? "KM" : "MILES";
QGridLayout* gl = new QGridLayout();
QGridLayout* gl = new QGridLayout(this);
gl->setMargin(0);
gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3);
add_stats_layouts(gl, all_, 1, distance_unit);
gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3);
add_stats_layouts(gl, week_, 7, distance_unit);
QVBoxLayout* vlayout = new QVBoxLayout(this);
vlayout->addLayout(gl);
// TODO: do we really need to update this frequently?
QString dongleId = QString::fromStdString(Params().get("DongleId"));
QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/stats";
RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 13);
RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30);
QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &DriveStats::parseResponse);
setLayout(gl);
setStyleSheet(R"(QLabel {font-size: 48px; font-weight: 500;})");
}

View File

@ -9,6 +9,7 @@ public:
explicit DriveStats(QWidget* parent = 0);
private:
bool metric;
struct StatsLabels {
QLabel *routes, *distance, *hours;
} all_, week_;

View File

@ -8,34 +8,18 @@
#include "selfdrive/common/util.h"
OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) {
QVBoxLayout *layout = new QVBoxLayout();
QVBoxLayout *layout = new QVBoxLayout;
layout->setMargin(50);
layout->setSpacing(30);
QWidget *alerts_widget = new QWidget;
QVBoxLayout *alerts_layout = new QVBoxLayout;
QWidget *alerts_widget = new QWidget(this);
alerts_layout = new QVBoxLayout;
alerts_layout->setMargin(0);
alerts_layout->setSpacing(30);
alerts_layout->addStretch(1);
alerts_widget->setLayout(alerts_layout);
alerts_widget->setStyleSheet("background-color: transparent;");
// 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);
alerts_layout->addWidget(l);
}
alerts_layout->addStretch(1);
// release notes
releaseNotes.setWordWrap(true);
releaseNotes.setVisible(false);
@ -80,10 +64,26 @@ OffroadAlert::OffroadAlert(QWidget* parent) : QFrame(parent) {
background-color: white;
}
)");
}
void OffroadAlert::refresh() {
if (alerts.empty()) {
// 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);
alerts_layout->addWidget(l);
}
}
updateAlerts();
rebootBtn.setVisible(updateAvailable);

View File

@ -4,6 +4,7 @@
#include <QFrame>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include "common/params.h"
#include "widgets/scrollview.h"
@ -17,14 +18,16 @@ public:
bool updateAvailable;
private:
Params params;
QLabel releaseNotes;
std::map<std::string, QLabel*> alerts;
QPushButton rebootBtn;
void updateAlerts();
ScrollView *releaseNotesScroll;
Params params;
std::map<std::string, QLabel*> alerts;
QLabel releaseNotes;
QPushButton rebootBtn;
ScrollView *alertsScroll;
ScrollView *releaseNotesScroll;
QVBoxLayout *alerts_layout;
signals:
void closeAlerts();

View File

@ -24,12 +24,16 @@ PairingQRWidget::PairingQRWidget(QWidget* parent) : QWidget(parent) {
QTimer* timer = new QTimer(this);
timer->start(30 * 1000);
connect(timer, &QTimer::timeout, this, &PairingQRWidget::refresh);
refresh(); // don't wait for the first refresh
}
void PairingQRWidget::showEvent(QShowEvent *event){
refresh();
}
void PairingQRWidget::refresh(){
QString IMEI = QString::fromStdString(Params().get("IMEI"));
QString serial = QString::fromStdString(Params().get("HardwareSerial"));
Params params;
QString IMEI = QString::fromStdString(params.get("IMEI"));
QString serial = QString::fromStdString(params.get("HardwareSerial"));
if (std::min(IMEI.length(), serial.length()) <= 5) {
qrCode->setText("Error getting serial: contact support");

View File

@ -16,6 +16,7 @@ public:
private:
QLabel* qrCode;
void updateQrCode(QString text);
void showEvent(QShowEvent *event);
private slots:
void refresh();

View File

@ -34,8 +34,8 @@ SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH
getUserKeys(username);
}
} else {
Params().remove("GithubUsername");
Params().remove("GithubSshKeys");
params.remove("GithubUsername");
params.remove("GithubSshKeys");
refresh();
}
});
@ -51,9 +51,9 @@ SshControl::SshControl() : AbstractControl("SSH Keys", "Warning: This grants SSH
}
void SshControl::refresh() {
QString param = QString::fromStdString(Params().get("GithubSshKeys"));
QString param = QString::fromStdString(params.get("GithubSshKeys"));
if (param.length()) {
username_label.setText(QString::fromStdString(Params().get("GithubUsername")));
username_label.setText(QString::fromStdString(params.get("GithubUsername")));
btn.setText("REMOVE");
} else {
username_label.setText("");
@ -82,8 +82,8 @@ void SshControl::parseResponse(){
networkTimer->stop();
QString response = reply->readAll();
if (reply->error() == QNetworkReply::NoError && response.length()) {
Params().put("GithubUsername", username.toStdString());
Params().put("GithubSshKeys", response.toStdString());
params.put("GithubUsername", username.toStdString());
params.put("GithubSshKeys", response.toStdString());
} else if(reply->error() == QNetworkReply::NoError){
err = "Username '" + username + "' has no keys on GitHub";
} else {

View File

@ -27,6 +27,8 @@ public:
SshControl();
private:
Params params;
QPushButton btn;
QString username;
QLabel username_label;