Files
sunnypilot/selfdrive/ui/qt/setup/setup.cc
Shane Smiskol 2c5e890a23 UI: wrap all text for translation (#24961)
* rough multiple language demo

* more wrappings

* stash

* add some bad translations

* updates

* map from french to spanish still has same problem of needing to call setText on everything

* add files

* restart UI

* use return code

* relative path

* more translations

* don't loop restart

* Toggle and prime translations

* try on device

* try QComboBox with readable style

* stash

* not yet scrollable

* stash

* dynamic translations (doesn't work for dynamic widget strings yet)

* clean up multiple option selector

* store languages in json

* try transparent

* Try transparent popup

* see how this looks

* tweaks

* clean up

* clean up

* clean up 2 and missing tr

* wrap more strings

* missing updater

* fixes

* add basic test to ensure all strings wrapped

* try in CI

* clean up

* test name

* fix test

* always install qt dev tools

* fix deps

* fast test

* add section so it prints multiple errors

* debug

* debug

get rid of those

* make any difference?

* comment

* oh...

* run with offscreen platform

* try out section

* clean up

* fix missing wrappings (it works!)

* move down

* space

* clear relevant params, set TICI=1
old-commit-hash: 879a7c3201
2022-06-29 14:47:46 -07:00

431 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "selfdrive/ui/qt/setup/setup.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <QApplication>
#include <QLabel>
#include <QVBoxLayout>
#include <curl/curl.h>
#include "common/util.h"
#include "system/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"
const std::string USER_AGENT = "AGNOSSetup-";
const QString DASHCAM_URL = "https://dashcam.comma.ai";
void Setup::download(QString url) {
CURL *curl = curl_easy_init();
if (!curl) {
emit finished(false);
return;
}
auto version = util::read_file("/VERSION");
char tmpfile[] = "/tmp/installer_XXXXXX";
FILE *fp = fdopen(mkstemp(tmpfile), "w");
curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, (USER_AGENT + version).c_str());
int ret = curl_easy_perform(curl);
long res_status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status);
if (ret == CURLE_OK && res_status == 200) {
rename(tmpfile, "/tmp/installer");
emit finished(true);
} else {
emit finished(false);
}
curl_easy_cleanup(curl);
fclose(fp);
}
QWidget * Setup::low_voltage() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
main_layout->setContentsMargins(55, 0, 55, 55);
main_layout->setSpacing(0);
// inner text layout: warning icon, title, and body
QVBoxLayout *inner_layout = new QVBoxLayout();
inner_layout->setContentsMargins(110, 144, 365, 0);
main_layout->addLayout(inner_layout);
QLabel *triangle = new QLabel();
triangle->setPixmap(QPixmap(ASSET_PATH + "offroad/icon_warning.png"));
inner_layout->addWidget(triangle, 0, Qt::AlignTop | Qt::AlignLeft);
inner_layout->addSpacing(80);
QLabel *title = new QLabel(tr("WARNING: Low Voltage"));
title->setStyleSheet("font-size: 90px; font-weight: 500; color: #FF594F;");
inner_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
inner_layout->addSpacing(25);
QLabel *body = new QLabel(tr("Power your device in a car with a harness or proceed at your own risk."));
body->setWordWrap(true);
body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
body->setStyleSheet("font-size: 80px; font-weight: 300;");
inner_layout->addWidget(body);
inner_layout->addStretch();
// power off + continue buttons
QHBoxLayout *blayout = new QHBoxLayout();
blayout->setSpacing(50);
main_layout->addLayout(blayout, 0);
QPushButton *poweroff = new QPushButton(tr("Power off"));
poweroff->setObjectName("navBtn");
blayout->addWidget(poweroff);
QObject::connect(poweroff, &QPushButton::clicked, this, [=]() {
Hardware::poweroff();
});
QPushButton *cont = new QPushButton(tr("Continue"));
cont->setObjectName("navBtn");
blayout->addWidget(cont);
QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
return widget;
}
QWidget * Setup::getting_started() {
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(tr("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(tr("Before we get on the road, lets 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(":/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(tr("Connect to Wi-Fi"));
title->setStyleSheet("font-size: 90px; font-weight: 500;");
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
main_layout->addSpacing(25);
// wifi widget
Networking *networking = new Networking(this, false);
networking->setStyleSheet("Networking {background-color: #292929; border-radius: 13px;}");
main_layout->addWidget(networking, 1);
main_layout->addSpacing(35);
// back + continue buttons
QHBoxLayout *blayout = new QHBoxLayout;
main_layout->addLayout(blayout);
blayout->setSpacing(50);
QPushButton *back = new QPushButton(tr("Back"));
back->setObjectName("navBtn");
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
blayout->addWidget(back);
QPushButton *cont = new QPushButton();
cont->setObjectName("navBtn");
cont->setProperty("primary", true);
QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
blayout->addWidget(cont);
// setup timer for testing internet connection
HttpRequest *request = new HttpRequest(this, false, 2500);
QObject::connect(request, &HttpRequest::requestDone, [=](const QString &, bool success) {
cont->setEnabled(success);
if (success) {
const bool cell = networking->wifi->currentNetworkType() == NetworkType::CELL;
cont->setText(cell ? tr("Continue without Wi-Fi") : tr("Continue"));
} else {
cont->setText(tr("Waiting for internet"));
}
repaint();
});
request->sendRequest(DASHCAM_URL);
QTimer *timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, [=]() {
if (!request->active() && cont->isVisible()) {
request->sendRequest(DASHCAM_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(":/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);
// title
QLabel *title = new QLabel(tr("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);
// dashcam + custom radio buttons
QButtonGroup *group = new QButtonGroup(widget);
group->setExclusive(true);
QWidget *dashcam = radio_button(tr("Dashcam"), group);
main_layout->addWidget(dashcam);
main_layout->addSpacing(30);
QWidget *custom = radio_button(tr("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(tr("Back"));
back->setObjectName("navBtn");
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
blayout->addWidget(back);
QPushButton *cont = new QPushButton(tr("Continue"));
cont->setObjectName("navBtn");
cont->setEnabled(false);
cont->setProperty("primary", true);
blayout->addWidget(cont);
QObject::connect(cont, &QPushButton::clicked, [=]() {
auto w = currentWidget();
QTimer::singleShot(0, [=]() {
setCurrentWidget(downloading_widget);
});
QString url = DASHCAM_URL;
if (group->checkedButton() != dashcam) {
url = InputDialog::getText(tr("Enter URL"), this, tr("for Custom Software"));
}
if (!url.isEmpty()) {
QTimer::singleShot(1000, this, [=]() {
download(url);
});
} else {
setCurrentWidget(w);
}
});
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);
QLabel *txt = new QLabel(tr("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(55, 225, 55, 55);
main_layout->setSpacing(0);
QLabel *title = new QLabel(tr("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(tr("Ensure the entered URL is valid, and the devices internet connection is good."));
body->setWordWrap(true);
body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;");
main_layout->addWidget(body);
main_layout->addStretch();
// reboot + start over buttons
QHBoxLayout *blayout = new QHBoxLayout();
blayout->setSpacing(50);
main_layout->addLayout(blayout, 0);
QPushButton *reboot = new QPushButton(tr("Reboot device"));
reboot->setObjectName("navBtn");
blayout->addWidget(reboot);
QObject::connect(reboot, &QPushButton::clicked, this, [=]() {
Hardware::reboot();
});
QPushButton *restart = new QPushButton(tr("Start over"));
restart->setObjectName("navBtn");
restart->setProperty("primary", true);
blayout->addWidget(restart);
QObject::connect(restart, &QPushButton::clicked, this, [=]() {
setCurrentIndex(2);
});
widget->setStyleSheet(R"(
QLabel {
margin-left: 117;
}
)");
return widget;
}
void Setup::prevPage() {
setCurrentIndex(currentIndex() - 1);
}
void Setup::nextPage() {
setCurrentIndex(currentIndex() + 1);
}
Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
std::stringstream buffer;
buffer << std::ifstream("/sys/class/hwmon/hwmon1/in1_input").rdbuf();
float voltage = (float)std::atoi(buffer.str().c_str()) / 1000.;
if (voltage < 7) {
addWidget(low_voltage());
}
addWidget(getting_started());
addWidget(network_setup());
addWidget(software_selection());
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;
if (success) {
QTimer::singleShot(3000, this, &QWidget::hide);
} else {
setCurrentWidget(failed_widget);
}
});
// TODO: revisit pressed bg color
setStyleSheet(R"(
* {
color: white;
font-family: Inter;
}
Setup {
background-color: black;
}
QPushButton#navBtn {
height: 160;
font-size: 55px;
font-weight: 400;
border-radius: 10px;
background-color: #333333;
}
QPushButton#navBtn:disabled, QPushButton[primary='true']:disabled {
color: #808080;
background-color: #333333;
}
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;
}
)");
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Setup setup;
setMainWindow(&setup);
return a.exec();
}