A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add chapter selection screen

+178
+107
src/screens/EpubReaderChapterSelectionScreen.cpp
··· 1 + #include "EpubReaderChapterSelectionScreen.h" 2 + 3 + #include <GfxRenderer.h> 4 + #include <SD.h> 5 + 6 + #include "config.h" 7 + 8 + constexpr int PAGE_ITEMS = 24; 9 + constexpr int SKIP_PAGE_MS = 700; 10 + 11 + void EpubReaderChapterSelectionScreen::taskTrampoline(void* param) { 12 + auto* self = static_cast<EpubReaderChapterSelectionScreen*>(param); 13 + self->displayTaskLoop(); 14 + } 15 + 16 + void EpubReaderChapterSelectionScreen::onEnter() { 17 + if (!epub) { 18 + return; 19 + } 20 + 21 + renderingMutex = xSemaphoreCreateMutex(); 22 + selectorIndex = currentSpineIndex; 23 + 24 + // Trigger first update 25 + updateRequired = true; 26 + xTaskCreate(&EpubReaderChapterSelectionScreen::taskTrampoline, "EpubReaderChapterSelectionScreenTask", 27 + 2048, // Stack size 28 + this, // Parameters 29 + 1, // Priority 30 + &displayTaskHandle // Task handle 31 + ); 32 + } 33 + 34 + void EpubReaderChapterSelectionScreen::onExit() { 35 + // Wait until not rendering to delete task to avoid killing mid-instruction to EPD 36 + xSemaphoreTake(renderingMutex, portMAX_DELAY); 37 + if (displayTaskHandle) { 38 + vTaskDelete(displayTaskHandle); 39 + displayTaskHandle = nullptr; 40 + } 41 + vSemaphoreDelete(renderingMutex); 42 + renderingMutex = nullptr; 43 + } 44 + 45 + void EpubReaderChapterSelectionScreen::handleInput() { 46 + const bool prevReleased = 47 + inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT); 48 + const bool nextReleased = 49 + inputManager.wasReleased(InputManager::BTN_DOWN) || inputManager.wasReleased(InputManager::BTN_RIGHT); 50 + 51 + const bool skipPage = inputManager.getHeldTime() > SKIP_PAGE_MS; 52 + 53 + if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) { 54 + onSelectSpineIndex(selectorIndex); 55 + } else if (inputManager.wasPressed(InputManager::BTN_BACK)) { 56 + onGoBack(); 57 + } else if (prevReleased) { 58 + if (skipPage) { 59 + selectorIndex = 60 + ((selectorIndex / PAGE_ITEMS - 1) * PAGE_ITEMS + epub->getSpineItemsCount()) % epub->getSpineItemsCount(); 61 + } else { 62 + selectorIndex = (selectorIndex + epub->getSpineItemsCount() - 1) % epub->getSpineItemsCount(); 63 + } 64 + updateRequired = true; 65 + } else if (nextReleased) { 66 + if (skipPage) { 67 + selectorIndex = ((selectorIndex / PAGE_ITEMS + 1) * PAGE_ITEMS) % epub->getSpineItemsCount(); 68 + } else { 69 + selectorIndex = (selectorIndex + 1) % epub->getSpineItemsCount(); 70 + } 71 + updateRequired = true; 72 + } 73 + } 74 + 75 + void EpubReaderChapterSelectionScreen::displayTaskLoop() { 76 + while (true) { 77 + if (updateRequired) { 78 + updateRequired = false; 79 + xSemaphoreTake(renderingMutex, portMAX_DELAY); 80 + renderScreen(); 81 + xSemaphoreGive(renderingMutex); 82 + } 83 + vTaskDelay(10 / portTICK_PERIOD_MS); 84 + } 85 + } 86 + 87 + void EpubReaderChapterSelectionScreen::renderScreen() { 88 + renderer.clearScreen(); 89 + 90 + const auto pageWidth = renderer.getScreenWidth(); 91 + renderer.drawCenteredText(READER_FONT_ID, 10, "Select Chapter", true, BOLD); 92 + 93 + const auto pageStartIndex = selectorIndex / PAGE_ITEMS * PAGE_ITEMS; 94 + renderer.fillRect(0, 60 + (selectorIndex % PAGE_ITEMS) * 30 + 2, pageWidth - 1, 30); 95 + for (int i = pageStartIndex; i < epub->getSpineItemsCount() && i < pageStartIndex + PAGE_ITEMS; i++) { 96 + const int tocIndex = epub->getTocIndexForSpineIndex(i); 97 + if (tocIndex == -1) { 98 + renderer.drawText(UI_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, "Unnamed", i != selectorIndex); 99 + } else { 100 + auto item = epub->getTocItem(tocIndex); 101 + renderer.drawText(UI_FONT_ID, 20 + (item.level - 1) * 15, 60 + (i % PAGE_ITEMS) * 30, item.title.c_str(), 102 + i != selectorIndex); 103 + } 104 + } 105 + 106 + renderer.displayBuffer(); 107 + }
+38
src/screens/EpubReaderChapterSelectionScreen.h
··· 1 + #pragma once 2 + #include <Epub.h> 3 + #include <freertos/FreeRTOS.h> 4 + #include <freertos/semphr.h> 5 + #include <freertos/task.h> 6 + 7 + #include <memory> 8 + 9 + #include "Screen.h" 10 + 11 + class EpubReaderChapterSelectionScreen final : public Screen { 12 + std::shared_ptr<Epub> epub; 13 + TaskHandle_t displayTaskHandle = nullptr; 14 + SemaphoreHandle_t renderingMutex = nullptr; 15 + int currentSpineIndex = 0; 16 + int selectorIndex = 0; 17 + bool updateRequired = false; 18 + const std::function<void()> onGoBack; 19 + const std::function<void(int newSpineIndex)> onSelectSpineIndex; 20 + 21 + static void taskTrampoline(void* param); 22 + [[noreturn]] void displayTaskLoop(); 23 + void renderScreen(); 24 + 25 + public: 26 + explicit EpubReaderChapterSelectionScreen(GfxRenderer& renderer, InputManager& inputManager, 27 + const std::shared_ptr<Epub>& epub, const int currentSpineIndex, 28 + const std::function<void()>& onGoBack, 29 + const std::function<void(int newSpineIndex)>& onSelectSpineIndex) 30 + : Screen(renderer, inputManager), 31 + epub(epub), 32 + currentSpineIndex(currentSpineIndex), 33 + onGoBack(onGoBack), 34 + onSelectSpineIndex(onSelectSpineIndex) {} 35 + void onEnter() override; 36 + void onExit() override; 37 + void handleInput() override; 38 + };
+32
src/screens/EpubReaderScreen.cpp
··· 5 5 #include <SD.h> 6 6 7 7 #include "Battery.h" 8 + #include "EpubReaderChapterSelectionScreen.h" 8 9 #include "config.h" 9 10 10 11 constexpr int PAGES_PER_REFRESH = 15; ··· 65 66 } 66 67 67 68 void EpubReaderScreen::handleInput() { 69 + // Pass input responsibility to sub screen if exists 70 + if (subScreen) { 71 + subScreen->handleInput(); 72 + return; 73 + } 74 + 75 + // Enter chapter selection screen 76 + if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) { 77 + // Don't start screen transition while rendering 78 + xSemaphoreTake(renderingMutex, portMAX_DELAY); 79 + subScreen.reset(new EpubReaderChapterSelectionScreen( 80 + this->renderer, this->inputManager, epub, currentSpineIndex, 81 + [this] { 82 + subScreen->onExit(); 83 + subScreen.reset(); 84 + updateRequired = true; 85 + }, 86 + [this](const int newSpineIndex) { 87 + if (currentSpineIndex != newSpineIndex) { 88 + currentSpineIndex = newSpineIndex; 89 + nextPageNumber = 0; 90 + section.reset(); 91 + } 92 + subScreen->onExit(); 93 + subScreen.reset(); 94 + updateRequired = true; 95 + })); 96 + subScreen->onEnter(); 97 + xSemaphoreGive(renderingMutex); 98 + } 99 + 68 100 if (inputManager.wasPressed(InputManager::BTN_BACK)) { 69 101 onGoHome(); 70 102 return;
+1
src/screens/EpubReaderScreen.h
··· 12 12 std::unique_ptr<Section> section = nullptr; 13 13 TaskHandle_t displayTaskHandle = nullptr; 14 14 SemaphoreHandle_t renderingMutex = nullptr; 15 + std::unique_ptr<Screen> subScreen = nullptr; 15 16 int currentSpineIndex = 0; 16 17 int nextPageNumber = 0; 17 18 int pagesUntilFullRefresh = 0;