From 999feae5f39889c06540b70e1216979e4fced6bc Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 25 Jan 2025 21:25:06 -0500 Subject: [PATCH] search with user input --- common/params.cc | 2 + selfdrive/ui/sunnypilot/SConscript | 6 +- .../settings/vehicle/platform_selector.cc | 178 ++++++++++++++++++ .../settings/vehicle/platform_selector.h | 24 +++ .../qt/offroad/settings/vehicle_panel.cc | 17 ++ .../qt/offroad/settings/vehicle_panel.h | 5 + selfdrive/ui/translations/main_ar.ts | 35 +++- selfdrive/ui/translations/main_de.ts | 35 +++- selfdrive/ui/translations/main_es.ts | 31 +++ selfdrive/ui/translations/main_fr.ts | 35 +++- selfdrive/ui/translations/main_ja.ts | 35 +++- selfdrive/ui/translations/main_ko.ts | 35 +++- selfdrive/ui/translations/main_pt-BR.ts | 35 +++- selfdrive/ui/translations/main_th.ts | 35 +++- selfdrive/ui/translations/main_tr.ts | 35 +++- selfdrive/ui/translations/main_zh-CHS.ts | 35 +++- selfdrive/ui/translations/main_zh-CHT.ts | 35 +++- 17 files changed, 572 insertions(+), 41 deletions(-) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h diff --git a/common/params.cc b/common/params.cc index 989c8e1a90..4d05220107 100644 --- a/common/params.cc +++ b/common/params.cc @@ -205,6 +205,8 @@ std::unordered_map keys = { {"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CarParamsSPCache", CLEAR_ON_MANAGER_START}, {"CarParamsSPPersistent", PERSISTENT}, + {"CarPlatform", PERSISTENT}, + {"CarPlatformName", PERSISTENT}, {"EnableGithubRunner", PERSISTENT | BACKUP}, {"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION}, {"OffroadMode", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index e80ecf7867..2975450124 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -35,8 +35,12 @@ sunnypilot_panel_qt_src = [ "sunnypilot/qt/offroad/settings/sunnypilot/mads_settings.cc", ] +vehicle_panel_qt_src = [ + "sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc", +] + sp_widgets_src = widgets_src -sp_qt_src = qt_src + sunnypilot_panel_qt_src +sp_qt_src = qt_src + sunnypilot_panel_qt_src + vehicle_panel_qt_src sp_qt_util = qt_util Export('sp_widgets_src', 'sp_qt_src', "sp_qt_util") diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc new file mode 100644 index 0000000000..35039baf0c --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h" + +#include +#include +#include +#include +#include +#include + +PlatformSelector::PlatformSelector() : ButtonControl(tr("Vehicle"), "", "") { + QObject::connect(this, &ButtonControl::clicked, [=]() { + if (text() == tr("SEARCH")) { + QString query = InputDialog::getText(tr("Search your vehicle"), this, tr("Enter model year (e.g., 2021) and model name (Toyota Corolla):"), false); + if (query.length() > 0) { + setText(tr("SEARCHING")); + setEnabled(false); + searchPlatforms(query); + refresh(); + } + } else { + params.remove("CarPlatform"); + params.remove("CarPlatformName"); + refresh(); + } + }); + + refresh(); +} + +void PlatformSelector::refresh() { + QString platform_param = QString::fromStdString(params.get("CarPlatform")); + if (platform_param.length()) { + setValue(QString::fromStdString(params.get("CarPlatformName"))); + setText("REMOVE"); + } else { + setValue(""); + setText("SEARCH"); + } + setEnabled(true); +} + +QMap PlatformSelector::loadPlatformList() { + QMap platforms; + + std::string json_data = util::read_file("../../sunnypilot/selfdrive/car/car_list_extra.json").c_str(); + + if (json_data.empty()) { + return platforms; + } + + QJsonParseError json_error; + QJsonDocument doc = QJsonDocument::fromJson(QString::fromStdString(json_data).toUtf8(), &json_error); + if (doc.isNull()) { + return platforms; + } + + if (doc.isObject()) { + QJsonObject obj = doc.object(); + for (const QString &key : obj.keys()) { + QJsonObject attributes = obj.value(key).toObject(); + QVariantMap platform_data; + + QJsonArray yearArray = attributes.value("year").toArray(); + QVariantList yearList; + for (const QJsonValue &year : yearArray) { + yearList.append(year.toString()); + } + + platform_data["year"] = yearList; + platform_data["model"] = attributes.value("model").toString(); + platform_data["package"] = attributes.value("package").toString(); + + platforms[key] = platform_data; + } + } + + return platforms; +} + +void PlatformSelector::searchPlatforms(const QString &query) { + if (query.isEmpty()) { + return; + } + + QMap platforms = loadPlatformList(); + QSet matched_cars; + + QString normalized_query = query.simplified().toLower(); + QStringList tokens = normalized_query.split(" ", Qt::SkipEmptyParts); + + int search_year = -1; + QStringList search_terms; + + for (const QString &token : tokens) { + bool ok; + int year = token.toInt(&ok); + if (ok && year >= 1900 && year <= 2100) { + search_year = year; + } else { + search_terms << token; + } + } + + for (auto it = platforms.constBegin(); it != platforms.constEnd(); ++it) { + QString platform_name = it.key(); + QVariantMap platform_data = it.value(); + QVariantList year_list = platform_data["year"].toList(); + + if (search_year != -1) { + bool year_match = false; + for (const QVariant &year_var : year_list) { + int year = year_var.toString().toInt(); + if (year == search_year) { + year_match = true; + break; + } + } + if (!year_match) { + continue; + } + } + + bool all_terms_match = true; + QString platform_search = platform_name.toLower(); + + // Normalize platform name for searching (remove diacritical marks) + QString normalized_platform = platform_search.normalized(QString::NormalizationForm_KD); + normalized_platform.remove(QRegExp("[^a-zA-Z0-9\\s]")); + + for (const QString &term : search_terms) { + QString normalized_term = term.normalized(QString::NormalizationForm_KD); + normalized_term.remove(QRegExp("[^a-zA-Z0-9\\s]")); + + if (term.contains(QRegExp("[a-z]\\d|\\d[a-z]", Qt::CaseInsensitive))) { + QString clean_platform = normalized_platform; + QString clean_term = normalized_term; + clean_platform.remove(" "); + clean_term.remove(" "); + if (!clean_platform.contains(clean_term, Qt::CaseInsensitive)) { + all_terms_match = false; + break; + } + } else { + QRegExp wordMatch(QString("\\b%1\\b").arg(QRegExp::escape(normalized_term)), Qt::CaseInsensitive); + if (!normalized_platform.contains(wordMatch)) { + all_terms_match = false; + break; + } + } + } + + if (all_terms_match) { + matched_cars.insert(platform_name); + } + } + + QStringList results = QStringList(matched_cars.begin(), matched_cars.end()); + results.sort(); + + if (results.isEmpty()) { + ConfirmationDialog::alert(tr("No vehicles found for query: %1").arg(query), this); + return; + } + + QString selected_platform = MultiOptionDialog::getSelection(tr("Select a vehicle"), results, "", this); + + if (!selected_platform.isEmpty()) { + params.put("CarPlatform", selected_platform.toStdString()); + params.put("CarPlatformName", selected_platform.toStdString()); + } +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h new file mode 100644 index 0000000000..7e7a2588bb --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#pragma once + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" + +class PlatformSelector : public ButtonControl { + Q_OBJECT + +public: + PlatformSelector(); + +private: + Params params; + + void refresh(); + void searchPlatforms(const QString &query); + QMap loadPlatformList(); +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc index 1dcd8330b7..2fdb9048e4 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc @@ -6,6 +6,23 @@ */ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h" + +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" VehiclePanel::VehiclePanel(QWidget *parent) : QFrame(parent) { + main_layout = new QStackedLayout(this); + ListWidget *list = new ListWidget(this); + + vehicleScreen = new QWidget(this); + QVBoxLayout *vlayout = new QVBoxLayout(vehicleScreen); + vlayout->setContentsMargins(50, 20, 50, 20); + + list->addItem(new PlatformSelector()); + + ScrollViewSP *scroller = new ScrollViewSP(list, this); + vlayout->addWidget(scroller); + + main_layout->addWidget(vehicleScreen); + main_layout->setCurrentWidget(vehicleScreen); } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h index 75b038626a..d4b75feeab 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h @@ -14,4 +14,9 @@ class VehiclePanel : public QFrame { public: explicit VehiclePanel(QWidget *parent = nullptr); + +private: + QStackedLayout* main_layout = nullptr; + QWidget* vehicleScreen = nullptr; + ButtonControl* carSelector = nullptr; }; diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index ddfffa248c..f946ec20e9 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -509,10 +509,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - متقدم - Scan @@ -658,6 +654,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.إلغاء + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 3f495b7998..1985d8e10d 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -505,10 +505,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - Erweitert - Scan @@ -653,6 +649,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.Aktivieren + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 86ea11fb4e..aed42574de 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -650,6 +650,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.Cancelar + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 202f0b9027..db522a1289 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -505,10 +505,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - Avancé - Scan @@ -654,6 +650,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.Annuler + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 59cb8071b4..21d1e86219 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - 詳細 - Scan @@ -652,6 +648,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.を有効化 + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 2bac59dfc1..16fc811528 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - 고급 설정 - Scan @@ -653,6 +649,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.활성화 + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 9c5f08036b..bbf431da46 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -505,10 +505,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - Avançado - Scan @@ -654,6 +650,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.Ativar + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index dd45f23fe9..a0d0f591a5 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - ขั้นสูง - Scan @@ -653,6 +649,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.ยกเลิก + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index 4623e3e139..82eded261a 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - Gelişmiş Seçenekler - Scan @@ -652,6 +648,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index d84924e8be..b3c8cb0396 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - 高级 - Scan @@ -653,6 +649,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.启用 + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 88ba7c029f..cedf824d21 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -504,10 +504,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed. NetworkingSP - - Advanced - 進階 - Scan @@ -653,6 +649,37 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.啟用 + + PlatformSelector + + Vehicle + + + + SEARCH + + + + Search your vehicle + + + + SEARCHING + + + + No vehicles found for query: %1 + + + + Select a vehicle + + + + Enter model year (e.g., 2021) and model name (Toyota Corolla): + + + PrimeAdWidget