Add option to remove a downloaded font

This commit is contained in:
jpirnay
2026-05-12 14:33:14 +02:00
parent 8d2cfb17a7
commit 693a650094
4 changed files with 101 additions and 8 deletions
@@ -7,11 +7,13 @@
#include <Logging.h>
#include <WiFi.h>
#include <algorithm>
#include <cstring>
#include "MappedInputManager.h"
#include "SdCardFontGlobals.h"
#include "activities/network/WifiSelectionActivity.h"
#include "activities/util/ConfirmationActivity.h"
#include "components/UITheme.h"
#include "fontIds.h"
#include "network/HttpDownloader.h"
@@ -202,6 +204,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
LOG_ERR("FONT", "Failed to clean staging dir: %s", stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Failed to prepare staging area";
return;
}
@@ -210,6 +214,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
LOG_ERR("FONT", "Failed to create staging dir: %s", stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Failed to create staging area";
return;
}
@@ -254,6 +260,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
Storage.removeDir(stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Download failed: " + file.name;
return;
}
@@ -263,6 +271,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
Storage.removeDir(stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Invalid font file: " + file.name;
return;
}
@@ -275,6 +285,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
Storage.removeDir(stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Failed to prepare backup area";
return;
}
@@ -284,6 +296,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
Storage.removeDir(stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Failed to replace installed font";
return;
}
@@ -296,6 +310,8 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
Storage.removeDir(stagingDir);
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
downloadingFamilyIndex_ = static_cast<int>(&family - families_.data());
errorMessage_ = "Failed to finalize font install";
return;
}
@@ -312,6 +328,61 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) {
state_ = COMPLETE;
}
void FontDownloadActivity::promptDeleteFamily(int familyIndex) {
if (familyIndex < 0 || familyIndex >= static_cast<int>(families_.size())) return;
const auto& family = families_[familyIndex];
const std::string heading = tr(STR_DELETE) + std::string("?");
const std::string body = family.name;
startActivityForResult(std::make_unique<ConfirmationActivity>(renderer, mappedInput, heading, body),
[this, familyIndex](const ActivityResult& result) {
if (result.isCancelled) return;
deleteFamilyAtIndex(familyIndex);
});
}
void FontDownloadActivity::deleteFamilyAtIndex(int familyIndex) {
if (familyIndex < 0 || familyIndex >= static_cast<int>(families_.size())) return;
auto& family = families_[familyIndex];
const auto result = fontInstaller_.deleteFamily(family.name.c_str());
if (result == FontInstaller::Error::OK) {
fontInstaller_.refreshRegistry();
family.installed = false;
family.hasUpdate = false;
pendingErrorAction_ = PendingFontAction::None;
errorMessage_.clear();
if (selectedIndex_ >= listItemCount()) {
selectedIndex_ = std::max(0, listItemCount() - 1);
}
RenderLock lock(*this);
state_ = FAMILY_LIST;
requestUpdate();
return;
}
std::string message = "Failed to delete font";
if (result == FontInstaller::Error::INVALID_FAMILY_NAME) {
message = "Invalid font family";
}
RenderLock lock(*this);
state_ = ERROR;
downloadingFamilyIndex_ = familyIndex;
pendingErrorAction_ = PendingFontAction::Delete;
errorMessage_ = message;
}
std::string FontDownloadActivity::confirmButtonLabel() const {
if (families_.empty()) return tr(STR_DOWNLOAD);
if (isDownloadAllSelected()) return tr(STR_DOWNLOAD);
const auto& family = families_[familyIndexFromList(selectedIndex_)];
if (family.installed && !family.hasUpdate) return tr(STR_DELETE);
if (family.hasUpdate) return tr(STR_UPDATE);
return tr(STR_DOWNLOAD);
}
// --- Input handling ---
void FontDownloadActivity::loop() {
@@ -339,13 +410,17 @@ void FontDownloadActivity::loop() {
if (!families_.empty()) {
if (isDownloadAllSelected()) {
downloadAll();
requestUpdateAndWait();
} else {
const auto& family = families_[familyIndexFromList(selectedIndex_)];
if (!family.installed || family.hasUpdate) {
downloadFamily(families_[familyIndexFromList(selectedIndex_)]);
const int familyIndex = familyIndexFromList(selectedIndex_);
const auto& family = families_[familyIndex];
if (family.installed && !family.hasUpdate) {
promptDeleteFamily(familyIndex);
} else {
downloadFamily(families_[familyIndex]);
requestUpdateAndWait();
}
}
requestUpdateAndWait();
}
}
} else if (state_ == COMPLETE) {
@@ -366,7 +441,11 @@ void FontDownloadActivity::loop() {
requestUpdate();
} else if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
if (downloadingFamilyIndex_ >= 0 && downloadingFamilyIndex_ < static_cast<int>(families_.size())) {
downloadFamily(families_[downloadingFamilyIndex_]);
if (pendingErrorAction_ == PendingFontAction::Delete) {
deleteFamilyAtIndex(downloadingFamilyIndex_);
} else {
downloadFamily(families_[downloadingFamilyIndex_]);
}
requestUpdateAndWait();
} else {
{
@@ -400,7 +479,7 @@ void FontDownloadActivity::render(RenderLock&&) {
renderer.clearScreen();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_FONT_DOWNLOAD));
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_FONT_MANAGER));
const auto lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
const auto contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
@@ -434,7 +513,8 @@ void FontDownloadActivity::render(RenderLock&&) {
},
true);
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_DOWNLOAD), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
const std::string confirmLabel = confirmButtonLabel();
const auto labels = mappedInput.mapLabels(tr(STR_BACK), confirmLabel.c_str(), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
}
} else if (state_ == DOWNLOADING) {