Merge branch 'master' of https://github.com/jpirnay/crosspoint-reader into feat-page-overlay
This commit is contained in:
@@ -135,6 +135,9 @@ class CrossPointSettings {
|
||||
// UI Theme
|
||||
enum UI_THEME { CLASSIC = 0, LYRA = 1, LYRA_3_COVERS = 2 };
|
||||
|
||||
// Image rendering in EPUB reader
|
||||
enum IMAGE_RENDERING { IMAGES_DISPLAY = 0, IMAGES_PLACEHOLDER = 1, IMAGES_SUPPRESS = 2, IMAGE_RENDERING_COUNT };
|
||||
|
||||
// Sleep screen settings
|
||||
uint8_t sleepScreen = DARK;
|
||||
// Sleep screen cover mode settings
|
||||
@@ -193,6 +196,10 @@ class CrossPointSettings {
|
||||
uint8_t fadingFix = 0;
|
||||
// Use book's embedded CSS styles for EPUB rendering (1 = enabled, 0 = disabled)
|
||||
uint8_t embeddedStyle = 1;
|
||||
// Show hidden files/directories (starting with '.') in the file browser (0 = hidden, 1 = show)
|
||||
uint8_t showHiddenFiles = 0;
|
||||
// Image rendering mode in EPUB reader
|
||||
uint8_t imageRendering = IMAGES_DISPLAY;
|
||||
|
||||
~CrossPointSettings() = default;
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ inline const std::vector<SettingInfo>& getSettingsList() {
|
||||
StrId::STR_CAT_READER),
|
||||
SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing",
|
||||
StrId::STR_CAT_READER),
|
||||
SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering,
|
||||
{StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS},
|
||||
"imageRendering", StrId::STR_CAT_READER),
|
||||
// --- Controls ---
|
||||
SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout,
|
||||
{StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS),
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "boot_sleep/BootActivity.h"
|
||||
#include "boot_sleep/SleepActivity.h"
|
||||
#include "browser/OpdsBookBrowserActivity.h"
|
||||
#include "home/FileBrowserActivity.h"
|
||||
#include "home/HomeActivity.h"
|
||||
#include "home/MyLibraryActivity.h"
|
||||
#include "home/RecentBooksActivity.h"
|
||||
#include "network/CrossPointWebServerActivity.h"
|
||||
#include "reader/ReaderActivity.h"
|
||||
@@ -169,8 +169,8 @@ void ActivityManager::goToFileTransfer() {
|
||||
|
||||
void ActivityManager::goToSettings() { replaceActivity(std::make_unique<SettingsActivity>(renderer, mappedInput)); }
|
||||
|
||||
void ActivityManager::goToMyLibrary(std::string path) {
|
||||
replaceActivity(std::make_unique<MyLibraryActivity>(renderer, mappedInput, std::move(path)));
|
||||
void ActivityManager::goToFileBrowser(std::string path) {
|
||||
replaceActivity(std::make_unique<FileBrowserActivity>(renderer, mappedInput, std::move(path)));
|
||||
}
|
||||
|
||||
void ActivityManager::goToRecentBooks() {
|
||||
|
||||
@@ -79,7 +79,7 @@ class ActivityManager {
|
||||
// goTo... functions are convenient wrapper for replaceActivity()
|
||||
void goToFileTransfer();
|
||||
void goToSettings();
|
||||
void goToMyLibrary(std::string path = {});
|
||||
void goToFileBrowser(std::string path = {});
|
||||
void goToRecentBooks();
|
||||
void goToBrowser();
|
||||
void goToReader(std::string path);
|
||||
|
||||
@@ -182,9 +182,20 @@ void SleepActivity::onEnter() {
|
||||
}
|
||||
|
||||
void SleepActivity::renderCustomSleepScreen() const {
|
||||
// Check if we have a /sleep directory
|
||||
auto dir = Storage.open("/sleep");
|
||||
// Check if we have a /.sleep (preferred) or /sleep directory
|
||||
const char* sleepDir = nullptr;
|
||||
auto dir = Storage.open("/.sleep");
|
||||
if (dir && dir.isDirectory()) {
|
||||
sleepDir = "/.sleep";
|
||||
} else {
|
||||
if (dir) dir.close();
|
||||
dir = Storage.open("/sleep");
|
||||
if (dir && dir.isDirectory()) {
|
||||
sleepDir = "/sleep";
|
||||
}
|
||||
}
|
||||
|
||||
if (sleepDir) {
|
||||
std::vector<std::string> files;
|
||||
char name[500];
|
||||
// collect all valid BMP files
|
||||
@@ -224,10 +235,10 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
}
|
||||
APP_STATE.lastSleepImage = randomFileIndex;
|
||||
APP_STATE.saveToFile();
|
||||
const auto filename = "/sleep/" + files[randomFileIndex];
|
||||
const auto filename = std::string(sleepDir) + "/" + files[randomFileIndex];
|
||||
FsFile file;
|
||||
if (Storage.openFileForRead("SLP", filename, file)) {
|
||||
LOG_DBG("SLP", "Randomly loading: /sleep/%s", files[randomFileIndex].c_str());
|
||||
LOG_DBG("SLP", "Randomly loading: %s/%s", sleepDir, files[randomFileIndex].c_str());
|
||||
delay(100);
|
||||
Bitmap bitmap(file, true);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
+13
-13
@@ -1,4 +1,4 @@
|
||||
#include "MyLibraryActivity.h"
|
||||
#include "FileBrowserActivity.h"
|
||||
|
||||
#include <Epub.h>
|
||||
#include <GfxRenderer.h>
|
||||
@@ -69,7 +69,7 @@ void sortFileList(std::vector<std::string>& strs) {
|
||||
});
|
||||
}
|
||||
|
||||
void MyLibraryActivity::loadFiles() {
|
||||
void FileBrowserActivity::loadFiles() {
|
||||
files.clear();
|
||||
|
||||
auto root = Storage.open(basepath.c_str());
|
||||
@@ -104,7 +104,7 @@ void MyLibraryActivity::loadFiles() {
|
||||
sortFileList(files);
|
||||
}
|
||||
|
||||
void MyLibraryActivity::onEnter() {
|
||||
void FileBrowserActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
|
||||
loadFiles();
|
||||
@@ -113,20 +113,20 @@ void MyLibraryActivity::onEnter() {
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void MyLibraryActivity::onExit() {
|
||||
void FileBrowserActivity::onExit() {
|
||||
Activity::onExit();
|
||||
files.clear();
|
||||
}
|
||||
|
||||
void MyLibraryActivity::clearFileMetadata(const std::string& fullPath) {
|
||||
void FileBrowserActivity::clearFileMetadata(const std::string& fullPath) {
|
||||
// Only clear cache for .epub files
|
||||
if (StringUtils::checkFileExtension(fullPath, ".epub")) {
|
||||
Epub(fullPath, "/.crosspoint").clearCache();
|
||||
LOG_DBG("MyLibrary", "Cleared metadata cache for: %s", fullPath.c_str());
|
||||
LOG_DBG("FileBrowser", "Cleared metadata cache for: %s", fullPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void MyLibraryActivity::loop() {
|
||||
void FileBrowserActivity::loop() {
|
||||
// Long press BACK (1s+) goes to root folder
|
||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= GO_HOME_MS &&
|
||||
basepath != "/") {
|
||||
@@ -152,10 +152,10 @@ void MyLibraryActivity::loop() {
|
||||
|
||||
auto handler = [this, fullPath](const ActivityResult& res) {
|
||||
if (!res.isCancelled) {
|
||||
LOG_DBG("MyLibrary", "Attempting to delete: %s", fullPath.c_str());
|
||||
LOG_DBG("FileBrowser", "Attempting to delete: %s", fullPath.c_str());
|
||||
clearFileMetadata(fullPath);
|
||||
if (Storage.remove(fullPath.c_str())) {
|
||||
LOG_DBG("MyLibrary", "Deleted successfully");
|
||||
LOG_DBG("FileBrowser", "Deleted successfully");
|
||||
loadFiles();
|
||||
if (files.empty()) {
|
||||
selectorIndex = 0;
|
||||
@@ -166,10 +166,10 @@ void MyLibraryActivity::loop() {
|
||||
|
||||
requestUpdate(true);
|
||||
} else {
|
||||
LOG_ERR("MyLibrary", "Failed to delete file: %s", fullPath.c_str());
|
||||
LOG_ERR("FileBrowser", "Failed to delete file: %s", fullPath.c_str());
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("MyLibrary", "Delete cancelled by user");
|
||||
LOG_DBG("FileBrowser", "Delete cancelled by user");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -244,7 +244,7 @@ std::string getFileName(std::string filename) {
|
||||
return filename.substr(0, pos);
|
||||
}
|
||||
|
||||
void MyLibraryActivity::render(RenderLock&&) {
|
||||
void FileBrowserActivity::render(RenderLock&&) {
|
||||
renderer.clearScreen();
|
||||
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
@@ -274,7 +274,7 @@ void MyLibraryActivity::render(RenderLock&&) {
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
size_t MyLibraryActivity::findEntry(const std::string& name) const {
|
||||
size_t FileBrowserActivity::findEntry(const std::string& name) const {
|
||||
for (size_t i = 0; i < files.size(); i++)
|
||||
if (files[i] == name) return i;
|
||||
return 0;
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "RecentBooksStore.h"
|
||||
#include "util/ButtonNavigator.h"
|
||||
|
||||
class MyLibraryActivity final : public Activity {
|
||||
class FileBrowserActivity final : public Activity {
|
||||
private:
|
||||
// Deletion
|
||||
void clearFileMetadata(const std::string& fullPath);
|
||||
@@ -26,8 +26,8 @@ class MyLibraryActivity final : public Activity {
|
||||
size_t findEntry(const std::string& name) const;
|
||||
|
||||
public:
|
||||
explicit MyLibraryActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialPath = "/")
|
||||
: Activity("MyLibrary", renderer, mappedInput), basepath(initialPath.empty() ? "/" : std::move(initialPath)) {}
|
||||
explicit FileBrowserActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialPath = "/")
|
||||
: Activity("FileBrowser", renderer, mappedInput), basepath(initialPath.empty() ? "/" : std::move(initialPath)) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "util/StringUtils.h"
|
||||
|
||||
int HomeActivity::getMenuItemCount() const {
|
||||
int count = 4; // My Library, Recents, File transfer, Settings
|
||||
int count = 4; // File Browser, Recents, File transfer, Settings
|
||||
if (!recentBooks.empty()) {
|
||||
count += recentBooks.size();
|
||||
}
|
||||
@@ -189,7 +189,7 @@ void HomeActivity::loop() {
|
||||
// Calculate dynamic indices based on which options are available
|
||||
int idx = 0;
|
||||
int menuSelectedIndex = selectorIndex - static_cast<int>(recentBooks.size());
|
||||
const int myLibraryIdx = idx++;
|
||||
const int fileBrowserIdx = idx++;
|
||||
const int recentsIdx = idx++;
|
||||
const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1;
|
||||
const int fileTransferIdx = idx++;
|
||||
@@ -197,8 +197,8 @@ void HomeActivity::loop() {
|
||||
|
||||
if (selectorIndex < recentBooks.size()) {
|
||||
onSelectBook(recentBooks[selectorIndex].path);
|
||||
} else if (menuSelectedIndex == myLibraryIdx) {
|
||||
onMyLibraryOpen();
|
||||
} else if (menuSelectedIndex == fileBrowserIdx) {
|
||||
onFileBrowserOpen();
|
||||
} else if (menuSelectedIndex == recentsIdx) {
|
||||
onRecentsOpen();
|
||||
} else if (menuSelectedIndex == opdsLibraryIdx) {
|
||||
@@ -231,7 +231,7 @@ void HomeActivity::render(RenderLock&&) {
|
||||
std::vector<UIIcon> menuIcons = {Folder, Recent, Transfer, Settings};
|
||||
|
||||
if (hasOpdsUrl) {
|
||||
// Insert OPDS Browser after My Library
|
||||
// Insert OPDS Browser after File Browser
|
||||
menuItems.insert(menuItems.begin() + 2, tr(STR_OPDS_BROWSER));
|
||||
menuIcons.insert(menuIcons.begin() + 2, Library);
|
||||
}
|
||||
@@ -261,7 +261,7 @@ void HomeActivity::render(RenderLock&&) {
|
||||
|
||||
void HomeActivity::onSelectBook(const std::string& path) { activityManager.goToReader(path); }
|
||||
|
||||
void HomeActivity::onMyLibraryOpen() { activityManager.goToMyLibrary(); }
|
||||
void HomeActivity::onFileBrowserOpen() { activityManager.goToFileBrowser(); }
|
||||
|
||||
void HomeActivity::onRecentsOpen() { activityManager.goToRecentBooks(); }
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "../Activity.h"
|
||||
#include "./MyLibraryActivity.h"
|
||||
#include "./FileBrowserActivity.h"
|
||||
#include "util/ButtonNavigator.h"
|
||||
|
||||
struct RecentBook;
|
||||
@@ -21,7 +21,7 @@ class HomeActivity final : public Activity {
|
||||
uint8_t* coverBuffer = nullptr; // HomeActivity's own buffer for cover image
|
||||
std::vector<RecentBook> recentBooks;
|
||||
void onSelectBook(const std::string& path);
|
||||
void onMyLibraryOpen();
|
||||
void onFileBrowserOpen();
|
||||
void onRecentsOpen();
|
||||
void onSettingsOpen();
|
||||
void onFileTransferOpen();
|
||||
|
||||
@@ -182,7 +182,7 @@ void EpubReaderActivity::loop() {
|
||||
|
||||
// Long press BACK (1s+) goes to file selection
|
||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||
activityManager.goToMyLibrary(epub ? epub->getPath() : "");
|
||||
activityManager.goToFileBrowser(epub ? epub->getPath() : "");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -573,14 +573,16 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
|
||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) {
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering)) {
|
||||
LOG_DBG("ERS", "Cache not found, building...");
|
||||
|
||||
const auto popupFn = [this]() { GUI.drawPopup(renderer, tr(STR_INDEXING)); };
|
||||
|
||||
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, popupFn)) {
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering, popupFn)) {
|
||||
LOG_ERR("ERS", "Failed to persist page data to SD");
|
||||
section.reset();
|
||||
return;
|
||||
|
||||
@@ -204,25 +204,7 @@ void KOReaderSyncActivity::onEnter() {
|
||||
// Check if already connected (e.g. from settings page auth)
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
LOG_DBG("KOSync", "Already connected to WiFi");
|
||||
state = SYNCING;
|
||||
statusMessage = tr(STR_SYNCING_TIME);
|
||||
requestUpdate(true);
|
||||
|
||||
// Perform sync directly (will be handled in loop)
|
||||
xTaskCreate(
|
||||
[](void* param) {
|
||||
auto* self = static_cast<KOReaderSyncActivity*>(param);
|
||||
// Sync time first
|
||||
syncTimeWithNTP();
|
||||
{
|
||||
RenderLock lock(*self);
|
||||
self->statusMessage = tr(STR_CALC_HASH);
|
||||
}
|
||||
self->requestUpdate(true);
|
||||
self->performSync();
|
||||
vTaskDelete(nullptr);
|
||||
},
|
||||
"SyncTask", 4096, this, 1, nullptr);
|
||||
onWifiSelectionComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
|
||||
void ReaderActivity::goToLibrary(const std::string& fromBookPath) {
|
||||
// If coming from a book, start in that book's folder; otherwise start from root
|
||||
auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
|
||||
activityManager.goToMyLibrary(std::move(initialPath));
|
||||
activityManager.goToFileBrowser(std::move(initialPath));
|
||||
}
|
||||
|
||||
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "../Activity.h"
|
||||
#include "activities/home/MyLibraryActivity.h"
|
||||
#include "activities/home/FileBrowserActivity.h"
|
||||
|
||||
class Epub;
|
||||
class Xtc;
|
||||
|
||||
@@ -135,7 +135,7 @@ void TxtReaderActivity::onExit() {
|
||||
void TxtReaderActivity::loop() {
|
||||
// Long press BACK (1s+) goes to file selection
|
||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||
activityManager.goToMyLibrary(txt ? txt->getPath() : "");
|
||||
activityManager.goToFileBrowser(txt ? txt->getPath() : "");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ void XtcReaderActivity::loop() {
|
||||
|
||||
// Long press BACK (1s+) goes to file selection
|
||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||
activityManager.goToMyLibrary(xtc ? xtc->getPath() : "");
|
||||
activityManager.goToFileBrowser(xtc ? xtc->getPath() : "");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,23 +51,9 @@ void KOReaderAuthActivity::performAuthentication() {
|
||||
void KOReaderAuthActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
|
||||
// Turn on WiFi
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Check if already connected
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
state = AUTHENTICATING;
|
||||
statusMessage = tr(STR_AUTHENTICATING);
|
||||
requestUpdate();
|
||||
|
||||
// Perform authentication in a separate task
|
||||
xTaskCreate(
|
||||
[](void* param) {
|
||||
auto* self = static_cast<KOReaderAuthActivity*>(param);
|
||||
self->performAuthentication();
|
||||
vTaskDelete(nullptr);
|
||||
},
|
||||
"AuthTask", 4096, this, 1, nullptr);
|
||||
onWifiSelectionComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user