From 8320a153fb530f973669fa1aafa693a17d4ef035 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 4 Dec 2020 15:21:55 -0800 Subject: [PATCH] move offroad alerts to home screen (#2681) * move offroad alerts to home screen * offroad aletrs work, but sidebar doesn't look nice * fix sidebar * looks better * cleanup * little bigger Co-authored-by: grekiki --- selfdrive/ui/qt/home.cc | 94 ++++++++++++--- selfdrive/ui/qt/home.hpp | 28 ++++- selfdrive/ui/qt/offroad/settings.cc | 63 ---------- selfdrive/ui/qt/offroad/settings.hpp | 5 - selfdrive/ui/qt/widgets/offroad_alerts.cc | 111 ++++++++---------- selfdrive/ui/qt/widgets/offroad_alerts.hpp | 13 +- selfdrive/ui/qt/window.cc | 1 - selfdrive/ui/{test => tests}/.gitignore | 0 selfdrive/ui/{test => tests}/__init__.py | 0 selfdrive/ui/tests/cycle_offroad_alerts.py | 33 ++++++ .../{test => tests}/test_sound_stability.py | 0 11 files changed, 192 insertions(+), 156 deletions(-) rename selfdrive/ui/{test => tests}/.gitignore (100%) rename selfdrive/ui/{test => tests}/__init__.py (100%) create mode 100755 selfdrive/ui/tests/cycle_offroad_alerts.py rename selfdrive/ui/{test => tests}/test_sound_stability.py (100%) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 6f5f9bf125..41c0e25358 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -3,10 +3,12 @@ #include #include -#include +#include #include #include #include +#include +#include #include #include "common/params.h" @@ -19,14 +21,16 @@ #define BACKLIGHT_TS 2.00 -QWidget * home_widget() { +OffroadHome::OffroadHome(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(); main_layout->setContentsMargins(sbr_w + 50, 50, 50, 50); + center_layout = new QStackedLayout(); + // header QHBoxLayout *header_layout = new QHBoxLayout(); - QString date_str = QDateTime::currentDateTime().toString("dddd, MMMM d"); - QLabel *date = new QLabel(date_str); + + date = new QLabel(); date->setStyleSheet(R"(font-size: 55px;)"); header_layout->addWidget(date, 0, Qt::AlignTop | Qt::AlignLeft); @@ -36,33 +40,91 @@ QWidget * home_widget() { main_layout->addLayout(header_layout); + alert_notification = new QPushButton(); + QObject::connect(alert_notification, SIGNAL(released()), this, SLOT(openAlerts())); + main_layout->addWidget(alert_notification, 0, Qt::AlignTop | Qt::AlignRight); + // center QLabel *drive = new QLabel("Drive me"); drive->setStyleSheet(R"(font-size: 175px;)"); - main_layout->addWidget(drive, 1, Qt::AlignHCenter); + center_layout->addWidget(drive); - QWidget *w = new QWidget(); - w->setLayout(main_layout); - w->setStyleSheet(R"( - * { - background-color: none; - } - )"); - return w; + alerts_widget = new OffroadAlert(); + QObject::connect(alerts_widget, SIGNAL(closeAlerts()), this, SLOT(closeAlerts())); + center_layout->addWidget(alerts_widget); + center_layout->setAlignment(alerts_widget, Qt::AlignCenter); + + main_layout->addLayout(center_layout, 1); + + // set up refresh timer + timer = new QTimer(this); + QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh())); + refresh(); + timer->start(10 * 1000); + + setLayout(main_layout); + setStyleSheet(R"(background-color: none;)"); } -HomeWindow::HomeWindow(QWidget *parent) : QWidget(parent) { +void OffroadHome::openAlerts() { + center_layout->setCurrentIndex(1); +} + +void OffroadHome::closeAlerts() { + center_layout->setCurrentIndex(0); +} +void OffroadHome::refresh() { + bool first_refresh = !date->text().size(); + if (!isVisible() && !first_refresh) { + return; + } + + date->setText(QDateTime::currentDateTime().toString("dddd, MMMM d")); + + // update alerts + + alerts_widget->refresh(); + if (!alerts_widget->alerts.size() && !alerts_widget->updateAvailable){ + alert_notification->setVisible(false); + return; + } + + if (alerts_widget->updateAvailable){ + // There is a new release + alert_notification->setText("UPDATE"); + } else { + int alerts = alerts_widget->alerts.size(); + alert_notification->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S")); + } + + alert_notification->setVisible(true); + alert_notification->setStyleSheet(QString(R"( + padding: 15px; + padding-left: 30px; + padding-right: 30px; + border: 1px solid; + border-radius: 5px; + font-size: 40px; + font-weight: bold; + background-color: red; + )")); +} + + +HomeWindow::HomeWindow(QWidget *parent) : QWidget(parent) { layout = new QGridLayout; layout->setMargin(0); + // onroad UI glWindow = new GLWindow(this); layout->addWidget(glWindow, 0, 0); - home = home_widget(); + // draw offroad UI on top of onroad UI + home = new OffroadHome(); layout->addWidget(home, 0, 0); QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), this, SLOT(setVisibility(bool))); - + QObject::connect(this, SIGNAL(openSettings()), home, SLOT(refresh())); setLayout(layout); setStyleSheet(R"( * { diff --git a/selfdrive/ui/qt/home.hpp b/selfdrive/ui/qt/home.hpp index e159668cc6..5f71e0e4f6 100644 --- a/selfdrive/ui/qt/home.hpp +++ b/selfdrive/ui/qt/home.hpp @@ -1,13 +1,17 @@ #pragma once +#include #include #include #include #include +#include #include #include +#include #include "qt_sound.hpp" +#include "widgets/offroad_alerts.hpp" #include "ui/ui.hpp" @@ -49,6 +53,28 @@ public slots: void backlightUpdate(); }; +// offroad home screen +class OffroadHome : public QWidget { + Q_OBJECT + +public: + explicit OffroadHome(QWidget *parent = 0); + +private: + QTimer *timer; + + // offroad home screen widgets + QLabel *date; + QStackedLayout *center_layout; + OffroadAlert *alerts_widget; + QPushButton *alert_notification; + +public slots: + void closeAlerts(); + void openAlerts(); + void refresh(); +}; + class HomeWindow : public QWidget { Q_OBJECT @@ -64,8 +90,8 @@ protected: void mousePressEvent(QMouseEvent *e) override; private: - QWidget *home; QGridLayout *layout; + OffroadHome *home; private slots: void setVisibility(bool offroad); diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 20c5ce5918..50b42f4e8b 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -227,15 +227,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) { sidebar_layout->addWidget(close_button); QObject::connect(close_button, SIGNAL(released()), this, SIGNAL(closeSettings())); - // offroad alerts - alerts_widget = new OffroadAlert(); - QObject::connect(alerts_widget, SIGNAL(closeAlerts()), this, SLOT(closeAlerts())); - panel_layout->addWidget(alerts_widget); - - sidebar_alert_widget = new QPushButton("");//Should get text when it is visible - QObject::connect(sidebar_alert_widget, SIGNAL(released()), this, SLOT(openAlerts())); - sidebar_layout->addWidget(sidebar_alert_widget); - // setup panels panels = { {"developer", developer_panel()}, @@ -263,11 +254,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) { QObject::connect(btn, SIGNAL(released()), this, SLOT(setActivePanel())); } - // We either show the alerts, or the developer panel - if (alerts_widget->show_alert){ - panel_layout->setCurrentWidget(alerts_widget); - } - QHBoxLayout *settings_layout = new QHBoxLayout(); settings_layout->addSpacing(45); @@ -288,55 +274,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) { )"); } -// Refreshes the offroad alerts from the params folder and sets up the sidebar alerts widget. -// The function gets called every time a user opens the settings page -void SettingsWindow::refreshParams() { - alerts_widget->refresh(); - if (!alerts_widget->show_alert){ - sidebar_alert_widget->setFixedHeight(0); - panel_layout->setCurrentIndex(1); - return; - } - - // Panel 0 contains the alerts or release notes. - panel_layout->setCurrentIndex(0); - sidebar_alert_widget->setFixedHeight(100); - sidebar_alert_widget->setStyleSheet(R"( - background-color: #114267; - )"); // light blue - - // Check for alerts - int alerts = alerts_widget->alerts.size(); - if (!alerts){ - // There is a new release - sidebar_alert_widget->setText("UPDATE"); - return; - } - - // Check if there is an important alert - bool existsImportantAlert = false; - for (auto alert : alerts_widget->alerts){ - if (alert.severity){ - existsImportantAlert = true; - } - } - - sidebar_alert_widget->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S")); - if (existsImportantAlert){ - sidebar_alert_widget->setStyleSheet(R"( - background-color: #661111; - )"); //dark red - } -} - -void SettingsWindow::closeAlerts() { - panel_layout->setCurrentIndex(1); -} - -void SettingsWindow::openAlerts() { - panel_layout->setCurrentIndex(0); -} - void SettingsWindow::closeSidebar() { sidebar_widget->setVisible(false); } diff --git a/selfdrive/ui/qt/offroad/settings.hpp b/selfdrive/ui/qt/offroad/settings.hpp index a0be4712dd..b2c0a911d7 100644 --- a/selfdrive/ui/qt/offroad/settings.hpp +++ b/selfdrive/ui/qt/offroad/settings.hpp @@ -7,7 +7,6 @@ #include #include "wifi.hpp" -#include "widgets/offroad_alerts.hpp" // *** settings widgets *** @@ -33,7 +32,6 @@ class SettingsWindow : public QWidget { public: explicit SettingsWindow(QWidget *parent = 0); - void refreshParams(); signals: void closeSettings(); @@ -41,14 +39,11 @@ signals: private: QPushButton *sidebar_alert_widget; QWidget *sidebar_widget; - OffroadAlert *alerts_widget; std::map panels; QStackedLayout *panel_layout; public slots: void setActivePanel(); - void closeAlerts(); - void openAlerts(); void closeSidebar(); void openSidebar(); }; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc index 925c6fcf2f..452ee10218 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ b/selfdrive/ui/qt/widgets/offroad_alerts.cc @@ -1,8 +1,8 @@ -#include #include #include -#include +#include #include +#include #include #include "offroad_alerts.hpp" @@ -32,110 +32,99 @@ OffroadAlert::OffroadAlert(QWidget* parent){ setLayout(vlayout); } -void OffroadAlert::refresh(){ +void OffroadAlert::refresh() { cleanLayout(vlayout); parse_alerts(); - bool updateAvailable = false; + updateAvailable = false; std::vector bytes = Params().read_db_bytes("UpdateAvailable"); if (bytes.size() && bytes[0] == '1'){ updateAvailable = true; } - show_alert = updateAvailable || alerts.size() ; - - if (updateAvailable){ - //If there is update available, don't show alerts + + if (updateAvailable) { + // If there is an update available, don't show alerts alerts.clear(); QFrame *f = new QFrame(); QVBoxLayout *update_layout = new QVBoxLayout; - update_layout->addWidget(new QLabel("Update available")); + update_layout->setMargin(10); + update_layout->setSpacing(20); - std::vector release_notes_bytes = Params().read_db_bytes("ReleaseNotes"); - QString releaseNotes = vectorToQString(release_notes_bytes); - QLabel *notes_label = new QLabel(releaseNotes); + QLabel *title = new QLabel("Update available"); + title->setStyleSheet(R"( + font-size: 55px; + font-weight: bold; + )"); + update_layout->addWidget(title, 0, Qt::AlignTop); + + QString release_notes = QString::fromStdString(Params().get("ReleaseNotes")); + QLabel *notes_label = new QLabel(release_notes); + notes_label->setStyleSheet(R"(font-size: 40px;)"); notes_label->setWordWrap(true); - update_layout->addSpacing(20); - update_layout->addWidget(notes_label); - update_layout->addSpacing(20); + update_layout->addWidget(notes_label, 1, Qt::AlignTop); QPushButton *update_button = new QPushButton("Reboot and Update"); update_layout->addWidget(update_button); - update_layout->setMargin(10); #ifdef __aarch64__ - QObject::connect(update_button, &QPushButton::released,[=]() {std::system("sudo reboot");}); + QObject::connect(update_button, &QPushButton::released, [=]() {std::system("sudo reboot");}); #endif f->setLayout(update_layout); f->setStyleSheet(R"( .QFrame{ - border-radius: 30px; + border-radius: 20px; border: 2px solid white; background-color: #114267; } - QLabel{ - font-size: 60px; - background-color: #114267; + QPushButton { + padding: 20px; + font-size: 35px; + color: white; + background-color: blue; } )"); vlayout->addWidget(f); vlayout->addSpacing(60); - }else{ + } else { vlayout->addSpacing(60); for (auto alert : alerts){ QLabel *l = new QLabel(alert.text); l->setWordWrap(true); l->setMargin(60); - - if (alert.severity){ - l->setStyleSheet(R"( - QLabel { - font-size: 40px; - font-weight: bold; - border-radius: 30px; - background-color: #971b1c; - border-style: solid; - border-width: 2px; - border-color: white; - } - )");//red rounded rectange with white surround - }else{ - l->setStyleSheet(R"( - QLabel { - font-size: 40px; - font-weight: bold; - border-radius: 30px; - background-color: #114267; - border-style: solid; - border-width: 2px; - border-color: white; - } - )");//blue rounded rectange with white surround - } + QString style = R"( + font-size: 40px; + font-weight: bold; + border-radius: 30px; + border: 2px solid; + border-color: white; + )"; + style.append("background-color: " + QString(alert.severity ? "#971b1c" : "#114267")); + + l->setStyleSheet(style); vlayout->addWidget(l); vlayout->addSpacing(20); } - - //Pad the vlayout - for (int i = alerts.size(); i < 4; i++){ - QWidget *w = new QWidget(); - vlayout->addWidget(w); - vlayout->addSpacing(50); - } } - QPushButton *hide_alerts_button = new QPushButton(updateAvailable ? "Later" : "Hide alerts"); - vlayout->addWidget(hide_alerts_button); - QObject::connect(hide_alerts_button, SIGNAL(released()), this, SIGNAL(closeAlerts())); + QPushButton *hide_btn = new QPushButton(updateAvailable ? "Later" : "Hide alerts"); + hide_btn->setStyleSheet(R"( + padding: 20px; + font-size: 35px; + color: white; + background-color: blue; + )"); + vlayout->addWidget(hide_btn); + QObject::connect(hide_btn, SIGNAL(released()), this, SIGNAL(closeAlerts())); } void OffroadAlert::parse_alerts(){ alerts.clear(); - //We launch in selfdrive/ui + // We launch in selfdrive/ui QFile inFile("../controls/lib/alerts_offroad.json"); inFile.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray data = inFile.readAll(); @@ -145,11 +134,11 @@ void OffroadAlert::parse_alerts(){ if (doc.isNull()) { qDebug() << "Parse failed"; } - + QJsonObject json = doc.object(); for (const QString& key : json.keys()) { std::vector bytes = Params().read_db_bytes(key.toStdString().c_str()); - + if (bytes.size()){ QJsonDocument doc_par = QJsonDocument::fromJson(QByteArray(bytes.data(), bytes.size())); QJsonObject obj = doc_par.object(); diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.hpp b/selfdrive/ui/qt/widgets/offroad_alerts.hpp index e7347c4f41..1e425158fd 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.hpp +++ b/selfdrive/ui/qt/widgets/offroad_alerts.hpp @@ -1,25 +1,20 @@ #pragma once - #include -#include -#include -#include -#include -#include +#include -struct Alert{ +struct Alert { QString text; int severity; }; -class OffroadAlert : public QWidget{ +class OffroadAlert : public QWidget { Q_OBJECT public: explicit OffroadAlert(QWidget *parent = 0); - bool show_alert; QVector alerts; + bool updateAvailable; private: QVBoxLayout *vlayout; diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 78fe877c82..8893ca3671 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -32,7 +32,6 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { void MainWindow::openSettings() { main_layout->setCurrentWidget(settingsWindow); - settingsWindow->refreshParams(); } void MainWindow::closeSettings() { diff --git a/selfdrive/ui/test/.gitignore b/selfdrive/ui/tests/.gitignore similarity index 100% rename from selfdrive/ui/test/.gitignore rename to selfdrive/ui/tests/.gitignore diff --git a/selfdrive/ui/test/__init__.py b/selfdrive/ui/tests/__init__.py similarity index 100% rename from selfdrive/ui/test/__init__.py rename to selfdrive/ui/tests/__init__.py diff --git a/selfdrive/ui/tests/cycle_offroad_alerts.py b/selfdrive/ui/tests/cycle_offroad_alerts.py new file mode 100755 index 0000000000..f15486662a --- /dev/null +++ b/selfdrive/ui/tests/cycle_offroad_alerts.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import os +import sys +import time +import json + +from common.basedir import BASEDIR +from common.params import Params +from selfdrive.controls.lib.alertmanager import set_offroad_alert + +if __name__ == "__main__": + params = Params() + + with open(os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")) as f: + offroad_alerts = json.load(f) + + t = 10 if len(sys.argv) < 2 else int(sys.argv[1]) + while True: + print("setting alert update") + params.put("UpdateAvailable", "1") + params.put("ReleaseNotes", "this is a new version") + time.sleep(t) + params.put("UpdateAvailable", "0") + + # cycle through normal alerts + for a in offroad_alerts: + print("setting alert:", a) + set_offroad_alert(a, True) + time.sleep(t) + set_offroad_alert(a, False) + + print("no alert") + time.sleep(t) diff --git a/selfdrive/ui/test/test_sound_stability.py b/selfdrive/ui/tests/test_sound_stability.py similarity index 100% rename from selfdrive/ui/test/test_sound_stability.py rename to selfdrive/ui/tests/test_sound_stability.py