Files
crosspoint-reader/src/activities/reader/ReaderActivity.cpp

188 lines
5.7 KiB
C++
Raw Normal View History

#include "ReaderActivity.h"
#include "Epub.h"
#include "EpubReaderActivity.h"
#include "FileSelectionActivity.h"
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
#include "Txt.h"
#include "TxtReaderActivity.h"
#include "Xtc.h"
#include "XtcReaderActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
#include "util/StringUtils.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);
}
bool ReaderActivity::isXtcFile(const std::string& path) {
return StringUtils::checkFileExtension(path, ".xtc") || StringUtils::checkFileExtension(path, ".xtch");
}
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
bool ReaderActivity::isTxtFile(const std::string& path) {
if (path.length() < 4) return false;
std::string ext4 = path.substr(path.length() - 4);
return ext4 == ".txt" || ext4 == ".TXT";
}
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto epub = std::unique_ptr<Epub>(new Epub(path, "/.crosspoint"));
if (epub->load()) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
return nullptr;
}
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto xtc = std::unique_ptr<Xtc>(new Xtc(path, "/.crosspoint"));
if (xtc->load()) {
return xtc;
}
Serial.printf("[%lu] [ ] Failed to load XTC\n", millis());
return nullptr;
}
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto txt = std::unique_ptr<Txt>(new Txt(path, "/.crosspoint"));
if (txt->load()) {
return txt;
}
Serial.printf("[%lu] [ ] Failed to load TXT\n", millis());
return nullptr;
}
void ReaderActivity::onSelectBookFile(const std::string& path) {
currentBookPath = path; // Track current book path
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Loading..."));
if (isXtcFile(path)) {
// Load XTC file
auto xtc = loadXtc(path);
if (xtc) {
onGoToXtcReader(std::move(xtc));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Failed to load XTC",
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
} else if (isTxtFile(path)) {
// Load TXT file
auto txt = loadTxt(path);
if (txt) {
onGoToTxtReader(std::move(txt));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Failed to load TXT",
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
} else {
// Load EPUB file
auto epub = loadEpub(path);
if (epub) {
onGoToEpubReader(std::move(epub));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Failed to load epub",
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
}
}
void ReaderActivity::onGoToFileSelection(const std::string& fromBookPath) {
exitActivity();
// If coming from a book, start in that book's folder; otherwise start from root
const auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
enterNewActivity(new FileSelectionActivity(
renderer, mappedInput, [this](const std::string& path) { onSelectBookFile(path); }, onGoBack, initialPath));
}
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
const auto epubPath = epub->getPath();
currentBookPath = epubPath;
exitActivity();
enterNewActivity(new EpubReaderActivity(
renderer, mappedInput, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); },
[this] { onGoBack(); }));
}
void ReaderActivity::onGoToXtcReader(std::unique_ptr<Xtc> xtc) {
const auto xtcPath = xtc->getPath();
currentBookPath = xtcPath;
exitActivity();
enterNewActivity(new XtcReaderActivity(
renderer, mappedInput, std::move(xtc), [this, xtcPath] { onGoToFileSelection(xtcPath); },
[this] { onGoBack(); }));
}
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
void ReaderActivity::onGoToTxtReader(std::unique_ptr<Txt> txt) {
const auto txtPath = txt->getPath();
currentBookPath = txtPath;
exitActivity();
enterNewActivity(new TxtReaderActivity(
renderer, mappedInput, std::move(txt), [this, txtPath] { onGoToFileSelection(txtPath); },
[this] { onGoBack(); }));
}
void ReaderActivity::onEnter() {
ActivityWithSubactivity::onEnter();
if (initialBookPath.empty()) {
onGoToFileSelection(); // Start from root when entering via Browse
return;
}
currentBookPath = initialBookPath;
if (isXtcFile(initialBookPath)) {
auto xtc = loadXtc(initialBookPath);
if (!xtc) {
onGoBack();
return;
}
onGoToXtcReader(std::move(xtc));
Add TXT file reader support (#240) ## Summary * **What is the goal of this PR?** Add support for reading plain text (.txt) files, enabling users to browse, read, and track progress in TXT documents alongside existing EPUB and XTC formats. * **What changes are included?** - New Txt library for loading and parsing plain text files - New TxtReaderActivity with streaming page rendering using 8KB chunks to handle large files without memory issues on ESP32-C3 - Page index caching system (index.bin) for instant re-open after sleep or app restart - Progress bar UI during initial file indexing (matching EPUB style) - Word wrapping with proper UTF-8 support - Cover image support for TXT files: - Primary: image with same filename as TXT (e.g., book.jpg for book.txt) - Fallback: cover.bmp/jpg/jpeg in the same folder - JPG to BMP conversion using existing converter - Sleep screen cover mode now works with TXT files - File browser now shows .txt files ## Additional Context * Add any other information that might be helpful for the reviewer * Memory constraints: The streaming approach was necessary because ESP32-C3 only has 320KB RAM. A 700KB TXT file cannot be loaded entirely into memory, so we read 8KB chunks and build a page offset index instead. * Cache invalidation: The page index cache automatically invalidates when file size, viewport width, or lines per page changes (e.g., font size or orientation change). * Performance: First open requires indexing (with progress bar), subsequent opens load from cache instantly. * Cover image format: PNG is detected but not supported for conversion (no PNG decoder available). Only BMP and JPG/JPEG work.
2026-01-14 19:36:40 +09:00
} else if (isTxtFile(initialBookPath)) {
auto txt = loadTxt(initialBookPath);
if (!txt) {
onGoBack();
return;
}
onGoToTxtReader(std::move(txt));
} else {
auto epub = loadEpub(initialBookPath);
if (!epub) {
onGoBack();
return;
}
onGoToEpubReader(std::move(epub));
}
}