feat: add Clear Cache action to Settings
This commit is contained in:
parent
24866e16ef
commit
d05f3f4681
178
src/activities/settings/ClearCacheActivity.cpp
Normal file
178
src/activities/settings/ClearCacheActivity.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "ClearCacheActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <SDCardManager.h>
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
void ClearCacheActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<ClearCacheActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void ClearCacheActivity::onEnter() {
|
||||
ActivityWithSubactivity::onEnter();
|
||||
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
state = WARNING;
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&ClearCacheActivity::taskTrampoline, "ClearCacheActivityTask",
|
||||
4096, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&displayTaskHandle // Task handle
|
||||
);
|
||||
}
|
||||
|
||||
void ClearCacheActivity::onExit() {
|
||||
ActivityWithSubactivity::onExit();
|
||||
|
||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
if (displayTaskHandle) {
|
||||
vTaskDelete(displayTaskHandle);
|
||||
displayTaskHandle = nullptr;
|
||||
}
|
||||
vSemaphoreDelete(renderingMutex);
|
||||
renderingMutex = nullptr;
|
||||
}
|
||||
|
||||
void ClearCacheActivity::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) {
|
||||
updateRequired = false;
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
render();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearCacheActivity::render() {
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
|
||||
renderer.clearScreen();
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Clear Cache", true, EpdFontFamily::BOLD);
|
||||
|
||||
if (state == WARNING) {
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 60, "This will clear all cached book data.", true);
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 30, "All reading progress will be lost!", true,
|
||||
EpdFontFamily::BOLD);
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, "Books will need to be re-indexed", true);
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 30, "when opened again.", true);
|
||||
|
||||
const auto labels = mappedInput.mapLabels("« Cancel", "Clear", "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
renderer.displayBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == CLEARING) {
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, "Clearing cache...", true, EpdFontFamily::BOLD);
|
||||
renderer.displayBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == SUCCESS) {
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, "Cache Cleared", true, EpdFontFamily::BOLD);
|
||||
String resultText = String(clearedCount) + " items removed";
|
||||
if (failedCount > 0) {
|
||||
resultText += ", " + String(failedCount) + " failed";
|
||||
}
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, resultText.c_str());
|
||||
|
||||
const auto labels = mappedInput.mapLabels("« Back", "", "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
renderer.displayBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == FAILED) {
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, "Failed to clear cache", true, EpdFontFamily::BOLD);
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, "Check serial output for details");
|
||||
|
||||
const auto labels = mappedInput.mapLabels("« Back", "", "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
renderer.displayBuffer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearCacheActivity::clearCache() {
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] Clearing cache...\n", millis());
|
||||
|
||||
// Open .crosspoint directory
|
||||
auto root = SdMan.open("/.crosspoint");
|
||||
if (!root || !root.isDirectory()) {
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] Failed to open cache directory\n", millis());
|
||||
if (root) root.close();
|
||||
state = FAILED;
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
clearedCount = 0;
|
||||
failedCount = 0;
|
||||
char name[128];
|
||||
|
||||
// Iterate through all entries in the directory
|
||||
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
||||
file.getName(name, sizeof(name));
|
||||
String itemName(name);
|
||||
|
||||
// Only delete directories starting with epub_ or xtc_
|
||||
if (file.isDirectory() && (itemName.startsWith("epub_") || itemName.startsWith("xtc_"))) {
|
||||
String fullPath = "/.crosspoint/" + itemName;
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] Removing cache: %s\n", millis(), fullPath.c_str());
|
||||
|
||||
file.close(); // Close before attempting to delete
|
||||
|
||||
if (SdMan.removeDir(fullPath.c_str())) {
|
||||
clearedCount++;
|
||||
} else {
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] Failed to remove: %s\n", millis(), fullPath.c_str());
|
||||
failedCount++;
|
||||
}
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
root.close();
|
||||
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] Cache cleared: %d removed, %d failed\n", millis(), clearedCount, failedCount);
|
||||
|
||||
state = SUCCESS;
|
||||
updateRequired = true;
|
||||
}
|
||||
|
||||
void ClearCacheActivity::loop() {
|
||||
if (state == WARNING) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] User confirmed, starting cache clear\n", millis());
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
state = CLEARING;
|
||||
xSemaphoreGive(renderingMutex);
|
||||
updateRequired = true;
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
Serial.printf("[%lu] [CLEAR_CACHE] User cancelled\n", millis());
|
||||
goBack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == SUCCESS || state == FAILED) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
goBack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
37
src/activities/settings/ClearCacheActivity.h
Normal file
37
src/activities/settings/ClearCacheActivity.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "activities/ActivityWithSubactivity.h"
|
||||
|
||||
class ClearCacheActivity final : public ActivityWithSubactivity {
|
||||
public:
|
||||
explicit ClearCacheActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::function<void()>& goBack)
|
||||
: ActivityWithSubactivity("ClearCache", renderer, mappedInput), goBack(goBack) {}
|
||||
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
private:
|
||||
enum State { WARNING, CLEARING, SUCCESS, FAILED };
|
||||
|
||||
State state = WARNING;
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> goBack;
|
||||
|
||||
int clearedCount = 0;
|
||||
int failedCount = 0;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render();
|
||||
void clearCache();
|
||||
};
|
||||
@ -6,6 +6,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "CalibreSettingsActivity.h"
|
||||
#include "ClearCacheActivity.h"
|
||||
#include "CrossPointSettings.h"
|
||||
#include "KOReaderSettingsActivity.h"
|
||||
#include "MappedInputManager.h"
|
||||
@ -14,7 +15,7 @@
|
||||
|
||||
// Define the static settings list
|
||||
namespace {
|
||||
constexpr int settingsCount = 22;
|
||||
constexpr int settingsCount = 23;
|
||||
const SettingInfo settingsList[settingsCount] = {
|
||||
// Should match with SLEEP_SCREEN_MODE
|
||||
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
|
||||
@ -44,6 +45,7 @@ const SettingInfo settingsList[settingsCount] = {
|
||||
SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency,
|
||||
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}),
|
||||
SettingInfo::Action("KOReader Sync"),
|
||||
SettingInfo::Action("Clear Cache"),
|
||||
SettingInfo::Action("Calibre Settings"),
|
||||
SettingInfo::Action("Check for updates")};
|
||||
} // namespace
|
||||
@ -149,6 +151,14 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
updateRequired = true;
|
||||
}));
|
||||
xSemaphoreGive(renderingMutex);
|
||||
} else if (strcmp(setting.name, "Clear Cache") == 0) {
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
exitActivity();
|
||||
enterNewActivity(new ClearCacheActivity(renderer, mappedInput, [this] {
|
||||
exitActivity();
|
||||
updateRequired = true;
|
||||
}));
|
||||
xSemaphoreGive(renderingMutex);
|
||||
} else if (strcmp(setting.name, "Calibre Settings") == 0) {
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
exitActivity();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user