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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
- **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.
|
||||
| Mode | Behavior |
|
||||
|------|----------|
|
||||
| **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]
|
||||
> You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images.
|
||||
#### Cover settings
|
||||
|
||||
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]
|
||||
> 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)
|
||||
- [Skrzakk](https://github.com/Skrzakk)
|
||||
- [pablohc](https://github.com/pablohc)
|
||||
- [DaniPhii](https://github.com/DaniPhii)
|
||||
|
||||
## Swedish
|
||||
- [dawiik](https://github.com/dawiik)
|
||||
|
||||
@@ -274,11 +274,13 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
}
|
||||
|
||||
bool BookMetadataCache::cleanupTmpFiles() const {
|
||||
if (Storage.exists((cachePath + tmpSpineBinFile).c_str())) {
|
||||
Storage.remove((cachePath + tmpSpineBinFile).c_str());
|
||||
const auto spineBinFile = cachePath + tmpSpineBinFile;
|
||||
if (Storage.exists(spineBinFile.c_str())) {
|
||||
Storage.remove(spineBinFile.c_str());
|
||||
}
|
||||
if (Storage.exists((cachePath + tmpTocBinFile).c_str())) {
|
||||
Storage.remove((cachePath + tmpTocBinFile).c_str());
|
||||
const auto tocBinFile = cachePath + tmpTocBinFile;
|
||||
if (Storage.exists(tocBinFile.c_str())) {
|
||||
Storage.remove(tocBinFile.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -144,9 +144,12 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
|
||||
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 =
|
||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 0;
|
||||
@@ -275,9 +278,12 @@ std::vector<size_t> ParsedText::computeHyphenatedLineBreaks(const GfxRenderer& r
|
||||
const int pageWidth, const int spaceWidth,
|
||||
std::vector<uint16_t>& wordWidths,
|
||||
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 =
|
||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 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 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 int firstLineIndent =
|
||||
isFirstLine && blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
isFirstLine && blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 0;
|
||||
@@ -485,8 +494,9 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
||||
? spareSpace / static_cast<int>(actualGapCount)
|
||||
: 0;
|
||||
|
||||
// Calculate initial x position (first line starts at indent for left/justified text)
|
||||
auto xpos = static_cast<uint16_t>(firstLineIndent);
|
||||
// Calculate initial x position (first line starts at indent for left/justified text;
|
||||
// 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) {
|
||||
xpos = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
|
||||
} 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
|
||||
// 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);
|
||||
|
||||
for (size_t wordIdx = 0; wordIdx < lineWordCount; wordIdx++) {
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
#include "parsers/ChapterHtmlSlimParser.h"
|
||||
|
||||
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) +
|
||||
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) +
|
||||
sizeof(uint32_t);
|
||||
sizeof(uint8_t) + sizeof(uint32_t);
|
||||
} // namespace
|
||||
|
||||
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,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const bool embeddedStyle) {
|
||||
const bool embeddedStyle, const uint8_t imageRendering) {
|
||||
if (!file) {
|
||||
LOG_DBG("SCT", "File not open for writing header");
|
||||
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) +
|
||||
sizeof(extraParagraphSpacing) + sizeof(paragraphAlignment) + sizeof(viewportWidth) +
|
||||
sizeof(viewportHeight) + sizeof(pageCount) + sizeof(hyphenationEnabled) +
|
||||
sizeof(embeddedStyle) + sizeof(uint32_t),
|
||||
sizeof(embeddedStyle) + sizeof(imageRendering) + sizeof(uint32_t),
|
||||
"Header size mismatch");
|
||||
serialization::writePod(file, SECTION_FILE_VERSION);
|
||||
serialization::writePod(file, fontId);
|
||||
@@ -55,13 +55,15 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
||||
serialization::writePod(file, viewportHeight);
|
||||
serialization::writePod(file, hyphenationEnabled);
|
||||
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, static_cast<uint32_t>(0)); // Placeholder for LUT offset
|
||||
}
|
||||
|
||||
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
@@ -84,6 +86,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
uint8_t fileParagraphAlignment;
|
||||
bool fileHyphenationEnabled;
|
||||
bool fileEmbeddedStyle;
|
||||
uint8_t fileImageRendering;
|
||||
serialization::readPod(file, fileFontId);
|
||||
serialization::readPod(file, fileLineCompression);
|
||||
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, fileHyphenationEnabled);
|
||||
serialization::readPod(file, fileEmbeddedStyle);
|
||||
serialization::readPod(file, fileImageRendering);
|
||||
|
||||
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
||||
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
||||
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) {
|
||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle ||
|
||||
imageRendering != fileImageRendering) {
|
||||
file.close();
|
||||
LOG_ERR("SCT", "Deserialization failed: Parameters do not match");
|
||||
clearCache();
|
||||
@@ -129,7 +134,7 @@ bool Section::clearCache() const {
|
||||
bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
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 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;
|
||||
}
|
||||
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
||||
viewportHeight, hyphenationEnabled, embeddedStyle);
|
||||
viewportHeight, hyphenationEnabled, embeddedStyle, imageRendering);
|
||||
std::vector<uint32_t> lut = {};
|
||||
|
||||
// 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,
|
||||
viewportHeight, hyphenationEnabled,
|
||||
[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());
|
||||
success = visitor.parseAndBuildPages();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class Section {
|
||||
|
||||
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
|
||||
bool embeddedStyle);
|
||||
bool embeddedStyle, uint8_t imageRendering);
|
||||
uint32_t onPageComplete(std::unique_ptr<Page> page);
|
||||
|
||||
public:
|
||||
@@ -30,10 +30,11 @@ class Section {
|
||||
filePath(epub->getCachePath() + "/sections/" + std::to_string(spineIndex) + ".bin") {}
|
||||
~Section() = default;
|
||||
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 createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ bool TextBlock::serialize(FsFile& file) const {
|
||||
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||
uint16_t wc;
|
||||
std::vector<std::string> words;
|
||||
std::vector<uint16_t> wordXpos;
|
||||
std::vector<int16_t> wordXpos;
|
||||
std::vector<EpdFontFamily::Style> wordStyles;
|
||||
BlockStyle blockStyle;
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
class TextBlock final : public Block {
|
||||
private:
|
||||
std::vector<std::string> words;
|
||||
std::vector<uint16_t> wordXpos;
|
||||
std::vector<int16_t> wordXpos;
|
||||
std::vector<EpdFontFamily::Style> wordStyles;
|
||||
BlockStyle blockStyle;
|
||||
|
||||
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())
|
||||
: words(std::move(words)),
|
||||
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());
|
||||
|
||||
{
|
||||
@@ -278,8 +285,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
const float emSize =
|
||||
static_cast<float>(self->renderer.getLineHeight(self->fontId)) * self->lineCompression;
|
||||
const float emSize = static_cast<float>(self->renderer.getFontAscenderSize(self->fontId));
|
||||
CssStyle imgStyle = self->cssParser ? self->cssParser->resolveStyle("img", classAttr) : CssStyle{};
|
||||
// Merge inline style (e.g. style="height: 2em") so it overrides stylesheet rules
|
||||
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(
|
||||
cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth);
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class ChapterHtmlSlimParser {
|
||||
bool hyphenationEnabled;
|
||||
const CssParser* cssParser;
|
||||
bool embeddedStyle;
|
||||
uint8_t imageRendering;
|
||||
std::string contentBase;
|
||||
std::string imageBasePath;
|
||||
int imageCounter = 0;
|
||||
@@ -94,8 +95,8 @@ class ChapterHtmlSlimParser {
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||
const bool embeddedStyle, const std::string& contentBase,
|
||||
const std::string& imageBasePath, const std::function<void()>& popupFn = nullptr,
|
||||
const CssParser* cssParser = nullptr)
|
||||
const std::string& imageBasePath, const uint8_t imageRendering = 0,
|
||||
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
|
||||
|
||||
: epub(epub),
|
||||
filepath(filepath),
|
||||
@@ -111,6 +112,7 @@ class ChapterHtmlSlimParser {
|
||||
popupFn(popupFn),
|
||||
cssParser(cssParser),
|
||||
embeddedStyle(embeddedStyle),
|
||||
imageRendering(imageRendering),
|
||||
contentBase(contentBase),
|
||||
imageBasePath(imageBasePath) {}
|
||||
|
||||
|
||||
@@ -36,12 +36,10 @@ ContentOpfParser::~ContentOpfParser() {
|
||||
if (tempItemStore) {
|
||||
tempItemStore.close();
|
||||
}
|
||||
if (Storage.exists((cachePath + itemCacheFile).c_str())) {
|
||||
Storage.remove((cachePath + itemCacheFile).c_str());
|
||||
const auto itemCachePath = cachePath + itemCacheFile;
|
||||
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); }
|
||||
|
||||
@@ -92,6 +92,10 @@ STR_STATUS_BAR: "Status Bar"
|
||||
STR_HIDE_BATTERY: "Hide Battery %"
|
||||
STR_EXTRA_SPACING: "Extra Paragraph Spacing"
|
||||
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_ORIENTATION: "Reading Orientation"
|
||||
STR_FRONT_BTN_LAYOUT: "Front Button Layout"
|
||||
|
||||
@@ -63,7 +63,7 @@ STR_MAC_ADDRESS: "MAC-Adresse:"
|
||||
STR_CHECKING_WIFI: "WLAN prüfen…"
|
||||
STR_ENTER_WIFI_PASSWORD: "WLAN-Passwort eingeben"
|
||||
STR_ENTER_TEXT: "Text eingeben"
|
||||
STR_TO_PREFIX: "bis"
|
||||
STR_TO_PREFIX: "mit "
|
||||
STR_CALIBRE_DISCOVERING: "Calibre finden..."
|
||||
STR_CALIBRE_CONNECTING_TO: "Verbinden mit"
|
||||
STR_CALIBRE_CONNECTED_TO: "Verbunden mit"
|
||||
@@ -120,7 +120,7 @@ STR_SELECT_WALLPAPER: "Bildauswahl Standby"
|
||||
STR_CLEAR_READING_CACHE: "Lese-Cache leeren"
|
||||
STR_CALIBRE: "Calibre"
|
||||
STR_USERNAME: "Benutzername"
|
||||
STR_PASSWORD: "Passwort nötig"
|
||||
STR_PASSWORD: "Passwort"
|
||||
STR_SYNC_SERVER_URL: "Sync-Server-URL"
|
||||
STR_DOCUMENT_MATCHING: "Dateizuordnung"
|
||||
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_LBCR: "L, Zurück, Bst, R"
|
||||
STR_PREV_NEXT: "Zurück/Weiter"
|
||||
STR_NEXT_PREV: "Weiter/Zuürck"
|
||||
STR_NEXT_PREV: "Weiter/Zurück"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
@@ -236,6 +236,8 @@ STR_DOWNLOAD: "Herunterladen"
|
||||
STR_RETRY: "Wiederh."
|
||||
STR_YES: "Ja"
|
||||
STR_NO: "Nein"
|
||||
STR_SHOW: "Zeigen"
|
||||
STR_HIDE: "Ausblenden"
|
||||
STR_STATE_ON: "An"
|
||||
STR_STATE_OFF: "Aus"
|
||||
STR_NOT_SET: "Leer"
|
||||
@@ -248,6 +250,21 @@ STR_CAPS_OFF: "umsch"
|
||||
STR_OK_BUTTON: "OK"
|
||||
STR_SLEEP_COVER_FILTER: "Standby-Coverfilter"
|
||||
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_THEME_CLASSIC: "Klassisch"
|
||||
STR_THEME_LYRA: "Lyra"
|
||||
@@ -280,6 +297,7 @@ STR_GO_TO_PERCENT: "Gehe zu %"
|
||||
STR_GO_HOME_BUTTON: "Zum Anfang"
|
||||
STR_SYNC_PROGRESS: "Fortschritt synchronisieren"
|
||||
STR_DELETE_CACHE: "Buch-Cache leeren"
|
||||
STR_DISPLAY_QR: "Seite als QR anzeigen"
|
||||
STR_DELETE: "Löschen"
|
||||
STR_CHAPTER_PREFIX: "Kapitel:"
|
||||
STR_PAGES_SEPARATOR: " Seiten | "
|
||||
@@ -289,7 +307,7 @@ STR_KBD_SHIFT_CAPS: "UMSCH"
|
||||
STR_KBD_LOCK: "FESTST"
|
||||
STR_CALIBRE_URL_HINT: "Calibre: URL um /opds ergänzen"
|
||||
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_HASH_FAILED: "Dokument-Hash fehlgeschlagen"
|
||||
STR_FETCH_PROGRESS: "Externen Fortschritt abrufen..."
|
||||
@@ -302,8 +320,8 @@ STR_LOCAL_LABEL: "Lokal:"
|
||||
STR_PAGE_OVERALL_FORMAT: " Seite %d, %.2f%% insgesamt"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: " Seite %d/%d, %.2f%% insgesamt"
|
||||
STR_DEVICE_FROM_FORMAT: " Von: %s"
|
||||
STR_APPLY_REMOTE: "Ext. Fortschritt übern."
|
||||
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochl."
|
||||
STR_APPLY_REMOTE: "Externen Fortschritt übernehmen"
|
||||
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochladen"
|
||||
STR_NO_REMOTE_MSG: "Kein externer Fortschritt"
|
||||
STR_UPLOAD_PROMPT: "Aktuelle Position hochladen?"
|
||||
STR_UPLOAD_SUCCESS: "Hochgeladen!"
|
||||
@@ -314,3 +332,8 @@ STR_BOOK_S_STYLE: "Buch-Stil"
|
||||
STR_EMBEDDED_STYLE: "Eingebetteter Stil"
|
||||
STR_OPDS_SERVER_URL: "OPDS-Server-URL"
|
||||
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_SLEEPING: "Suspendido"
|
||||
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_SETTINGS_TITLE: "Ajustes"
|
||||
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_HOW_CONNECT: "¿Cómo desea conectarse?"
|
||||
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_HOTSPOT_DESC: "Conectarse a este dispositivo"
|
||||
STR_STARTING_HOTSPOT: "Iniciando Punto de Acceso..."
|
||||
STR_HOTSPOT_MODE: "Modo Punto de Acceso"
|
||||
STR_STARTING_HOTSPOT: "Iniciando punto de acceso..."
|
||||
STR_HOTSPOT_MODE: "Modo punto de acceso"
|
||||
STR_CONNECT_WIFI_HINT: "Conecte su dispositivo a esta red Wi-Fi"
|
||||
STR_OPEN_URL_HINT: "Abra esta dirección en su navegador"
|
||||
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_TO_PREFIX: "a "
|
||||
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_WAITING_COMMANDS: "Esperando comandos..."
|
||||
STR_CONNECTION_FAILED_RETRYING: "(Error de conexión, reintentando...)"
|
||||
STR_CALIBRE_DISCONNECTED: "Calibre desconectado"
|
||||
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_RECEIVED: "Recibido: "
|
||||
STR_CALIBRE_WAITING_MORE: "Esperando más..."
|
||||
STR_CALIBRE_FAILED_CREATE_FILE: "Error al crear el archivo"
|
||||
STR_CALIBRE_PASSWORD_REQUIRED: "Contraseña requerida"
|
||||
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_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_CAT_DISPLAY: "Pantalla"
|
||||
STR_CAT_READER: "Lector"
|
||||
@@ -92,15 +92,15 @@ STR_STATUS_BAR: "Barra de estado"
|
||||
STR_HIDE_BATTERY: "Ocultar % de batería"
|
||||
STR_EXTRA_SPACING: "Espaciado entre párrafos"
|
||||
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_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_FONT_FAMILY: "Tipografía"
|
||||
STR_EXT_READER_FONT: "Tipografía externa"
|
||||
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_LINE_SPACING: "Interlineado"
|
||||
STR_ASCII_LETTER_SPACING: "Espaciado entre letras ASCII"
|
||||
@@ -126,7 +126,7 @@ STR_DOCUMENT_MATCHING: "Coincidencia de doc."
|
||||
STR_AUTHENTICATE: "Autenticar"
|
||||
STR_KOREADER_USERNAME: "Usuario de KOReader"
|
||||
STR_KOREADER_PASSWORD: "Contraseña de KOReader"
|
||||
STR_FILENAME: "Nombre del archivo"
|
||||
STR_FILENAME: "Nombre de archivo"
|
||||
STR_BINARY: "Binario"
|
||||
STR_SET_CREDENTIALS_FIRST: "Configurar credenciales"
|
||||
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_CLEARING_CACHE: "Borrando caché..."
|
||||
STR_CACHE_CLEARED: "Caché borrada"
|
||||
STR_ITEMS_REMOVED: "Elementos eliminados"
|
||||
STR_FAILED_LOWER: "Error"
|
||||
STR_ITEMS_REMOVED: "elementos eliminados"
|
||||
STR_FAILED_LOWER: "falló"
|
||||
STR_CLEAR_CACHE_FAILED: "No se pudo borrar la caché"
|
||||
STR_CHECK_SERIAL_OUTPUT: "Consulte los registros del puerto serie"
|
||||
STR_DARK: "Oscuro"
|
||||
@@ -184,16 +184,16 @@ STR_JUSTIFY: "Justificado"
|
||||
STR_ALIGN_LEFT: "Izquierda"
|
||||
STR_CENTER: "Centro"
|
||||
STR_ALIGN_RIGHT: "Derecha"
|
||||
STR_MIN_1: "1 Minuto"
|
||||
STR_MIN_5: "5 Minutos"
|
||||
STR_MIN_10: "10 Minutos"
|
||||
STR_MIN_15: "15 Minutos"
|
||||
STR_MIN_30: "30 Minutos"
|
||||
STR_PAGES_1: "1 Página"
|
||||
STR_PAGES_5: "5 Páginas"
|
||||
STR_PAGES_10: "10 Páginas"
|
||||
STR_PAGES_15: "15 Páginas"
|
||||
STR_PAGES_30: "30 Páginas"
|
||||
STR_MIN_1: "1 min."
|
||||
STR_MIN_5: "5 min."
|
||||
STR_MIN_10: "10 min."
|
||||
STR_MIN_15: "15 min."
|
||||
STR_MIN_30: "30 min."
|
||||
STR_PAGES_1: "1 pág."
|
||||
STR_PAGES_5: "5 pág."
|
||||
STR_PAGES_10: "10 pág."
|
||||
STR_PAGES_15: "15 pág."
|
||||
STR_PAGES_30: "30 pág."
|
||||
STR_UPDATE: "Actualizar"
|
||||
STR_CHECKING_UPDATE: "Verificando actualización..."
|
||||
STR_NEW_UPDATE: "¡Nueva actualización disponible!"
|
||||
@@ -203,20 +203,20 @@ STR_UPDATING: "Actualizando..."
|
||||
STR_NO_UPDATE: "No hay actualizaciones disponibles"
|
||||
STR_UPDATE_FAILED: "Fallo de actualización"
|
||||
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_BUILTIN_DISABLED: "Incorporado (Desactivado)"
|
||||
STR_BUILTIN_DISABLED: "Incorporado (desactivado)"
|
||||
STR_NO_ENTRIES: "No se encontraron elementos"
|
||||
STR_DOWNLOADING: "Descargando..."
|
||||
STR_DOWNLOAD_FAILED: "Fallo de descarga"
|
||||
STR_ERROR_MSG: "Error"
|
||||
STR_ERROR_MSG: "Error:"
|
||||
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_PARSE_FEED_FAILED: "Fallo al procesar el feed"
|
||||
STR_NETWORK_PREFIX: "Red: "
|
||||
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_NETWORK_NOT_FOUND: "Error: Red no encontrada"
|
||||
STR_ERROR_CONNECTION_TIMEOUT: "Error: Tiempo de conexión agotado"
|
||||
@@ -225,7 +225,8 @@ STR_BACK: "« Atrás"
|
||||
STR_EXIT: "« Salir"
|
||||
STR_HOME: "« Inicio"
|
||||
STR_SAVE: "« Guardar"
|
||||
STR_SELECT: "Elegir"
|
||||
STR_SELECT: "Selec."
|
||||
STR_SELECTED: "Seleccionado"
|
||||
STR_TOGGLE: "Cambiar"
|
||||
STR_CONFIRM: "Confirmar"
|
||||
STR_CANCEL: "Cancelar"
|
||||
@@ -235,6 +236,8 @@ STR_DOWNLOAD: "Descargar"
|
||||
STR_RETRY: "Reintentar"
|
||||
STR_YES: "Sí"
|
||||
STR_NO: "No"
|
||||
STR_SHOW: "Mostrar"
|
||||
STR_HIDE: "Ocultar"
|
||||
STR_STATE_ON: "Activado"
|
||||
STR_STATE_OFF: "Desactivado"
|
||||
STR_NOT_SET: "No configurado"
|
||||
@@ -247,6 +250,21 @@ STR_CAPS_OFF: "minúsculas"
|
||||
STR_OK_BUTTON: "OK"
|
||||
STR_SLEEP_COVER_FILTER: "Filtro de pantalla de suspensión"
|
||||
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_THEME_CLASSIC: "Clásico"
|
||||
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_UNASSIGNED: "Sin asignar"
|
||||
STR_ALREADY_ASSIGNED: "Ya asignado"
|
||||
STR_REMAP_RESET_HINT: "Botón lateral arriba: Restablecer configuración"
|
||||
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: Anular reconfiguración"
|
||||
STR_HW_BACK_LABEL: "Atrás (Primer botón)"
|
||||
STR_HW_CONFIRM_LABEL: "Confirmar (Segundo botón)"
|
||||
STR_HW_LEFT_LABEL: "Izq. (Tercer botón)"
|
||||
STR_HW_RIGHT_LABEL: "Der. (Cuarto botón)"
|
||||
STR_REMAP_RESET_HINT: "Botón lateral arriba: restablecer configuración"
|
||||
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: anular reconfiguración"
|
||||
STR_HW_BACK_LABEL: "Atrás (primer botón)"
|
||||
STR_HW_CONFIRM_LABEL: "Confirmar (segundo botón)"
|
||||
STR_HW_LEFT_LABEL: "Izq. (tercer botón)"
|
||||
STR_HW_RIGHT_LABEL: "Der. (cuarto botón)"
|
||||
STR_GO_TO_PERCENT: "Ir a %"
|
||||
STR_GO_HOME_BUTTON: "Volver a inicio"
|
||||
STR_DELETE: "Borrar"
|
||||
STR_GO_HOME_BUTTON: "Volver al menú Inicio"
|
||||
STR_SYNC_PROGRESS: "Sincronizar progreso de lectura"
|
||||
STR_DELETE_CACHE: "Borrar caché del libro"
|
||||
STR_CHAPTER_PREFIX: "Cap.:"
|
||||
STR_PAGES_SEPARATOR: " Páginas |"
|
||||
STR_BOOK_PREFIX: "Libro:"
|
||||
STR_KBD_SHIFT: "shift"
|
||||
STR_KBD_SHIFT_CAPS: "SHIFT"
|
||||
STR_DELETE: "Borrar"
|
||||
STR_DISPLAY_QR: "Mostrar página como QR"
|
||||
STR_CHAPTER_PREFIX: "Cap.: "
|
||||
STR_PAGES_SEPARATOR: " Págs. | "
|
||||
STR_BOOK_PREFIX: "Libro: "
|
||||
STR_KBD_SHIFT: "minús."
|
||||
STR_KBD_SHIFT_CAPS: "MAYÚS."
|
||||
STR_KBD_LOCK: "BLOQUEAR"
|
||||
STR_CALIBRE_URL_HINT: "Para Calibre, agregue /opds a su URL"
|
||||
STR_PERCENT_STEP_HINT: "Izq./Der.: 1% | Subir/Bajar: 10%"
|
||||
STR_SYNCING_TIME: "Tiempo de sincronización..."
|
||||
STR_CALC_HASH: "Calculando HASH del documento..."
|
||||
STR_HASH_FAILED: "No se pudo calcular el HASH del documento"
|
||||
STR_CALC_HASH: "Calculando hash del documento..."
|
||||
STR_HASH_FAILED: "No se pudo calcular el hash del documento"
|
||||
STR_FETCH_PROGRESS: "Recuperando progreso remoto..."
|
||||
STR_UPLOAD_PROGRESS: "Subiendo progreso..."
|
||||
STR_NO_CREDENTIALS_MSG: "No se han configurado credenciales"
|
||||
STR_KOREADER_SETUP_HINT: "Configure una cuenta de KOReader en la configuración"
|
||||
STR_PROGRESS_FOUND: "¡Progreso encontrado!"
|
||||
STR_REMOTE_LABEL: "Remoto"
|
||||
STR_LOCAL_LABEL: "Local"
|
||||
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% Completada"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% Completada"
|
||||
STR_REMOTE_LABEL: "Remoto:"
|
||||
STR_LOCAL_LABEL: "Local:"
|
||||
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% completado"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% completado"
|
||||
STR_DEVICE_FROM_FORMAT: " De: %s"
|
||||
STR_APPLY_REMOTE: "Aplicar progreso remoto"
|
||||
STR_UPLOAD_LOCAL: "Subir progreso local"
|
||||
@@ -312,4 +331,9 @@ STR_UPLOAD: "Subir"
|
||||
STR_BOOK_S_STYLE: "Estilo del libro"
|
||||
STR_EMBEDDED_STYLE: "Estilo integrado"
|
||||
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_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_SYNC_PROGRESS: "Прогрес синхронізації"
|
||||
STR_DELETE_CACHE: "Видалити кеш книги"
|
||||
STR_DELETE: "Видалити"
|
||||
STR_DISPLAY_QR: "Показати сторінку як QR-код"
|
||||
STR_CHAPTER_PREFIX: "Розділ: "
|
||||
STR_PAGES_SEPARATOR: " сторінок | "
|
||||
@@ -334,3 +335,5 @@ STR_FOOTNOTES: "Зноски"
|
||||
STR_NO_FOOTNOTES: "На цій сторінці немає зносок"
|
||||
STR_LINK: "[посилання]"
|
||||
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
|
||||
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
|
||||
-DDISABLE_FS_H_WARNING=1
|
||||
-DDESTRUCTOR_CLOSES_FILE=1
|
||||
# https://libexpat.github.io/doc/api/latest/#XML_GE
|
||||
-DXML_GE=0
|
||||
-DXML_CONTEXT_BYTES=1024
|
||||
|
||||
@@ -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