mod: adapt mod activities to #774 render() pattern
Migrate 5 mod Activity subclasses from old polling-based display task pattern to the upstream render() super-class pattern with freeRTOS notification: - EpubReaderBookmarkSelectionActivity - DictionaryWordSelectActivity - DictionarySuggestionsActivity - DictionaryDefinitionActivity - LookedUpWordsActivity Changes: remove own TaskHandle/SemaphoreHandle/updateRequired, use requestUpdate() + render(RenderLock&&) override, fix potential deadlocks around enterNewActivity() calls. Also fix stale conflict marker in EpubReaderMenuActivity.h. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,40 +11,14 @@
|
|||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
void DictionaryDefinitionActivity::taskTrampoline(void* param) {
|
|
||||||
auto* self = static_cast<DictionaryDefinitionActivity*>(param);
|
|
||||||
self->displayTaskLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionaryDefinitionActivity::displayTaskLoop() {
|
|
||||||
while (true) {
|
|
||||||
if (updateRequired) {
|
|
||||||
updateRequired = false;
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
renderScreen();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
}
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionaryDefinitionActivity::onEnter() {
|
void DictionaryDefinitionActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
|
||||||
wrapText();
|
wrapText();
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
xTaskCreate(&DictionaryDefinitionActivity::taskTrampoline, "DictDefTask", 4096, this, 1, &displayTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionaryDefinitionActivity::onExit() {
|
void DictionaryDefinitionActivity::onExit() {
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
if (displayTaskHandle) {
|
|
||||||
vTaskDelete(displayTaskHandle);
|
|
||||||
displayTaskHandle = nullptr;
|
|
||||||
}
|
|
||||||
vSemaphoreDelete(renderingMutex);
|
|
||||||
renderingMutex = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -442,12 +416,12 @@ void DictionaryDefinitionActivity::loop() {
|
|||||||
|
|
||||||
if (prevPage && currentPage > 0) {
|
if (prevPage && currentPage > 0) {
|
||||||
currentPage--;
|
currentPage--;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextPage && currentPage < totalPages - 1) {
|
if (nextPage && currentPage < totalPages - 1) {
|
||||||
currentPage++;
|
currentPage++;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
@@ -465,7 +439,7 @@ void DictionaryDefinitionActivity::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionaryDefinitionActivity::renderScreen() {
|
void DictionaryDefinitionActivity::render(Activity::RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const bool landscape = orientation == CrossPointSettings::ORIENTATION::LANDSCAPE_CW ||
|
const bool landscape = orientation == CrossPointSettings::ORIENTATION::LANDSCAPE_CW ||
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <EpdFontFamily.h>
|
#include <EpdFontFamily.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/semphr.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -27,6 +24,7 @@ class DictionaryDefinitionActivity final : public Activity {
|
|||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
void render(Activity::RenderLock&&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A positioned text segment within a wrapped line (pre-calculated x offset and style).
|
// A positioned text segment within a wrapped line (pre-calculated x offset and style).
|
||||||
@@ -61,17 +59,10 @@ class DictionaryDefinitionActivity final : public Activity {
|
|||||||
int currentPage = 0;
|
int currentPage = 0;
|
||||||
int linesPerPage = 0;
|
int linesPerPage = 0;
|
||||||
int totalPages = 0;
|
int totalPages = 0;
|
||||||
bool updateRequired = false;
|
|
||||||
bool firstRender = true;
|
bool firstRender = true;
|
||||||
|
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
|
||||||
|
|
||||||
std::vector<TextAtom> parseHtml(const std::string& html);
|
std::vector<TextAtom> parseHtml(const std::string& html);
|
||||||
static std::string decodeEntity(const std::string& entity);
|
static std::string decodeEntity(const std::string& entity);
|
||||||
static bool isRenderableCodepoint(uint32_t cp);
|
static bool isRenderableCodepoint(uint32_t cp);
|
||||||
void wrapText();
|
void wrapText();
|
||||||
void renderScreen();
|
|
||||||
static void taskTrampoline(void* param);
|
|
||||||
[[noreturn]] void displayTaskLoop();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,39 +8,13 @@
|
|||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
#include "util/Dictionary.h"
|
#include "util/Dictionary.h"
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::taskTrampoline(void* param) {
|
|
||||||
auto* self = static_cast<DictionarySuggestionsActivity*>(param);
|
|
||||||
self->displayTaskLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::displayTaskLoop() {
|
|
||||||
while (true) {
|
|
||||||
if (updateRequired && !subActivity) {
|
|
||||||
updateRequired = false;
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
renderScreen();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
}
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::onEnter() {
|
void DictionarySuggestionsActivity::onEnter() {
|
||||||
ActivityWithSubactivity::onEnter();
|
ActivityWithSubactivity::onEnter();
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
requestUpdate();
|
||||||
updateRequired = true;
|
|
||||||
xTaskCreate(&DictionarySuggestionsActivity::taskTrampoline, "DictSugTask", 4096, this, 1, &displayTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::onExit() {
|
void DictionarySuggestionsActivity::onExit() {
|
||||||
ActivityWithSubactivity::onExit();
|
ActivityWithSubactivity::onExit();
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
if (displayTaskHandle) {
|
|
||||||
vTaskDelete(displayTaskHandle);
|
|
||||||
displayTaskHandle = nullptr;
|
|
||||||
}
|
|
||||||
vSemaphoreDelete(renderingMutex);
|
|
||||||
renderingMutex = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::loop() {
|
void DictionarySuggestionsActivity::loop() {
|
||||||
@@ -49,7 +23,7 @@ void DictionarySuggestionsActivity::loop() {
|
|||||||
if (pendingBackFromDef) {
|
if (pendingBackFromDef) {
|
||||||
pendingBackFromDef = false;
|
pendingBackFromDef = false;
|
||||||
exitActivity();
|
exitActivity();
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
if (pendingExitToReader) {
|
if (pendingExitToReader) {
|
||||||
pendingExitToReader = false;
|
pendingExitToReader = false;
|
||||||
@@ -68,12 +42,12 @@ void DictionarySuggestionsActivity::loop() {
|
|||||||
|
|
||||||
buttonNavigator.onNext([this] {
|
buttonNavigator.onNext([this] {
|
||||||
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast<int>(suggestions.size()));
|
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast<int>(suggestions.size()));
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPrevious([this] {
|
buttonNavigator.onPrevious([this] {
|
||||||
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast<int>(suggestions.size()));
|
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast<int>(suggestions.size()));
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
@@ -81,10 +55,13 @@ void DictionarySuggestionsActivity::loop() {
|
|||||||
std::string definition = Dictionary::lookup(selected);
|
std::string definition = Dictionary::lookup(selected);
|
||||||
|
|
||||||
if (definition.empty()) {
|
if (definition.empty()) {
|
||||||
GUI.drawPopup(renderer, "Not found");
|
{
|
||||||
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
Activity::RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, "Not found");
|
||||||
|
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
||||||
|
}
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +77,7 @@ void DictionarySuggestionsActivity::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionarySuggestionsActivity::renderScreen() {
|
void DictionarySuggestionsActivity::render(Activity::RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const auto orient = renderer.getOrientation();
|
const auto orient = renderer.getOrientation();
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/semphr.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -28,6 +24,7 @@ class DictionarySuggestionsActivity final : public ActivityWithSubactivity {
|
|||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
void render(Activity::RenderLock&&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string originalWord;
|
std::string originalWord;
|
||||||
@@ -39,15 +36,7 @@ class DictionarySuggestionsActivity final : public ActivityWithSubactivity {
|
|||||||
const std::function<void()> onDone;
|
const std::function<void()> onDone;
|
||||||
|
|
||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
bool updateRequired = false;
|
|
||||||
bool pendingBackFromDef = false;
|
bool pendingBackFromDef = false;
|
||||||
bool pendingExitToReader = false;
|
bool pendingExitToReader = false;
|
||||||
ButtonNavigator buttonNavigator;
|
ButtonNavigator buttonNavigator;
|
||||||
|
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
|
||||||
|
|
||||||
void renderScreen();
|
|
||||||
static void taskTrampoline(void* param);
|
|
||||||
[[noreturn]] void displayTaskLoop();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,45 +14,19 @@
|
|||||||
#include "util/Dictionary.h"
|
#include "util/Dictionary.h"
|
||||||
#include "util/LookupHistory.h"
|
#include "util/LookupHistory.h"
|
||||||
|
|
||||||
void DictionaryWordSelectActivity::taskTrampoline(void* param) {
|
|
||||||
auto* self = static_cast<DictionaryWordSelectActivity*>(param);
|
|
||||||
self->displayTaskLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionaryWordSelectActivity::displayTaskLoop() {
|
|
||||||
while (true) {
|
|
||||||
if (updateRequired && !subActivity) {
|
|
||||||
updateRequired = false;
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
renderScreen();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
}
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictionaryWordSelectActivity::onEnter() {
|
void DictionaryWordSelectActivity::onEnter() {
|
||||||
ActivityWithSubactivity::onEnter();
|
ActivityWithSubactivity::onEnter();
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
|
||||||
extractWords();
|
extractWords();
|
||||||
mergeHyphenatedWords();
|
mergeHyphenatedWords();
|
||||||
if (!rows.empty()) {
|
if (!rows.empty()) {
|
||||||
currentRow = static_cast<int>(rows.size()) / 3;
|
currentRow = static_cast<int>(rows.size()) / 3;
|
||||||
currentWordInRow = 0;
|
currentWordInRow = 0;
|
||||||
}
|
}
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
xTaskCreate(&DictionaryWordSelectActivity::taskTrampoline, "DictWordSelTask", 4096, this, 1, &displayTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionaryWordSelectActivity::onExit() {
|
void DictionaryWordSelectActivity::onExit() {
|
||||||
ActivityWithSubactivity::onExit();
|
ActivityWithSubactivity::onExit();
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
if (displayTaskHandle) {
|
|
||||||
vTaskDelete(displayTaskHandle);
|
|
||||||
displayTaskHandle = nullptr;
|
|
||||||
}
|
|
||||||
vSemaphoreDelete(renderingMutex);
|
|
||||||
renderingMutex = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DictionaryWordSelectActivity::isLandscape() const {
|
bool DictionaryWordSelectActivity::isLandscape() const {
|
||||||
@@ -231,7 +205,7 @@ void DictionaryWordSelectActivity::loop() {
|
|||||||
if (pendingBackFromDef) {
|
if (pendingBackFromDef) {
|
||||||
pendingBackFromDef = false;
|
pendingBackFromDef = false;
|
||||||
exitActivity();
|
exitActivity();
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
if (pendingExitToReader) {
|
if (pendingExitToReader) {
|
||||||
pendingExitToReader = false;
|
pendingExitToReader = false;
|
||||||
@@ -353,25 +327,28 @@ void DictionaryWordSelectActivity::loop() {
|
|||||||
std::string cleaned = Dictionary::cleanWord(rawWord);
|
std::string cleaned = Dictionary::cleanWord(rawWord);
|
||||||
|
|
||||||
if (cleaned.empty()) {
|
if (cleaned.empty()) {
|
||||||
GUI.drawPopup(renderer, "No word");
|
{
|
||||||
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
Activity::RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, "No word");
|
||||||
|
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
||||||
|
}
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show looking up popup, then release mutex so display task can run
|
Rect popupLayout;
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
{
|
||||||
Rect popupLayout = GUI.drawPopup(renderer, "Looking up...");
|
Activity::RenderLock lock(*this);
|
||||||
xSemaphoreGive(renderingMutex);
|
popupLayout = GUI.drawPopup(renderer, "Looking up...");
|
||||||
|
}
|
||||||
|
|
||||||
bool cancelled = false;
|
bool cancelled = false;
|
||||||
std::string definition = Dictionary::lookup(
|
std::string definition = Dictionary::lookup(
|
||||||
cleaned,
|
cleaned,
|
||||||
[this, &popupLayout](int percent) {
|
[this, &popupLayout](int percent) {
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
Activity::RenderLock lock(*this);
|
||||||
GUI.fillPopupProgress(renderer, popupLayout, percent);
|
GUI.fillPopupProgress(renderer, popupLayout, percent);
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
},
|
},
|
||||||
[this, &cancelled]() -> bool {
|
[this, &cancelled]() -> bool {
|
||||||
mappedInput.update();
|
mappedInput.update();
|
||||||
@@ -383,7 +360,7 @@ void DictionaryWordSelectActivity::loop() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,10 +394,13 @@ void DictionaryWordSelectActivity::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.drawPopup(renderer, "Not found");
|
{
|
||||||
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
Activity::RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, "Not found");
|
||||||
|
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
||||||
|
}
|
||||||
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,11 +410,11 @@ void DictionaryWordSelectActivity::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictionaryWordSelectActivity::renderScreen() {
|
void DictionaryWordSelectActivity::render(Activity::RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
// Render the page content
|
// Render the page content
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Epub/Page.h>
|
#include <Epub/Page.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/semphr.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -31,6 +28,7 @@ class DictionaryWordSelectActivity final : public ActivityWithSubactivity {
|
|||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
void render(Activity::RenderLock&&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct WordInfo {
|
struct WordInfo {
|
||||||
@@ -64,19 +62,12 @@ class DictionaryWordSelectActivity final : public ActivityWithSubactivity {
|
|||||||
std::vector<Row> rows;
|
std::vector<Row> rows;
|
||||||
int currentRow = 0;
|
int currentRow = 0;
|
||||||
int currentWordInRow = 0;
|
int currentWordInRow = 0;
|
||||||
bool updateRequired = false;
|
|
||||||
bool pendingBackFromDef = false;
|
bool pendingBackFromDef = false;
|
||||||
bool pendingExitToReader = false;
|
bool pendingExitToReader = false;
|
||||||
|
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
|
||||||
|
|
||||||
bool isLandscape() const;
|
bool isLandscape() const;
|
||||||
bool isInverted() const;
|
bool isInverted() const;
|
||||||
void extractWords();
|
void extractWords();
|
||||||
void mergeHyphenatedWords();
|
void mergeHyphenatedWords();
|
||||||
void renderScreen();
|
|
||||||
void drawHints();
|
void drawHints();
|
||||||
static void taskTrampoline(void* param);
|
|
||||||
[[noreturn]] void displayTaskLoop();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,36 +42,13 @@ std::string EpubReaderBookmarkSelectionActivity::getPageSuffix(const Bookmark& b
|
|||||||
return " - Page " + std::to_string(bookmark.pageNumber + 1);
|
return " - Page " + std::to_string(bookmark.pageNumber + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::taskTrampoline(void* param) {
|
|
||||||
auto* self = static_cast<EpubReaderBookmarkSelectionActivity*>(param);
|
|
||||||
self->displayTaskLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::onEnter() {
|
void EpubReaderBookmarkSelectionActivity::onEnter() {
|
||||||
ActivityWithSubactivity::onEnter();
|
ActivityWithSubactivity::onEnter();
|
||||||
|
requestUpdate();
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
|
||||||
|
|
||||||
// Trigger first update
|
|
||||||
updateRequired = true;
|
|
||||||
xTaskCreate(&EpubReaderBookmarkSelectionActivity::taskTrampoline, "BookmarkSelTask",
|
|
||||||
4096, // Stack size
|
|
||||||
this, // Parameters
|
|
||||||
1, // Priority
|
|
||||||
&displayTaskHandle // Task handle
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::onExit() {
|
void EpubReaderBookmarkSelectionActivity::onExit() {
|
||||||
ActivityWithSubactivity::onExit();
|
ActivityWithSubactivity::onExit();
|
||||||
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
if (displayTaskHandle) {
|
|
||||||
vTaskDelete(displayTaskHandle);
|
|
||||||
displayTaskHandle = nullptr;
|
|
||||||
}
|
|
||||||
vSemaphoreDelete(renderingMutex);
|
|
||||||
renderingMutex = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::loop() {
|
void EpubReaderBookmarkSelectionActivity::loop() {
|
||||||
@@ -83,7 +60,6 @@ void EpubReaderBookmarkSelectionActivity::loop() {
|
|||||||
const int totalItems = getTotalItems();
|
const int totalItems = getTotalItems();
|
||||||
|
|
||||||
if (totalItems == 0) {
|
if (totalItems == 0) {
|
||||||
// All bookmarks deleted, go back
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back) ||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Back) ||
|
||||||
mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
onGoBack();
|
onGoBack();
|
||||||
@@ -91,14 +67,11 @@ void EpubReaderBookmarkSelectionActivity::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete confirmation mode: wait for confirm (delete) or back (cancel)
|
|
||||||
if (deleteConfirmMode) {
|
if (deleteConfirmMode) {
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
if (ignoreNextConfirmRelease) {
|
if (ignoreNextConfirmRelease) {
|
||||||
// Ignore the release from the initial long press
|
|
||||||
ignoreNextConfirmRelease = false;
|
ignoreNextConfirmRelease = false;
|
||||||
} else {
|
} else {
|
||||||
// Confirm delete
|
|
||||||
BookmarkStore::removeBookmark(cachePath, bookmarks[pendingDeleteIndex].spineIndex,
|
BookmarkStore::removeBookmark(cachePath, bookmarks[pendingDeleteIndex].spineIndex,
|
||||||
bookmarks[pendingDeleteIndex].pageNumber);
|
bookmarks[pendingDeleteIndex].pageNumber);
|
||||||
bookmarks.erase(bookmarks.begin() + pendingDeleteIndex);
|
bookmarks.erase(bookmarks.begin() + pendingDeleteIndex);
|
||||||
@@ -106,25 +79,24 @@ void EpubReaderBookmarkSelectionActivity::loop() {
|
|||||||
selectorIndex = std::max(0, static_cast<int>(bookmarks.size()) - 1);
|
selectorIndex = std::max(0, static_cast<int>(bookmarks.size()) - 1);
|
||||||
}
|
}
|
||||||
deleteConfirmMode = false;
|
deleteConfirmMode = false;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||||
deleteConfirmMode = false;
|
deleteConfirmMode = false;
|
||||||
ignoreNextConfirmRelease = false;
|
ignoreNextConfirmRelease = false;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect long press on Confirm to trigger delete
|
|
||||||
constexpr unsigned long DELETE_HOLD_MS = 700;
|
constexpr unsigned long DELETE_HOLD_MS = 700;
|
||||||
if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= DELETE_HOLD_MS) {
|
if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= DELETE_HOLD_MS) {
|
||||||
if (totalItems > 0 && selectorIndex >= 0 && selectorIndex < totalItems) {
|
if (totalItems > 0 && selectorIndex >= 0 && selectorIndex < totalItems) {
|
||||||
deleteConfirmMode = true;
|
deleteConfirmMode = true;
|
||||||
ignoreNextConfirmRelease = true;
|
ignoreNextConfirmRelease = true;
|
||||||
pendingDeleteIndex = selectorIndex;
|
pendingDeleteIndex = selectorIndex;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -144,38 +116,26 @@ void EpubReaderBookmarkSelectionActivity::loop() {
|
|||||||
|
|
||||||
buttonNavigator.onNextRelease([this, totalItems] {
|
buttonNavigator.onNextRelease([this, totalItems] {
|
||||||
selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems);
|
selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPreviousRelease([this, totalItems] {
|
buttonNavigator.onPreviousRelease([this, totalItems] {
|
||||||
selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems);
|
selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onNextContinuous([this, totalItems, pageItems] {
|
buttonNavigator.onNextContinuous([this, totalItems, pageItems] {
|
||||||
selectorIndex = ButtonNavigator::nextPageIndex(selectorIndex, totalItems, pageItems);
|
selectorIndex = ButtonNavigator::nextPageIndex(selectorIndex, totalItems, pageItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPreviousContinuous([this, totalItems, pageItems] {
|
buttonNavigator.onPreviousContinuous([this, totalItems, pageItems] {
|
||||||
selectorIndex = ButtonNavigator::previousPageIndex(selectorIndex, totalItems, pageItems);
|
selectorIndex = ButtonNavigator::previousPageIndex(selectorIndex, totalItems, pageItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::displayTaskLoop() {
|
void EpubReaderBookmarkSelectionActivity::render(Activity::RenderLock&&) {
|
||||||
while (true) {
|
|
||||||
if (updateRequired && !subActivity) {
|
|
||||||
updateRequired = false;
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
renderScreen();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
}
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EpubReaderBookmarkSelectionActivity::renderScreen() {
|
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
@@ -191,7 +151,6 @@ void EpubReaderBookmarkSelectionActivity::renderScreen() {
|
|||||||
const int pageItems = getPageItems();
|
const int pageItems = getPageItems();
|
||||||
const int totalItems = getTotalItems();
|
const int totalItems = getTotalItems();
|
||||||
|
|
||||||
// Title
|
|
||||||
const int titleX =
|
const int titleX =
|
||||||
contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, "Go to Bookmark", EpdFontFamily::BOLD)) / 2;
|
contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, "Go to Bookmark", EpdFontFamily::BOLD)) / 2;
|
||||||
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, "Go to Bookmark", true, EpdFontFamily::BOLD);
|
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, "Go to Bookmark", true, EpdFontFamily::BOLD);
|
||||||
@@ -213,7 +172,6 @@ void EpubReaderBookmarkSelectionActivity::renderScreen() {
|
|||||||
const std::string suffix = getPageSuffix(bookmarks[itemIndex]);
|
const std::string suffix = getPageSuffix(bookmarks[itemIndex]);
|
||||||
const int suffixWidth = renderer.getTextWidth(UI_10_FONT_ID, suffix.c_str());
|
const int suffixWidth = renderer.getTextWidth(UI_10_FONT_ID, suffix.c_str());
|
||||||
|
|
||||||
// Truncate the prefix (chapter + snippet) to leave room for the page suffix
|
|
||||||
const std::string prefix = getBookmarkPrefix(bookmarks[itemIndex]);
|
const std::string prefix = getBookmarkPrefix(bookmarks[itemIndex]);
|
||||||
const std::string truncatedPrefix =
|
const std::string truncatedPrefix =
|
||||||
renderer.truncatedText(UI_10_FONT_ID, prefix.c_str(), maxLabelWidth - suffixWidth);
|
renderer.truncatedText(UI_10_FONT_ID, prefix.c_str(), maxLabelWidth - suffixWidth);
|
||||||
@@ -225,7 +183,6 @@ void EpubReaderBookmarkSelectionActivity::renderScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deleteConfirmMode && pendingDeleteIndex < static_cast<int>(bookmarks.size())) {
|
if (deleteConfirmMode && pendingDeleteIndex < static_cast<int>(bookmarks.size())) {
|
||||||
// Draw delete confirmation overlay
|
|
||||||
const std::string suffix = getPageSuffix(bookmarks[pendingDeleteIndex]);
|
const std::string suffix = getPageSuffix(bookmarks[pendingDeleteIndex]);
|
||||||
std::string msg = "Delete bookmark" + suffix + "?";
|
std::string msg = "Delete bookmark" + suffix + "?";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Epub.h>
|
#include <Epub.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/semphr.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -15,32 +12,19 @@ class EpubReaderBookmarkSelectionActivity final : public ActivityWithSubactivity
|
|||||||
std::shared_ptr<Epub> epub;
|
std::shared_ptr<Epub> epub;
|
||||||
std::vector<Bookmark> bookmarks;
|
std::vector<Bookmark> bookmarks;
|
||||||
std::string cachePath;
|
std::string cachePath;
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
|
||||||
ButtonNavigator buttonNavigator;
|
ButtonNavigator buttonNavigator;
|
||||||
int selectorIndex = 0;
|
int selectorIndex = 0;
|
||||||
bool updateRequired = false;
|
|
||||||
bool deleteConfirmMode = false;
|
bool deleteConfirmMode = false;
|
||||||
bool ignoreNextConfirmRelease = false;
|
bool ignoreNextConfirmRelease = false;
|
||||||
int pendingDeleteIndex = 0;
|
int pendingDeleteIndex = 0;
|
||||||
const std::function<void()> onGoBack;
|
const std::function<void()> onGoBack;
|
||||||
const std::function<void(int newSpineIndex, int newPage)> onSelectBookmark;
|
const std::function<void(int newSpineIndex, int newPage)> onSelectBookmark;
|
||||||
|
|
||||||
// Number of items that fit on a page, derived from logical screen height.
|
|
||||||
int getPageItems() const;
|
int getPageItems() const;
|
||||||
|
|
||||||
int getTotalItems() const;
|
int getTotalItems() const;
|
||||||
|
|
||||||
// Build the prefix portion of a bookmark label (chapter + snippet, without page suffix)
|
|
||||||
std::string getBookmarkPrefix(const Bookmark& bookmark) const;
|
std::string getBookmarkPrefix(const Bookmark& bookmark) const;
|
||||||
|
|
||||||
// Build the page suffix (e.g. " - Page 5")
|
|
||||||
static std::string getPageSuffix(const Bookmark& bookmark);
|
static std::string getPageSuffix(const Bookmark& bookmark);
|
||||||
|
|
||||||
static void taskTrampoline(void* param);
|
|
||||||
[[noreturn]] void displayTaskLoop();
|
|
||||||
void renderScreen();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EpubReaderBookmarkSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
explicit EpubReaderBookmarkSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
const std::shared_ptr<Epub>& epub,
|
const std::shared_ptr<Epub>& epub,
|
||||||
@@ -57,4 +41,5 @@ class EpubReaderBookmarkSelectionActivity final : public ActivityWithSubactivity
|
|||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
void render(Activity::RenderLock&&) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
|||||||
|
|
||||||
const std::function<void(uint8_t)> onBack;
|
const std::function<void(uint8_t)> onBack;
|
||||||
const std::function<void(MenuAction)> onAction;
|
const std::function<void(MenuAction)> onAction;
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
// Map the internal override value to an index into letterboxFillLabels.
|
// Map the internal override value to an index into letterboxFillLabels.
|
||||||
int letterboxFillToIndex() const {
|
int letterboxFillToIndex() const {
|
||||||
|
|||||||
@@ -12,41 +12,15 @@
|
|||||||
#include "util/Dictionary.h"
|
#include "util/Dictionary.h"
|
||||||
#include "util/LookupHistory.h"
|
#include "util/LookupHistory.h"
|
||||||
|
|
||||||
void LookedUpWordsActivity::taskTrampoline(void* param) {
|
|
||||||
auto* self = static_cast<LookedUpWordsActivity*>(param);
|
|
||||||
self->displayTaskLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LookedUpWordsActivity::displayTaskLoop() {
|
|
||||||
while (true) {
|
|
||||||
if (updateRequired && !subActivity) {
|
|
||||||
updateRequired = false;
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
renderScreen();
|
|
||||||
xSemaphoreGive(renderingMutex);
|
|
||||||
}
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LookedUpWordsActivity::onEnter() {
|
void LookedUpWordsActivity::onEnter() {
|
||||||
ActivityWithSubactivity::onEnter();
|
ActivityWithSubactivity::onEnter();
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
|
||||||
words = LookupHistory::load(cachePath);
|
words = LookupHistory::load(cachePath);
|
||||||
std::reverse(words.begin(), words.end());
|
std::reverse(words.begin(), words.end());
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
xTaskCreate(&LookedUpWordsActivity::taskTrampoline, "LookedUpTask", 4096, this, 1, &displayTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookedUpWordsActivity::onExit() {
|
void LookedUpWordsActivity::onExit() {
|
||||||
ActivityWithSubactivity::onExit();
|
ActivityWithSubactivity::onExit();
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
||||||
if (displayTaskHandle) {
|
|
||||||
vTaskDelete(displayTaskHandle);
|
|
||||||
displayTaskHandle = nullptr;
|
|
||||||
}
|
|
||||||
vSemaphoreDelete(renderingMutex);
|
|
||||||
renderingMutex = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookedUpWordsActivity::loop() {
|
void LookedUpWordsActivity::loop() {
|
||||||
@@ -55,7 +29,7 @@ void LookedUpWordsActivity::loop() {
|
|||||||
if (pendingBackFromDef) {
|
if (pendingBackFromDef) {
|
||||||
pendingBackFromDef = false;
|
pendingBackFromDef = false;
|
||||||
exitActivity();
|
exitActivity();
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
if (pendingExitToReader) {
|
if (pendingExitToReader) {
|
||||||
pendingExitToReader = false;
|
pendingExitToReader = false;
|
||||||
@@ -87,13 +61,13 @@ void LookedUpWordsActivity::loop() {
|
|||||||
selectedIndex = std::max(0, static_cast<int>(words.size()) - 1);
|
selectedIndex = std::max(0, static_cast<int>(words.size()) - 1);
|
||||||
}
|
}
|
||||||
deleteConfirmMode = false;
|
deleteConfirmMode = false;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||||
deleteConfirmMode = false;
|
deleteConfirmMode = false;
|
||||||
ignoreNextConfirmRelease = false;
|
ignoreNextConfirmRelease = false;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -104,7 +78,7 @@ void LookedUpWordsActivity::loop() {
|
|||||||
deleteConfirmMode = true;
|
deleteConfirmMode = true;
|
||||||
ignoreNextConfirmRelease = true;
|
ignoreNextConfirmRelease = true;
|
||||||
pendingDeleteIndex = selectedIndex;
|
pendingDeleteIndex = selectedIndex;
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,30 +87,37 @@ void LookedUpWordsActivity::loop() {
|
|||||||
|
|
||||||
buttonNavigator.onNextRelease([this, totalItems] {
|
buttonNavigator.onNextRelease([this, totalItems] {
|
||||||
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, totalItems);
|
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, totalItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPreviousRelease([this, totalItems] {
|
buttonNavigator.onPreviousRelease([this, totalItems] {
|
||||||
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, totalItems);
|
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, totalItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onNextContinuous([this, totalItems, pageItems] {
|
buttonNavigator.onNextContinuous([this, totalItems, pageItems] {
|
||||||
selectedIndex = ButtonNavigator::nextPageIndex(selectedIndex, totalItems, pageItems);
|
selectedIndex = ButtonNavigator::nextPageIndex(selectedIndex, totalItems, pageItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPreviousContinuous([this, totalItems, pageItems] {
|
buttonNavigator.onPreviousContinuous([this, totalItems, pageItems] {
|
||||||
selectedIndex = ButtonNavigator::previousPageIndex(selectedIndex, totalItems, pageItems);
|
selectedIndex = ButtonNavigator::previousPageIndex(selectedIndex, totalItems, pageItems);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
const std::string& headword = words[selectedIndex];
|
const std::string& headword = words[selectedIndex];
|
||||||
|
|
||||||
Rect popupLayout = GUI.drawPopup(renderer, "Looking up...");
|
Rect popupLayout;
|
||||||
|
{
|
||||||
|
Activity::RenderLock lock(*this);
|
||||||
|
popupLayout = GUI.drawPopup(renderer, "Looking up...");
|
||||||
|
}
|
||||||
std::string definition = Dictionary::lookup(
|
std::string definition = Dictionary::lookup(
|
||||||
headword, [this, &popupLayout](int percent) { GUI.fillPopupProgress(renderer, popupLayout, percent); });
|
headword, [this, &popupLayout](int percent) {
|
||||||
|
Activity::RenderLock lock(*this);
|
||||||
|
GUI.fillPopupProgress(renderer, popupLayout, percent);
|
||||||
|
});
|
||||||
|
|
||||||
if (!definition.empty()) {
|
if (!definition.empty()) {
|
||||||
enterNewActivity(new DictionaryDefinitionActivity(
|
enterNewActivity(new DictionaryDefinitionActivity(
|
||||||
@@ -166,10 +147,13 @@ void LookedUpWordsActivity::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.drawPopup(renderer, "Not found");
|
{
|
||||||
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
Activity::RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, "Not found");
|
||||||
|
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
||||||
|
}
|
||||||
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
||||||
updateRequired = true;
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +174,7 @@ int LookedUpWordsActivity::getPageItems() const {
|
|||||||
return std::max(1, contentHeight / metrics.listRowHeight);
|
return std::max(1, contentHeight / metrics.listRowHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookedUpWordsActivity::renderScreen() {
|
void LookedUpWordsActivity::render(Activity::RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const auto orient = renderer.getOrientation();
|
const auto orient = renderer.getOrientation();
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/semphr.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -25,6 +21,7 @@ class LookedUpWordsActivity final : public ActivityWithSubactivity {
|
|||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
void render(Activity::RenderLock&&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string cachePath;
|
std::string cachePath;
|
||||||
@@ -35,7 +32,6 @@ class LookedUpWordsActivity final : public ActivityWithSubactivity {
|
|||||||
|
|
||||||
std::vector<std::string> words;
|
std::vector<std::string> words;
|
||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
bool updateRequired = false;
|
|
||||||
bool pendingBackFromDef = false;
|
bool pendingBackFromDef = false;
|
||||||
bool pendingExitToReader = false;
|
bool pendingExitToReader = false;
|
||||||
ButtonNavigator buttonNavigator;
|
ButtonNavigator buttonNavigator;
|
||||||
@@ -45,11 +41,5 @@ class LookedUpWordsActivity final : public ActivityWithSubactivity {
|
|||||||
bool ignoreNextConfirmRelease = false;
|
bool ignoreNextConfirmRelease = false;
|
||||||
int pendingDeleteIndex = 0;
|
int pendingDeleteIndex = 0;
|
||||||
|
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
|
||||||
|
|
||||||
int getPageItems() const;
|
int getPageItems() const;
|
||||||
void renderScreen();
|
|
||||||
static void taskTrampoline(void* param);
|
|
||||||
[[noreturn]] void displayTaskLoop();
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user