Thumbnail background loading
This commit is contained in:
parent
666d3a9179
commit
f40ab574b2
@ -18,8 +18,8 @@ constexpr int TILE_PADDING = 5;
|
|||||||
constexpr int THUMB_W = 90;
|
constexpr int THUMB_W = 90;
|
||||||
constexpr int THUMB_H = 120;
|
constexpr int THUMB_H = 120;
|
||||||
constexpr int TILE_TEXT_H = 60;
|
constexpr int TILE_TEXT_H = 60;
|
||||||
constexpr int gridLeftOffset = 37;
|
constexpr int GRID_OFFSET_LEFT = 37;
|
||||||
constexpr int gridTopOffset = 125;
|
constexpr int GRID_OFFSET_TOP = 125;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
inline int min(const int a, const int b) { return a < b ? a : b; }
|
inline int min(const int a, const int b) { return a < b ? a : b; }
|
||||||
@ -39,10 +39,40 @@ void GridBrowserActivity::displayTaskTrampoline(void* param) {
|
|||||||
self->displayTaskLoop();
|
self->displayTaskLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void GridBrowserActivity::loadThumbsTaskTrampoline(void* param) {
|
void GridBrowserActivity::loadThumbsTaskTrampoline(void* param) {
|
||||||
// auto* self = static_cast<GridBrowserActivity*>(param);
|
auto* self = static_cast<GridBrowserActivity*>(param);
|
||||||
// self->displayTaskLoop();
|
self->loadThumbsTaskLoop();
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
void GridBrowserActivity::loadThumbsTaskLoop() {
|
||||||
|
while (true) {
|
||||||
|
if (thumbsLoadingRequired) {
|
||||||
|
xSemaphoreTake(loadThumbsMutex, portMAX_DELAY);
|
||||||
|
loadThumbs();
|
||||||
|
xSemaphoreGive(loadThumbsMutex);
|
||||||
|
thumbsLoadingRequired = false;
|
||||||
|
}
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GridBrowserActivity::loadThumbs() {
|
||||||
|
int thumbsCount = min(PAGE_ITEMS, files.size() - page * PAGE_ITEMS);
|
||||||
|
for (int i = 0; i < thumbsCount; i++) {
|
||||||
|
const auto file = files[i + page * PAGE_ITEMS];
|
||||||
|
if (file.type == F_EPUB) {
|
||||||
|
if (file.thumbPath.empty()) {
|
||||||
|
Serial.printf("[%lu] Loading thumb for epub: %s\n", millis(), file.name.c_str());
|
||||||
|
std::string thumbPath = loadEpubThumb(basepath + "/" + file.name);
|
||||||
|
if (!thumbPath.empty()) {
|
||||||
|
files[i + page * PAGE_ITEMS].thumbPath = thumbPath;
|
||||||
|
}
|
||||||
|
renderRequired = true;
|
||||||
|
taskYIELD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string GridBrowserActivity::loadEpubThumb(std::string path) {
|
std::string GridBrowserActivity::loadEpubThumb(std::string path) {
|
||||||
File file;
|
File file;
|
||||||
@ -87,12 +117,6 @@ void GridBrowserActivity::loadFiles() {
|
|||||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ return std::tolower(c); });
|
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ return std::tolower(c); });
|
||||||
if (ext == ".epub") {
|
if (ext == ".epub") {
|
||||||
type = F_EPUB;
|
type = F_EPUB;
|
||||||
// xTaskCreate(&GridBrowserActivity::taskTrampoline, "GridFileBrowserTask",
|
|
||||||
// 2048, // Stack size
|
|
||||||
// this, // Parameters
|
|
||||||
// 1, // Priority
|
|
||||||
// &displayTaskHandle // Task handle
|
|
||||||
// );
|
|
||||||
} else if (ext == ".bmp") {
|
} else if (ext == ".bmp") {
|
||||||
type = F_BMP;
|
type = F_BMP;
|
||||||
}
|
}
|
||||||
@ -102,30 +126,32 @@ void GridBrowserActivity::loadFiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
count ++;
|
count++;
|
||||||
}
|
}
|
||||||
root.close();
|
root.close();
|
||||||
Serial.printf("Files loaded\n");
|
|
||||||
GridBrowserActivity::sortFileList(files);
|
GridBrowserActivity::sortFileList(files);
|
||||||
Serial.printf("Files sorted\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridBrowserActivity::onEnter() {
|
void GridBrowserActivity::onEnter() {
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
loadThumbsMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
loadFiles();
|
|
||||||
selectorIndex = 0;
|
|
||||||
page = 0;
|
page = 0;
|
||||||
|
loadFiles();
|
||||||
// Trigger first render
|
onPageChanged();
|
||||||
renderRequired = true;
|
|
||||||
|
|
||||||
xTaskCreate(&GridBrowserActivity::displayTaskTrampoline, "GridFileBrowserTask",
|
xTaskCreate(&GridBrowserActivity::displayTaskTrampoline, "GridFileBrowserTask",
|
||||||
8192, // Stack size
|
8192, // Stack size
|
||||||
this, // Parameters
|
this, // Parameters
|
||||||
1, // Priority
|
2, // Priority
|
||||||
&displayTaskHandle // Task handle
|
&displayTaskHandle // Task handle
|
||||||
);
|
);
|
||||||
|
xTaskCreate(&GridBrowserActivity::loadThumbsTaskTrampoline, "LoadThumbsTask",
|
||||||
|
8192, // Stack size
|
||||||
|
this, // Parameters
|
||||||
|
1, // Priority
|
||||||
|
&loadThumbsTaskHandle // Task handle
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridBrowserActivity::onExit() {
|
void GridBrowserActivity::onExit() {
|
||||||
@ -139,9 +165,24 @@ void GridBrowserActivity::onExit() {
|
|||||||
}
|
}
|
||||||
vSemaphoreDelete(renderingMutex);
|
vSemaphoreDelete(renderingMutex);
|
||||||
renderingMutex = nullptr;
|
renderingMutex = nullptr;
|
||||||
|
|
||||||
|
if (loadThumbsTaskHandle) {
|
||||||
|
vTaskDelete(loadThumbsTaskHandle);
|
||||||
|
loadThumbsTaskHandle = nullptr;
|
||||||
|
}
|
||||||
|
vSemaphoreDelete(loadThumbsMutex);
|
||||||
|
loadThumbsMutex = nullptr;
|
||||||
|
|
||||||
files.clear();
|
files.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GridBrowserActivity::onPageChanged() {
|
||||||
|
selectorIndex = 0;
|
||||||
|
previousSelectorIndex = -1;
|
||||||
|
renderRequired = true;
|
||||||
|
thumbsLoadingRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
void GridBrowserActivity::loop() {
|
void GridBrowserActivity::loop() {
|
||||||
const bool prevReleased = inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT);
|
const bool prevReleased = inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT);
|
||||||
const bool nextReleased = inputManager.wasReleased(InputManager::BTN_DOWN) || inputManager.wasReleased(InputManager::BTN_RIGHT);
|
const bool nextReleased = inputManager.wasReleased(InputManager::BTN_DOWN) || inputManager.wasReleased(InputManager::BTN_RIGHT);
|
||||||
@ -160,7 +201,7 @@ void GridBrowserActivity::loop() {
|
|||||||
// open subfolder
|
// open subfolder
|
||||||
basepath += files[selected].name;
|
basepath += files[selected].name;
|
||||||
loadFiles();
|
loadFiles();
|
||||||
renderRequired = true;
|
onPageChanged();
|
||||||
} else {
|
} else {
|
||||||
onSelect(basepath + files[selected].name);
|
onSelect(basepath + files[selected].name);
|
||||||
}
|
}
|
||||||
@ -169,7 +210,7 @@ void GridBrowserActivity::loop() {
|
|||||||
basepath.resize(basepath.rfind('/'));
|
basepath.resize(basepath.rfind('/'));
|
||||||
if (basepath.empty()) basepath = "/";
|
if (basepath.empty()) basepath = "/";
|
||||||
loadFiles();
|
loadFiles();
|
||||||
renderRequired = true;
|
onPageChanged();
|
||||||
} else {
|
} else {
|
||||||
// At root level, go back home
|
// At root level, go back home
|
||||||
onGoHome();
|
onGoHome();
|
||||||
@ -179,9 +220,7 @@ void GridBrowserActivity::loop() {
|
|||||||
if (selectorIndex == 0 || skipPage) {
|
if (selectorIndex == 0 || skipPage) {
|
||||||
if (page > 0) {
|
if (page > 0) {
|
||||||
page--;
|
page--;
|
||||||
selectorIndex = 0;
|
onPageChanged();
|
||||||
previousSelectorIndex = -1;
|
|
||||||
renderRequired = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectorIndex--;
|
selectorIndex--;
|
||||||
@ -192,9 +231,7 @@ void GridBrowserActivity::loop() {
|
|||||||
if (selectorIndex == min(PAGE_ITEMS, files.size() - page * PAGE_ITEMS) - 1 || skipPage) {
|
if (selectorIndex == min(PAGE_ITEMS, files.size() - page * PAGE_ITEMS) - 1 || skipPage) {
|
||||||
if (page < files.size() / PAGE_ITEMS) {
|
if (page < files.size() / PAGE_ITEMS) {
|
||||||
page++;
|
page++;
|
||||||
selectorIndex = 0;
|
onPageChanged();
|
||||||
previousSelectorIndex = -1;
|
|
||||||
renderRequired = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectorIndex++;
|
selectorIndex++;
|
||||||
@ -205,16 +242,12 @@ void GridBrowserActivity::loop() {
|
|||||||
|
|
||||||
void GridBrowserActivity::displayTaskLoop() {
|
void GridBrowserActivity::displayTaskLoop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (renderRequired) {
|
if (renderRequired || updateRequired) {
|
||||||
|
bool didRequireRender = renderRequired;
|
||||||
renderRequired = false;
|
renderRequired = false;
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
render(true);
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
} else if (updateRequired) {
|
|
||||||
updateRequired = false;
|
updateRequired = false;
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
// update(true);
|
render(didRequireRender);
|
||||||
render(false);
|
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
}
|
}
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
@ -232,8 +265,8 @@ void GridBrowserActivity::render(bool clear) const {
|
|||||||
for (size_t i = 0; i < min(PAGE_ITEMS, files.size() - page * PAGE_ITEMS); i++) {
|
for (size_t i = 0; i < min(PAGE_ITEMS, files.size() - page * PAGE_ITEMS); i++) {
|
||||||
const auto file = files[i + page * PAGE_ITEMS];
|
const auto file = files[i + page * PAGE_ITEMS];
|
||||||
|
|
||||||
const int16_t tileX = gridLeftOffset + i % 3 * TILE_W;
|
const int16_t tileX = GRID_OFFSET_LEFT + i % 3 * TILE_W;
|
||||||
const int16_t tileY = gridTopOffset + i / 3 * TILE_H;
|
const int16_t tileY = GRID_OFFSET_TOP + i / 3 * TILE_H;
|
||||||
|
|
||||||
if (file.type == F_DIRECTORY) {
|
if (file.type == F_DIRECTORY) {
|
||||||
constexpr int iconOffsetX = (TILE_W - FOLDERICON_WIDTH) / 2;
|
constexpr int iconOffsetX = (TILE_W - FOLDERICON_WIDTH) / 2;
|
||||||
@ -263,7 +296,7 @@ void GridBrowserActivity::render(bool clear) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GridBrowserActivity::drawSelectionRectangle(int tileIndex, bool black) const {
|
void GridBrowserActivity::drawSelectionRectangle(int tileIndex, bool black) const {
|
||||||
renderer.drawRoundedRect(gridLeftOffset + tileIndex % 3 * TILE_W, gridTopOffset + tileIndex / 3 * TILE_H, TILE_W, TILE_H, 2, 5, black);
|
renderer.drawRoundedRect(GRID_OFFSET_LEFT + tileIndex % 3 * TILE_W, GRID_OFFSET_TOP + tileIndex / 3 * TILE_H, TILE_W, TILE_H, 2, 5, black);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridBrowserActivity::update(bool render) const {
|
void GridBrowserActivity::update(bool render) const {
|
||||||
|
|||||||
@ -27,6 +27,8 @@ struct FileInfo {
|
|||||||
class GridBrowserActivity final : public Activity {
|
class GridBrowserActivity final : public Activity {
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
|
TaskHandle_t loadThumbsTaskHandle = nullptr;
|
||||||
|
SemaphoreHandle_t loadThumbsMutex = nullptr;
|
||||||
std::string basepath = "/";
|
std::string basepath = "/";
|
||||||
std::vector<FileInfo> files;
|
std::vector<FileInfo> files;
|
||||||
int selectorIndex = 0;
|
int selectorIndex = 0;
|
||||||
@ -34,6 +36,7 @@ class GridBrowserActivity final : public Activity {
|
|||||||
int page = 0;
|
int page = 0;
|
||||||
bool updateRequired = false;
|
bool updateRequired = false;
|
||||||
bool renderRequired = false;
|
bool renderRequired = false;
|
||||||
|
bool thumbsLoadingRequired = false;
|
||||||
const std::function<void(const std::string&)> onSelect;
|
const std::function<void(const std::string&)> onSelect;
|
||||||
const std::function<void()> onGoHome;
|
const std::function<void()> onGoHome;
|
||||||
|
|
||||||
@ -45,6 +48,9 @@ class GridBrowserActivity final : public Activity {
|
|||||||
void loadFiles();
|
void loadFiles();
|
||||||
void drawSelectionRectangle(int tileIndex, bool black) const;
|
void drawSelectionRectangle(int tileIndex, bool black) const;
|
||||||
std::string loadEpubThumb(std::string path);
|
std::string loadEpubThumb(std::string path);
|
||||||
|
void loadThumbsTaskLoop();
|
||||||
|
void loadThumbs();
|
||||||
|
void onPageChanged();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GridBrowserActivity(GfxRenderer& renderer, InputManager& inputManager,
|
explicit GridBrowserActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Define the static settings list
|
// Define the static settings list
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int settingsCount = 5;
|
constexpr int settingsCount = 6;
|
||||||
const SettingInfo settingsList[settingsCount] = {
|
const SettingInfo settingsList[settingsCount] = {
|
||||||
// Should match with SLEEP_SCREEN_MODE
|
// Should match with SLEEP_SCREEN_MODE
|
||||||
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
||||||
@ -17,7 +17,7 @@ const SettingInfo settingsList[settingsCount] = {
|
|||||||
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing, {}},
|
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing, {}},
|
||||||
{"Short Power Button Click", SettingType::TOGGLE, &CrossPointSettings::shortPwrBtn, {}},
|
{"Short Power Button Click", SettingType::TOGGLE, &CrossPointSettings::shortPwrBtn, {}},
|
||||||
{"UI Theme", SettingType::ENUM, &CrossPointSettings::uiTheme, {"List", "Grid"}},
|
{"UI Theme", SettingType::ENUM, &CrossPointSettings::uiTheme, {"List", "Grid"}},
|
||||||
{"Check for updates", SettingType::ACTION, nullptr, {}},
|
{"Check for updates", SettingType::ACTION, nullptr, {}}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user