setup improvements (#21505)
* getting started * downloading * some more * nice checkmark * nice triangle * fixup style * wait for internet * more responsive * waiting for internetpull/21212/head
parent
0eefdb506e
commit
ddd1342fc5
|
@ -0,0 +1,4 @@
|
|||
<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M76.3 36L43.8 67.7L28 51.9" stroke="white" stroke-width="7" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M52 101.5C79.3381 101.5 101.5 79.3381 101.5 52C101.5 24.6619 79.3381 2.5 52 2.5C24.6619 2.5 2.5 24.6619 2.5 52C2.5 79.3381 24.6619 101.5 52 101.5Z" stroke="white" stroke-width="5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 439 B |
|
@ -0,0 +1,3 @@
|
|||
<svg width="54" height="106" viewBox="0 0 54 106" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.01946 4.01488L47.249 54.0666L6.1184 102.141" stroke="white" stroke-width="10"/>
|
||||
</svg>
|
After Width: | Height: | Size: 197 B |
|
@ -67,18 +67,23 @@ QString create_jwt(const QJsonObject &payloads, int expiry) {
|
|||
|
||||
} // namespace CommaApi
|
||||
|
||||
HttpRequest::HttpRequest(QObject *parent, const QString &requestURL, bool create_jwt_) : create_jwt(create_jwt_), QObject(parent) {
|
||||
HttpRequest::HttpRequest(QObject *parent, const QString &requestURL, bool create_jwt_,
|
||||
int timeout) : create_jwt(create_jwt_), QObject(parent) {
|
||||
networkAccessManager = new QNetworkAccessManager(this);
|
||||
reply = NULL;
|
||||
|
||||
networkTimer = new QTimer(this);
|
||||
networkTimer->setSingleShot(true);
|
||||
networkTimer->setInterval(20000);
|
||||
networkTimer->setInterval(timeout);
|
||||
connect(networkTimer, &QTimer::timeout, this, &HttpRequest::requestTimeout);
|
||||
|
||||
sendRequest(requestURL);
|
||||
}
|
||||
|
||||
bool HttpRequest::active() {
|
||||
return reply != NULL;
|
||||
}
|
||||
|
||||
void HttpRequest::sendRequest(const QString &requestURL) {
|
||||
QString token;
|
||||
if(create_jwt) {
|
||||
|
@ -105,11 +110,13 @@ void HttpRequest::requestTimeout() {
|
|||
|
||||
// This function should always emit something
|
||||
void HttpRequest::requestFinished() {
|
||||
bool success = false;
|
||||
if (reply->error() != QNetworkReply::OperationCanceledError) {
|
||||
networkTimer->stop();
|
||||
QString response = reply->readAll();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
success = true;
|
||||
emit receivedResponse(response);
|
||||
} else {
|
||||
qDebug() << reply->errorString();
|
||||
|
@ -118,6 +125,7 @@ void HttpRequest::requestFinished() {
|
|||
} else {
|
||||
emit timeoutResponse("timeout");
|
||||
}
|
||||
emit requestDone(success);
|
||||
reply->deleteLater();
|
||||
reply = NULL;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,9 @@ class HttpRequest : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HttpRequest(QObject* parent, const QString &requestURL, bool create_jwt_ = true);
|
||||
explicit HttpRequest(QObject* parent, const QString &requestURL, bool create_jwt_ = true, int timeout = 20000);
|
||||
void sendRequest(const QString &requestURL);
|
||||
bool active();
|
||||
|
||||
protected:
|
||||
QNetworkReply *reply;
|
||||
|
@ -36,6 +37,7 @@ private slots:
|
|||
void requestFinished();
|
||||
|
||||
signals:
|
||||
void requestDone(bool success);
|
||||
void receivedResponse(const QString &response);
|
||||
void failedResponse(const QString &errorString);
|
||||
void timeoutResponse(const QString &errorString);
|
||||
|
|
|
@ -10,20 +10,21 @@
|
|||
#include <curl/curl.h>
|
||||
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/offroad/networking.h"
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
#define USER_AGENT "AGNOSSetup-0.1"
|
||||
const char* USER_AGENT = "AGNOSSetup-0.1";
|
||||
const QString DASHCAM_URL = "https://dashcam.comma.ai";
|
||||
|
||||
const QString TEST_URL = "https://api.commadotai.com/v1/me";
|
||||
|
||||
void Setup::download(QString url) {
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
|
||||
setCurrentIndex(count() - 2);
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
emit downloadFailed();
|
||||
emit finished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
char tmpfile[] = "/tmp/installer_XXXXXX";
|
||||
|
@ -38,121 +39,245 @@ void Setup::download(QString url) {
|
|||
|
||||
int ret = curl_easy_perform(curl);
|
||||
if (ret != CURLE_OK) {
|
||||
emit downloadFailed();
|
||||
emit finished(false);
|
||||
return;
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
fclose(fp);
|
||||
|
||||
rename(tmpfile, "/tmp/installer");
|
||||
}
|
||||
|
||||
QLabel * title_label(QString text) {
|
||||
QLabel *l = new QLabel(text);
|
||||
l->setStyleSheet(R"(
|
||||
font-size: 100px;
|
||||
font-weight: 500;
|
||||
)");
|
||||
return l;
|
||||
}
|
||||
|
||||
QWidget * Setup::build_page(QString title, QWidget *content, bool next, bool prev) {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(widget);
|
||||
|
||||
main_layout->setMargin(50);
|
||||
main_layout->addWidget(title_label(title), 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
main_layout->addWidget(content);
|
||||
|
||||
QHBoxLayout *nav_layout = new QHBoxLayout();
|
||||
|
||||
if (prev) {
|
||||
QPushButton *back_btn = new QPushButton("Back");
|
||||
nav_layout->addWidget(back_btn, 1, Qt::AlignBottom | Qt::AlignLeft);
|
||||
QObject::connect(back_btn, &QPushButton::released, this, &Setup::prevPage);
|
||||
}
|
||||
|
||||
if (next) {
|
||||
QPushButton *continue_btn = new QPushButton("Continue");
|
||||
nav_layout->addWidget(continue_btn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
QObject::connect(continue_btn, &QPushButton::released, this, &Setup::nextPage);
|
||||
}
|
||||
|
||||
main_layout->addLayout(nav_layout, 0);
|
||||
return widget;
|
||||
emit finished(true);
|
||||
}
|
||||
|
||||
QWidget * Setup::getting_started() {
|
||||
QLabel *body = new QLabel("Before we get on the road, let's finish\ninstallation and cover some details.");
|
||||
body->setAlignment(Qt::AlignHCenter);
|
||||
body->setStyleSheet(R"(font-size: 80px;)");
|
||||
return build_page("Getting Started", body, true, false);
|
||||
QWidget *widget = new QWidget();
|
||||
|
||||
QHBoxLayout *main_layout = new QHBoxLayout(widget);
|
||||
main_layout->setMargin(0);
|
||||
|
||||
QVBoxLayout *vlayout = new QVBoxLayout();
|
||||
vlayout->setContentsMargins(165, 280, 100, 0);
|
||||
main_layout->addLayout(vlayout);
|
||||
|
||||
QLabel *title = new QLabel("Getting Started");
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
|
||||
|
||||
vlayout->addSpacing(90);
|
||||
QLabel *desc = new QLabel("Before we get on the road, let’s finish installation and cover some details.");
|
||||
desc->setWordWrap(true);
|
||||
desc->setStyleSheet("font-size: 80px; font-weight: 300;");
|
||||
vlayout->addWidget(desc, 0, Qt::AlignTop | Qt::AlignLeft);
|
||||
|
||||
vlayout->addStretch();
|
||||
|
||||
QPushButton *btn = new QPushButton();
|
||||
btn->setIcon(QIcon("../../../assets/img_continue_triangle.svg"));
|
||||
btn->setIconSize(QSize(54, 106));
|
||||
btn->setFixedSize(310, 1080);
|
||||
btn->setProperty("primary", true);
|
||||
btn->setStyleSheet("border: none;");
|
||||
main_layout->addWidget(btn, 0, Qt::AlignRight);
|
||||
QObject::connect(btn, &QPushButton::clicked, this, &Setup::nextPage);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget * Setup::network_setup() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(widget);
|
||||
main_layout->setContentsMargins(55, 50, 55, 50);
|
||||
|
||||
// title
|
||||
QLabel *title = new QLabel("Connect to WiFi");
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
// wifi widget
|
||||
Networking *wifi = new Networking(this, false);
|
||||
return build_page("Connect to WiFi", wifi, true, true);
|
||||
main_layout->addWidget(wifi, 1);
|
||||
|
||||
// back + continue buttons
|
||||
QHBoxLayout *blayout = new QHBoxLayout;
|
||||
main_layout->addLayout(blayout);
|
||||
blayout->setSpacing(50);
|
||||
|
||||
QPushButton *back = new QPushButton("Back");
|
||||
back->setObjectName("navBtn");
|
||||
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
|
||||
blayout->addWidget(back);
|
||||
|
||||
QPushButton *cont = new QPushButton();
|
||||
cont->setObjectName("navBtn");
|
||||
QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
|
||||
blayout->addWidget(cont);
|
||||
|
||||
// setup timer for testing internet connection
|
||||
HttpRequest *request = new HttpRequest(this, TEST_URL, false, 2500);
|
||||
QObject::connect(request, &HttpRequest::requestDone, [=](bool success) {
|
||||
cont->setEnabled(success);
|
||||
cont->setText(success ? "Continue" : "Waiting for internet");
|
||||
repaint();
|
||||
});
|
||||
QTimer *timer = new QTimer(this);
|
||||
QObject::connect(timer, &QTimer::timeout, [=]() {
|
||||
if (!request->active() && cont->isVisible()) {
|
||||
request->sendRequest(TEST_URL);
|
||||
}
|
||||
});
|
||||
timer->start(1000);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget * radio_button(QString title, QButtonGroup *group) {
|
||||
QPushButton *btn = new QPushButton(title);
|
||||
btn->setCheckable(true);
|
||||
group->addButton(btn);
|
||||
btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
height: 230;
|
||||
padding-left: 100px;
|
||||
padding-right: 100px;
|
||||
text-align: left;
|
||||
font-size: 80px;
|
||||
font-weight: 400;
|
||||
border-radius: 10px;
|
||||
background-color: #4F4F4F;
|
||||
}
|
||||
QPushButton:checked {
|
||||
background-color: #465BEA;
|
||||
}
|
||||
)");
|
||||
|
||||
// checkmark icon
|
||||
QPixmap pix("../../../assets/img_circled_check.svg");
|
||||
btn->setIcon(pix);
|
||||
btn->setIconSize(QSize(0, 0));
|
||||
btn->setLayoutDirection(Qt::RightToLeft);
|
||||
QObject::connect(btn, &QPushButton::toggled, [=](bool checked) {
|
||||
btn->setIconSize(checked ? QSize(104, 104) : QSize(0, 0));
|
||||
});
|
||||
return btn;
|
||||
}
|
||||
|
||||
QWidget * Setup::software_selection() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(widget);
|
||||
main_layout->setContentsMargins(55, 50, 55, 50);
|
||||
main_layout->setSpacing(0);
|
||||
|
||||
QPushButton *dashcam_btn = new QPushButton("Dashcam");
|
||||
main_layout->addWidget(dashcam_btn);
|
||||
QObject::connect(dashcam_btn, &QPushButton::released, this, [=]() {
|
||||
this->download("https://dashcam.comma.ai");
|
||||
});
|
||||
// title
|
||||
QLabel *title = new QLabel("Choose Software to Install");
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
main_layout->addSpacing(50);
|
||||
|
||||
QPushButton *custom_btn = new QPushButton("Custom");
|
||||
main_layout->addWidget(custom_btn);
|
||||
QObject::connect(custom_btn, &QPushButton::released, this, [=]() {
|
||||
QString input_url = InputDialog::getText("Enter URL", this);
|
||||
if (input_url.size()) {
|
||||
this->download(input_url);
|
||||
// dashcam + custom radio buttons
|
||||
QButtonGroup *group = new QButtonGroup(widget);
|
||||
group->setExclusive(true);
|
||||
|
||||
QWidget *dashcam = radio_button("Dashcam", group);
|
||||
main_layout->addWidget(dashcam);
|
||||
|
||||
main_layout->addSpacing(30);
|
||||
|
||||
QWidget *custom = radio_button("Custom Software", group);
|
||||
main_layout->addWidget(custom);
|
||||
|
||||
main_layout->addStretch();
|
||||
|
||||
// back + continue buttons
|
||||
QHBoxLayout *blayout = new QHBoxLayout;
|
||||
main_layout->addLayout(blayout);
|
||||
blayout->setSpacing(50);
|
||||
|
||||
QPushButton *back = new QPushButton("Back");
|
||||
back->setObjectName("navBtn");
|
||||
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
|
||||
blayout->addWidget(back);
|
||||
|
||||
QPushButton *cont = new QPushButton("Continue");
|
||||
cont->setObjectName("navBtn");
|
||||
cont->setEnabled(false);
|
||||
blayout->addWidget(cont);
|
||||
|
||||
QObject::connect(cont, &QPushButton::clicked, [=]() {
|
||||
QString url = DASHCAM_URL;
|
||||
if (group->checkedButton() != dashcam) {
|
||||
url = InputDialog::getText("Enter URL", this);
|
||||
}
|
||||
if (!url.isEmpty()) {
|
||||
setCurrentWidget(downloading_widget);
|
||||
QTimer::singleShot(100, this, [=]() {
|
||||
download(url);
|
||||
});
|
||||
}
|
||||
});
|
||||
return build_page("Choose Software", widget, false, true);
|
||||
|
||||
connect(group, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) {
|
||||
btn->setChecked(true);
|
||||
cont->setEnabled(true);
|
||||
});
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget * Setup::downloading() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(widget);
|
||||
main_layout->addWidget(title_label("Downloading..."), 0, Qt::AlignCenter);
|
||||
QLabel *txt = new QLabel("Downloading...");
|
||||
txt->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
main_layout->addWidget(txt, 0, Qt::AlignCenter);
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget * Setup::download_failed() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(widget);
|
||||
main_layout->setContentsMargins(50, 50, 50, 50);
|
||||
main_layout->addWidget(title_label("Download Failed"), 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
main_layout->setContentsMargins(55, 225, 55, 55);
|
||||
main_layout->setSpacing(0);
|
||||
|
||||
QLabel *body = new QLabel("Ensure the entered URL is valid, and the device's network connection is good.");
|
||||
QLabel *title = new QLabel("Download Failed");
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
main_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
|
||||
|
||||
main_layout->addSpacing(67);
|
||||
|
||||
QLabel *body = new QLabel("Ensure the entered URL is valid, and the device’s internet connection is good.");
|
||||
body->setWordWrap(true);
|
||||
body->setAlignment(Qt::AlignHCenter);
|
||||
body->setStyleSheet(R"(font-size: 80px;)");
|
||||
body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;");
|
||||
main_layout->addWidget(body);
|
||||
|
||||
QHBoxLayout *nav_layout = new QHBoxLayout();
|
||||
main_layout->addStretch();
|
||||
|
||||
QPushButton *reboot_btn = new QPushButton("Reboot");
|
||||
nav_layout->addWidget(reboot_btn, 0, Qt::AlignBottom | Qt::AlignLeft);
|
||||
QObject::connect(reboot_btn, &QPushButton::released, this, [=]() {
|
||||
if (Hardware::TICI()) {
|
||||
std::system("sudo reboot");
|
||||
}
|
||||
// reboot + start over buttons
|
||||
QHBoxLayout *blayout = new QHBoxLayout();
|
||||
blayout->setSpacing(50);
|
||||
main_layout->addLayout(blayout, 0);
|
||||
|
||||
QPushButton *reboot = new QPushButton("Reboot device");
|
||||
reboot->setObjectName("navBtn");
|
||||
blayout->addWidget(reboot);
|
||||
QObject::connect(reboot, &QPushButton::released, this, [=]() {
|
||||
Hardware::reboot();
|
||||
});
|
||||
|
||||
QPushButton *restart_btn = new QPushButton("Start over");
|
||||
nav_layout->addWidget(restart_btn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
QObject::connect(restart_btn, &QPushButton::released, this, [=]() {
|
||||
QPushButton *restart = new QPushButton("Start over");
|
||||
restart->setObjectName("navBtn");
|
||||
restart->setProperty("primary", true);
|
||||
blayout->addWidget(restart);
|
||||
QObject::connect(restart, &QPushButton::released, this, [=]() {
|
||||
setCurrentIndex(0);
|
||||
});
|
||||
|
||||
main_layout->addLayout(nav_layout, 0);
|
||||
widget->setStyleSheet(R"(
|
||||
QLabel {
|
||||
margin-left: 117;
|
||||
}
|
||||
)");
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
@ -168,24 +293,47 @@ Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
|
|||
addWidget(getting_started());
|
||||
addWidget(network_setup());
|
||||
addWidget(software_selection());
|
||||
addWidget(downloading());
|
||||
addWidget(download_failed());
|
||||
|
||||
QObject::connect(this, &Setup::downloadFailed, this, &Setup::nextPage);
|
||||
downloading_widget = downloading();
|
||||
addWidget(downloading_widget);
|
||||
|
||||
failed_widget = download_failed();
|
||||
addWidget(failed_widget);
|
||||
|
||||
QObject::connect(this, &Setup::finished, [=](bool success) {
|
||||
// hide setup on success
|
||||
qDebug() << "finished" << success;
|
||||
setVisible(!success);
|
||||
setCurrentWidget(failed_widget);
|
||||
});
|
||||
|
||||
// TODO: revisit pressed bg color
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
font-family: Inter;
|
||||
color: white;
|
||||
font-family: Inter;
|
||||
}
|
||||
Setup {
|
||||
background-color: black;
|
||||
}
|
||||
QPushButton {
|
||||
padding: 50px;
|
||||
padding-right: 100px;
|
||||
padding-left: 100px;
|
||||
border: 7px solid white;
|
||||
border-radius: 20px;
|
||||
font-size: 50px;
|
||||
QPushButton#navBtn {
|
||||
height: 160;
|
||||
font-size: 55px;
|
||||
font-weight: 400;
|
||||
border-radius: 10px;
|
||||
background-color: #333333;
|
||||
}
|
||||
QPushButton#navBtn:disabled {
|
||||
color: #808080;
|
||||
}
|
||||
QPushButton#navBtn:pressed {
|
||||
background-color: #444444;
|
||||
}
|
||||
QPushButton[primary='true'], #navBtn[primary='true'] {
|
||||
background-color: #465BEA;
|
||||
}
|
||||
QPushButton[primary='true']:pressed, #navBtn:pressed[primary='true'] {
|
||||
background-color: #3049F4;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ private:
|
|||
QWidget *getting_started();
|
||||
QWidget *network_setup();
|
||||
QWidget *software_selection();
|
||||
QWidget *custom_software();
|
||||
QWidget *downloading();
|
||||
QWidget *download_failed();
|
||||
|
||||
QWidget *build_page(QString title, QWidget *content, bool next, bool prev);
|
||||
QWidget *failed_widget;
|
||||
QWidget *downloading_widget;
|
||||
|
||||
signals:
|
||||
void downloadFailed();
|
||||
void finished(bool success);
|
||||
|
||||
public slots:
|
||||
void nextPage();
|
||||
|
|
Loading…
Reference in New Issue