From 17432e1b0d90ea0fd6011a7cf126cd1b5cbc09e6 Mon Sep 17 00:00:00 2001 From: Nayan Date: Fri, 27 Jun 2025 04:44:14 -0400 Subject: [PATCH] ui: model panel - added download progress bars (#998) * progress bars!! * too many changes --------- Co-authored-by: DevTekVE --- .../qt/offroad/settings/models_panel.cc | 152 ++++++++++++++---- .../qt/offroad/settings/models_panel.h | 13 ++ 2 files changed, 135 insertions(+), 30 deletions(-) diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc index 44a6bd3b48..b8237c3627 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc @@ -7,21 +7,55 @@ #include #include +#include #include "common/model.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h" #include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" +static const QString progressStyleActive = "QProgressBar {" + " font-size: 40px;" + " font-weight: 200;" + " padding: 1px;" + " border: 3px solid black;" + " border-radius: 10px;" + "}" + "QProgressBar::chunk {" + " background-color: #1e79e8;" + " border-radius: 10px;" + "}"; + +static const QString progressStyleInactive = progressStyleActive + + "QProgressBar::chunk {" + " background-color: transparent;" + "}"; + +static const QString progressStyleDone = progressStyleActive + + "QProgressBar {" + " color: #33ab4c;" + "}" + "QProgressBar::chunk {" + " background-color: transparent;" + "}"; + +static const QString progressStyleError = progressStyleActive + + "QProgressBar {" + " color: red;" + "}" + "QProgressBar::chunk {" + " background-color: transparent;" + "}"; + ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(50, 20, 50, 20); - ListWidgetSP *list = new ListWidgetSP(this); + ListWidgetSP *list = new ListWidgetSP(this, false); ScrollViewSP *scroller = new ScrollViewSP(list, this); main_layout->addWidget(scroller); const auto current_model = GetActiveModelName(); - currentModelLblBtn = new ButtonControlSP(tr("Current Model"), tr("SELECT"), current_model); + currentModelLblBtn = new ButtonControlSP(tr("Current Model"), tr("SELECT"), "", this); currentModelLblBtn->setValue(current_model); connect(currentModelLblBtn, &ButtonControlSP::clicked, this, &ModelsPanel::handleCurrentModelLblBtnClicked); @@ -32,6 +66,29 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels); list->addItem(currentModelLblBtn); + // Create progress bars for downloads + supercomboProgressBar = createProgressBar(this); + QString supercomboType = tr("Driving Model"); + supercomboFrame = createModelDetailFrame(this, supercomboType, supercomboProgressBar); + list->addItem(supercomboFrame); + + navigationProgressBar = createProgressBar(this); + QString navigationType = tr("Navigation Model"); + navigationFrame = createModelDetailFrame(this, navigationType, navigationProgressBar); + list->addItem(navigationFrame); + + visionProgressBar = createProgressBar(this); + QString visionType = tr("Vision Model"); + visionFrame = createModelDetailFrame(this, visionType, visionProgressBar); + list->addItem(visionFrame); + + policyProgressBar = createProgressBar(this); + QString policyType = tr("Policy Model"); + policyFrame = createModelDetailFrame(this, policyType, policyProgressBar); + list->addItem(policyFrame); + + list->addItem(horizontal_line()); + // LiveDelay toggle list->addItem(new ParamControlSP("LagdToggle", tr("Live Learning Steer Delay"), @@ -40,15 +97,38 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { "../assets/offroad/icon_shell.png")); } +QProgressBar* ModelsPanel::createProgressBar(QWidget *parent) { + QProgressBar *progressBar = new QProgressBar(parent); + progressBar->setRange(0, 100); + progressBar->setValue(0); + progressBar->setTextVisible(true); + progressBar->setAlignment(Qt::AlignVCenter); + return progressBar; +} + +QFrame* ModelsPanel::createModelDetailFrame(QWidget *parent, QString &typeName, QProgressBar *progressBar) { + QFrame *frame = new QFrame(parent); + QHBoxLayout *layout = new QHBoxLayout(frame); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(50); + layout->addWidget(new QLabel(typeName)); + layout->addWidget(progressBar); + frame->setVisible(false); + return frame; +} /** * @brief Updates the UI with bundle download progress information * Reads status from modelManagerSP cereal message and displays status for all models */ void ModelsPanel::handleBundleDownloadProgress() { + supercomboFrame->setVisible(false); + visionFrame->setVisible(false); + policyFrame->setVisible(false); + navigationFrame->setVisible(false); + using DS = cereal::ModelManagerSP::DownloadStatus; if (!model_manager.hasSelectedBundle() && !model_manager.hasActiveBundle()) { - currentModelLblBtn->setDescription(tr("No custom model selected!")); return; } @@ -61,21 +141,27 @@ void ModelsPanel::handleBundleDownloadProgress() { // Get status for each model type in order for (const auto &model: models) { - QString typeName; QString modelName = QString::fromStdString(bundle.getDisplayName()); + QProgressBar *progressBar = nullptr; + QFrame *modelFrame = nullptr; + switch (model.getType()) { case cereal::ModelManagerSP::Model::Type::SUPERCOMBO: - typeName = tr("Driving"); + progressBar = supercomboProgressBar; + modelFrame = supercomboFrame; break; case cereal::ModelManagerSP::Model::Type::NAVIGATION: - typeName = tr("Navigation"); + progressBar = navigationProgressBar; + modelFrame = navigationFrame; break; case cereal::ModelManagerSP::Model::Type::VISION: - typeName = tr("Vision"); + progressBar = visionProgressBar; + modelFrame = visionFrame; break; case cereal::ModelManagerSP::Model::Type::POLICY: - typeName = tr("Policy"); + progressBar = policyProgressBar; + modelFrame = policyFrame; break; } @@ -83,31 +169,26 @@ void ModelsPanel::handleBundleDownloadProgress() { QString line; if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::DOWNLOADING) { - line = tr("Downloading %1 model [%2]... (%3%)").arg(typeName, modelName).arg(progress.getProgress(), 0, 'f', 2); + progressBar->setStyleSheet(progressStyleActive); + progressBar->setValue(progress.getProgress()); + progressBar->setFormat(QString(" %1% - %2").arg(static_cast(progress.getProgress())).arg(modelName)); + device()->resetInteractiveTimeout(); } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::DOWNLOADED) { - line = tr("%1 model [%2] %3").arg(typeName, modelName, download_status_changed ? tr("downloaded") : tr("ready")); + progressBar->setStyleSheet(progressStyleDone); + progressBar->setFormat(tr(" %1 - %2").arg(modelName, download_status_changed ? tr("downloaded") : tr("ready"))); } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::CACHED) { - line = tr("%1 model [%2] %3").arg(typeName, modelName, download_status_changed ? tr("from cache") : tr("ready")); + progressBar->setStyleSheet(progressStyleDone); + progressBar->setFormat(tr(" %1 - %2").arg(modelName, download_status_changed ? tr("from cache") : tr("ready"))); } else if (progress.getStatus() == cereal::ModelManagerSP::DownloadStatus::FAILED) { - line = tr("%1 model [%2] download failed").arg(typeName, modelName); + progressBar->setStyleSheet(progressStyleError); + progressBar->setFormat(tr(" download failed - %1").arg(modelName)); } else { - line = tr("%1 model [%2] pending...").arg(typeName, modelName); + progressBar->setStyleSheet(progressStyleInactive); + progressBar->setFormat(tr(" pending - %1").arg(modelName)); } - status.append(line); - } - - currentModelLblBtn->setDescription(status.join("\n")); - - if (prev_download_status != download_status) { - switch (bundle.getStatus()) { - case cereal::ModelManagerSP::DownloadStatus::DOWNLOADING: - case cereal::ModelManagerSP::DownloadStatus::CACHED: - case cereal::ModelManagerSP::DownloadStatus::DOWNLOADED: - currentModelLblBtn->showDescription(); - break; - case cereal::ModelManagerSP::DownloadStatus::FAILED: - default: - break; + // keep navigation hidden for now to avoid confusion + if (model.getType() != cereal::ModelManagerSP::Model::Type::NAVIGATION) { + modelFrame->setVisible(true); } } prev_download_status = download_status; @@ -125,6 +206,17 @@ QString ModelsPanel::GetActiveModelName() { return DEFAULT_MODEL; } +/** + * @brief Gets the short name of the currently selected model bundle + * @return Display short name of the selected bundle or default model name + */ +QString ModelsPanel::GetActiveModelInternalName() { + if (model_manager.hasActiveBundle()) { + return QString::fromStdString(model_manager.getActiveBundle().getInternalName()); + } + return DEFAULT_MODEL; +} + void ModelsPanel::updateModelManagerState() { const SubMaster &sm = *(uiStateSP()->sm); model_manager = sm["modelManagerSP"].getModelManagerSP(); @@ -156,7 +248,7 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() { bundleNames.append(index_to_bundle[index]); } - currentModelLblBtn->setValue(GetActiveModelName()); + currentModelLblBtn->setValue(GetActiveModelInternalName()); const QString selectedBundleName = MultiOptionDialog::getSelection( tr("Select a Model"), bundleNames, GetActiveModelName(), this); @@ -197,7 +289,7 @@ void ModelsPanel::updateLabels() { updateModelManagerState(); handleBundleDownloadProgress(); currentModelLblBtn->setEnabled(!is_onroad && !isDownloading()); - currentModelLblBtn->setValue(GetActiveModelName()); + currentModelLblBtn->setValue(GetActiveModelInternalName()); } /** diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h index 4ba526651e..8b8cf69759 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" class ModelsPanel : public QWidget { @@ -17,6 +19,7 @@ public: private: QString GetActiveModelName(); + QString GetActiveModelInternalName(); void updateModelManagerState(); bool isDownloading() const { @@ -33,6 +36,8 @@ private: void handleCurrentModelLblBtnClicked(); void handleBundleDownloadProgress(); void showResetParamsDialog(); + QProgressBar* createProgressBar(QWidget *parent); + QFrame* createModelDetailFrame(QWidget *parent, QString &typeName, QProgressBar *progressBar); cereal::ModelManagerSP::Reader model_manager; cereal::ModelManagerSP::DownloadStatus download_status{}; cereal::ModelManagerSP::DownloadStatus prev_download_status{}; @@ -59,6 +64,14 @@ private: bool is_onroad = false; ButtonControlSP *currentModelLblBtn; + QProgressBar *supercomboProgressBar; + QFrame *supercomboFrame; + QProgressBar *navigationProgressBar; + QFrame *navigationFrame; + QProgressBar *visionProgressBar; + QFrame *visionFrame; + QProgressBar *policyProgressBar; + QFrame *policyFrame; Params params; };