Merge branch 'master' of https://github.com/jpirnay/crosspoint-reader into feat-page-overlay
This commit is contained in:
@@ -39,6 +39,14 @@ usability over "swiss-army-knife" functionality.
|
|||||||
* **Complex Annotation:** No typed out notes. These features are better suited for devices with better input
|
* **Complex Annotation:** No typed out notes. These features are better suited for devices with better input
|
||||||
capabilities and more powerful chips.
|
capabilities and more powerful chips.
|
||||||
|
|
||||||
|
### In-scope — Technically Unsupported
|
||||||
|
|
||||||
|
*These features align with CrossPoint's goals but are impractical on the current hardware or produce poor UX.*
|
||||||
|
|
||||||
|
* **Clock Display:** The ESP32-C3's RTC drifts significantly during deep sleep; making the clock untrustworthy after any sleep cycle. NTP sync could help, but CrossPoint doesn't connect to the internet on every boot.
|
||||||
|
|
||||||
|
* **PDF Rendering:** PDFs are fixed-layout documents, so rendering them requires displaying pages as images rather than reflowable text — resulting in constant panning and zooming that makes for a poor reading experience on e-ink.
|
||||||
|
|
||||||
## 3. Idea Evaluation
|
## 3. Idea Evaluation
|
||||||
|
|
||||||
While I appreciate the desire to add new and exciting features to CrossPoint Reader, CrossPoint Reader is designed to be
|
While I appreciate the desire to add new and exciting features to CrossPoint Reader, CrossPoint Reader is designed to be
|
||||||
|
|||||||
+22
-5
@@ -308,13 +308,30 @@ If you use the HTTPS listener, use `https://<server-ip>:7200` (`curl -k` only fo
|
|||||||
|
|
||||||
### 3.7 Sleep Screen
|
### 3.7 Sleep Screen
|
||||||
|
|
||||||
You can customize the sleep screen by placing custom images in specific locations on the SD card:
|
The **Sleep Screen** setting controls what is displayed when the device goes to sleep:
|
||||||
|
|
||||||
- **Single Image:** Place a file named `sleep.bmp` in the root directory.
|
| Mode | Behavior |
|
||||||
- **Multiple Images:** Create a `sleep` directory in the root of the SD card and place any number of `.bmp` images inside. If images are found in this directory, they will take priority over the `sleep.bmp` file, and one will be randomly selected each time the device sleeps.
|
|------|----------|
|
||||||
|
| **Dark** (default) | The CrossPoint logo on a dark background. |
|
||||||
|
| **Light** | The CrossPoint logo on a white background. |
|
||||||
|
| **Custom** | A custom image from the SD card (see below). Falls back to **Dark** if no custom image is found. |
|
||||||
|
| **Cover** | The cover of the currently open book. Falls back to **Dark** if no book is open. |
|
||||||
|
| **Cover + Custom** | The cover of the currently open book. Falls back to **Custom** behavior if no book is open. |
|
||||||
|
| **None** | A blank screen. |
|
||||||
|
|
||||||
> [!NOTE]
|
#### Cover settings
|
||||||
> You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images.
|
|
||||||
|
When using **Cover** or **Cover + Custom**, two additional settings apply:
|
||||||
|
|
||||||
|
- **Sleep Screen Cover Mode**: **Fit** (scale to fit, white borders) or **Crop** (scale and crop to fill the screen).
|
||||||
|
- **Sleep Screen Cover Filter**: **None** (grayscale), **Contrast** (black & white), or **Inverted** (inverted black & white).
|
||||||
|
|
||||||
|
#### Custom images
|
||||||
|
|
||||||
|
To use custom sleep images, set the sleep screen mode to **Custom** or **Cover + Custom**, then place images on the SD card:
|
||||||
|
|
||||||
|
- **Multiple Images (recommended):** Create a `.sleep` directory in the root of the SD card and place any number of `.bmp` images inside. One will be randomly selected each time the device sleeps. (A directory named `sleep` is also accepted as a fallback.)
|
||||||
|
- **Single Image:** Place a file named `sleep.bmp` in the root directory. This is used as a fallback if no valid images are found in the `.sleep`/`sleep` directory.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> For best results:
|
> For best results:
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ If you'd like to add your name to this list, please open a PR adding yourself an
|
|||||||
- [yeyeto2788](https://github.com/yeyeto2788)
|
- [yeyeto2788](https://github.com/yeyeto2788)
|
||||||
- [Skrzakk](https://github.com/Skrzakk)
|
- [Skrzakk](https://github.com/Skrzakk)
|
||||||
- [pablohc](https://github.com/pablohc)
|
- [pablohc](https://github.com/pablohc)
|
||||||
|
- [DaniPhii](https://github.com/DaniPhii)
|
||||||
|
|
||||||
## Swedish
|
## Swedish
|
||||||
- [dawiik](https://github.com/dawiik)
|
- [dawiik](https://github.com/dawiik)
|
||||||
|
|||||||
@@ -274,11 +274,13 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BookMetadataCache::cleanupTmpFiles() const {
|
bool BookMetadataCache::cleanupTmpFiles() const {
|
||||||
if (Storage.exists((cachePath + tmpSpineBinFile).c_str())) {
|
const auto spineBinFile = cachePath + tmpSpineBinFile;
|
||||||
Storage.remove((cachePath + tmpSpineBinFile).c_str());
|
if (Storage.exists(spineBinFile.c_str())) {
|
||||||
|
Storage.remove(spineBinFile.c_str());
|
||||||
}
|
}
|
||||||
if (Storage.exists((cachePath + tmpTocBinFile).c_str())) {
|
const auto tocBinFile = cachePath + tmpTocBinFile;
|
||||||
Storage.remove((cachePath + tmpTocBinFile).c_str());
|
if (Storage.exists(tocBinFile.c_str())) {
|
||||||
|
Storage.remove(tocBinFile.c_str());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,9 +144,12 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
// Calculate first line indent (only for left/justified text).
|
||||||
|
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||||
|
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||||
|
// it is structural (positions the bullet/marker), not decorative.
|
||||||
const int firstLineIndent =
|
const int firstLineIndent =
|
||||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||||
? blockStyle.textIndent
|
? blockStyle.textIndent
|
||||||
: 0;
|
: 0;
|
||||||
@@ -275,9 +278,12 @@ std::vector<size_t> ParsedText::computeHyphenatedLineBreaks(const GfxRenderer& r
|
|||||||
const int pageWidth, const int spaceWidth,
|
const int pageWidth, const int spaceWidth,
|
||||||
std::vector<uint16_t>& wordWidths,
|
std::vector<uint16_t>& wordWidths,
|
||||||
std::vector<bool>& continuesVec) {
|
std::vector<bool>& continuesVec) {
|
||||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
// Calculate first line indent (only for left/justified text).
|
||||||
|
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||||
|
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||||
|
// it is structural (positions the bullet/marker), not decorative.
|
||||||
const int firstLineIndent =
|
const int firstLineIndent =
|
||||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||||
? blockStyle.textIndent
|
? blockStyle.textIndent
|
||||||
: 0;
|
: 0;
|
||||||
@@ -443,10 +449,13 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
|||||||
const size_t lastBreakAt = breakIndex > 0 ? lineBreakIndices[breakIndex - 1] : 0;
|
const size_t lastBreakAt = breakIndex > 0 ? lineBreakIndices[breakIndex - 1] : 0;
|
||||||
const size_t lineWordCount = lineBreak - lastBreakAt;
|
const size_t lineWordCount = lineBreak - lastBreakAt;
|
||||||
|
|
||||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
// Calculate first line indent (only for left/justified text).
|
||||||
|
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||||
|
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||||
|
// it is structural (positions the bullet/marker), not decorative.
|
||||||
const bool isFirstLine = breakIndex == 0;
|
const bool isFirstLine = breakIndex == 0;
|
||||||
const int firstLineIndent =
|
const int firstLineIndent =
|
||||||
isFirstLine && blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
isFirstLine && blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||||
? blockStyle.textIndent
|
? blockStyle.textIndent
|
||||||
: 0;
|
: 0;
|
||||||
@@ -485,8 +494,9 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
|||||||
? spareSpace / static_cast<int>(actualGapCount)
|
? spareSpace / static_cast<int>(actualGapCount)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
// Calculate initial x position (first line starts at indent for left/justified text)
|
// Calculate initial x position (first line starts at indent for left/justified text;
|
||||||
auto xpos = static_cast<uint16_t>(firstLineIndent);
|
// may be negative for hanging indents, e.g. margin-left:3em; text-indent:-1em).
|
||||||
|
auto xpos = static_cast<int16_t>(firstLineIndent);
|
||||||
if (blockStyle.alignment == CssTextAlign::Right) {
|
if (blockStyle.alignment == CssTextAlign::Right) {
|
||||||
xpos = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
|
xpos = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
|
||||||
} else if (blockStyle.alignment == CssTextAlign::Center) {
|
} else if (blockStyle.alignment == CssTextAlign::Center) {
|
||||||
@@ -495,7 +505,7 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
|||||||
|
|
||||||
// Pre-calculate X positions for words
|
// Pre-calculate X positions for words
|
||||||
// Continuation words attach to the previous word with no space before them
|
// Continuation words attach to the previous word with no space before them
|
||||||
std::vector<uint16_t> lineXPos;
|
std::vector<int16_t> lineXPos;
|
||||||
lineXPos.reserve(lineWordCount);
|
lineXPos.reserve(lineWordCount);
|
||||||
|
|
||||||
for (size_t wordIdx = 0; wordIdx < lineWordCount; wordIdx++) {
|
for (size_t wordIdx = 0; wordIdx < lineWordCount; wordIdx++) {
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
#include "parsers/ChapterHtmlSlimParser.h"
|
#include "parsers/ChapterHtmlSlimParser.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t SECTION_FILE_VERSION = 14;
|
constexpr uint8_t SECTION_FILE_VERSION = 17;
|
||||||
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(uint8_t) +
|
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(uint8_t) +
|
||||||
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) +
|
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) +
|
||||||
sizeof(uint32_t);
|
sizeof(uint8_t) + sizeof(uint32_t);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
||||||
@@ -36,7 +36,7 @@ uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
|||||||
void Section::writeSectionFileHeader(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
void Section::writeSectionFileHeader(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||||
const bool embeddedStyle) {
|
const bool embeddedStyle, const uint8_t imageRendering) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
LOG_DBG("SCT", "File not open for writing header");
|
LOG_DBG("SCT", "File not open for writing header");
|
||||||
return;
|
return;
|
||||||
@@ -44,7 +44,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
|||||||
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
||||||
sizeof(extraParagraphSpacing) + sizeof(paragraphAlignment) + sizeof(viewportWidth) +
|
sizeof(extraParagraphSpacing) + sizeof(paragraphAlignment) + sizeof(viewportWidth) +
|
||||||
sizeof(viewportHeight) + sizeof(pageCount) + sizeof(hyphenationEnabled) +
|
sizeof(viewportHeight) + sizeof(pageCount) + sizeof(hyphenationEnabled) +
|
||||||
sizeof(embeddedStyle) + sizeof(uint32_t),
|
sizeof(embeddedStyle) + sizeof(imageRendering) + sizeof(uint32_t),
|
||||||
"Header size mismatch");
|
"Header size mismatch");
|
||||||
serialization::writePod(file, SECTION_FILE_VERSION);
|
serialization::writePod(file, SECTION_FILE_VERSION);
|
||||||
serialization::writePod(file, fontId);
|
serialization::writePod(file, fontId);
|
||||||
@@ -55,13 +55,15 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
|||||||
serialization::writePod(file, viewportHeight);
|
serialization::writePod(file, viewportHeight);
|
||||||
serialization::writePod(file, hyphenationEnabled);
|
serialization::writePod(file, hyphenationEnabled);
|
||||||
serialization::writePod(file, embeddedStyle);
|
serialization::writePod(file, embeddedStyle);
|
||||||
|
serialization::writePod(file, imageRendering);
|
||||||
serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written)
|
serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written)
|
||||||
serialization::writePod(file, static_cast<uint32_t>(0)); // Placeholder for LUT offset
|
serialization::writePod(file, static_cast<uint32_t>(0)); // Placeholder for LUT offset
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||||
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle) {
|
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle,
|
||||||
|
const uint8_t imageRendering) {
|
||||||
if (!Storage.openFileForRead("SCT", filePath, file)) {
|
if (!Storage.openFileForRead("SCT", filePath, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
|||||||
uint8_t fileParagraphAlignment;
|
uint8_t fileParagraphAlignment;
|
||||||
bool fileHyphenationEnabled;
|
bool fileHyphenationEnabled;
|
||||||
bool fileEmbeddedStyle;
|
bool fileEmbeddedStyle;
|
||||||
|
uint8_t fileImageRendering;
|
||||||
serialization::readPod(file, fileFontId);
|
serialization::readPod(file, fileFontId);
|
||||||
serialization::readPod(file, fileLineCompression);
|
serialization::readPod(file, fileLineCompression);
|
||||||
serialization::readPod(file, fileExtraParagraphSpacing);
|
serialization::readPod(file, fileExtraParagraphSpacing);
|
||||||
@@ -92,11 +95,13 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
|||||||
serialization::readPod(file, fileViewportHeight);
|
serialization::readPod(file, fileViewportHeight);
|
||||||
serialization::readPod(file, fileHyphenationEnabled);
|
serialization::readPod(file, fileHyphenationEnabled);
|
||||||
serialization::readPod(file, fileEmbeddedStyle);
|
serialization::readPod(file, fileEmbeddedStyle);
|
||||||
|
serialization::readPod(file, fileImageRendering);
|
||||||
|
|
||||||
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
||||||
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
||||||
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
||||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) {
|
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle ||
|
||||||
|
imageRendering != fileImageRendering) {
|
||||||
file.close();
|
file.close();
|
||||||
LOG_ERR("SCT", "Deserialization failed: Parameters do not match");
|
LOG_ERR("SCT", "Deserialization failed: Parameters do not match");
|
||||||
clearCache();
|
clearCache();
|
||||||
@@ -129,7 +134,7 @@ bool Section::clearCache() const {
|
|||||||
bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||||
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle,
|
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle,
|
||||||
const std::function<void()>& popupFn) {
|
const uint8_t imageRendering, const std::function<void()>& popupFn) {
|
||||||
const auto localPath = epub->getSpineItem(spineIndex).href;
|
const auto localPath = epub->getSpineItem(spineIndex).href;
|
||||||
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
||||||
|
|
||||||
@@ -179,7 +184,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
||||||
viewportHeight, hyphenationEnabled, embeddedStyle);
|
viewportHeight, hyphenationEnabled, embeddedStyle, imageRendering);
|
||||||
std::vector<uint32_t> lut = {};
|
std::vector<uint32_t> lut = {};
|
||||||
|
|
||||||
// Derive the content base directory and image cache path prefix for the parser
|
// Derive the content base directory and image cache path prefix for the parser
|
||||||
@@ -201,7 +206,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
epub, tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
epub, tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
||||||
viewportHeight, hyphenationEnabled,
|
viewportHeight, hyphenationEnabled,
|
||||||
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
|
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
|
||||||
embeddedStyle, contentBase, imageBasePath, popupFn, cssParser);
|
embeddedStyle, contentBase, imageBasePath, imageRendering, popupFn, cssParser);
|
||||||
Hyphenator::setPreferredLanguage(epub->getLanguage());
|
Hyphenator::setPreferredLanguage(epub->getLanguage());
|
||||||
success = visitor.parseAndBuildPages();
|
success = visitor.parseAndBuildPages();
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Section {
|
|||||||
|
|
||||||
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
|
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
|
||||||
bool embeddedStyle);
|
bool embeddedStyle, uint8_t imageRendering);
|
||||||
uint32_t onPageComplete(std::unique_ptr<Page> page);
|
uint32_t onPageComplete(std::unique_ptr<Page> page);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -30,10 +30,11 @@ class Section {
|
|||||||
filePath(epub->getCachePath() + "/sections/" + std::to_string(spineIndex) + ".bin") {}
|
filePath(epub->getCachePath() + "/sections/" + std::to_string(spineIndex) + ".bin") {}
|
||||||
~Section() = default;
|
~Section() = default;
|
||||||
bool loadSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
bool loadSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle);
|
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle,
|
||||||
|
uint8_t imageRendering);
|
||||||
bool clearCache() const;
|
bool clearCache() const;
|
||||||
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle,
|
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle,
|
||||||
const std::function<void()>& popupFn = nullptr);
|
uint8_t imageRendering, const std::function<void()>& popupFn = nullptr);
|
||||||
std::unique_ptr<Page> loadPageFromSectionFile();
|
std::unique_ptr<Page> loadPageFromSectionFile();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ bool TextBlock::serialize(FsFile& file) const {
|
|||||||
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||||
uint16_t wc;
|
uint16_t wc;
|
||||||
std::vector<std::string> words;
|
std::vector<std::string> words;
|
||||||
std::vector<uint16_t> wordXpos;
|
std::vector<int16_t> wordXpos;
|
||||||
std::vector<EpdFontFamily::Style> wordStyles;
|
std::vector<EpdFontFamily::Style> wordStyles;
|
||||||
BlockStyle blockStyle;
|
BlockStyle blockStyle;
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
class TextBlock final : public Block {
|
class TextBlock final : public Block {
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> words;
|
std::vector<std::string> words;
|
||||||
std::vector<uint16_t> wordXpos;
|
std::vector<int16_t> wordXpos;
|
||||||
std::vector<EpdFontFamily::Style> wordStyles;
|
std::vector<EpdFontFamily::Style> wordStyles;
|
||||||
BlockStyle blockStyle;
|
BlockStyle blockStyle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TextBlock(std::vector<std::string> words, std::vector<uint16_t> word_xpos,
|
explicit TextBlock(std::vector<std::string> words, std::vector<int16_t> word_xpos,
|
||||||
std::vector<EpdFontFamily::Style> word_styles, const BlockStyle& blockStyle = BlockStyle())
|
std::vector<EpdFontFamily::Style> word_styles, const BlockStyle& blockStyle = BlockStyle())
|
||||||
: words(std::move(words)),
|
: words(std::move(words)),
|
||||||
wordXpos(std::move(word_xpos)),
|
wordXpos(std::move(word_xpos)),
|
||||||
|
|||||||
@@ -243,7 +243,14 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!src.empty()) {
|
// imageRendering: 0=display, 1=placeholder (alt text only), 2=suppress entirely
|
||||||
|
if (self->imageRendering == 2) {
|
||||||
|
self->skipUntilDepth = self->depth;
|
||||||
|
self->depth += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src.empty() && self->imageRendering != 1) {
|
||||||
LOG_DBG("EHP", "Found image: src=%s", src.c_str());
|
LOG_DBG("EHP", "Found image: src=%s", src.c_str());
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -278,8 +285,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
|
|
||||||
int displayWidth = 0;
|
int displayWidth = 0;
|
||||||
int displayHeight = 0;
|
int displayHeight = 0;
|
||||||
const float emSize =
|
const float emSize = static_cast<float>(self->renderer.getFontAscenderSize(self->fontId));
|
||||||
static_cast<float>(self->renderer.getLineHeight(self->fontId)) * self->lineCompression;
|
|
||||||
CssStyle imgStyle = self->cssParser ? self->cssParser->resolveStyle("img", classAttr) : CssStyle{};
|
CssStyle imgStyle = self->cssParser ? self->cssParser->resolveStyle("img", classAttr) : CssStyle{};
|
||||||
// Merge inline style (e.g. style="height: 2em") so it overrides stylesheet rules
|
// Merge inline style (e.g. style="height: 2em") so it overrides stylesheet rules
|
||||||
if (!styleAttr.empty()) {
|
if (!styleAttr.empty()) {
|
||||||
@@ -505,7 +511,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const float emSize = static_cast<float>(self->renderer.getLineHeight(self->fontId)) * self->lineCompression;
|
const float emSize = static_cast<float>(self->renderer.getFontAscenderSize(self->fontId));
|
||||||
const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle(
|
const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle(
|
||||||
cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth);
|
cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth);
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class ChapterHtmlSlimParser {
|
|||||||
bool hyphenationEnabled;
|
bool hyphenationEnabled;
|
||||||
const CssParser* cssParser;
|
const CssParser* cssParser;
|
||||||
bool embeddedStyle;
|
bool embeddedStyle;
|
||||||
|
uint8_t imageRendering;
|
||||||
std::string contentBase;
|
std::string contentBase;
|
||||||
std::string imageBasePath;
|
std::string imageBasePath;
|
||||||
int imageCounter = 0;
|
int imageCounter = 0;
|
||||||
@@ -94,8 +95,8 @@ class ChapterHtmlSlimParser {
|
|||||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||||
const bool embeddedStyle, const std::string& contentBase,
|
const bool embeddedStyle, const std::string& contentBase,
|
||||||
const std::string& imageBasePath, const std::function<void()>& popupFn = nullptr,
|
const std::string& imageBasePath, const uint8_t imageRendering = 0,
|
||||||
const CssParser* cssParser = nullptr)
|
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
|
||||||
|
|
||||||
: epub(epub),
|
: epub(epub),
|
||||||
filepath(filepath),
|
filepath(filepath),
|
||||||
@@ -111,6 +112,7 @@ class ChapterHtmlSlimParser {
|
|||||||
popupFn(popupFn),
|
popupFn(popupFn),
|
||||||
cssParser(cssParser),
|
cssParser(cssParser),
|
||||||
embeddedStyle(embeddedStyle),
|
embeddedStyle(embeddedStyle),
|
||||||
|
imageRendering(imageRendering),
|
||||||
contentBase(contentBase),
|
contentBase(contentBase),
|
||||||
imageBasePath(imageBasePath) {}
|
imageBasePath(imageBasePath) {}
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,10 @@ ContentOpfParser::~ContentOpfParser() {
|
|||||||
if (tempItemStore) {
|
if (tempItemStore) {
|
||||||
tempItemStore.close();
|
tempItemStore.close();
|
||||||
}
|
}
|
||||||
if (Storage.exists((cachePath + itemCacheFile).c_str())) {
|
const auto itemCachePath = cachePath + itemCacheFile;
|
||||||
Storage.remove((cachePath + itemCacheFile).c_str());
|
if (Storage.exists(itemCachePath.c_str())) {
|
||||||
|
Storage.remove(itemCachePath.c_str());
|
||||||
}
|
}
|
||||||
itemIndex.clear();
|
|
||||||
itemIndex.shrink_to_fit();
|
|
||||||
useItemIndex = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ContentOpfParser::write(const uint8_t data) { return write(&data, 1); }
|
size_t ContentOpfParser::write(const uint8_t data) { return write(&data, 1); }
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ STR_STATUS_BAR: "Status Bar"
|
|||||||
STR_HIDE_BATTERY: "Hide Battery %"
|
STR_HIDE_BATTERY: "Hide Battery %"
|
||||||
STR_EXTRA_SPACING: "Extra Paragraph Spacing"
|
STR_EXTRA_SPACING: "Extra Paragraph Spacing"
|
||||||
STR_TEXT_AA: "Text Anti-Aliasing"
|
STR_TEXT_AA: "Text Anti-Aliasing"
|
||||||
|
STR_IMAGES: "Images"
|
||||||
|
STR_IMAGES_DISPLAY: "Display"
|
||||||
|
STR_IMAGES_PLACEHOLDER: "Placeholder"
|
||||||
|
STR_IMAGES_SUPPRESS: "Suppress"
|
||||||
STR_SHORT_PWR_BTN: "Short Power Button Click"
|
STR_SHORT_PWR_BTN: "Short Power Button Click"
|
||||||
STR_ORIENTATION: "Reading Orientation"
|
STR_ORIENTATION: "Reading Orientation"
|
||||||
STR_FRONT_BTN_LAYOUT: "Front Button Layout"
|
STR_FRONT_BTN_LAYOUT: "Front Button Layout"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ STR_MAC_ADDRESS: "MAC-Adresse:"
|
|||||||
STR_CHECKING_WIFI: "WLAN prüfen…"
|
STR_CHECKING_WIFI: "WLAN prüfen…"
|
||||||
STR_ENTER_WIFI_PASSWORD: "WLAN-Passwort eingeben"
|
STR_ENTER_WIFI_PASSWORD: "WLAN-Passwort eingeben"
|
||||||
STR_ENTER_TEXT: "Text eingeben"
|
STR_ENTER_TEXT: "Text eingeben"
|
||||||
STR_TO_PREFIX: "bis"
|
STR_TO_PREFIX: "mit "
|
||||||
STR_CALIBRE_DISCOVERING: "Calibre finden..."
|
STR_CALIBRE_DISCOVERING: "Calibre finden..."
|
||||||
STR_CALIBRE_CONNECTING_TO: "Verbinden mit"
|
STR_CALIBRE_CONNECTING_TO: "Verbinden mit"
|
||||||
STR_CALIBRE_CONNECTED_TO: "Verbunden mit"
|
STR_CALIBRE_CONNECTED_TO: "Verbunden mit"
|
||||||
@@ -120,7 +120,7 @@ STR_SELECT_WALLPAPER: "Bildauswahl Standby"
|
|||||||
STR_CLEAR_READING_CACHE: "Lese-Cache leeren"
|
STR_CLEAR_READING_CACHE: "Lese-Cache leeren"
|
||||||
STR_CALIBRE: "Calibre"
|
STR_CALIBRE: "Calibre"
|
||||||
STR_USERNAME: "Benutzername"
|
STR_USERNAME: "Benutzername"
|
||||||
STR_PASSWORD: "Passwort nötig"
|
STR_PASSWORD: "Passwort"
|
||||||
STR_SYNC_SERVER_URL: "Sync-Server-URL"
|
STR_SYNC_SERVER_URL: "Sync-Server-URL"
|
||||||
STR_DOCUMENT_MATCHING: "Dateizuordnung"
|
STR_DOCUMENT_MATCHING: "Dateizuordnung"
|
||||||
STR_AUTHENTICATE: "Authentifizieren"
|
STR_AUTHENTICATE: "Authentifizieren"
|
||||||
@@ -169,7 +169,7 @@ STR_FRONT_LAYOUT_BCLR: "Zurück, Bst, L, R"
|
|||||||
STR_FRONT_LAYOUT_LRBC: "L, R, Zurück, Bst"
|
STR_FRONT_LAYOUT_LRBC: "L, R, Zurück, Bst"
|
||||||
STR_FRONT_LAYOUT_LBCR: "L, Zurück, Bst, R"
|
STR_FRONT_LAYOUT_LBCR: "L, Zurück, Bst, R"
|
||||||
STR_PREV_NEXT: "Zurück/Weiter"
|
STR_PREV_NEXT: "Zurück/Weiter"
|
||||||
STR_NEXT_PREV: "Weiter/Zuürck"
|
STR_NEXT_PREV: "Weiter/Zurück"
|
||||||
STR_BOOKERLY: "Bookerly"
|
STR_BOOKERLY: "Bookerly"
|
||||||
STR_NOTO_SANS: "Noto Sans"
|
STR_NOTO_SANS: "Noto Sans"
|
||||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||||
@@ -236,6 +236,8 @@ STR_DOWNLOAD: "Herunterladen"
|
|||||||
STR_RETRY: "Wiederh."
|
STR_RETRY: "Wiederh."
|
||||||
STR_YES: "Ja"
|
STR_YES: "Ja"
|
||||||
STR_NO: "Nein"
|
STR_NO: "Nein"
|
||||||
|
STR_SHOW: "Zeigen"
|
||||||
|
STR_HIDE: "Ausblenden"
|
||||||
STR_STATE_ON: "An"
|
STR_STATE_ON: "An"
|
||||||
STR_STATE_OFF: "Aus"
|
STR_STATE_OFF: "Aus"
|
||||||
STR_NOT_SET: "Leer"
|
STR_NOT_SET: "Leer"
|
||||||
@@ -248,6 +250,21 @@ STR_CAPS_OFF: "umsch"
|
|||||||
STR_OK_BUTTON: "OK"
|
STR_OK_BUTTON: "OK"
|
||||||
STR_SLEEP_COVER_FILTER: "Standby-Coverfilter"
|
STR_SLEEP_COVER_FILTER: "Standby-Coverfilter"
|
||||||
STR_FILTER_CONTRAST: "Kontrast"
|
STR_FILTER_CONTRAST: "Kontrast"
|
||||||
|
STR_CUSTOMISE_STATUS_BAR: "Statusleiste anpassen"
|
||||||
|
STR_CHAPTER_PAGE_COUNT: "Kapitel-Seitenanzahl"
|
||||||
|
STR_BOOK_PROGRESS_PERCENTAGE: "Buchfortschritt in %"
|
||||||
|
STR_PROGRESS_BAR: "Fortschrittsbalken"
|
||||||
|
STR_PROGRESS_BAR_THICKNESS: "Balkenstärke"
|
||||||
|
STR_PROGRESS_BAR_THIN: "Dünn"
|
||||||
|
STR_PROGRESS_BAR_MEDIUM: "Mittel"
|
||||||
|
STR_PROGRESS_BAR_THICK: "Dick"
|
||||||
|
STR_BOOK: "Buch"
|
||||||
|
STR_CHAPTER: "Kapitel"
|
||||||
|
STR_EXAMPLE_CHAPTER: "Kapitel 21"
|
||||||
|
STR_EXAMPLE_BOOK: "Buchtitel"
|
||||||
|
STR_PREVIEW: "Vorschau"
|
||||||
|
STR_TITLE: "Titel"
|
||||||
|
STR_BATTERY: "Batterie"
|
||||||
STR_UI_THEME: "System-Design"
|
STR_UI_THEME: "System-Design"
|
||||||
STR_THEME_CLASSIC: "Klassisch"
|
STR_THEME_CLASSIC: "Klassisch"
|
||||||
STR_THEME_LYRA: "Lyra"
|
STR_THEME_LYRA: "Lyra"
|
||||||
@@ -280,6 +297,7 @@ STR_GO_TO_PERCENT: "Gehe zu %"
|
|||||||
STR_GO_HOME_BUTTON: "Zum Anfang"
|
STR_GO_HOME_BUTTON: "Zum Anfang"
|
||||||
STR_SYNC_PROGRESS: "Fortschritt synchronisieren"
|
STR_SYNC_PROGRESS: "Fortschritt synchronisieren"
|
||||||
STR_DELETE_CACHE: "Buch-Cache leeren"
|
STR_DELETE_CACHE: "Buch-Cache leeren"
|
||||||
|
STR_DISPLAY_QR: "Seite als QR anzeigen"
|
||||||
STR_DELETE: "Löschen"
|
STR_DELETE: "Löschen"
|
||||||
STR_CHAPTER_PREFIX: "Kapitel:"
|
STR_CHAPTER_PREFIX: "Kapitel:"
|
||||||
STR_PAGES_SEPARATOR: " Seiten | "
|
STR_PAGES_SEPARATOR: " Seiten | "
|
||||||
@@ -289,7 +307,7 @@ STR_KBD_SHIFT_CAPS: "UMSCH"
|
|||||||
STR_KBD_LOCK: "FESTST"
|
STR_KBD_LOCK: "FESTST"
|
||||||
STR_CALIBRE_URL_HINT: "Calibre: URL um /opds ergänzen"
|
STR_CALIBRE_URL_HINT: "Calibre: URL um /opds ergänzen"
|
||||||
STR_PERCENT_STEP_HINT: "links/rechts: 1% hoch/runter: 10%"
|
STR_PERCENT_STEP_HINT: "links/rechts: 1% hoch/runter: 10%"
|
||||||
STR_SYNCING_TIME: "Zeit synchonisieren…"
|
STR_SYNCING_TIME: "Zeit synchronisieren…"
|
||||||
STR_CALC_HASH: "Dokument-Hash berechnen…"
|
STR_CALC_HASH: "Dokument-Hash berechnen…"
|
||||||
STR_HASH_FAILED: "Dokument-Hash fehlgeschlagen"
|
STR_HASH_FAILED: "Dokument-Hash fehlgeschlagen"
|
||||||
STR_FETCH_PROGRESS: "Externen Fortschritt abrufen..."
|
STR_FETCH_PROGRESS: "Externen Fortschritt abrufen..."
|
||||||
@@ -302,8 +320,8 @@ STR_LOCAL_LABEL: "Lokal:"
|
|||||||
STR_PAGE_OVERALL_FORMAT: " Seite %d, %.2f%% insgesamt"
|
STR_PAGE_OVERALL_FORMAT: " Seite %d, %.2f%% insgesamt"
|
||||||
STR_PAGE_TOTAL_OVERALL_FORMAT: " Seite %d/%d, %.2f%% insgesamt"
|
STR_PAGE_TOTAL_OVERALL_FORMAT: " Seite %d/%d, %.2f%% insgesamt"
|
||||||
STR_DEVICE_FROM_FORMAT: " Von: %s"
|
STR_DEVICE_FROM_FORMAT: " Von: %s"
|
||||||
STR_APPLY_REMOTE: "Ext. Fortschritt übern."
|
STR_APPLY_REMOTE: "Externen Fortschritt übernehmen"
|
||||||
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochl."
|
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochladen"
|
||||||
STR_NO_REMOTE_MSG: "Kein externer Fortschritt"
|
STR_NO_REMOTE_MSG: "Kein externer Fortschritt"
|
||||||
STR_UPLOAD_PROMPT: "Aktuelle Position hochladen?"
|
STR_UPLOAD_PROMPT: "Aktuelle Position hochladen?"
|
||||||
STR_UPLOAD_SUCCESS: "Hochgeladen!"
|
STR_UPLOAD_SUCCESS: "Hochgeladen!"
|
||||||
@@ -314,3 +332,8 @@ STR_BOOK_S_STYLE: "Buch-Stil"
|
|||||||
STR_EMBEDDED_STYLE: "Eingebetteter Stil"
|
STR_EMBEDDED_STYLE: "Eingebetteter Stil"
|
||||||
STR_OPDS_SERVER_URL: "OPDS-Server-URL"
|
STR_OPDS_SERVER_URL: "OPDS-Server-URL"
|
||||||
STR_SCREENSHOT_BUTTON: "Screenshot aufnehmen"
|
STR_SCREENSHOT_BUTTON: "Screenshot aufnehmen"
|
||||||
|
STR_FOOTNOTES: "Fußnoten"
|
||||||
|
STR_NO_FOOTNOTES: "Keine Fußnoten auf dieser Seite"
|
||||||
|
STR_LINK: "[Link]"
|
||||||
|
STR_AUTO_TURN_ENABLED: "Auto-Umblättern aktiv: "
|
||||||
|
STR_AUTO_TURN_PAGES_PER_MIN: "Auto-Umblättern (Seiten/Min.)"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ STR_CROSSPOINT: "CrossPoint"
|
|||||||
STR_BOOTING: "Iniciando..."
|
STR_BOOTING: "Iniciando..."
|
||||||
STR_SLEEPING: "Suspendido"
|
STR_SLEEPING: "Suspendido"
|
||||||
STR_ENTERING_SLEEP: "Entrando en suspensión"
|
STR_ENTERING_SLEEP: "Entrando en suspensión"
|
||||||
STR_BROWSE_FILES: "Explorador de Archivos"
|
STR_BROWSE_FILES: "Explorador de archivos"
|
||||||
STR_FILE_TRANSFER: "Transferir archivos"
|
STR_FILE_TRANSFER: "Transferir archivos"
|
||||||
STR_SETTINGS_TITLE: "Ajustes"
|
STR_SETTINGS_TITLE: "Ajustes"
|
||||||
STR_CALIBRE_LIBRARY: "Biblioteca de Calibre"
|
STR_CALIBRE_LIBRARY: "Biblioteca de Calibre"
|
||||||
@@ -46,11 +46,11 @@ STR_PRESS_ANY_CONTINUE: "Pulse cualquier botón para continuar"
|
|||||||
STR_SELECT_HINT: "Izq./Der.: Seleccionar | OK: Confirmar"
|
STR_SELECT_HINT: "Izq./Der.: Seleccionar | OK: Confirmar"
|
||||||
STR_HOW_CONNECT: "¿Cómo desea conectarse?"
|
STR_HOW_CONNECT: "¿Cómo desea conectarse?"
|
||||||
STR_JOIN_NETWORK: "Unirse a una red"
|
STR_JOIN_NETWORK: "Unirse a una red"
|
||||||
STR_CREATE_HOTSPOT: "Crear Punto de Acceso"
|
STR_CREATE_HOTSPOT: "Crear punto de acceso"
|
||||||
STR_JOIN_DESC: "Conectarse a una red Wi-Fi existente"
|
STR_JOIN_DESC: "Conectarse a una red Wi-Fi existente"
|
||||||
STR_HOTSPOT_DESC: "Conectarse a este dispositivo"
|
STR_HOTSPOT_DESC: "Conectarse a este dispositivo"
|
||||||
STR_STARTING_HOTSPOT: "Iniciando Punto de Acceso..."
|
STR_STARTING_HOTSPOT: "Iniciando punto de acceso..."
|
||||||
STR_HOTSPOT_MODE: "Modo Punto de Acceso"
|
STR_HOTSPOT_MODE: "Modo punto de acceso"
|
||||||
STR_CONNECT_WIFI_HINT: "Conecte su dispositivo a esta red Wi-Fi"
|
STR_CONNECT_WIFI_HINT: "Conecte su dispositivo a esta red Wi-Fi"
|
||||||
STR_OPEN_URL_HINT: "Abra esta dirección en su navegador"
|
STR_OPEN_URL_HINT: "Abra esta dirección en su navegador"
|
||||||
STR_OR_HTTP_PREFIX: "o http://"
|
STR_OR_HTTP_PREFIX: "o http://"
|
||||||
@@ -65,22 +65,22 @@ STR_ENTER_WIFI_PASSWORD: "Introduzca la contraseña del Wi-Fi"
|
|||||||
STR_ENTER_TEXT: "Introduzca el texto"
|
STR_ENTER_TEXT: "Introduzca el texto"
|
||||||
STR_TO_PREFIX: "a "
|
STR_TO_PREFIX: "a "
|
||||||
STR_CALIBRE_DISCOVERING: "Buscando Calibre..."
|
STR_CALIBRE_DISCOVERING: "Buscando Calibre..."
|
||||||
STR_CALIBRE_CONNECTING_TO: "Conectándose a"
|
STR_CALIBRE_CONNECTING_TO: "Conectándose a "
|
||||||
STR_CALIBRE_CONNECTED_TO: "Conectado a "
|
STR_CALIBRE_CONNECTED_TO: "Conectado a "
|
||||||
STR_CALIBRE_WAITING_COMMANDS: "Esperando comandos..."
|
STR_CALIBRE_WAITING_COMMANDS: "Esperando comandos..."
|
||||||
STR_CONNECTION_FAILED_RETRYING: "(Error de conexión, reintentando...)"
|
STR_CONNECTION_FAILED_RETRYING: "(Error de conexión, reintentando...)"
|
||||||
STR_CALIBRE_DISCONNECTED: "Calibre desconectado"
|
STR_CALIBRE_DISCONNECTED: "Calibre desconectado"
|
||||||
STR_CALIBRE_WAITING_TRANSFER: "Esperando transferencia..."
|
STR_CALIBRE_WAITING_TRANSFER: "Esperando transferencia..."
|
||||||
STR_CALIBRE_TRANSFER_HINT: "Si la transferencia falla, active \\n'Ignorar espacio libre' en la configuración del \\nPlugin Smart Device de Calibre."
|
STR_CALIBRE_TRANSFER_HINT: "Si la transferencia falla, active\\n\"Ignorar espacio libre\" en la configuración del\\ncomplemento SmartDevice de Calibre."
|
||||||
STR_CALIBRE_RECEIVING: "Recibiendo: "
|
STR_CALIBRE_RECEIVING: "Recibiendo: "
|
||||||
STR_CALIBRE_RECEIVED: "Recibido: "
|
STR_CALIBRE_RECEIVED: "Recibido: "
|
||||||
STR_CALIBRE_WAITING_MORE: "Esperando más..."
|
STR_CALIBRE_WAITING_MORE: "Esperando más..."
|
||||||
STR_CALIBRE_FAILED_CREATE_FILE: "Error al crear el archivo"
|
STR_CALIBRE_FAILED_CREATE_FILE: "Error al crear el archivo"
|
||||||
STR_CALIBRE_PASSWORD_REQUIRED: "Contraseña requerida"
|
STR_CALIBRE_PASSWORD_REQUIRED: "Contraseña requerida"
|
||||||
STR_CALIBRE_TRANSFER_INTERRUPTED: "Transferencia interrumpida"
|
STR_CALIBRE_TRANSFER_INTERRUPTED: "Transferencia interrumpida"
|
||||||
STR_CALIBRE_INSTRUCTION_1: "1) Instale el Plugin CrossPoint Reader"
|
STR_CALIBRE_INSTRUCTION_1: "1) Instale el complemento CrossPoint Reader"
|
||||||
STR_CALIBRE_INSTRUCTION_2: "2) Conéctese a la misma red Wi-Fi"
|
STR_CALIBRE_INSTRUCTION_2: "2) Conéctese a la misma red Wi-Fi"
|
||||||
STR_CALIBRE_INSTRUCTION_3: "3) Desde Calibre seleccione: \"Enviar a dispositivo\""
|
STR_CALIBRE_INSTRUCTION_3: "3) Desde Calibre, seleccione \"Enviar a dispositivo\""
|
||||||
STR_CALIBRE_INSTRUCTION_4: "\"Permanezca en esta pantalla mientras se envía\""
|
STR_CALIBRE_INSTRUCTION_4: "\"Permanezca en esta pantalla mientras se envía\""
|
||||||
STR_CAT_DISPLAY: "Pantalla"
|
STR_CAT_DISPLAY: "Pantalla"
|
||||||
STR_CAT_READER: "Lector"
|
STR_CAT_READER: "Lector"
|
||||||
@@ -92,15 +92,15 @@ STR_STATUS_BAR: "Barra de estado"
|
|||||||
STR_HIDE_BATTERY: "Ocultar % de batería"
|
STR_HIDE_BATTERY: "Ocultar % de batería"
|
||||||
STR_EXTRA_SPACING: "Espaciado entre párrafos"
|
STR_EXTRA_SPACING: "Espaciado entre párrafos"
|
||||||
STR_TEXT_AA: "Suavizado de texto"
|
STR_TEXT_AA: "Suavizado de texto"
|
||||||
STR_SHORT_PWR_BTN: "Función especial botón Power"
|
STR_SHORT_PWR_BTN: "Toque corto botón encendido"
|
||||||
STR_ORIENTATION: "Orientación"
|
STR_ORIENTATION: "Orientación"
|
||||||
STR_FRONT_BTN_LAYOUT: "Diseño de los botones frontales"
|
STR_FRONT_BTN_LAYOUT: "Diseño de los botones frontales"
|
||||||
STR_SIDE_BTN_LAYOUT: "Función botones laterales (Lector)"
|
STR_SIDE_BTN_LAYOUT: "Función botones laterales (lector)"
|
||||||
STR_LONG_PRESS_SKIP: "Saltar capítulo (pulsación larga)"
|
STR_LONG_PRESS_SKIP: "Saltar capítulo (pulsación larga)"
|
||||||
STR_FONT_FAMILY: "Tipografía"
|
STR_FONT_FAMILY: "Tipografía"
|
||||||
STR_EXT_READER_FONT: "Tipografía externa"
|
STR_EXT_READER_FONT: "Tipografía externa"
|
||||||
STR_EXT_CHINESE_FONT: "Tipografía"
|
STR_EXT_CHINESE_FONT: "Tipografía"
|
||||||
STR_EXT_UI_FONT: "Tipografía (Pantalla)"
|
STR_EXT_UI_FONT: "Tipografía (interfaz)"
|
||||||
STR_FONT_SIZE: "Tamaño"
|
STR_FONT_SIZE: "Tamaño"
|
||||||
STR_LINE_SPACING: "Interlineado"
|
STR_LINE_SPACING: "Interlineado"
|
||||||
STR_ASCII_LETTER_SPACING: "Espaciado entre letras ASCII"
|
STR_ASCII_LETTER_SPACING: "Espaciado entre letras ASCII"
|
||||||
@@ -126,7 +126,7 @@ STR_DOCUMENT_MATCHING: "Coincidencia de doc."
|
|||||||
STR_AUTHENTICATE: "Autenticar"
|
STR_AUTHENTICATE: "Autenticar"
|
||||||
STR_KOREADER_USERNAME: "Usuario de KOReader"
|
STR_KOREADER_USERNAME: "Usuario de KOReader"
|
||||||
STR_KOREADER_PASSWORD: "Contraseña de KOReader"
|
STR_KOREADER_PASSWORD: "Contraseña de KOReader"
|
||||||
STR_FILENAME: "Nombre del archivo"
|
STR_FILENAME: "Nombre de archivo"
|
||||||
STR_BINARY: "Binario"
|
STR_BINARY: "Binario"
|
||||||
STR_SET_CREDENTIALS_FIRST: "Configurar credenciales"
|
STR_SET_CREDENTIALS_FIRST: "Configurar credenciales"
|
||||||
STR_WIFI_CONN_FAILED: "Fallo de conexión Wi-Fi"
|
STR_WIFI_CONN_FAILED: "Fallo de conexión Wi-Fi"
|
||||||
@@ -142,8 +142,8 @@ STR_CLEAR_CACHE_WARNING_3: "Los libros deberán ser reindexados"
|
|||||||
STR_CLEAR_CACHE_WARNING_4: "cuando se vuelvan a abrir."
|
STR_CLEAR_CACHE_WARNING_4: "cuando se vuelvan a abrir."
|
||||||
STR_CLEARING_CACHE: "Borrando caché..."
|
STR_CLEARING_CACHE: "Borrando caché..."
|
||||||
STR_CACHE_CLEARED: "Caché borrada"
|
STR_CACHE_CLEARED: "Caché borrada"
|
||||||
STR_ITEMS_REMOVED: "Elementos eliminados"
|
STR_ITEMS_REMOVED: "elementos eliminados"
|
||||||
STR_FAILED_LOWER: "Error"
|
STR_FAILED_LOWER: "falló"
|
||||||
STR_CLEAR_CACHE_FAILED: "No se pudo borrar la caché"
|
STR_CLEAR_CACHE_FAILED: "No se pudo borrar la caché"
|
||||||
STR_CHECK_SERIAL_OUTPUT: "Consulte los registros del puerto serie"
|
STR_CHECK_SERIAL_OUTPUT: "Consulte los registros del puerto serie"
|
||||||
STR_DARK: "Oscuro"
|
STR_DARK: "Oscuro"
|
||||||
@@ -184,16 +184,16 @@ STR_JUSTIFY: "Justificado"
|
|||||||
STR_ALIGN_LEFT: "Izquierda"
|
STR_ALIGN_LEFT: "Izquierda"
|
||||||
STR_CENTER: "Centro"
|
STR_CENTER: "Centro"
|
||||||
STR_ALIGN_RIGHT: "Derecha"
|
STR_ALIGN_RIGHT: "Derecha"
|
||||||
STR_MIN_1: "1 Minuto"
|
STR_MIN_1: "1 min."
|
||||||
STR_MIN_5: "5 Minutos"
|
STR_MIN_5: "5 min."
|
||||||
STR_MIN_10: "10 Minutos"
|
STR_MIN_10: "10 min."
|
||||||
STR_MIN_15: "15 Minutos"
|
STR_MIN_15: "15 min."
|
||||||
STR_MIN_30: "30 Minutos"
|
STR_MIN_30: "30 min."
|
||||||
STR_PAGES_1: "1 Página"
|
STR_PAGES_1: "1 pág."
|
||||||
STR_PAGES_5: "5 Páginas"
|
STR_PAGES_5: "5 pág."
|
||||||
STR_PAGES_10: "10 Páginas"
|
STR_PAGES_10: "10 pág."
|
||||||
STR_PAGES_15: "15 Páginas"
|
STR_PAGES_15: "15 pág."
|
||||||
STR_PAGES_30: "30 Páginas"
|
STR_PAGES_30: "30 pág."
|
||||||
STR_UPDATE: "Actualizar"
|
STR_UPDATE: "Actualizar"
|
||||||
STR_CHECKING_UPDATE: "Verificando actualización..."
|
STR_CHECKING_UPDATE: "Verificando actualización..."
|
||||||
STR_NEW_UPDATE: "¡Nueva actualización disponible!"
|
STR_NEW_UPDATE: "¡Nueva actualización disponible!"
|
||||||
@@ -203,20 +203,20 @@ STR_UPDATING: "Actualizando..."
|
|||||||
STR_NO_UPDATE: "No hay actualizaciones disponibles"
|
STR_NO_UPDATE: "No hay actualizaciones disponibles"
|
||||||
STR_UPDATE_FAILED: "Fallo de actualización"
|
STR_UPDATE_FAILED: "Fallo de actualización"
|
||||||
STR_UPDATE_COMPLETE: "Actualización completada"
|
STR_UPDATE_COMPLETE: "Actualización completada"
|
||||||
STR_POWER_ON_HINT: "Pulse y mantenga presionado el botón de encendido para volver a encender"
|
STR_POWER_ON_HINT: "Reinicie manteniendo pulsado botón de encendido"
|
||||||
STR_EXTERNAL_FONT: "Fuente externa"
|
STR_EXTERNAL_FONT: "Fuente externa"
|
||||||
STR_BUILTIN_DISABLED: "Incorporado (Desactivado)"
|
STR_BUILTIN_DISABLED: "Incorporado (desactivado)"
|
||||||
STR_NO_ENTRIES: "No se encontraron elementos"
|
STR_NO_ENTRIES: "No se encontraron elementos"
|
||||||
STR_DOWNLOADING: "Descargando..."
|
STR_DOWNLOADING: "Descargando..."
|
||||||
STR_DOWNLOAD_FAILED: "Fallo de descarga"
|
STR_DOWNLOAD_FAILED: "Fallo de descarga"
|
||||||
STR_ERROR_MSG: "Error"
|
STR_ERROR_MSG: "Error:"
|
||||||
STR_UNNAMED: "Sin nombre"
|
STR_UNNAMED: "Sin nombre"
|
||||||
STR_NO_SERVER_URL: "No se ha configurado la URL del servidor"
|
STR_NO_SERVER_URL: "No se configuró URL de servidor"
|
||||||
STR_FETCH_FEED_FAILED: "Fallo al obtener el feed"
|
STR_FETCH_FEED_FAILED: "Fallo al obtener el feed"
|
||||||
STR_PARSE_FEED_FAILED: "Fallo al procesar el feed"
|
STR_PARSE_FEED_FAILED: "Fallo al procesar el feed"
|
||||||
STR_NETWORK_PREFIX: "Red: "
|
STR_NETWORK_PREFIX: "Red: "
|
||||||
STR_IP_ADDRESS_PREFIX: "IP: "
|
STR_IP_ADDRESS_PREFIX: "IP: "
|
||||||
STR_SCAN_QR_WIFI_HINT: "O escanee el código QR con su teléfono para conectarse a Wi-Fi."
|
STR_SCAN_QR_WIFI_HINT: "o lea el QR con su tfno. para conectarse al Wi-Fi."
|
||||||
STR_ERROR_GENERAL_FAILURE: "Error: Fallo general"
|
STR_ERROR_GENERAL_FAILURE: "Error: Fallo general"
|
||||||
STR_ERROR_NETWORK_NOT_FOUND: "Error: Red no encontrada"
|
STR_ERROR_NETWORK_NOT_FOUND: "Error: Red no encontrada"
|
||||||
STR_ERROR_CONNECTION_TIMEOUT: "Error: Tiempo de conexión agotado"
|
STR_ERROR_CONNECTION_TIMEOUT: "Error: Tiempo de conexión agotado"
|
||||||
@@ -225,7 +225,8 @@ STR_BACK: "« Atrás"
|
|||||||
STR_EXIT: "« Salir"
|
STR_EXIT: "« Salir"
|
||||||
STR_HOME: "« Inicio"
|
STR_HOME: "« Inicio"
|
||||||
STR_SAVE: "« Guardar"
|
STR_SAVE: "« Guardar"
|
||||||
STR_SELECT: "Elegir"
|
STR_SELECT: "Selec."
|
||||||
|
STR_SELECTED: "Seleccionado"
|
||||||
STR_TOGGLE: "Cambiar"
|
STR_TOGGLE: "Cambiar"
|
||||||
STR_CONFIRM: "Confirmar"
|
STR_CONFIRM: "Confirmar"
|
||||||
STR_CANCEL: "Cancelar"
|
STR_CANCEL: "Cancelar"
|
||||||
@@ -235,6 +236,8 @@ STR_DOWNLOAD: "Descargar"
|
|||||||
STR_RETRY: "Reintentar"
|
STR_RETRY: "Reintentar"
|
||||||
STR_YES: "Sí"
|
STR_YES: "Sí"
|
||||||
STR_NO: "No"
|
STR_NO: "No"
|
||||||
|
STR_SHOW: "Mostrar"
|
||||||
|
STR_HIDE: "Ocultar"
|
||||||
STR_STATE_ON: "Activado"
|
STR_STATE_ON: "Activado"
|
||||||
STR_STATE_OFF: "Desactivado"
|
STR_STATE_OFF: "Desactivado"
|
||||||
STR_NOT_SET: "No configurado"
|
STR_NOT_SET: "No configurado"
|
||||||
@@ -247,6 +250,21 @@ STR_CAPS_OFF: "minúsculas"
|
|||||||
STR_OK_BUTTON: "OK"
|
STR_OK_BUTTON: "OK"
|
||||||
STR_SLEEP_COVER_FILTER: "Filtro de pantalla de suspensión"
|
STR_SLEEP_COVER_FILTER: "Filtro de pantalla de suspensión"
|
||||||
STR_FILTER_CONTRAST: "Contraste"
|
STR_FILTER_CONTRAST: "Contraste"
|
||||||
|
STR_CUSTOMISE_STATUS_BAR: "Personalizar barra de estado"
|
||||||
|
STR_CHAPTER_PAGE_COUNT: "Contador pág. cap."
|
||||||
|
STR_BOOK_PROGRESS_PERCENTAGE: "Porcentaje progreso libro"
|
||||||
|
STR_PROGRESS_BAR: "Barra de progreso"
|
||||||
|
STR_PROGRESS_BAR_THICKNESS: "Grosor de barra de progreso"
|
||||||
|
STR_PROGRESS_BAR_THIN: "Fino"
|
||||||
|
STR_PROGRESS_BAR_MEDIUM: "Medio"
|
||||||
|
STR_PROGRESS_BAR_THICK: "Ancho"
|
||||||
|
STR_BOOK: "Libro"
|
||||||
|
STR_CHAPTER: "Capítulo"
|
||||||
|
STR_EXAMPLE_CHAPTER: "Capítulo 21"
|
||||||
|
STR_EXAMPLE_BOOK: "Título del libro"
|
||||||
|
STR_PREVIEW: "Previsualización"
|
||||||
|
STR_TITLE: "Título"
|
||||||
|
STR_BATTERY: "Batería"
|
||||||
STR_UI_THEME: "Interfaz"
|
STR_UI_THEME: "Interfaz"
|
||||||
STR_THEME_CLASSIC: "Clásico"
|
STR_THEME_CLASSIC: "Clásico"
|
||||||
STR_THEME_LYRA: "Lyra"
|
STR_THEME_LYRA: "Lyra"
|
||||||
@@ -269,37 +287,38 @@ STR_DEFAULT_VALUE: "Predeterminado"
|
|||||||
STR_REMAP_PROMPT: "Pulse un botón frontal para cada función"
|
STR_REMAP_PROMPT: "Pulse un botón frontal para cada función"
|
||||||
STR_UNASSIGNED: "Sin asignar"
|
STR_UNASSIGNED: "Sin asignar"
|
||||||
STR_ALREADY_ASSIGNED: "Ya asignado"
|
STR_ALREADY_ASSIGNED: "Ya asignado"
|
||||||
STR_REMAP_RESET_HINT: "Botón lateral arriba: Restablecer configuración"
|
STR_REMAP_RESET_HINT: "Botón lateral arriba: restablecer configuración"
|
||||||
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: Anular reconfiguración"
|
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: anular reconfiguración"
|
||||||
STR_HW_BACK_LABEL: "Atrás (Primer botón)"
|
STR_HW_BACK_LABEL: "Atrás (primer botón)"
|
||||||
STR_HW_CONFIRM_LABEL: "Confirmar (Segundo botón)"
|
STR_HW_CONFIRM_LABEL: "Confirmar (segundo botón)"
|
||||||
STR_HW_LEFT_LABEL: "Izq. (Tercer botón)"
|
STR_HW_LEFT_LABEL: "Izq. (tercer botón)"
|
||||||
STR_HW_RIGHT_LABEL: "Der. (Cuarto botón)"
|
STR_HW_RIGHT_LABEL: "Der. (cuarto botón)"
|
||||||
STR_GO_TO_PERCENT: "Ir a %"
|
STR_GO_TO_PERCENT: "Ir a %"
|
||||||
STR_GO_HOME_BUTTON: "Volver a inicio"
|
STR_GO_HOME_BUTTON: "Volver al menú Inicio"
|
||||||
STR_DELETE: "Borrar"
|
|
||||||
STR_SYNC_PROGRESS: "Sincronizar progreso de lectura"
|
STR_SYNC_PROGRESS: "Sincronizar progreso de lectura"
|
||||||
STR_DELETE_CACHE: "Borrar caché del libro"
|
STR_DELETE_CACHE: "Borrar caché del libro"
|
||||||
STR_CHAPTER_PREFIX: "Cap.:"
|
STR_DELETE: "Borrar"
|
||||||
STR_PAGES_SEPARATOR: " Páginas |"
|
STR_DISPLAY_QR: "Mostrar página como QR"
|
||||||
STR_BOOK_PREFIX: "Libro:"
|
STR_CHAPTER_PREFIX: "Cap.: "
|
||||||
STR_KBD_SHIFT: "shift"
|
STR_PAGES_SEPARATOR: " Págs. | "
|
||||||
STR_KBD_SHIFT_CAPS: "SHIFT"
|
STR_BOOK_PREFIX: "Libro: "
|
||||||
|
STR_KBD_SHIFT: "minús."
|
||||||
|
STR_KBD_SHIFT_CAPS: "MAYÚS."
|
||||||
STR_KBD_LOCK: "BLOQUEAR"
|
STR_KBD_LOCK: "BLOQUEAR"
|
||||||
STR_CALIBRE_URL_HINT: "Para Calibre, agregue /opds a su URL"
|
STR_CALIBRE_URL_HINT: "Para Calibre, agregue /opds a su URL"
|
||||||
STR_PERCENT_STEP_HINT: "Izq./Der.: 1% | Subir/Bajar: 10%"
|
STR_PERCENT_STEP_HINT: "Izq./Der.: 1% | Subir/Bajar: 10%"
|
||||||
STR_SYNCING_TIME: "Tiempo de sincronización..."
|
STR_SYNCING_TIME: "Tiempo de sincronización..."
|
||||||
STR_CALC_HASH: "Calculando HASH del documento..."
|
STR_CALC_HASH: "Calculando hash del documento..."
|
||||||
STR_HASH_FAILED: "No se pudo calcular el HASH del documento"
|
STR_HASH_FAILED: "No se pudo calcular el hash del documento"
|
||||||
STR_FETCH_PROGRESS: "Recuperando progreso remoto..."
|
STR_FETCH_PROGRESS: "Recuperando progreso remoto..."
|
||||||
STR_UPLOAD_PROGRESS: "Subiendo progreso..."
|
STR_UPLOAD_PROGRESS: "Subiendo progreso..."
|
||||||
STR_NO_CREDENTIALS_MSG: "No se han configurado credenciales"
|
STR_NO_CREDENTIALS_MSG: "No se han configurado credenciales"
|
||||||
STR_KOREADER_SETUP_HINT: "Configure una cuenta de KOReader en la configuración"
|
STR_KOREADER_SETUP_HINT: "Configure una cuenta de KOReader en la configuración"
|
||||||
STR_PROGRESS_FOUND: "¡Progreso encontrado!"
|
STR_PROGRESS_FOUND: "¡Progreso encontrado!"
|
||||||
STR_REMOTE_LABEL: "Remoto"
|
STR_REMOTE_LABEL: "Remoto:"
|
||||||
STR_LOCAL_LABEL: "Local"
|
STR_LOCAL_LABEL: "Local:"
|
||||||
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% Completada"
|
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% completado"
|
||||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% Completada"
|
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% completado"
|
||||||
STR_DEVICE_FROM_FORMAT: " De: %s"
|
STR_DEVICE_FROM_FORMAT: " De: %s"
|
||||||
STR_APPLY_REMOTE: "Aplicar progreso remoto"
|
STR_APPLY_REMOTE: "Aplicar progreso remoto"
|
||||||
STR_UPLOAD_LOCAL: "Subir progreso local"
|
STR_UPLOAD_LOCAL: "Subir progreso local"
|
||||||
@@ -312,4 +331,9 @@ STR_UPLOAD: "Subir"
|
|||||||
STR_BOOK_S_STYLE: "Estilo del libro"
|
STR_BOOK_S_STYLE: "Estilo del libro"
|
||||||
STR_EMBEDDED_STYLE: "Estilo integrado"
|
STR_EMBEDDED_STYLE: "Estilo integrado"
|
||||||
STR_OPDS_SERVER_URL: "URL del servidor OPDS"
|
STR_OPDS_SERVER_URL: "URL del servidor OPDS"
|
||||||
|
STR_FOOTNOTES: "Pie de página"
|
||||||
|
STR_NO_FOOTNOTES: "No hay notas al pie de esta página"
|
||||||
|
STR_LINK: "[enlace]"
|
||||||
STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla"
|
STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla"
|
||||||
|
STR_AUTO_TURN_ENABLED: "Paso pág. automático: "
|
||||||
|
STR_AUTO_TURN_PAGES_PER_MIN: "Páginas por minuto"
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ STR_GO_TO_PERCENT: "Перейти до %"
|
|||||||
STR_GO_HOME_BUTTON: "На головну"
|
STR_GO_HOME_BUTTON: "На головну"
|
||||||
STR_SYNC_PROGRESS: "Прогрес синхронізації"
|
STR_SYNC_PROGRESS: "Прогрес синхронізації"
|
||||||
STR_DELETE_CACHE: "Видалити кеш книги"
|
STR_DELETE_CACHE: "Видалити кеш книги"
|
||||||
|
STR_DELETE: "Видалити"
|
||||||
STR_DISPLAY_QR: "Показати сторінку як QR-код"
|
STR_DISPLAY_QR: "Показати сторінку як QR-код"
|
||||||
STR_CHAPTER_PREFIX: "Розділ: "
|
STR_CHAPTER_PREFIX: "Розділ: "
|
||||||
STR_PAGES_SEPARATOR: " сторінок | "
|
STR_PAGES_SEPARATOR: " сторінок | "
|
||||||
@@ -334,3 +335,5 @@ STR_FOOTNOTES: "Зноски"
|
|||||||
STR_NO_FOOTNOTES: "На цій сторінці немає зносок"
|
STR_NO_FOOTNOTES: "На цій сторінці немає зносок"
|
||||||
STR_LINK: "[посилання]"
|
STR_LINK: "[посилання]"
|
||||||
STR_SCREENSHOT_BUTTON: "Знімок екрана"
|
STR_SCREENSHOT_BUTTON: "Знімок екрана"
|
||||||
|
STR_AUTO_TURN_ENABLED: "Автоперегортання увімк: "
|
||||||
|
STR_AUTO_TURN_PAGES_PER_MIN: "Автоперегортання (ст/хв)"
|
||||||
@@ -24,6 +24,7 @@ build_flags =
|
|||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
|
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
|
||||||
-DDISABLE_FS_H_WARNING=1
|
-DDISABLE_FS_H_WARNING=1
|
||||||
|
-DDESTRUCTOR_CLOSES_FILE=1
|
||||||
# https://libexpat.github.io/doc/api/latest/#XML_GE
|
# https://libexpat.github.io/doc/api/latest/#XML_GE
|
||||||
-DXML_GE=0
|
-DXML_GE=0
|
||||||
-DXML_CONTEXT_BYTES=1024
|
-DXML_CONTEXT_BYTES=1024
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ class CrossPointSettings {
|
|||||||
// UI Theme
|
// UI Theme
|
||||||
enum UI_THEME { CLASSIC = 0, LYRA = 1, LYRA_3_COVERS = 2 };
|
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
|
// Sleep screen settings
|
||||||
uint8_t sleepScreen = DARK;
|
uint8_t sleepScreen = DARK;
|
||||||
// Sleep screen cover mode settings
|
// Sleep screen cover mode settings
|
||||||
@@ -193,6 +196,10 @@ class CrossPointSettings {
|
|||||||
uint8_t fadingFix = 0;
|
uint8_t fadingFix = 0;
|
||||||
// Use book's embedded CSS styles for EPUB rendering (1 = enabled, 0 = disabled)
|
// Use book's embedded CSS styles for EPUB rendering (1 = enabled, 0 = disabled)
|
||||||
uint8_t embeddedStyle = 1;
|
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;
|
~CrossPointSettings() = default;
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ inline const std::vector<SettingInfo>& getSettingsList() {
|
|||||||
StrId::STR_CAT_READER),
|
StrId::STR_CAT_READER),
|
||||||
SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing",
|
SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing",
|
||||||
StrId::STR_CAT_READER),
|
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 ---
|
// --- Controls ---
|
||||||
SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout,
|
SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout,
|
||||||
{StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS),
|
{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/BootActivity.h"
|
||||||
#include "boot_sleep/SleepActivity.h"
|
#include "boot_sleep/SleepActivity.h"
|
||||||
#include "browser/OpdsBookBrowserActivity.h"
|
#include "browser/OpdsBookBrowserActivity.h"
|
||||||
|
#include "home/FileBrowserActivity.h"
|
||||||
#include "home/HomeActivity.h"
|
#include "home/HomeActivity.h"
|
||||||
#include "home/MyLibraryActivity.h"
|
|
||||||
#include "home/RecentBooksActivity.h"
|
#include "home/RecentBooksActivity.h"
|
||||||
#include "network/CrossPointWebServerActivity.h"
|
#include "network/CrossPointWebServerActivity.h"
|
||||||
#include "reader/ReaderActivity.h"
|
#include "reader/ReaderActivity.h"
|
||||||
@@ -169,8 +169,8 @@ void ActivityManager::goToFileTransfer() {
|
|||||||
|
|
||||||
void ActivityManager::goToSettings() { replaceActivity(std::make_unique<SettingsActivity>(renderer, mappedInput)); }
|
void ActivityManager::goToSettings() { replaceActivity(std::make_unique<SettingsActivity>(renderer, mappedInput)); }
|
||||||
|
|
||||||
void ActivityManager::goToMyLibrary(std::string path) {
|
void ActivityManager::goToFileBrowser(std::string path) {
|
||||||
replaceActivity(std::make_unique<MyLibraryActivity>(renderer, mappedInput, std::move(path)));
|
replaceActivity(std::make_unique<FileBrowserActivity>(renderer, mappedInput, std::move(path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityManager::goToRecentBooks() {
|
void ActivityManager::goToRecentBooks() {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class ActivityManager {
|
|||||||
// goTo... functions are convenient wrapper for replaceActivity()
|
// goTo... functions are convenient wrapper for replaceActivity()
|
||||||
void goToFileTransfer();
|
void goToFileTransfer();
|
||||||
void goToSettings();
|
void goToSettings();
|
||||||
void goToMyLibrary(std::string path = {});
|
void goToFileBrowser(std::string path = {});
|
||||||
void goToRecentBooks();
|
void goToRecentBooks();
|
||||||
void goToBrowser();
|
void goToBrowser();
|
||||||
void goToReader(std::string path);
|
void goToReader(std::string path);
|
||||||
|
|||||||
@@ -182,9 +182,20 @@ void SleepActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SleepActivity::renderCustomSleepScreen() const {
|
void SleepActivity::renderCustomSleepScreen() const {
|
||||||
// Check if we have a /sleep directory
|
// Check if we have a /.sleep (preferred) or /sleep directory
|
||||||
auto dir = Storage.open("/sleep");
|
const char* sleepDir = nullptr;
|
||||||
|
auto dir = Storage.open("/.sleep");
|
||||||
if (dir && dir.isDirectory()) {
|
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;
|
std::vector<std::string> files;
|
||||||
char name[500];
|
char name[500];
|
||||||
// collect all valid BMP files
|
// collect all valid BMP files
|
||||||
@@ -224,10 +235,10 @@ void SleepActivity::renderCustomSleepScreen() const {
|
|||||||
}
|
}
|
||||||
APP_STATE.lastSleepImage = randomFileIndex;
|
APP_STATE.lastSleepImage = randomFileIndex;
|
||||||
APP_STATE.saveToFile();
|
APP_STATE.saveToFile();
|
||||||
const auto filename = "/sleep/" + files[randomFileIndex];
|
const auto filename = std::string(sleepDir) + "/" + files[randomFileIndex];
|
||||||
FsFile file;
|
FsFile file;
|
||||||
if (Storage.openFileForRead("SLP", filename, 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);
|
delay(100);
|
||||||
Bitmap bitmap(file, true);
|
Bitmap bitmap(file, true);
|
||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
|
|||||||
+13
-13
@@ -1,4 +1,4 @@
|
|||||||
#include "MyLibraryActivity.h"
|
#include "FileBrowserActivity.h"
|
||||||
|
|
||||||
#include <Epub.h>
|
#include <Epub.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
@@ -69,7 +69,7 @@ void sortFileList(std::vector<std::string>& strs) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyLibraryActivity::loadFiles() {
|
void FileBrowserActivity::loadFiles() {
|
||||||
files.clear();
|
files.clear();
|
||||||
|
|
||||||
auto root = Storage.open(basepath.c_str());
|
auto root = Storage.open(basepath.c_str());
|
||||||
@@ -104,7 +104,7 @@ void MyLibraryActivity::loadFiles() {
|
|||||||
sortFileList(files);
|
sortFileList(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyLibraryActivity::onEnter() {
|
void FileBrowserActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
|
|
||||||
loadFiles();
|
loadFiles();
|
||||||
@@ -113,20 +113,20 @@ void MyLibraryActivity::onEnter() {
|
|||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyLibraryActivity::onExit() {
|
void FileBrowserActivity::onExit() {
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
files.clear();
|
files.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyLibraryActivity::clearFileMetadata(const std::string& fullPath) {
|
void FileBrowserActivity::clearFileMetadata(const std::string& fullPath) {
|
||||||
// Only clear cache for .epub files
|
// Only clear cache for .epub files
|
||||||
if (StringUtils::checkFileExtension(fullPath, ".epub")) {
|
if (StringUtils::checkFileExtension(fullPath, ".epub")) {
|
||||||
Epub(fullPath, "/.crosspoint").clearCache();
|
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
|
// Long press BACK (1s+) goes to root folder
|
||||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= GO_HOME_MS &&
|
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= GO_HOME_MS &&
|
||||||
basepath != "/") {
|
basepath != "/") {
|
||||||
@@ -152,10 +152,10 @@ void MyLibraryActivity::loop() {
|
|||||||
|
|
||||||
auto handler = [this, fullPath](const ActivityResult& res) {
|
auto handler = [this, fullPath](const ActivityResult& res) {
|
||||||
if (!res.isCancelled) {
|
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);
|
clearFileMetadata(fullPath);
|
||||||
if (Storage.remove(fullPath.c_str())) {
|
if (Storage.remove(fullPath.c_str())) {
|
||||||
LOG_DBG("MyLibrary", "Deleted successfully");
|
LOG_DBG("FileBrowser", "Deleted successfully");
|
||||||
loadFiles();
|
loadFiles();
|
||||||
if (files.empty()) {
|
if (files.empty()) {
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
@@ -166,10 +166,10 @@ void MyLibraryActivity::loop() {
|
|||||||
|
|
||||||
requestUpdate(true);
|
requestUpdate(true);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERR("MyLibrary", "Failed to delete file: %s", fullPath.c_str());
|
LOG_ERR("FileBrowser", "Failed to delete file: %s", fullPath.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
return filename.substr(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyLibraryActivity::render(RenderLock&&) {
|
void FileBrowserActivity::render(RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
@@ -274,7 +274,7 @@ void MyLibraryActivity::render(RenderLock&&) {
|
|||||||
renderer.displayBuffer();
|
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++)
|
for (size_t i = 0; i < files.size(); i++)
|
||||||
if (files[i] == name) return i;
|
if (files[i] == name) return i;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "RecentBooksStore.h"
|
#include "RecentBooksStore.h"
|
||||||
#include "util/ButtonNavigator.h"
|
#include "util/ButtonNavigator.h"
|
||||||
|
|
||||||
class MyLibraryActivity final : public Activity {
|
class FileBrowserActivity final : public Activity {
|
||||||
private:
|
private:
|
||||||
// Deletion
|
// Deletion
|
||||||
void clearFileMetadata(const std::string& fullPath);
|
void clearFileMetadata(const std::string& fullPath);
|
||||||
@@ -26,8 +26,8 @@ class MyLibraryActivity final : public Activity {
|
|||||||
size_t findEntry(const std::string& name) const;
|
size_t findEntry(const std::string& name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MyLibraryActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialPath = "/")
|
explicit FileBrowserActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialPath = "/")
|
||||||
: Activity("MyLibrary", renderer, mappedInput), basepath(initialPath.empty() ? "/" : std::move(initialPath)) {}
|
: Activity("FileBrowser", renderer, mappedInput), basepath(initialPath.empty() ? "/" : std::move(initialPath)) {}
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "util/StringUtils.h"
|
#include "util/StringUtils.h"
|
||||||
|
|
||||||
int HomeActivity::getMenuItemCount() const {
|
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()) {
|
if (!recentBooks.empty()) {
|
||||||
count += recentBooks.size();
|
count += recentBooks.size();
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ void HomeActivity::loop() {
|
|||||||
// Calculate dynamic indices based on which options are available
|
// Calculate dynamic indices based on which options are available
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
int menuSelectedIndex = selectorIndex - static_cast<int>(recentBooks.size());
|
int menuSelectedIndex = selectorIndex - static_cast<int>(recentBooks.size());
|
||||||
const int myLibraryIdx = idx++;
|
const int fileBrowserIdx = idx++;
|
||||||
const int recentsIdx = idx++;
|
const int recentsIdx = idx++;
|
||||||
const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1;
|
const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1;
|
||||||
const int fileTransferIdx = idx++;
|
const int fileTransferIdx = idx++;
|
||||||
@@ -197,8 +197,8 @@ void HomeActivity::loop() {
|
|||||||
|
|
||||||
if (selectorIndex < recentBooks.size()) {
|
if (selectorIndex < recentBooks.size()) {
|
||||||
onSelectBook(recentBooks[selectorIndex].path);
|
onSelectBook(recentBooks[selectorIndex].path);
|
||||||
} else if (menuSelectedIndex == myLibraryIdx) {
|
} else if (menuSelectedIndex == fileBrowserIdx) {
|
||||||
onMyLibraryOpen();
|
onFileBrowserOpen();
|
||||||
} else if (menuSelectedIndex == recentsIdx) {
|
} else if (menuSelectedIndex == recentsIdx) {
|
||||||
onRecentsOpen();
|
onRecentsOpen();
|
||||||
} else if (menuSelectedIndex == opdsLibraryIdx) {
|
} else if (menuSelectedIndex == opdsLibraryIdx) {
|
||||||
@@ -231,7 +231,7 @@ void HomeActivity::render(RenderLock&&) {
|
|||||||
std::vector<UIIcon> menuIcons = {Folder, Recent, Transfer, Settings};
|
std::vector<UIIcon> menuIcons = {Folder, Recent, Transfer, Settings};
|
||||||
|
|
||||||
if (hasOpdsUrl) {
|
if (hasOpdsUrl) {
|
||||||
// Insert OPDS Browser after My Library
|
// Insert OPDS Browser after File Browser
|
||||||
menuItems.insert(menuItems.begin() + 2, tr(STR_OPDS_BROWSER));
|
menuItems.insert(menuItems.begin() + 2, tr(STR_OPDS_BROWSER));
|
||||||
menuIcons.insert(menuIcons.begin() + 2, Library);
|
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::onSelectBook(const std::string& path) { activityManager.goToReader(path); }
|
||||||
|
|
||||||
void HomeActivity::onMyLibraryOpen() { activityManager.goToMyLibrary(); }
|
void HomeActivity::onFileBrowserOpen() { activityManager.goToFileBrowser(); }
|
||||||
|
|
||||||
void HomeActivity::onRecentsOpen() { activityManager.goToRecentBooks(); }
|
void HomeActivity::onRecentsOpen() { activityManager.goToRecentBooks(); }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../Activity.h"
|
#include "../Activity.h"
|
||||||
#include "./MyLibraryActivity.h"
|
#include "./FileBrowserActivity.h"
|
||||||
#include "util/ButtonNavigator.h"
|
#include "util/ButtonNavigator.h"
|
||||||
|
|
||||||
struct RecentBook;
|
struct RecentBook;
|
||||||
@@ -21,7 +21,7 @@ class HomeActivity final : public Activity {
|
|||||||
uint8_t* coverBuffer = nullptr; // HomeActivity's own buffer for cover image
|
uint8_t* coverBuffer = nullptr; // HomeActivity's own buffer for cover image
|
||||||
std::vector<RecentBook> recentBooks;
|
std::vector<RecentBook> recentBooks;
|
||||||
void onSelectBook(const std::string& path);
|
void onSelectBook(const std::string& path);
|
||||||
void onMyLibraryOpen();
|
void onFileBrowserOpen();
|
||||||
void onRecentsOpen();
|
void onRecentsOpen();
|
||||||
void onSettingsOpen();
|
void onSettingsOpen();
|
||||||
void onFileTransferOpen();
|
void onFileTransferOpen();
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ void EpubReaderActivity::loop() {
|
|||||||
|
|
||||||
// Long press BACK (1s+) goes to file selection
|
// Long press BACK (1s+) goes to file selection
|
||||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||||
activityManager.goToMyLibrary(epub ? epub->getPath() : "");
|
activityManager.goToFileBrowser(epub ? epub->getPath() : "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,14 +573,16 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
|
|
||||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) {
|
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||||
|
SETTINGS.imageRendering)) {
|
||||||
LOG_DBG("ERS", "Cache not found, building...");
|
LOG_DBG("ERS", "Cache not found, building...");
|
||||||
|
|
||||||
const auto popupFn = [this]() { GUI.drawPopup(renderer, tr(STR_INDEXING)); };
|
const auto popupFn = [this]() { GUI.drawPopup(renderer, tr(STR_INDEXING)); };
|
||||||
|
|
||||||
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
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");
|
LOG_ERR("ERS", "Failed to persist page data to SD");
|
||||||
section.reset();
|
section.reset();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -204,25 +204,7 @@ void KOReaderSyncActivity::onEnter() {
|
|||||||
// Check if already connected (e.g. from settings page auth)
|
// Check if already connected (e.g. from settings page auth)
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
LOG_DBG("KOSync", "Already connected to WiFi");
|
LOG_DBG("KOSync", "Already connected to WiFi");
|
||||||
state = SYNCING;
|
onWifiSelectionComplete(true);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
|
|||||||
void ReaderActivity::goToLibrary(const std::string& fromBookPath) {
|
void ReaderActivity::goToLibrary(const std::string& fromBookPath) {
|
||||||
// If coming from a book, start in that book's folder; otherwise start from root
|
// If coming from a book, start in that book's folder; otherwise start from root
|
||||||
auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
|
auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
|
||||||
activityManager.goToMyLibrary(std::move(initialPath));
|
activityManager.goToFileBrowser(std::move(initialPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "../Activity.h"
|
#include "../Activity.h"
|
||||||
#include "activities/home/MyLibraryActivity.h"
|
#include "activities/home/FileBrowserActivity.h"
|
||||||
|
|
||||||
class Epub;
|
class Epub;
|
||||||
class Xtc;
|
class Xtc;
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ void TxtReaderActivity::onExit() {
|
|||||||
void TxtReaderActivity::loop() {
|
void TxtReaderActivity::loop() {
|
||||||
// Long press BACK (1s+) goes to file selection
|
// Long press BACK (1s+) goes to file selection
|
||||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||||
activityManager.goToMyLibrary(txt ? txt->getPath() : "");
|
activityManager.goToFileBrowser(txt ? txt->getPath() : "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ void XtcReaderActivity::loop() {
|
|||||||
|
|
||||||
// Long press BACK (1s+) goes to file selection
|
// Long press BACK (1s+) goes to file selection
|
||||||
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= goHomeMs) {
|
||||||
activityManager.goToMyLibrary(xtc ? xtc->getPath() : "");
|
activityManager.goToFileBrowser(xtc ? xtc->getPath() : "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,23 +51,9 @@ void KOReaderAuthActivity::performAuthentication() {
|
|||||||
void KOReaderAuthActivity::onEnter() {
|
void KOReaderAuthActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
|
|
||||||
// Turn on WiFi
|
|
||||||
WiFi.mode(WIFI_STA);
|
|
||||||
|
|
||||||
// Check if already connected
|
// Check if already connected
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
state = AUTHENTICATING;
|
onWifiSelectionComplete(true);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user