From 693a65009438b8b43dc914a4146aabcc75a44c71 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Tue, 12 May 2026 14:33:14 +0200 Subject: [PATCH] Add option to remove a downloaded font --- lib/I18n/translations/english.yaml | 1 + .../settings/FontDownloadActivity.cpp | 94 +++++++++++++++++-- .../settings/FontDownloadActivity.h | 12 +++ src/activities/settings/SettingsActivity.cpp | 2 +- 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index c9a67006..9fa1bee9 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -100,6 +100,7 @@ STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Create fallback for invalid TOC" STR_ORIENTATION: "Reading Orientation" STR_LONG_PRESS_SKIP: "Long-press Chapter Skip" STR_FONT_FAMILY: "Reader Font Family" +STR_FONT_MANAGER: "Font Manager" STR_FONT_DOWNLOAD: "Font Download" STR_FONT_INSTALLED: "Font installed!" STR_FONT_INSTALL_FAILED: "Font installation failed" diff --git a/src/activities/settings/FontDownloadActivity.cpp b/src/activities/settings/FontDownloadActivity.cpp index 3aec928f..f1ae7e43 100644 --- a/src/activities/settings/FontDownloadActivity.cpp +++ b/src/activities/settings/FontDownloadActivity.cpp @@ -7,11 +7,13 @@ #include #include +#include #include #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(&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(&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(&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(&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(&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(&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(&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(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(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(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(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) { diff --git a/src/activities/settings/FontDownloadActivity.h b/src/activities/settings/FontDownloadActivity.h index 33cdf934..62316ce5 100644 --- a/src/activities/settings/FontDownloadActivity.h +++ b/src/activities/settings/FontDownloadActivity.h @@ -56,11 +56,18 @@ class FontDownloadActivity : public Activity { std::vector families_; int selectedIndex_ = 0; + enum class PendingFontAction { + None, + Download, + Delete, + }; + size_t currentFileIndex_ = 0; size_t currentFileTotal_ = 0; size_t fileProgress_ = 0; size_t fileTotal_ = 0; int downloadingFamilyIndex_ = 0; + PendingFontAction pendingErrorAction_ = PendingFontAction::None; std::string errorMessage_; void onWifiSelectionComplete(bool success); @@ -71,5 +78,10 @@ class FontDownloadActivity : public Activity { int familyIndexFromList(int listIndex) const { return listIndex - 1; } int listItemCount() const { return families_.empty() ? 0 : static_cast(families_.size()) + 1; } size_t totalUninstalledSize() const; + + std::string confirmButtonLabel() const; + void promptDeleteFamily(int familyIndex); + void deleteFamilyAtIndex(int familyIndex); + static std::string formatSize(size_t bytes); }; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 7044b2b5..dbac7bd2 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -68,7 +68,7 @@ void SettingsActivity::onEnter() { SettingInfo includeBetaUpdatesSetting{}; auto insertFontDownloadBelowFontSection = [&]() { - auto fontDownload = SettingInfo::Action(StrId::STR_FONT_DOWNLOAD, SettingAction::DownloadFonts); + auto fontDownload = SettingInfo::Action(StrId::STR_FONT_MANAGER, SettingAction::DownloadFonts); fontDownload.withSubcategory(StrId::STR_MENU_READER_FONT); addToMoved(readerSettings, lastReaderSub, std::move(fontDownload)); insertedFontDownload = true;