diff --git a/src/SettingsList.h b/src/SettingsList.h index 79a8eb82..4183f067 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -23,6 +23,12 @@ inline const std::vector& getSettingsList() { SettingInfo::Enum(StrId::STR_SLEEP_COVER_FILTER, &CrossPointSettings::sleepScreenCoverFilter, {StrId::STR_NONE_OPT, StrId::STR_FILTER_CONTRAST, StrId::STR_INVERTED}, "sleepScreenCoverFilter", StrId::STR_CAT_DISPLAY), + SettingInfo::Enum(StrId::STR_LETTERBOX_FILL, &CrossPointSettings::sleepScreenLetterboxFill, + {StrId::STR_DITHERED, StrId::STR_SOLID, StrId::STR_NONE_OPT}, "sleepScreenLetterboxFill", + StrId::STR_CAT_DISPLAY), + SettingInfo::Enum(StrId::STR_INDEXING_DISPLAY, &CrossPointSettings::indexingDisplay, + {StrId::STR_INDEXING_POPUP, StrId::STR_INDEXING_STATUS_TEXT, StrId::STR_INDEXING_STATUS_ICON}, + "indexingDisplay", StrId::STR_CAT_DISPLAY), SettingInfo::Enum(StrId::STR_HIDE_BATTERY, &CrossPointSettings::hideBatteryPercentage, {StrId::STR_NEVER, StrId::STR_IN_READER, StrId::STR_ALWAYS}, "hideBatteryPercentage", StrId::STR_CAT_DISPLAY), @@ -133,10 +139,6 @@ inline const std::vector& getSettingsList() { SettingInfo::Toggle(StrId::STR_AUTO_NTP_SYNC, &CrossPointSettings::autoNtpSync, "autoNtpSync", StrId::STR_CAT_CLOCK), - // --- Mod: Sleep Screen --- - SettingInfo::Enum(StrId::STR_LETTERBOX_FILL, &CrossPointSettings::sleepScreenLetterboxFill, - {StrId::STR_DITHERED, StrId::STR_SOLID, StrId::STR_NONE_OPT}, "sleepScreenLetterboxFill", - StrId::STR_CAT_DISPLAY), // --- Status Bar Settings (web-only, uses StatusBarSettingsActivity) --- SettingInfo::Toggle(StrId::STR_CHAPTER_PAGE_COUNT, &CrossPointSettings::statusBarChapterPageCount, "statusBarChapterPageCount", StrId::STR_CUSTOMISE_STATUS_BAR), diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 22946418..31a54e5d 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -40,6 +40,10 @@ constexpr unsigned long longPressConfirmMs = 700; // pages per minute, first item is 1 to prevent division by zero if accessed const std::vector PAGE_TURN_LABELS = {1, 1, 3, 6, 12}; +// 8x8 1-bit hourglass icon for the indexing status bar indicator. +constexpr uint8_t kIndexingIcon[] = {0x00, 0x81, 0xC3, 0xE7, 0xE7, 0xC3, 0x81, 0x00}; +constexpr int kIndexingIconSize = 8; + int clampPercent(int percent) { if (percent < 0) { return 0; @@ -970,19 +974,44 @@ void EpubReaderActivity::render(RenderLock&& lock) { LOG_ERR("ERS", "Failed to load page from SD - clearing section cache"); section->clearCache(); section.reset(); - requestUpdate(); // Try again after clearing cache - // TODO: prevent infinite loop if the page keeps failing to load for some reason + silentIndexingActive = false; + requestUpdate(); automaticPageTurnActive = false; return; } + silentIndexingActive = false; + // Collect footnotes from the loaded page currentPageFootnotes = std::move(p->footnotes); + const bool textOnlyPage = !p->hasImages(); + if (textOnlyPage && SETTINGS.indexingDisplay != CrossPointSettings::INDEXING_DISPLAY::INDEXING_POPUP && + section->pageCount >= 1 && + ((section->pageCount == 1 && section->currentPage == 0) || + (section->pageCount >= 2 && section->currentPage == section->pageCount - 2)) && + currentSpineIndex + 1 < epub->getSpineItemsCount() && preIndexedNextSpine != currentSpineIndex + 1) { + const uint16_t vpW = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; + const uint16_t vpH = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom; + Section probe(epub, currentSpineIndex + 1, renderer); + if (probe.loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(), + SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, vpW, vpH, + SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) { + preIndexedNextSpine = currentSpineIndex + 1; + } else { + silentIndexingActive = true; + } + } + const auto start = millis(); renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft); LOG_DBG("ERS", "Rendered page in %dms", millis() - start); renderer.clearFontCache(); + + if (silentIndexingActive) { + silentIndexNextChapterIfNeeded(); + requestUpdate(); + } } saveProgress(currentSpineIndex, section->currentPage, section->pageCount); @@ -1105,6 +1134,22 @@ void EpubReaderActivity::renderStatusBar() const { } GUI.drawStatusBar(renderer, bookProgress, currentPage, pageCount, title, 0, textYOffset); + + if (silentIndexingActive && SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) { + int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft; + renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom, + &orientedMarginLeft); + const int textY = renderer.getScreenHeight() - UITheme::getInstance().getStatusBarHeight() - orientedMarginBottom - 4; + const bool showBatteryPercentage = + SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; + const int batteryWidth = SETTINGS.statusBarBattery ? (showBatteryPercentage ? 50 : 20) : 0; + const int indicatorX = orientedMarginLeft + batteryWidth + 8; + if (SETTINGS.indexingDisplay == CrossPointSettings::INDEXING_DISPLAY::INDEXING_STATUS_TEXT) { + renderer.drawText(SMALL_FONT_ID, indicatorX, textY, tr(STR_INDEXING)); + } else if (SETTINGS.indexingDisplay == CrossPointSettings::INDEXING_DISPLAY::INDEXING_STATUS_ICON) { + renderer.drawIcon(kIndexingIcon, indicatorX, textY - kIndexingIconSize + 2, kIndexingIconSize, kIndexingIconSize); + } + } } void EpubReaderActivity::navigateToHref(const std::string& hrefStr, const bool savePosition) { diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index b366e27b..9327a495 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -34,6 +34,7 @@ class EpubReaderActivity final : public Activity { // Silent pre-indexing: proactively creates section files for the next chapter // when the user is near the end of the current one, eliminating load times. int preIndexedNextSpine = -1; + bool silentIndexingActive = false; bool silentIndexNextChapterIfNeeded(); // Footnote support