610 lines
27 KiB
C++
610 lines
27 KiB
C++
#include "frogpilot/ui/qt/offroad/model_settings.h"
|
|
|
|
bool hasAllTinygradFiles(const QDir &modelDir, const QString &modelKey) {
|
|
QStringList tinygradSuffixes = {
|
|
"_driving_policy_metadata.pkl",
|
|
"_driving_policy_tinygrad.pkl",
|
|
"_driving_vision_metadata.pkl",
|
|
"_driving_vision_tinygrad.pkl"
|
|
};
|
|
|
|
for (const QString &suffix : tinygradSuffixes) {
|
|
if (!modelDir.exists(modelKey + suffix)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QString normalizeModelKey(QString key) {
|
|
key = key.toLower();
|
|
if (key.endsWith("_default")) {
|
|
key.chop(QString("_default").size());
|
|
}
|
|
return key;
|
|
}
|
|
|
|
FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
|
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
|
QString className = this->metaObject()->className();
|
|
|
|
if (!shownDescriptions.value(className).toBool(false)) {
|
|
forceOpenDescriptions = true;
|
|
shownDescriptions.insert(className, true);
|
|
params.put("ShownToggleDescriptions", QJsonDocument(shownDescriptions).toJson(QJsonDocument::Compact).toStdString());
|
|
}
|
|
|
|
QStackedLayout *modelLayout = new QStackedLayout();
|
|
addItem(modelLayout);
|
|
|
|
FrogPilotListWidget *modelList = new FrogPilotListWidget(this);
|
|
|
|
ScrollView *modelPanel = new ScrollView(modelList, this);
|
|
|
|
modelLayout->addWidget(modelPanel);
|
|
|
|
FrogPilotListWidget *modelLabelsList = new FrogPilotListWidget(this);
|
|
|
|
ScrollView *modelLabelsPanel = new ScrollView(modelLabelsList, this);
|
|
|
|
modelLayout->addWidget(modelLabelsPanel);
|
|
|
|
const std::vector<std::tuple<QString, QString, QString, QString>> modelToggles {
|
|
{"AutomaticallyDownloadModels", tr("Automatically Download New Models"), tr("<b>Automatically download new driving models</b> as they become available."), ""},
|
|
{"DeleteModel", tr("Delete Driving Models"), tr("<b>Delete downloaded driving models</b> to free up storage space."), ""},
|
|
{"DownloadModel", tr("Download Driving Models"), tr("<b>Manually download driving models</b> to the device."), ""},
|
|
{"ModelRandomizer", tr("Model Randomizer"), tr("<b>Select a random driving model each drive</b> and use feedback prompts at the end of the drive to help find the model that best suits you!"), ""},
|
|
{"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("<b>Add or remove driving models from the \"Model Randomizer\" blacklist.</b>"), ""},
|
|
{"ManageScores", tr("Manage Model Ratings"), tr("<b>View or reset saved model ratings</b> used by the \"Model Randomizer\"."), ""},
|
|
{"SelectModel", tr("Select Driving Model"), tr("<b>Choose which driving model openpilot uses.</b>"), ""},
|
|
{"UpdateTinygrad", tr("Update Model Manager"), tr("<b>Update the \"Model Manager\"</b> to support the latest models."), ""}
|
|
};
|
|
|
|
for (const auto &[param, title, desc, icon] : modelToggles) {
|
|
AbstractControl *modelToggle;
|
|
|
|
if (param == "DeleteModel") {
|
|
deleteModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DELETE ALL")});
|
|
QObject::connect(deleteModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
|
QStringList deletableModels;
|
|
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
|
QString base = QFileInfo(file).baseName();
|
|
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
|
if (base.startsWith(modelKey)) {
|
|
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
|
if (!deletableModels.contains(modelName)) {
|
|
deletableModels.append(modelName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
deletableModels.removeAll(processModelName(currentModel));
|
|
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
|
noModelsDownloaded = deletableModels.isEmpty();
|
|
|
|
if (id == 0) {
|
|
QString modelToDelete = MultiOptionDialog::getSelection(tr("Select a driving model to delete"), deletableModels, "", this);
|
|
if (!modelToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" model?").arg(modelToDelete), tr("Delete"), this)) {
|
|
QString modelFile = modelFileToNameMapProcessed.key(modelToDelete);
|
|
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
|
QString base = QFileInfo(file).baseName();
|
|
if (base.startsWith(modelFile)) {
|
|
QFile::remove(modelDir.filePath(file));
|
|
}
|
|
}
|
|
|
|
allModelsDownloaded = false;
|
|
}
|
|
} else if (id == 1) {
|
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all of your downloaded driving models?"), tr("Delete"), this)) {
|
|
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
|
QString base = QFileInfo(file).baseName();
|
|
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
|
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
|
if (deletableModels.contains(modelName) && base.startsWith(modelKey)) {
|
|
QFile::remove(modelDir.filePath(file));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
allModelsDownloaded = false;
|
|
noModelsDownloaded = true;
|
|
}
|
|
}
|
|
});
|
|
modelToggle = deleteModelButton;
|
|
} else if (param == "DownloadModel") {
|
|
downloadModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DOWNLOAD"), tr("DOWNLOAD ALL")});
|
|
QObject::connect(downloadModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
|
if (tinygradUpdate) {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("Tinygrad is out of date and must be updated before you can download new models. Update now?"), this)) {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("Updating Tinygrad will delete all existing Tinygrad-based models which will need to be re-downloaded. Proceed?"), this)) {
|
|
params_memory.putBool("UpdateTinygrad", true);
|
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
|
|
|
updateTinygradButton->setText(0, tr("CANCEL"));
|
|
updateTinygradButton->setValue(tr("Updating..."));
|
|
|
|
updatingTinygrad = true;
|
|
}
|
|
}
|
|
} else if (id == 0) {
|
|
if (modelDownloading) {
|
|
params_memory.putBool("CancelModelDownload", true);
|
|
|
|
cancellingDownload = true;
|
|
} else {
|
|
QStringList downloadableModels = availableModelNames;
|
|
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
|
QString modelName = modelFileToNameMap.value(modelKey);
|
|
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
|
downloadableModels.removeAll(modelName);
|
|
}
|
|
}
|
|
allModelsDownloaded = downloadableModels.isEmpty();
|
|
|
|
QString modelToDownload = MultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableModels, "", this);
|
|
if (!modelToDownload.isEmpty()) {
|
|
params_memory.put("ModelToDownload", modelFileToNameMap.key(modelToDownload).toStdString());
|
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
|
|
|
downloadModelButton->setText(0, tr("CANCEL"));
|
|
|
|
downloadModelButton->setValue(tr("Downloading..."));
|
|
|
|
downloadModelButton->setVisibleButton(1, false);
|
|
|
|
modelDownloading = true;
|
|
}
|
|
}
|
|
} else if (id == 1) {
|
|
if (allModelsDownloading) {
|
|
params_memory.putBool("CancelModelDownload", true);
|
|
|
|
cancellingDownload = true;
|
|
} else {
|
|
params_memory.putBool("DownloadAllModels", true);
|
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
|
|
|
downloadModelButton->setText(1, tr("CANCEL"));
|
|
|
|
downloadModelButton->setValue(tr("Downloading..."));
|
|
|
|
downloadModelButton->setVisibleButton(0, false);
|
|
|
|
allModelsDownloading = true;
|
|
}
|
|
}
|
|
});
|
|
modelToggle = downloadModelButton;
|
|
} else if (param == "ManageBlacklistedModels") {
|
|
FrogPilotButtonsControl *blacklistButton = new FrogPilotButtonsControl(title, desc, icon, {tr("ADD"), tr("REMOVE"), tr("REMOVE ALL")});
|
|
QObject::connect(blacklistButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
|
QStringList blacklistedModels = QString::fromStdString(params.get("BlacklistedModels")).split(",");
|
|
blacklistedModels.removeAll("");
|
|
|
|
if (id == 0) {
|
|
QStringList blacklistableModels;
|
|
for (const QString &model : modelFileToNameMapProcessed.keys()) {
|
|
if (!blacklistedModels.contains(model)) {
|
|
blacklistableModels.append(modelFileToNameMapProcessed.value(model));
|
|
}
|
|
}
|
|
|
|
if (blacklistableModels.size() <= 1) {
|
|
ConfirmationDialog::alert(tr("There are no more driving models to blacklist. The only available model is \"%1\"!").arg(blacklistableModels.first()), this);
|
|
} else {
|
|
QString modelToBlacklist = MultiOptionDialog::getSelection(tr("Select a driving model to add to the blacklist"), blacklistableModels, "", this);
|
|
if (!modelToBlacklist.isEmpty()) {
|
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to add the \"%1\" model to the blacklist?").arg(modelToBlacklist), tr("Add"), this)) {
|
|
blacklistedModels.append(modelFileToNameMapProcessed.key(modelToBlacklist));
|
|
|
|
params.put("BlacklistedModels", blacklistedModels.join(",").toStdString());
|
|
}
|
|
}
|
|
}
|
|
} else if (id == 1) {
|
|
QStringList whitelistableModels;
|
|
for (const QString &model : blacklistedModels) {
|
|
QString modelName = modelFileToNameMapProcessed.value(model);
|
|
whitelistableModels.append(modelName);
|
|
}
|
|
whitelistableModels.sort();
|
|
|
|
QString modelToWhitelist = MultiOptionDialog::getSelection(tr("Select a driving model to remove from the blacklist"), whitelistableModels, "", this);
|
|
if (!modelToWhitelist.isEmpty()) {
|
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to remove the \"%1\" model from the blacklist?").arg(modelToWhitelist), tr("Remove"), this)) {
|
|
blacklistedModels.removeAll(modelFileToNameMapProcessed.key(modelToWhitelist));
|
|
|
|
params.put("BlacklistedModels", blacklistedModels.join(",").toStdString());
|
|
}
|
|
}
|
|
} else if (id == 2) {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove all of your blacklisted driving models?"), this)) {
|
|
params.remove("BlacklistedModels");
|
|
params_cache.remove("BlacklistedModels");
|
|
}
|
|
}
|
|
});
|
|
modelToggle = blacklistButton;
|
|
} else if (param == "ManageScores") {
|
|
FrogPilotButtonsControl *manageScoresButton = new FrogPilotButtonsControl(title, desc, icon, {tr("RESET"), tr("VIEW")});
|
|
QObject::connect(manageScoresButton, &FrogPilotButtonsControl::buttonClicked, [modelLayout, modelLabelsList, modelLabelsPanel, this](int id) {
|
|
if (id == 0) {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("Reset all model drives and ratings? This clears your drive history and collected feedback!"), this)) {
|
|
params.remove("ModelDrivesAndScores");
|
|
params_cache.remove("ModelDrivesAndScores");
|
|
}
|
|
} else if (id == 1) {
|
|
openSubPanel();
|
|
|
|
updateModelLabels(modelLabelsList);
|
|
|
|
modelLayout->setCurrentWidget(modelLabelsPanel);
|
|
}
|
|
});
|
|
modelToggle = manageScoresButton;
|
|
} else if (param == "SelectModel") {
|
|
selectModelButton = new ButtonControl(title, tr("SELECT"), desc);
|
|
QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() {
|
|
QStringList selectableModels;
|
|
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
|
QString modelName = modelFileToNameMap.value(modelKey);
|
|
if (modelName.contains("(Default)")) {
|
|
continue;
|
|
}
|
|
|
|
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
|
selectableModels.append(modelName);
|
|
}
|
|
}
|
|
selectableModels.sort();
|
|
selectableModels.prepend(modelFileToNameMap.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
|
|
|
QString modelToSelect = MultiOptionDialog::getSelection(tr("Select a Model — 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), selectableModels, currentModel, this);
|
|
if (!modelToSelect.isEmpty()) {
|
|
currentModel = modelToSelect;
|
|
|
|
params.put("Model", modelFileToNameMap.key(modelToSelect).toStdString());
|
|
|
|
updateFrogPilotToggles();
|
|
|
|
if (started) {
|
|
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
|
Hardware::reboot();
|
|
}
|
|
}
|
|
selectModelButton->setValue(modelToSelect);
|
|
|
|
QStringList deletableModels;
|
|
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
|
QString base = QFileInfo(file).baseName();
|
|
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
|
if (base.startsWith(modelKey)) {
|
|
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
|
if (!deletableModels.contains(modelName)) {
|
|
deletableModels.append(modelName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
deletableModels.removeAll(processModelName(currentModel));
|
|
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
|
noModelsDownloaded = deletableModels.isEmpty();
|
|
}
|
|
});
|
|
modelToggle = selectModelButton;
|
|
|
|
} else if (param == "UpdateTinygrad") {
|
|
updateTinygradButton = new FrogPilotButtonsControl(title, desc, icon, {tr("UPDATE")});
|
|
QObject::connect(updateTinygradButton, &FrogPilotButtonsControl::buttonClicked, [this]() {
|
|
if (updatingTinygrad) {
|
|
params_memory.putBool("CancelModelDownload", true);
|
|
|
|
updateTinygradButton->setEnabled(false);
|
|
updateTinygradButton->setValue(tr("Cancelling..."));
|
|
|
|
cancellingDownload = true;
|
|
} else {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("Updating Tinygrad will delete existing Tinygrad-based driving models and need to be re-downloaded. Proceed?"), this)) {
|
|
params_memory.putBool("UpdateTinygrad", true);
|
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
|
|
|
updateTinygradButton->setText(0, tr("CANCEL"));
|
|
updateTinygradButton->setValue(tr("Updating..."));
|
|
|
|
updatingTinygrad = true;
|
|
}
|
|
}
|
|
});
|
|
modelToggle = updateTinygradButton;
|
|
|
|
} else {
|
|
modelToggle = new ParamControl(param, title, desc, icon);
|
|
}
|
|
|
|
toggles[param] = modelToggle;
|
|
|
|
modelList->addItem(modelToggle);
|
|
|
|
QObject::connect(modelToggle, &AbstractControl::hideDescriptionEvent, [this]() {
|
|
update();
|
|
});
|
|
QObject::connect(modelToggle, &AbstractControl::showDescriptionEvent, [this]() {
|
|
update();
|
|
});
|
|
}
|
|
|
|
openDescriptions(forceOpenDescriptions, toggles);
|
|
|
|
QObject::connect(static_cast<ToggleControl*>(toggles["ModelRandomizer"]), &ToggleControl::toggleFlipped, [this](bool state) {
|
|
updateToggles();
|
|
|
|
if (state && !allModelsDownloaded) {
|
|
if (FrogPilotConfirmationDialog::yesorno(tr("The \"Model Randomizer\" works only with downloaded models. Download all models now?"), this)) {
|
|
params_memory.putBool("DownloadAllModels", true);
|
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
|
|
|
downloadModelButton->setValue(tr("Downloading..."));
|
|
|
|
allModelsDownloading = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [modelLayout, modelPanel, this] {
|
|
openDescriptions(forceOpenDescriptions, toggles);
|
|
modelLayout->setCurrentWidget(modelPanel);
|
|
});
|
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotModelPanel::updateState);
|
|
}
|
|
|
|
void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
|
FrogPilotUIState &fs = *frogpilotUIState();
|
|
UIState &s = *uiState();
|
|
|
|
allModelsDownloading = params_memory.getBool("DownloadAllModels");
|
|
modelDownloading = !params_memory.get("ModelDownloadProgress").empty();
|
|
tinygradUpdate = params.getBool("TinygradUpdateAvailable");
|
|
updatingTinygrad = params_memory.getBool("UpdateTinygrad");
|
|
|
|
modelDownloading &= !updatingTinygrad;
|
|
|
|
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",");
|
|
availableModels.sort();
|
|
availableModelNames = QString::fromStdString(params.get("AvailableModelNames")).split(",");
|
|
availableModelNames.sort();
|
|
|
|
modelFileToNameMap.clear();
|
|
modelFileToNameMapProcessed.clear();
|
|
for (int i = 0; i < qMin(availableModels.size(), availableModelNames.size()); ++i) {
|
|
modelFileToNameMap.insert(availableModels[i], availableModelNames[i]);
|
|
modelFileToNameMapProcessed.insert(availableModels[i], processModelName(availableModelNames[i]));
|
|
}
|
|
|
|
QStringList downloadableModels = availableModelNames;
|
|
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
|
QString modelName = modelFileToNameMap.value(modelKey);
|
|
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
|
downloadableModels.removeAll(modelName);
|
|
}
|
|
}
|
|
allModelsDownloaded = downloadableModels.isEmpty();
|
|
|
|
QStringList deletableModels;
|
|
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
|
QString base = QFileInfo(file).baseName();
|
|
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
|
if (base.startsWith(modelKey)) {
|
|
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
|
if (!deletableModels.contains(modelName)) {
|
|
deletableModels.append(modelName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
deletableModels.removeAll(processModelName(currentModel));
|
|
deletableModels.removeAll(modelFileToNameMapProcessed.value(normalizeModelKey(QString::fromStdString(params_default.get("Model")))));
|
|
noModelsDownloaded = deletableModels.isEmpty();
|
|
|
|
QString modelKey = normalizeModelKey(QString::fromStdString(params.get("Model")));
|
|
if (!modelDir.exists(modelKey + ".thneed") && !hasAllTinygradFiles(modelDir, modelKey)) {
|
|
modelKey = normalizeModelKey(QString::fromStdString(params_default.get("Model")));
|
|
}
|
|
currentModel = modelFileToNameMap.value(modelKey);
|
|
selectModelButton->setValue(currentModel);
|
|
|
|
bool parked = !s.scene.started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
|
|
|
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
|
|
|
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
|
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
|
|
|
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
|
|
|
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
|
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
|
|
|
started = s.scene.started;
|
|
|
|
updateToggles();
|
|
}
|
|
|
|
void FrogPilotModelPanel::updateState(const UIState &s, const FrogPilotUIState &fs) {
|
|
if (!isVisible() || finalizingDownload) {
|
|
return;
|
|
}
|
|
|
|
bool parked = !started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
|
|
|
if (allModelsDownloading || modelDownloading) {
|
|
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
|
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
|
|
|
{
|
|
QString translatedProgress;
|
|
if (progress == "Downloading...") {
|
|
translatedProgress = tr("Downloading...");
|
|
} else if (progress == "Downloaded!") {
|
|
translatedProgress = tr("Downloaded!");
|
|
} else if (progress == "All models downloaded!") {
|
|
translatedProgress = tr("All models downloaded!");
|
|
} else if (progress.contains("cancelled", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("Download cancelled...");
|
|
} else if (progress.contains("failed", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("Download failed...");
|
|
} else if (progress.contains("offline", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("GitHub and GitLab are offline...");
|
|
} else if (progress == "Repository unavailable") {
|
|
translatedProgress = tr("Repository unavailable");
|
|
} else {
|
|
translatedProgress = progress;
|
|
}
|
|
downloadModelButton->setValue(translatedProgress);
|
|
}
|
|
|
|
if (progress == "All models downloaded!" || progress == "Downloaded!" && !allModelsDownloading || downloadFailed) {
|
|
finalizingDownload = true;
|
|
|
|
QTimer::singleShot(2500, [progress, this]() {
|
|
allModelsDownloading = false;
|
|
cancellingDownload = false;
|
|
finalizingDownload = false;
|
|
modelDownloading = false;
|
|
noModelsDownloaded = false;
|
|
|
|
QStringList downloadableModels = availableModelNames;
|
|
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
|
QString modelName = modelFileToNameMap.value(modelKey);
|
|
if (modelDir.exists(modelKey + ".thneed") || hasAllTinygradFiles(modelDir, modelKey)) {
|
|
downloadableModels.removeAll(modelName);
|
|
}
|
|
}
|
|
allModelsDownloaded = downloadableModels.isEmpty();
|
|
|
|
params_memory.remove("ModelDownloadProgress");
|
|
|
|
downloadModelButton->setEnabled(true);
|
|
downloadModelButton->setValue("");
|
|
});
|
|
}
|
|
} else {
|
|
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
|
}
|
|
|
|
if (updatingTinygrad) {
|
|
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
|
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
|
|
|
{
|
|
QString translatedProgress;
|
|
if (progress == "Downloading...") {
|
|
translatedProgress = tr("Downloading...");
|
|
} else if (progress == "Downloaded!") {
|
|
translatedProgress = tr("Downloaded!");
|
|
} else if (progress == "All models downloaded!") {
|
|
translatedProgress = tr("All models downloaded!");
|
|
} else if (progress.contains("cancelled", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("Download cancelled...");
|
|
} else if (progress.contains("failed", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("Download failed...");
|
|
} else if (progress.contains("offline", Qt::CaseInsensitive)) {
|
|
translatedProgress = tr("GitHub and GitLab are offline...");
|
|
} else if (progress == "Repository unavailable") {
|
|
translatedProgress = tr("Repository unavailable");
|
|
} else {
|
|
translatedProgress = progress;
|
|
}
|
|
updateTinygradButton->setValue(translatedProgress);
|
|
}
|
|
|
|
if (progress == "Updated!" && updatingTinygrad || downloadFailed) {
|
|
finalizingDownload = true;
|
|
|
|
QTimer::singleShot(2500, [progress, this]() {
|
|
modelDownloading = !params_memory.get("ModelDownloadProgress").empty();
|
|
|
|
if (modelDownloading) {
|
|
downloadModelButton->setText(1, tr("CANCEL"));
|
|
|
|
downloadModelButton->setValue(tr("Downloading..."));
|
|
|
|
downloadModelButton->setVisibleButton(0, false);
|
|
} else {
|
|
cancellingDownload = false;
|
|
}
|
|
|
|
tinygradUpdate = params.getBool("TinygradUpdateAvailable");
|
|
|
|
finalizingDownload = false;
|
|
updatingTinygrad = false;
|
|
|
|
updateTinygradButton->setEnabled(tinygradUpdate);
|
|
updateTinygradButton->setText(0, tr("UPDATE"));
|
|
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
|
});
|
|
}
|
|
}
|
|
|
|
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
|
|
|
downloadModelButton->setText(0, modelDownloading ? tr("CANCEL") : tr("DOWNLOAD"));
|
|
downloadModelButton->setText(1, allModelsDownloading ? tr("CANCEL") : tr("DOWNLOAD ALL"));
|
|
|
|
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !finalizingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
|
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !finalizingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
|
|
|
downloadModelButton->setVisibleButton(0, !allModelsDownloading);
|
|
downloadModelButton->setVisibleButton(1, !modelDownloading);
|
|
|
|
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && !cancellingDownload && !finalizingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
|
|
|
started = s.scene.started;
|
|
|
|
parent->keepScreenOn = allModelsDownloading || modelDownloading || updatingTinygrad;
|
|
}
|
|
|
|
void FrogPilotModelPanel::updateModelLabels(FrogPilotListWidget *labelsList) {
|
|
labelsList->clear();
|
|
|
|
QJsonObject modelDrivesAndScores = QJsonDocument::fromJson(QString::fromStdString(params.get("ModelDrivesAndScores")).toUtf8()).object();
|
|
|
|
for (const QString &modelName : availableModelNames) {
|
|
QJsonObject modelData = modelDrivesAndScores.value(processModelName(modelName)).toObject();
|
|
|
|
int drives = modelData.value("Drives").toInt(0);
|
|
int score = modelData.value("Score").toInt(0);
|
|
|
|
QString drivesDisplay = drives == 1 ? QString("%1 Drive").arg(drives) : drives > 0 ? QString("%1 Drives").arg(drives) : "N/A";
|
|
QString scoreDisplay = drives > 0 ? QString("Score: %1%").arg(score) : "N/A";
|
|
|
|
QString labelTitle = processModelName(modelName);
|
|
QString labelText = QString("%1 (%2)").arg(scoreDisplay, drivesDisplay);
|
|
|
|
LabelControl *labelControl = new LabelControl(labelTitle, labelText, "", this);
|
|
labelsList->addItem(labelControl);
|
|
}
|
|
}
|
|
|
|
void FrogPilotModelPanel::updateToggles() {
|
|
for (auto &[key, toggle] : toggles) {
|
|
bool setVisible = parent->tuningLevel >= parent->frogpilotToggleLevels[key].toDouble();
|
|
|
|
if (key == "ManageBlacklistedModels" || key == "ManageScores") {
|
|
setVisible &= params.getBool("ModelRandomizer");
|
|
}
|
|
|
|
else if (key == "SelectModel") {
|
|
setVisible &= !params.getBool("ModelRandomizer");
|
|
}
|
|
|
|
toggle->setVisible(setVisible);
|
|
}
|
|
|
|
openDescriptions(forceOpenDescriptions, toggles);
|
|
|
|
update();
|
|
}
|