Compare commits

..

No commits in common. "fc48cd91016d43f1a82d3f52428d3a42ae661d13" and "aeb8a339f6fbc2c55bdb8d4e6ed095035edaa73a" have entirely different histories.

17 changed files with 68 additions and 191 deletions

View File

@ -12,6 +12,12 @@ jobs:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- uses: actions/cache@v5
with:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: '3.14' python-version: '3.14'

View File

@ -59,28 +59,14 @@ bool EpdFont::hasPrintableChars(const char* string) const {
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const { const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
const EpdUnicodeInterval* intervals = data->intervals; const EpdUnicodeInterval* intervals = data->intervals;
const int count = data->intervalCount; for (int i = 0; i < data->intervalCount; i++) {
const EpdUnicodeInterval* interval = &intervals[i];
if (count == 0) return nullptr; if (cp >= interval->first && cp <= interval->last) {
// Binary search for O(log n) lookup instead of O(n)
// Critical for Korean fonts with many unicode intervals
int left = 0;
int right = count - 1;
while (left <= right) {
const int mid = left + (right - left) / 2;
const EpdUnicodeInterval* interval = &intervals[mid];
if (cp < interval->first) {
right = mid - 1;
} else if (cp > interval->last) {
left = mid + 1;
} else {
// Found: cp >= interval->first && cp <= interval->last
return &data->glyph[interval->offset + (cp - interval->first)]; return &data->glyph[interval->offset + (cp - interval->first)];
} }
if (cp < interval->first) {
return nullptr;
}
} }
return nullptr; return nullptr;
} }

View File

@ -239,28 +239,6 @@ int GfxRenderer::getLineHeight(const int fontId) const {
return fontMap.at(fontId).getData(REGULAR)->advanceY; return fontMap.at(fontId).getData(REGULAR)->advanceY;
} }
void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char* btn2, const char* btn3,
const char* btn4) const {
const int pageHeight = getScreenHeight();
constexpr int buttonWidth = 106;
constexpr int buttonHeight = 40;
constexpr int buttonY = 40; // Distance from bottom
constexpr int textYOffset = 5; // Distance from top of button to text baseline
constexpr int buttonPositions[] = {25, 130, 245, 350};
const char* labels[] = {btn1, btn2, btn3, btn4};
for (int i = 0; i < 4; i++) {
// Only draw if the label is non-empty
if (labels[i] != nullptr && labels[i][0] != '\0') {
const int x = buttonPositions[i];
drawRect(x, pageHeight - buttonY, buttonWidth, buttonHeight);
const int textWidth = getTextWidth(fontId, labels[i]);
const int textX = x + (buttonWidth - 1 - textWidth) / 2;
drawText(fontId, textX, pageHeight - buttonY + textYOffset, labels[i]);
}
}
}
uint8_t* GfxRenderer::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); } uint8_t* GfxRenderer::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); }
size_t GfxRenderer::getBufferSize() { return EInkDisplay::BUFFER_SIZE; } size_t GfxRenderer::getBufferSize() { return EInkDisplay::BUFFER_SIZE; }

View File

@ -57,9 +57,6 @@ class GfxRenderer {
int getSpaceWidth(int fontId) const; int getSpaceWidth(int fontId) const;
int getLineHeight(int fontId) const; int getLineHeight(int fontId) const;
// UI Components
void drawButtonHints(int fontId, const char* btn1, const char* btn2, const char* btn3, const char* btn4) const;
// Grayscale functions // Grayscale functions
void setRenderMode(const RenderMode mode) { this->renderMode = mode; } void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
void copyGrayscaleLsbBuffers() const; void copyGrayscaleLsbBuffers() const;

View File

@ -4,24 +4,22 @@
#include <InputManager.h> #include <InputManager.h>
#include <SD.h> #include <SD.h>
#include "CrossPointState.h"
#include "config.h" #include "config.h"
namespace {
constexpr int menuItemCount = 3;
}
void HomeActivity::taskTrampoline(void* param) { void HomeActivity::taskTrampoline(void* param) {
auto* self = static_cast<HomeActivity*>(param); auto* self = static_cast<HomeActivity*>(param);
self->displayTaskLoop(); self->displayTaskLoop();
} }
int HomeActivity::getMenuItemCount() const { return hasContinueReading ? 4 : 3; }
void HomeActivity::onEnter() { void HomeActivity::onEnter() {
Activity::onEnter(); Activity::onEnter();
renderingMutex = xSemaphoreCreateMutex(); renderingMutex = xSemaphoreCreateMutex();
// Check if we have a book to continue reading
hasContinueReading = !APP_STATE.openEpubPath.empty() && SD.exists(APP_STATE.openEpubPath.c_str());
selectorIndex = 0; selectorIndex = 0;
// Trigger first update // Trigger first update
@ -54,22 +52,7 @@ void HomeActivity::loop() {
const bool nextPressed = const bool nextPressed =
inputManager.wasPressed(InputManager::BTN_DOWN) || inputManager.wasPressed(InputManager::BTN_RIGHT); inputManager.wasPressed(InputManager::BTN_DOWN) || inputManager.wasPressed(InputManager::BTN_RIGHT);
const int menuCount = getMenuItemCount();
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) { if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
if (hasContinueReading) {
// Menu: Continue Reading, Browse, File transfer, Settings
if (selectorIndex == 0) {
onContinueReading();
} else if (selectorIndex == 1) {
onReaderOpen();
} else if (selectorIndex == 2) {
onFileTransferOpen();
} else if (selectorIndex == 3) {
onSettingsOpen();
}
} else {
// Menu: Browse, File transfer, Settings
if (selectorIndex == 0) { if (selectorIndex == 0) {
onReaderOpen(); onReaderOpen();
} else if (selectorIndex == 1) { } else if (selectorIndex == 1) {
@ -77,12 +60,11 @@ void HomeActivity::loop() {
} else if (selectorIndex == 2) { } else if (selectorIndex == 2) {
onSettingsOpen(); onSettingsOpen();
} }
}
} else if (prevPressed) { } else if (prevPressed) {
selectorIndex = (selectorIndex + menuCount - 1) % menuCount; selectorIndex = (selectorIndex + menuItemCount - 1) % menuItemCount;
updateRequired = true; updateRequired = true;
} else if (nextPressed) { } else if (nextPressed) {
selectorIndex = (selectorIndex + 1) % menuCount; selectorIndex = (selectorIndex + 1) % menuItemCount;
updateRequired = true; updateRequired = true;
} }
} }
@ -103,47 +85,27 @@ void HomeActivity::render() const {
renderer.clearScreen(); renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth(); const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD); renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
// Draw selection // Draw selection
renderer.fillRect(0, 60 + selectorIndex * 30 + 2, pageWidth - 1, 30); renderer.fillRect(0, 60 + selectorIndex * 30 + 2, pageWidth - 1, 30);
renderer.drawText(UI_FONT_ID, 20, 60, "Read", selectorIndex != 0);
renderer.drawText(UI_FONT_ID, 20, 90, "File transfer", selectorIndex != 1);
renderer.drawText(UI_FONT_ID, 20, 120, "Settings", selectorIndex != 2);
int menuY = 60; renderer.drawRect(25, pageHeight - 40, 106, 40);
int menuIndex = 0; renderer.drawText(UI_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_FONT_ID, "Back")) / 2, pageHeight - 35, "Back");
if (hasContinueReading) { renderer.drawRect(130, pageHeight - 40, 106, 40);
// Extract filename from path for display renderer.drawText(UI_FONT_ID, 130 + (105 - renderer.getTextWidth(UI_FONT_ID, "Confirm")) / 2, pageHeight - 35,
std::string bookName = APP_STATE.openEpubPath; "Confirm");
const size_t lastSlash = bookName.find_last_of('/');
if (lastSlash != std::string::npos) {
bookName = bookName.substr(lastSlash + 1);
}
// Remove .epub extension
if (bookName.length() > 5 && bookName.substr(bookName.length() - 5) == ".epub") {
bookName.resize(bookName.length() - 5);
}
// Truncate if too long
if (bookName.length() > 25) {
bookName.resize(22);
bookName += "...";
}
std::string continueLabel = "Continue: " + bookName;
renderer.drawText(UI_FONT_ID, 20, menuY, continueLabel.c_str(), selectorIndex != menuIndex);
menuY += 30;
menuIndex++;
}
renderer.drawText(UI_FONT_ID, 20, menuY, "Browse", selectorIndex != menuIndex); renderer.drawRect(245, pageHeight - 40, 106, 40);
menuY += 30; renderer.drawText(UI_FONT_ID, 245 + (105 - renderer.getTextWidth(UI_FONT_ID, "Left")) / 2, pageHeight - 35, "Left");
menuIndex++;
renderer.drawText(UI_FONT_ID, 20, menuY, "File transfer", selectorIndex != menuIndex); renderer.drawRect(350, pageHeight - 40, 106, 40);
menuY += 30; renderer.drawText(UI_FONT_ID, 350 + (105 - renderer.getTextWidth(UI_FONT_ID, "Right")) / 2, pageHeight - 35, "Right");
menuIndex++;
renderer.drawText(UI_FONT_ID, 20, menuY, "Settings", selectorIndex != menuIndex);
renderer.drawButtonHints(UI_FONT_ID, "Back", "Confirm", "Left", "Right");
renderer.displayBuffer(); renderer.displayBuffer();
} }

View File

@ -12,8 +12,6 @@ class HomeActivity final : public Activity {
SemaphoreHandle_t renderingMutex = nullptr; SemaphoreHandle_t renderingMutex = nullptr;
int selectorIndex = 0; int selectorIndex = 0;
bool updateRequired = false; bool updateRequired = false;
bool hasContinueReading = false;
const std::function<void()> onContinueReading;
const std::function<void()> onReaderOpen; const std::function<void()> onReaderOpen;
const std::function<void()> onSettingsOpen; const std::function<void()> onSettingsOpen;
const std::function<void()> onFileTransferOpen; const std::function<void()> onFileTransferOpen;
@ -21,14 +19,11 @@ class HomeActivity final : public Activity {
static void taskTrampoline(void* param); static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop(); [[noreturn]] void displayTaskLoop();
void render() const; void render() const;
int getMenuItemCount() const;
public: public:
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
const std::function<void()>& onContinueReading, const std::function<void()>& onReaderOpen,
const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen) const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen)
: Activity("Home", renderer, inputManager), : Activity("Home", renderer, inputManager),
onContinueReading(onContinueReading),
onReaderOpen(onReaderOpen), onReaderOpen(onReaderOpen),
onSettingsOpen(onSettingsOpen), onSettingsOpen(onSettingsOpen),
onFileTransferOpen(onFileTransferOpen) {} onFileTransferOpen(onFileTransferOpen) {}

View File

@ -340,7 +340,7 @@ void CrossPointWebServerActivity::render() const {
} }
} }
void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std::string& data) { void drawQRCode(GfxRenderer& renderer, const int x, const int y, const std::string& data) {
// Implementation of QR code calculation // Implementation of QR code calculation
// The structure to manage the QR code // The structure to manage the QR code
QRCode qrcode; QRCode qrcode;
@ -363,6 +363,8 @@ void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std
} }
void CrossPointWebServerActivity::renderServerRunning() const { void CrossPointWebServerActivity::renderServerRunning() const {
const auto pageHeight = renderer.getScreenHeight();
// Use consistent line spacing // Use consistent line spacing
constexpr int LINE_SPACING = 28; // Space between lines constexpr int LINE_SPACING = 28; // Space between lines
@ -429,5 +431,5 @@ void CrossPointWebServerActivity::renderServerRunning() const {
REGULAR); REGULAR);
} }
renderer.drawButtonHints(UI_FONT_ID, "« Exit", "", "", ""); renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press BACK to exit", true, REGULAR);
} }

View File

@ -122,7 +122,7 @@ void NetworkModeSelectionActivity::render() const {
} }
// Draw help text at bottom // Draw help text at bottom
renderer.drawButtonHints(UI_FONT_ID, "« Back", "Select", "", ""); renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press OK to select, BACK to cancel", true, REGULAR);
renderer.displayBuffer(); renderer.displayBuffer();
} }

View File

@ -553,12 +553,11 @@ void WifiSelectionActivity::renderNetworkList() const {
// Show network count // Show network count
char countStr[32]; char countStr[32];
snprintf(countStr, sizeof(countStr), "%zu networks found", networks.size()); snprintf(countStr, sizeof(countStr), "%zu networks found", networks.size());
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 90, countStr); renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 45, countStr);
} }
// Draw help text // Draw help text
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved"); renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "OK: Connect | * = Encrypted | + = Saved");
renderer.drawButtonHints(UI_FONT_ID, "« Back", "Connect", "", "");
} }
void WifiSelectionActivity::renderPasswordEntry() const { void WifiSelectionActivity::renderPasswordEntry() const {

View File

@ -14,7 +14,6 @@
namespace { namespace {
constexpr int pagesPerRefresh = 15; constexpr int pagesPerRefresh = 15;
constexpr unsigned long skipChapterMs = 700; constexpr unsigned long skipChapterMs = 700;
constexpr unsigned long goHomeMs = 1000;
constexpr float lineCompression = 0.95f; constexpr float lineCompression = 0.95f;
constexpr int marginTop = 8; constexpr int marginTop = 8;
constexpr int marginRight = 10; constexpr int marginRight = 10;
@ -109,14 +108,7 @@ void EpubReaderActivity::loop() {
xSemaphoreGive(renderingMutex); xSemaphoreGive(renderingMutex);
} }
// Long press BACK (1s+) goes directly to home if (inputManager.wasPressed(InputManager::BTN_BACK)) {
if (inputManager.isPressed(InputManager::BTN_BACK) && inputManager.getHeldTime() >= goHomeMs) {
onGoHome();
return;
}
// Short press BACK goes to file selection
if (inputManager.wasReleased(InputManager::BTN_BACK) && inputManager.getHeldTime() < goHomeMs) {
onGoBack(); onGoBack();
return; return;
} }

View File

@ -17,7 +17,6 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
int pagesUntilFullRefresh = 0; int pagesUntilFullRefresh = 0;
bool updateRequired = false; bool updateRequired = false;
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
const std::function<void()> onGoHome;
static void taskTrampoline(void* param); static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop(); [[noreturn]] void displayTaskLoop();
@ -27,11 +26,8 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
public: public:
explicit EpubReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub, explicit EpubReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
const std::function<void()>& onGoBack, const std::function<void()>& onGoHome) const std::function<void()>& onGoBack)
: ActivityWithSubactivity("EpubReader", renderer, inputManager), : ActivityWithSubactivity("EpubReader", renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
epub(std::move(epub)),
onGoBack(onGoBack),
onGoHome(onGoHome) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -9,7 +9,6 @@
namespace { namespace {
constexpr int PAGE_ITEMS = 23; constexpr int PAGE_ITEMS = 23;
constexpr int SKIP_PAGE_MS = 700; constexpr int SKIP_PAGE_MS = 700;
constexpr unsigned long GO_HOME_MS = 1000;
} // namespace } // namespace
void sortFileList(std::vector<std::string>& strs) { void sortFileList(std::vector<std::string>& strs) {
@ -54,7 +53,7 @@ void FileSelectionActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex(); renderingMutex = xSemaphoreCreateMutex();
// basepath is set via constructor parameter (defaults to "/" if not specified) basepath = "/";
loadFiles(); loadFiles();
selectorIndex = 0; selectorIndex = 0;
@ -84,16 +83,6 @@ void FileSelectionActivity::onExit() {
} }
void FileSelectionActivity::loop() { void FileSelectionActivity::loop() {
// Long press BACK (1s+) goes to root folder
if (inputManager.isPressed(InputManager::BTN_BACK) && inputManager.getHeldTime() >= GO_HOME_MS) {
if (basepath != "/") {
basepath = "/";
loadFiles();
updateRequired = true;
}
return;
}
const bool prevReleased = const bool prevReleased =
inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT); inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT);
const bool nextReleased = const bool nextReleased =
@ -114,18 +103,16 @@ void FileSelectionActivity::loop() {
} else { } else {
onSelect(basepath + files[selectorIndex]); onSelect(basepath + files[selectorIndex]);
} }
} else if (inputManager.wasReleased(InputManager::BTN_BACK)) { } else if (inputManager.wasPressed(InputManager::BTN_BACK)) {
// Short press: go up one directory, or go home if at root
if (inputManager.getHeldTime() < GO_HOME_MS) {
if (basepath != "/") { if (basepath != "/") {
basepath.replace(basepath.find_last_of('/'), std::string::npos, ""); basepath.replace(basepath.find_last_of('/'), std::string::npos, "");
if (basepath.empty()) basepath = "/"; if (basepath.empty()) basepath = "/";
loadFiles(); loadFiles();
updateRequired = true; updateRequired = true;
} else { } else {
// At root level, go back home
onGoHome(); onGoHome();
} }
}
} else if (prevReleased) { } else if (prevReleased) {
if (skipPage) { if (skipPage) {
selectorIndex = ((selectorIndex / PAGE_ITEMS - 1) * PAGE_ITEMS + files.size()) % files.size(); selectorIndex = ((selectorIndex / PAGE_ITEMS - 1) * PAGE_ITEMS + files.size()) % files.size();
@ -162,7 +149,7 @@ void FileSelectionActivity::render() const {
renderer.drawCenteredText(READER_FONT_ID, 10, "Books", true, BOLD); renderer.drawCenteredText(READER_FONT_ID, 10, "Books", true, BOLD);
// Help text // Help text
renderer.drawButtonHints(UI_FONT_ID, "« Home", "", "", ""); renderer.drawText(SMALL_FONT_ID, 20, GfxRenderer::getScreenHeight() - 30, "Press BACK for Home");
if (files.empty()) { if (files.empty()) {
renderer.drawText(UI_FONT_ID, 20, 60, "No EPUBs found"); renderer.drawText(UI_FONT_ID, 20, 60, "No EPUBs found");

View File

@ -27,11 +27,8 @@ class FileSelectionActivity final : public Activity {
public: public:
explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager, explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
const std::function<void(const std::string&)>& onSelect, const std::function<void(const std::string&)>& onSelect,
const std::function<void()>& onGoHome, std::string initialPath = "/") const std::function<void()>& onGoHome)
: Activity("FileSelection", renderer, inputManager), : Activity("FileSelection", renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {}
basepath(initialPath.empty() ? "/" : std::move(initialPath)),
onSelect(onSelect),
onGoHome(onGoHome) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -7,14 +7,6 @@
#include "FileSelectionActivity.h" #include "FileSelectionActivity.h"
#include "activities/util/FullScreenMessageActivity.h" #include "activities/util/FullScreenMessageActivity.h"
std::string ReaderActivity::extractFolderPath(const std::string& filePath) {
const auto lastSlash = filePath.find_last_of('/');
if (lastSlash == std::string::npos || lastSlash == 0) {
return "/";
}
return filePath.substr(0, lastSlash);
}
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) { std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) { if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
@ -31,7 +23,6 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
} }
void ReaderActivity::onSelectEpubFile(const std::string& path) { void ReaderActivity::onSelectEpubFile(const std::string& path) {
currentEpubPath = path; // Track current book path
exitActivity(); exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading...")); enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
@ -47,32 +38,25 @@ void ReaderActivity::onSelectEpubFile(const std::string& path) {
} }
} }
void ReaderActivity::onGoToFileSelection(const std::string& fromEpubPath) { void ReaderActivity::onGoToFileSelection() {
exitActivity(); exitActivity();
// If coming from a book, start in that book's folder; otherwise start from root
const auto initialPath = fromEpubPath.empty() ? "/" : extractFolderPath(fromEpubPath);
enterNewActivity(new FileSelectionActivity( enterNewActivity(new FileSelectionActivity(
renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack, initialPath)); renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack));
} }
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) { void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
const auto epubPath = epub->getPath();
currentEpubPath = epubPath;
exitActivity(); exitActivity();
enterNewActivity(new EpubReaderActivity( enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), [this] { onGoToFileSelection(); }));
renderer, inputManager, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); },
[this] { onGoBack(); }));
} }
void ReaderActivity::onEnter() { void ReaderActivity::onEnter() {
ActivityWithSubactivity::onEnter(); ActivityWithSubactivity::onEnter();
if (initialEpubPath.empty()) { if (initialEpubPath.empty()) {
onGoToFileSelection(); // Start from root when entering via Browse onGoToFileSelection();
return; return;
} }
currentEpubPath = initialEpubPath;
auto epub = loadEpub(initialEpubPath); auto epub = loadEpub(initialEpubPath);
if (!epub) { if (!epub) {
onGoBack(); onGoBack();

View File

@ -7,13 +7,11 @@ class Epub;
class ReaderActivity final : public ActivityWithSubactivity { class ReaderActivity final : public ActivityWithSubactivity {
std::string initialEpubPath; std::string initialEpubPath;
std::string currentEpubPath; // Track current book path for navigation
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
static std::unique_ptr<Epub> loadEpub(const std::string& path); static std::unique_ptr<Epub> loadEpub(const std::string& path);
static std::string extractFolderPath(const std::string& filePath);
void onSelectEpubFile(const std::string& path); void onSelectEpubFile(const std::string& path);
void onGoToFileSelection(const std::string& fromEpubPath = ""); void onGoToFileSelection();
void onGoToEpubReader(std::unique_ptr<Epub> epub); void onGoToEpubReader(std::unique_ptr<Epub> epub);
public: public:

View File

@ -169,7 +169,7 @@ void SettingsActivity::render() const {
} }
// Draw help text // Draw help text
renderer.drawButtonHints(UI_FONT_ID, "« Save", "Toggle", "", ""); renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "Press OK to toggle, BACK to save & exit");
renderer.drawText(SMALL_FONT_ID, pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION), renderer.drawText(SMALL_FONT_ID, pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION),
pageHeight - 30, CROSSPOINT_VERSION); pageHeight - 30, CROSSPOINT_VERSION);

View File

@ -142,7 +142,6 @@ void onGoToReader(const std::string& initialEpubPath) {
enterNewActivity(new ReaderActivity(renderer, inputManager, initialEpubPath, onGoHome)); enterNewActivity(new ReaderActivity(renderer, inputManager, initialEpubPath, onGoHome));
} }
void onGoToReaderHome() { onGoToReader(std::string()); } void onGoToReaderHome() { onGoToReader(std::string()); }
void onContinueReading() { onGoToReader(APP_STATE.openEpubPath); }
void onGoToFileTransfer() { void onGoToFileTransfer() {
exitActivity(); exitActivity();
@ -156,8 +155,7 @@ void onGoToSettings() {
void onGoHome() { void onGoHome() {
exitActivity(); exitActivity();
enterNewActivity(new HomeActivity(renderer, inputManager, onContinueReading, onGoToReaderHome, onGoToSettings, enterNewActivity(new HomeActivity(renderer, inputManager, onGoToReaderHome, onGoToSettings, onGoToFileTransfer));
onGoToFileTransfer));
} }
void setupDisplayAndFonts() { void setupDisplayAndFonts() {