You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
8.2 KiB
257 lines
8.2 KiB
#include "selfdrive/ui/qt/widgets/prime.h"
|
|
|
|
#include <QDebug>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QStackedWidget>
|
|
#include <QTimer>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <QrCode.hpp>
|
|
|
|
#include "selfdrive/ui/qt/request_repeater.h"
|
|
#include "selfdrive/ui/qt/util.h"
|
|
#include "selfdrive/ui/qt/qt_window.h"
|
|
#include "selfdrive/ui/qt/widgets/wifi.h"
|
|
|
|
using qrcodegen::QrCode;
|
|
|
|
PairingQRWidget::PairingQRWidget(QWidget* parent) : QWidget(parent) {
|
|
timer = new QTimer(this);
|
|
connect(timer, &QTimer::timeout, this, &PairingQRWidget::refresh);
|
|
}
|
|
|
|
void PairingQRWidget::showEvent(QShowEvent *event) {
|
|
refresh();
|
|
timer->start(5 * 60 * 1000);
|
|
device()->setOffroadBrightness(100);
|
|
}
|
|
|
|
void PairingQRWidget::hideEvent(QHideEvent *event) {
|
|
timer->stop();
|
|
device()->setOffroadBrightness(BACKLIGHT_OFFROAD);
|
|
}
|
|
|
|
void PairingQRWidget::refresh() {
|
|
QString pairToken = CommaApi::create_jwt({{"pair", true}});
|
|
QString qrString = "https://connect.comma.ai/?pair=" + pairToken;
|
|
this->updateQrCode(qrString);
|
|
update();
|
|
}
|
|
|
|
void PairingQRWidget::updateQrCode(const QString &text) {
|
|
QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW);
|
|
qint32 sz = qr.getSize();
|
|
QImage im(sz, sz, QImage::Format_RGB32);
|
|
|
|
QRgb black = qRgb(0, 0, 0);
|
|
QRgb white = qRgb(255, 255, 255);
|
|
for (int y = 0; y < sz; y++) {
|
|
for (int x = 0; x < sz; x++) {
|
|
im.setPixel(x, y, qr.getModule(x, y) ? black : white);
|
|
}
|
|
}
|
|
|
|
// Integer division to prevent anti-aliasing
|
|
int final_sz = ((width() / sz) - 1) * sz;
|
|
img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly);
|
|
}
|
|
|
|
void PairingQRWidget::paintEvent(QPaintEvent *e) {
|
|
QPainter p(this);
|
|
p.fillRect(rect(), Qt::white);
|
|
|
|
QSize s = (size() - img.size()) / 2;
|
|
p.drawPixmap(s.width(), s.height(), img);
|
|
}
|
|
|
|
|
|
PairingPopup::PairingPopup(QWidget *parent) : DialogBase(parent) {
|
|
QHBoxLayout *hlayout = new QHBoxLayout(this);
|
|
hlayout->setContentsMargins(0, 0, 0, 0);
|
|
hlayout->setSpacing(0);
|
|
|
|
setStyleSheet("PairingPopup { background-color: #E0E0E0; }");
|
|
|
|
// text
|
|
QVBoxLayout *vlayout = new QVBoxLayout();
|
|
vlayout->setContentsMargins(85, 70, 50, 70);
|
|
vlayout->setSpacing(50);
|
|
hlayout->addLayout(vlayout, 1);
|
|
{
|
|
QPushButton *close = new QPushButton(QIcon(":/icons/close.svg"), "", this);
|
|
close->setIconSize(QSize(80, 80));
|
|
close->setStyleSheet("border: none;");
|
|
vlayout->addWidget(close, 0, Qt::AlignLeft);
|
|
QObject::connect(close, &QPushButton::clicked, this, &QDialog::reject);
|
|
|
|
vlayout->addSpacing(30);
|
|
|
|
QLabel *title = new QLabel(tr("Pair your device to your comma account"), this);
|
|
title->setStyleSheet("font-size: 75px; color: black;");
|
|
title->setWordWrap(true);
|
|
vlayout->addWidget(title);
|
|
|
|
QLabel *instructions = new QLabel(QString(R"(
|
|
<ol type='1' style='margin-left: 15px;'>
|
|
<li style='margin-bottom: 50px;'>%1</li>
|
|
<li style='margin-bottom: 50px;'>%2</li>
|
|
<li style='margin-bottom: 50px;'>%3</li>
|
|
</ol>
|
|
)").arg(tr("Go to https://connect.comma.ai on your phone"))
|
|
.arg(tr("Click \"add new device\" and scan the QR code on the right"))
|
|
.arg(tr("Bookmark connect.comma.ai to your home screen to use it like an app")), this);
|
|
|
|
instructions->setStyleSheet("font-size: 47px; font-weight: bold; color: black;");
|
|
instructions->setWordWrap(true);
|
|
vlayout->addWidget(instructions);
|
|
|
|
vlayout->addStretch();
|
|
}
|
|
|
|
// QR code
|
|
PairingQRWidget *qr = new PairingQRWidget(this);
|
|
hlayout->addWidget(qr, 1);
|
|
}
|
|
|
|
|
|
PrimeUserWidget::PrimeUserWidget(QWidget *parent) : QFrame(parent) {
|
|
setObjectName("primeWidget");
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
mainLayout->setContentsMargins(56, 40, 56, 40);
|
|
mainLayout->setSpacing(20);
|
|
|
|
QLabel *subscribed = new QLabel(tr("✓ SUBSCRIBED"));
|
|
subscribed->setStyleSheet("font-size: 41px; font-weight: bold; color: #86FF4E;");
|
|
mainLayout->addWidget(subscribed);
|
|
|
|
QLabel *commaPrime = new QLabel(tr("comma prime"));
|
|
commaPrime->setStyleSheet("font-size: 75px; font-weight: bold;");
|
|
mainLayout->addWidget(commaPrime);
|
|
}
|
|
|
|
|
|
PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QFrame(parent) {
|
|
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
|
main_layout->setContentsMargins(80, 90, 80, 60);
|
|
main_layout->setSpacing(0);
|
|
|
|
QLabel *upgrade = new QLabel(tr("Upgrade Now"));
|
|
upgrade->setStyleSheet("font-size: 75px; font-weight: bold;");
|
|
main_layout->addWidget(upgrade, 0, Qt::AlignTop);
|
|
main_layout->addSpacing(50);
|
|
|
|
QLabel *description = new QLabel(tr("Become a comma prime member at connect.comma.ai"));
|
|
description->setStyleSheet("font-size: 56px; font-weight: light; color: white;");
|
|
description->setWordWrap(true);
|
|
main_layout->addWidget(description, 0, Qt::AlignTop);
|
|
|
|
main_layout->addStretch();
|
|
|
|
QLabel *features = new QLabel(tr("PRIME FEATURES:"));
|
|
features->setStyleSheet("font-size: 41px; font-weight: bold; color: #E5E5E5;");
|
|
main_layout->addWidget(features, 0, Qt::AlignBottom);
|
|
main_layout->addSpacing(30);
|
|
|
|
QVector<QString> bullets = {tr("Remote access"), tr("24/7 LTE connectivity"), tr("1 year of drive storage"), tr("Remote snapshots")};
|
|
for (auto &b : bullets) {
|
|
const QString check = "<b><font color='#465BEA'>✓</font></b> ";
|
|
QLabel *l = new QLabel(check + b);
|
|
l->setAlignment(Qt::AlignLeft);
|
|
l->setStyleSheet("font-size: 50px; margin-bottom: 15px;");
|
|
main_layout->addWidget(l, 0, Qt::AlignBottom);
|
|
}
|
|
|
|
setStyleSheet(R"(
|
|
PrimeAdWidget {
|
|
border-radius: 10px;
|
|
background-color: #333333;
|
|
}
|
|
)");
|
|
}
|
|
|
|
|
|
SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) {
|
|
mainLayout = new QStackedWidget;
|
|
|
|
// Unpaired, registration prompt layout
|
|
|
|
QFrame* finishRegistration = new QFrame;
|
|
finishRegistration->setObjectName("primeWidget");
|
|
QVBoxLayout* finishRegistrationLayout = new QVBoxLayout(finishRegistration);
|
|
finishRegistrationLayout->setSpacing(38);
|
|
finishRegistrationLayout->setContentsMargins(64, 48, 64, 48);
|
|
|
|
QLabel* registrationTitle = new QLabel(tr("Finish Setup"));
|
|
registrationTitle->setStyleSheet("font-size: 75px; font-weight: bold;");
|
|
finishRegistrationLayout->addWidget(registrationTitle);
|
|
|
|
QLabel* registrationDescription = new QLabel(tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer."));
|
|
registrationDescription->setWordWrap(true);
|
|
registrationDescription->setStyleSheet("font-size: 50px; font-weight: light;");
|
|
finishRegistrationLayout->addWidget(registrationDescription);
|
|
|
|
finishRegistrationLayout->addStretch();
|
|
|
|
QPushButton* pair = new QPushButton(tr("Pair device"));
|
|
pair->setStyleSheet(R"(
|
|
QPushButton {
|
|
font-size: 55px;
|
|
font-weight: 500;
|
|
border-radius: 10px;
|
|
background-color: #465BEA;
|
|
padding: 64px;
|
|
}
|
|
QPushButton:pressed {
|
|
background-color: #3049F4;
|
|
}
|
|
)");
|
|
finishRegistrationLayout->addWidget(pair);
|
|
|
|
popup = new PairingPopup(this);
|
|
QObject::connect(pair, &QPushButton::clicked, popup, &PairingPopup::exec);
|
|
|
|
mainLayout->addWidget(finishRegistration);
|
|
|
|
// build stacked layout
|
|
QVBoxLayout *outer_layout = new QVBoxLayout(this);
|
|
outer_layout->setContentsMargins(0, 0, 0, 0);
|
|
outer_layout->addWidget(mainLayout);
|
|
|
|
QWidget *content = new QWidget;
|
|
QVBoxLayout *content_layout = new QVBoxLayout(content);
|
|
content_layout->setContentsMargins(0, 0, 0, 0);
|
|
content_layout->setSpacing(30);
|
|
|
|
WiFiPromptWidget *wifi_prompt = new WiFiPromptWidget;
|
|
QObject::connect(wifi_prompt, &WiFiPromptWidget::openSettings, this, &SetupWidget::openSettings);
|
|
content_layout->addWidget(wifi_prompt);
|
|
content_layout->addStretch();
|
|
|
|
mainLayout->addWidget(content);
|
|
|
|
mainLayout->setCurrentIndex(1);
|
|
|
|
setStyleSheet(R"(
|
|
#primeWidget {
|
|
border-radius: 10px;
|
|
background-color: #333333;
|
|
}
|
|
)");
|
|
|
|
// Retain size while hidden
|
|
QSizePolicy sp_retain = sizePolicy();
|
|
sp_retain.setRetainSizeWhenHidden(true);
|
|
setSizePolicy(sp_retain);
|
|
|
|
QObject::connect(uiState()->prime_state, &PrimeState::changed, [this](PrimeState::Type type) {
|
|
if (type == PrimeState::PRIME_TYPE_UNPAIRED) {
|
|
mainLayout->setCurrentIndex(0); // Display "Pair your device" widget
|
|
} else {
|
|
popup->reject();
|
|
mainLayout->setCurrentIndex(1); // Display Wi-Fi prompt widget
|
|
}
|
|
});
|
|
}
|
|
|