diff --git a/selfdrive/assets/navigation/home.png b/selfdrive/assets/navigation/home.png
new file mode 100644
index 0000000000..8a4f65c7d7
Binary files /dev/null and b/selfdrive/assets/navigation/home.png differ
diff --git a/selfdrive/assets/navigation/home.svg b/selfdrive/assets/navigation/home.svg
new file mode 100644
index 0000000000..f5d89514c3
--- /dev/null
+++ b/selfdrive/assets/navigation/home.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/selfdrive/assets/navigation/home_inactive.png b/selfdrive/assets/navigation/home_inactive.png
new file mode 100644
index 0000000000..a58fd3864f
Binary files /dev/null and b/selfdrive/assets/navigation/home_inactive.png differ
diff --git a/selfdrive/assets/navigation/work.png b/selfdrive/assets/navigation/work.png
new file mode 100644
index 0000000000..611f9b038d
Binary files /dev/null and b/selfdrive/assets/navigation/work.png differ
diff --git a/selfdrive/assets/navigation/work.svg b/selfdrive/assets/navigation/work.svg
new file mode 100644
index 0000000000..2da7bb7d39
--- /dev/null
+++ b/selfdrive/assets/navigation/work.svg
@@ -0,0 +1,66 @@
+
+
diff --git a/selfdrive/assets/navigation/work_inactive.png b/selfdrive/assets/navigation/work_inactive.png
new file mode 100644
index 0000000000..679e6a54b2
Binary files /dev/null and b/selfdrive/assets/navigation/work_inactive.png differ
diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc
index 582291c183..a440352743 100644
--- a/selfdrive/common/params.cc
+++ b/selfdrive/common/params.cc
@@ -151,6 +151,7 @@ std::unordered_map keys = {
{"ApiCache_DriveStats", PERSISTENT},
{"ApiCache_Device", PERSISTENT},
{"ApiCache_Owner", PERSISTENT},
+ {"ApiCache_NavDestinations", PERSISTENT},
{"AthenadPid", PERSISTENT},
{"CalibrationParams", PERSISTENT},
{"CarBatteryCapacity", PERSISTENT},
diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc
index 4fef26de24..f2ac7ff6d2 100644
--- a/selfdrive/ui/qt/home.cc
+++ b/selfdrive/ui/qt/home.cc
@@ -44,6 +44,10 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
slayout->addWidget(driver_view);
}
+void HomeWindow::showSidebar(bool show) {
+ sidebar->setVisible(show);
+}
+
void HomeWindow::offroadTransition(bool offroad) {
if (offroad) {
slayout->setCurrentWidget(home);
diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h
index db3e2f8f6e..ab60af0a21 100644
--- a/selfdrive/ui/qt/home.h
+++ b/selfdrive/ui/qt/home.h
@@ -54,6 +54,7 @@ signals:
public slots:
void offroadTransition(bool offroad);
void showDriverView(bool show);
+ void showSidebar(bool show);
protected:
void mousePressEvent(QMouseEvent* e) override;
diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc
index d74e753d90..7bfb97b581 100644
--- a/selfdrive/ui/qt/maps/map.cc
+++ b/selfdrive/ui/qt/maps/map.cc
@@ -276,6 +276,7 @@ void MapWindow::recomputeRoute() {
if (*new_destination != nav_destination) {
setVisible(true); // Show map on destination set/change
+ // TODO: close sidebar
should_recompute = true;
}
diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc
index f6a3bdaeb2..bf17091bc9 100644
--- a/selfdrive/ui/qt/maps/map_settings.cc
+++ b/selfdrive/ui/qt/maps/map_settings.cc
@@ -1,19 +1,124 @@
#include "map_settings.h"
+#include
+
+#include "selfdrive/ui/qt/request_repeater.h"
#include "selfdrive/ui/qt/widgets/controls.h"
+#include "selfdrive/common/util.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) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
Params params = Params();
- QString dongle = QString::fromStdString(params.get("DongleId", false));
- // TODO: Add buttons for home/work shortcuts
+ // Home
+ QHBoxLayout *home_layout = new QHBoxLayout;
+ home_button = new QPushButton;
+ home_button->setIconSize(QSize(200, 200));
+ 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(200, 200));
+ 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(50);
+ main_layout->addWidget(horizontal_line());
+
+ // Settings
main_layout->addWidget(new ParamControl("NavSettingTime24h",
"Show ETA in 24h format",
"Use 24h format instead of am/pm",
"",
this));
main_layout->addStretch();
+
+ clear();
+
+ std::string dongle_id = Params().get("DongleId");
+ if (util::is_valid_dongle_id(dongle_id)) {
+ std::string url = "https://api.commadotai.com/v1/navigation/" + dongle_id + "/locations";
+ RequestRepeater* repeater = new RequestRepeater(this, QString::fromStdString(url), "ApiCache_NavDestinations", 30);
+ QObject::connect(repeater, &RequestRepeater::receivedResponse, this, &MapPanel::parseResponse);
+ }
+}
+
+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();
+}
+
+
+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();
+
+ 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 = shorten(obj["place_details"].toString(), 30);
+
+ if (type == "favorite") {
+ if (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 (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();
+ });
+ }
+ }
+ }
+}
+
+void MapPanel::navigateTo(const QJsonObject &place) {
+ QJsonDocument doc(place);
+ Params().put("NavDestination", doc.toJson().toStdString());
}
diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h
index b2deec696f..26e4f95f95 100644
--- a/selfdrive/ui/qt/maps/map_settings.h
+++ b/selfdrive/ui/qt/maps/map_settings.h
@@ -1,8 +1,24 @@
#pragma once
#include
+#include
+#include
+#include
+#include
+#include
class MapPanel : public QWidget {
Q_OBJECT
public:
explicit MapPanel(QWidget* parent = nullptr);
-};
\ No newline at end of file
+
+ void navigateTo(const QJsonObject &place);
+ void parseResponse(const QString &response);
+ void clear();
+
+private:
+ QPushButton *home_button, *work_button;
+ QLabel *home_address, *work_address;
+
+signals:
+ void closeSettings();
+};
diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc
index 84f3533858..4ec5b6ebe0 100644
--- a/selfdrive/ui/qt/offroad/settings.cc
+++ b/selfdrive/ui/qt/offroad/settings.cc
@@ -345,7 +345,9 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
#ifdef ENABLE_MAPS
if (!Params().get("MapboxToken").empty()) {
- panels.push_back({"Navigation", new MapPanel(this)});
+ auto map_panel = new MapPanel(this);
+ panels.push_back({"Navigation", map_panel});
+ QObject::connect(map_panel, &MapPanel::closeSettings, this, &SettingsWindow::closeSettings);
}
#endif
const int padding = panels.size() > 3 ? 25 : 35;
diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc
index 2a821abde4..04c50684b0 100644
--- a/selfdrive/ui/qt/window.cc
+++ b/selfdrive/ui/qt/window.cc
@@ -67,6 +67,10 @@ void MainWindow::openSettings() {
void MainWindow::closeSettings() {
main_layout->setCurrentWidget(homeWindow);
+
+ if (QUIState::ui_state.scene.started) {
+ emit homeWindow->showSidebar(false);
+ }
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event) {