From c6adafedc253b6897e3c724e0c2f8125ef0f2137 Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:12:18 -0700 Subject: [PATCH] Add back the drive stats to the home screen Added back the drive strats to the home screen to show the total drives, miles, and hours the user has driven with openpilot. --- common/params.cc | 1 + selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/home.cc | 6 +- selfdrive/ui/qt/widgets/drive_stats.cc | 97 ++++++++++++++++++++++++++ selfdrive/ui/qt/widgets/drive_stats.h | 25 +++++++ 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 selfdrive/ui/qt/widgets/drive_stats.cc create mode 100644 selfdrive/ui/qt/widgets/drive_stats.h diff --git a/common/params.cc b/common/params.cc index 5024ce96e..b967a478e 100644 --- a/common/params.cc +++ b/common/params.cc @@ -211,6 +211,7 @@ std::unordered_map keys = { // FrogPilot parameters {"AccelerationPath", PERSISTENT}, {"AccelerationProfile", PERSISTENT}, + {"ApiCache_DriveStats", PERSISTENT}, {"CustomAlerts", PERSISTENT}, {"CustomPaths", PERSISTENT}, {"CustomUI", PERSISTENT}, diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index bff18d602..3598ebb0a 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -19,7 +19,7 @@ if arch == "Darwin": qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) -widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", +widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/drive_stats.cc", "qt/widgets/wifi.cc", "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 254ddd6f7..56f318999 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -7,6 +7,7 @@ #include "selfdrive/ui/qt/offroad/experimental_mode.h" #include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/widgets/drive_stats.h" #include "selfdrive/ui/qt/widgets/prime.h" #ifdef ENABLE_MAPS @@ -155,11 +156,12 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { left_widget->addWidget(new QWidget); #endif left_widget->addWidget(new PrimeAdWidget); + left_widget->addWidget(new DriveStats); left_widget->setStyleSheet("border-radius: 10px;"); - left_widget->setCurrentIndex(uiState()->hasPrime() ? 0 : 1); + left_widget->setCurrentIndex(2); connect(uiState(), &UIState::primeChanged, [=](bool prime) { - left_widget->setCurrentIndex(prime ? 0 : 1); + left_widget->setCurrentIndex(2); }); home_layout->addWidget(left_widget, 1); diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc new file mode 100644 index 000000000..31009f03c --- /dev/null +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -0,0 +1,97 @@ +#include "selfdrive/ui/qt/widgets/drive_stats.h" + +#include +#include +#include +#include + +#include "common/params.h" +#include "selfdrive/ui/qt/request_repeater.h" +#include "selfdrive/ui/qt/util.h" + +static QLabel* newLabel(const QString& text, const QString &type) { + QLabel* label = new QLabel(text); + label->setProperty("type", type); + return label; +} + +DriveStats::DriveStats(QWidget* parent) : QFrame(parent) { + metric_ = Params().getBool("IsMetric"); + + QVBoxLayout* main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(50, 50, 50, 60); + + auto add_stats_layouts = [=](const QString &title, StatsLabels& labels) { + QGridLayout* grid_layout = new QGridLayout; + grid_layout->setVerticalSpacing(10); + grid_layout->setContentsMargins(0, 10, 0, 10); + + int row = 0; + grid_layout->addWidget(newLabel(title, "title"), row++, 0, 1, 3); + grid_layout->addItem(new QSpacerItem(0, 50), row++, 0, 1, 1); + + grid_layout->addWidget(labels.routes = newLabel("0", "number"), row, 0, Qt::AlignLeft); + grid_layout->addWidget(labels.distance = newLabel("0", "number"), row, 1, Qt::AlignLeft); + grid_layout->addWidget(labels.hours = newLabel("0", "number"), row, 2, Qt::AlignLeft); + + grid_layout->addWidget(newLabel((tr("Drives")), "unit"), row + 1, 0, Qt::AlignLeft); + grid_layout->addWidget(labels.distance_unit = newLabel(getDistanceUnit(), "unit"), row + 1, 1, Qt::AlignLeft); + grid_layout->addWidget(newLabel(tr("Hours"), "unit"), row + 1, 2, Qt::AlignLeft); + + main_layout->addLayout(grid_layout); + }; + + add_stats_layouts(tr("ALL TIME"), all_); + main_layout->addStretch(); + add_stats_layouts(tr("PAST WEEK"), week_); + + if (auto dongleId = getDongleId()) { + QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/stats"; + RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30); + QObject::connect(repeater, &RequestRepeater::requestDone, this, &DriveStats::parseResponse); + } + + setStyleSheet(R"( + DriveStats { + background-color: #333333; + border-radius: 10px; + } + + QLabel[type="title"] { font-size: 51px; font-weight: 500; } + QLabel[type="number"] { font-size: 78px; font-weight: 500; } + QLabel[type="unit"] { font-size: 51px; font-weight: 300; color: #A0A0A0; } + )"); +} + +void DriveStats::updateStats() { + auto update = [=](const QJsonObject& obj, StatsLabels& labels) { + labels.routes->setText(QString::number((int)obj["routes"].toDouble())); + labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric_ ? MILE_TO_KM : 1)))); + labels.distance_unit->setText(getDistanceUnit()); + labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); + }; + + QJsonObject json = stats_.object(); + update(json["all"].toObject(), all_); + update(json["week"].toObject(), week_); +} + +void DriveStats::parseResponse(const QString& response, bool success) { + if (!success) return; + + QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8()); + if (doc.isNull()) { + qDebug() << "JSON Parse failed on getting past drives statistics"; + return; + } + stats_ = doc; + updateStats(); +} + +void DriveStats::showEvent(QShowEvent* event) { + bool metric = Params().getBool("IsMetric"); + if (metric_ != metric) { + metric_ = metric; + updateStats(); + } +} diff --git a/selfdrive/ui/qt/widgets/drive_stats.h b/selfdrive/ui/qt/widgets/drive_stats.h new file mode 100644 index 000000000..5e2d96b24 --- /dev/null +++ b/selfdrive/ui/qt/widgets/drive_stats.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class DriveStats : public QFrame { + Q_OBJECT + +public: + explicit DriveStats(QWidget* parent = 0); + +private: + void showEvent(QShowEvent *event) override; + void updateStats(); + inline QString getDistanceUnit() const { return metric_ ? tr("KM") : tr("Miles"); } + + bool metric_; + QJsonDocument stats_; + struct StatsLabels { + QLabel *routes, *distance, *distance_unit, *hours; + } all_, week_; + +private slots: + void parseResponse(const QString &response, bool success); +};