nopenpilot/selfdrive/ui/qt/maps/map_settings.cc

294 lines
9.5 KiB
C++

#include "map_settings.h"
#include <QDebug>
#include "selfdrive/common/util.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/request_repeater.h"
#include "selfdrive/ui/qt/widgets/controls.h"
#include "selfdrive/ui/qt/widgets/scrollview.h"
static QString shorten(const QString &str, int max_len) {
return str.size() > max_len ? str.left(max_len).trimmed() + "" : str;
}
MapPanel::MapPanel(QWidget* parent) : QWidget(parent) {
stack = new QStackedWidget;
QWidget * main_widget = new QWidget;
QVBoxLayout *main_layout = new QVBoxLayout(main_widget);
const int icon_size = 200;
// Home
QHBoxLayout *home_layout = new QHBoxLayout;
home_button = new QPushButton;
home_button->setIconSize(QSize(icon_size, icon_size));
home_layout->addWidget(home_button);
home_address = new QLabel;
home_address->setWordWrap(true);
home_layout->addSpacing(30);
home_layout->addWidget(home_address);
home_layout->addStretch();
// Work
QHBoxLayout *work_layout = new QHBoxLayout;
work_button = new QPushButton;
work_button->setIconSize(QSize(icon_size, icon_size));
work_layout->addWidget(work_button);
work_address = new QLabel;
work_address->setWordWrap(true);
work_layout->addSpacing(30);
work_layout->addWidget(work_address);
work_layout->addStretch();
// Home & Work layout
QHBoxLayout *home_work_layout = new QHBoxLayout;
home_work_layout->addLayout(home_layout, 1);
home_work_layout->addSpacing(50);
home_work_layout->addLayout(work_layout, 1);
main_layout->addLayout(home_work_layout);
main_layout->addSpacing(20);
main_layout->addWidget(horizontal_line());
main_layout->addSpacing(20);
// Current route
{
current_widget = new QWidget(this);
QVBoxLayout *current_layout = new QVBoxLayout(current_widget);
QLabel *title = new QLabel("Current Destination");
title->setStyleSheet("font-size: 55px");
current_layout->addWidget(title);
current_route = new ButtonControl("", "CLEAR");
current_route->setStyleSheet("padding-left: 40px;");
current_layout->addWidget(current_route);
QObject::connect(current_route, &ButtonControl::clicked, [=]() {
params.remove("NavDestination");
updateCurrentRoute();
});
current_layout->addSpacing(10);
current_layout->addWidget(horizontal_line());
current_layout->addSpacing(20);
}
main_layout->addWidget(current_widget);
// Recents
QLabel *recents_title = new QLabel("Recent Destinations");
recents_title->setStyleSheet("font-size: 55px");
main_layout->addWidget(recents_title);
main_layout->addSpacing(20);
recent_layout = new QVBoxLayout;
QWidget *recent_widget = new LayoutWidget(recent_layout, this);
ScrollView *recent_scroller = new ScrollView(recent_widget, this);
main_layout->addWidget(recent_scroller);
// No prime upsell
QWidget * no_prime_widget = new QWidget;
{
QVBoxLayout *no_prime_layout = new QVBoxLayout(no_prime_widget);
QLabel *signup_header = new QLabel("Try the Navigation Beta");
signup_header->setStyleSheet(R"(font-size: 75px; color: white; font-weight:600;)");
signup_header->setAlignment(Qt::AlignCenter);
no_prime_layout->addWidget(signup_header);
no_prime_layout->addSpacing(50);
QLabel *screenshot = new QLabel;
QPixmap pm = QPixmap("../assets/navigation/screenshot.png");
screenshot->setPixmap(pm.scaledToWidth(1080, Qt::SmoothTransformation));
no_prime_layout->addWidget(screenshot, 0, Qt::AlignHCenter);
QLabel *signup = new QLabel("Get turn-by-turn directions displayed and more with a comma \nprime subscription. Sign up now: https://connect.comma.ai");
signup->setStyleSheet(R"(font-size: 45px; color: white; font-weight:300;)");
signup->setAlignment(Qt::AlignCenter);
no_prime_layout->addSpacing(20);
no_prime_layout->addWidget(signup);
no_prime_layout->addStretch();
}
stack->addWidget(main_widget);
stack->addWidget(no_prime_widget);
stack->setCurrentIndex(1);
QVBoxLayout *wrapper = new QVBoxLayout(this);
wrapper->addWidget(stack);
clear();
if (auto dongle_id = getDongleId()) {
// Fetch favorite and recent locations
{
QString url = CommaApi::BASE_URL + "/v1/navigation/" + *dongle_id + "/locations";
RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_NavDestinations", 30, true);
QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &MapPanel::parseResponse);
QObject::connect(repeater, &RequestRepeater::failedResponse, this, &MapPanel::failedResponse);
}
// Destination set while offline
{
QString url = CommaApi::BASE_URL + "/v1/navigation/" + *dongle_id + "/next";
RequestRepeater* repeater = new RequestRepeater(this, url, "", 10, true);
HttpRequest* deleter = new HttpRequest(this);
QObject::connect(repeater, &RequestRepeater::receivedResponse, [=](QString resp) {
if (resp != "null") {
if (params.get("NavDestination").empty()) {
qWarning() << "Setting NavDestination from /next" << resp;
params.put("NavDestination", resp.toStdString());
} else {
qWarning() << "Got location from /next, but NavDestination already set";
}
// Send DELETE to clear destination server side
deleter->sendRequest(url, HttpRequest::Method::DELETE);
}
});
}
}
}
void MapPanel::showEvent(QShowEvent *event) {
updateCurrentRoute();
}
void MapPanel::clear() {
home_button->setIcon(QPixmap("../assets/navigation/home_inactive.png"));
home_address->setStyleSheet(R"(font-size: 50px; color: grey;)");
home_address->setText("No home\nlocation set");
home_button->disconnect();
work_button->setIcon(QPixmap("../assets/navigation/work_inactive.png"));
work_address->setStyleSheet(R"(font-size: 50px; color: grey;)");
work_address->setText("No work\nlocation set");
work_button->disconnect();
clearLayout(recent_layout);
}
void MapPanel::updateCurrentRoute() {
auto dest = QString::fromStdString(params.get("NavDestination"));
QJsonDocument doc = QJsonDocument::fromJson(dest.trimmed().toUtf8());
if (dest.size() && !doc.isNull()) {
auto name = doc["place_name"].toString();
auto details = doc["place_details"].toString();
current_route->setTitle(shorten(name + " " + details, 42));
}
current_widget->setVisible(dest.size() && !doc.isNull());
}
void MapPanel::parseResponse(const QString &response) {
QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8());
if (doc.isNull()) {
qDebug() << "JSON Parse failed on navigation locations";
return;
}
clear();
bool has_recents = false;
for (auto &save_type: {"favorite", "recent"}) {
for (auto location : doc.array()) {
auto obj = location.toObject();
auto type = obj["save_type"].toString();
auto label = obj["label"].toString();
auto name = obj["place_name"].toString();
auto details = obj["place_details"].toString();
if (type != save_type) continue;
if (type == "favorite" && label == "home") {
home_address->setText(name);
home_address->setStyleSheet(R"(font-size: 50px; color: white;)");
home_button->setIcon(QPixmap("../assets/navigation/home.png"));
QObject::connect(home_button, &QPushButton::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
} else if (type == "favorite" && label == "work") {
work_address->setText(name);
work_address->setStyleSheet(R"(font-size: 50px; color: white;)");
work_button->setIcon(QPixmap("../assets/navigation/work.png"));
QObject::connect(work_button, &QPushButton::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
} else {
ClickableWidget *widget = new ClickableWidget;
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->setContentsMargins(15, 14, 40, 14);
QLabel *star = new QLabel("");
auto sp = star->sizePolicy();
sp.setRetainSizeWhenHidden(true);
star->setSizePolicy(sp);
star->setVisible(type == "favorite");
star->setStyleSheet(R"(font-size: 60px;)");
layout->addWidget(star);
layout->addSpacing(10);
QLabel *recent_label = new QLabel(shorten(name + " " + details, 45));
recent_label->setStyleSheet(R"(font-size: 50px;)");
layout->addWidget(recent_label);
layout->addStretch();
QLabel *arrow = new QLabel("");
arrow->setStyleSheet(R"(font-size: 60px;)");
layout->addWidget(arrow);
widget->setStyleSheet(R"(
.ClickableWidget {
border-radius: 10px;
border-width: 1px;
border-style: solid;
border-color: gray;
}
QWidget {
background-color: #393939;
color: #9c9c9c;
}
)");
QObject::connect(widget, &ClickableWidget::clicked, [=]() {
navigateTo(obj);
emit closeSettings();
});
recent_layout->addWidget(widget);
recent_layout->addSpacing(10);
has_recents = true;
}
}
}
if (!has_recents) {
QLabel *no_recents = new QLabel("no recent destinations");
no_recents->setStyleSheet(R"(font-size: 50px; color: #9c9c9c)");
recent_layout->addWidget(no_recents);
}
recent_layout->addStretch();
stack->setCurrentIndex(0);
repaint();
}
void MapPanel::failedResponse(const QString &response) {
stack->setCurrentIndex(1);
}
void MapPanel::navigateTo(const QJsonObject &place) {
QJsonDocument doc(place);
params.put("NavDestination", doc.toJson().toStdString());
}