diff --git a/lib/I18n/I18n.cpp b/lib/I18n/I18n.cpp index ae9fc53c..9b00d8c0 100644 --- a/lib/I18n/I18n.cpp +++ b/lib/I18n/I18n.cpp @@ -93,4 +93,4 @@ const char* I18n::getCharacterSet(Language lang) { } return CHARACTER_SETS[static_cast(lang)]; -} \ No newline at end of file +} diff --git a/lib/I18n/translations/catalan.yaml b/lib/I18n/translations/catalan.yaml index e45374cd..b04fb704 100644 --- a/lib/I18n/translations/catalan.yaml +++ b/lib/I18n/translations/catalan.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ON]" STR_SLEEP_COVER_FILTER: "Filtre de pantalla de repòs" STR_FILTER_CONTRAST: "Contrast" -STR_STATUS_BAR_FULL_PERCENT: "Amb percentatge" -STR_STATUS_BAR_FULL_BOOK: "Amb progrés llibre" -STR_STATUS_BAR_BOOK_ONLY: "Només progrés llibre" -STR_STATUS_BAR_FULL_CHAPTER: "Amb progrés capítol" STR_UI_THEME: "Tema de la interfície" STR_THEME_CLASSIC: "Clàssic" STR_THEME_LYRA: "Lyra" diff --git a/lib/I18n/translations/czech.yaml b/lib/I18n/translations/czech.yaml index 4c449556..0f6f6f30 100644 --- a/lib/I18n/translations/czech.yaml +++ b/lib/I18n/translations/czech.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ZAP]" STR_SLEEP_COVER_FILTER: "Filtr obrazovky spánku" STR_FILTER_CONTRAST: "Kontrast" -STR_STATUS_BAR_FULL_PERCENT: "Plný s procenty" -STR_STATUS_BAR_FULL_BOOK: "Plný s pruhem knih" -STR_STATUS_BAR_BOOK_ONLY: "Pouze pruh knih" -STR_STATUS_BAR_FULL_CHAPTER: "Plná s pruhem kapitol" STR_UI_THEME: "Šablona rozhraní" STR_THEME_CLASSIC: "Klasická" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Nahrát" STR_BOOK_S_STYLE: "Styl knihy" STR_EMBEDDED_STYLE: "Vložený styl" STR_OPDS_SERVER_URL: "URL serveru OPDS" -STR_SCREENSHOT_BUTTON: "Udělat snímek obrazovky" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Udělat snímek obrazovky" diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index 578a42b6..073e2c9b 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -235,6 +235,8 @@ STR_DOWNLOAD: "Download" STR_RETRY: "Retry" STR_YES: "Yes" STR_NO: "No" +STR_SHOW: "Show" +STR_HIDE: "Hide" STR_STATE_ON: "ON" STR_STATE_OFF: "OFF" STR_SET: "Set" @@ -249,10 +251,21 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ON]" STR_SLEEP_COVER_FILTER: "Sleep Screen Cover Filter" STR_FILTER_CONTRAST: "Contrast" -STR_STATUS_BAR_FULL_PERCENT: "Full w/ Percentage" -STR_STATUS_BAR_FULL_BOOK: "Full w/ Book Bar" -STR_STATUS_BAR_BOOK_ONLY: "Book Bar Only" -STR_STATUS_BAR_FULL_CHAPTER: "Full w/ Chapter Bar" +STR_CUSTOMISE_STATUS_BAR: "Customise Status Bar" +STR_CHAPTER_PAGE_COUNT: "Chapter Page Count" +STR_BOOK_PROGRESS_PERCENTAGE: "Book Progress Percentage" +STR_PROGRESS_BAR: "Progress Bar" +STR_PROGRESS_BAR_THICKNESS: "Progress Bar Thickness" +STR_PROGRESS_BAR_THIN: "Thin" +STR_PROGRESS_BAR_MEDIUM: "Medium" +STR_PROGRESS_BAR_THICK: "Thick" +STR_BOOK: "Book" +STR_CHAPTER: "Chapter" +STR_EXAMPLE_CHAPTER: "Chapter 21" +STR_EXAMPLE_BOOK: "Book Title" +STR_PREVIEW: "Preview" +STR_TITLE: "Title" +STR_BATTERY: "Battery" STR_UI_THEME: "UI Theme" STR_THEME_CLASSIC: "Classic" STR_THEME_LYRA: "Lyra" diff --git a/lib/I18n/translations/french.yaml b/lib/I18n/translations/french.yaml index 9fc615d4..84c1a30e 100644 --- a/lib/I18n/translations/french.yaml +++ b/lib/I18n/translations/french.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ON]" STR_SLEEP_COVER_FILTER: "Filtre écran de veille" STR_FILTER_CONTRAST: "Contraste" -STR_STATUS_BAR_FULL_PERCENT: "Complète + %" -STR_STATUS_BAR_FULL_BOOK: "Complète + barre livre" -STR_STATUS_BAR_BOOK_ONLY: "Barre livre seule" -STR_STATUS_BAR_FULL_CHAPTER: "Complète + barre chap." STR_UI_THEME: "Thème interface" STR_THEME_CLASSIC: "Classique" STR_THEME_LYRA: "Lyra" diff --git a/lib/I18n/translations/german.yaml b/lib/I18n/translations/german.yaml index ca74329e..ddb23663 100644 --- a/lib/I18n/translations/german.yaml +++ b/lib/I18n/translations/german.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[AN]" STR_SLEEP_COVER_FILTER: "Standby-Coverfilter" STR_FILTER_CONTRAST: "Kontrast" -STR_STATUS_BAR_FULL_PERCENT: "Komplett + Prozent" -STR_STATUS_BAR_FULL_BOOK: "Komplett + Buch" -STR_STATUS_BAR_BOOK_ONLY: "Nur Buch" -STR_STATUS_BAR_FULL_CHAPTER: "Komplett + Kapitel" STR_UI_THEME: "System-Design" STR_THEME_CLASSIC: "Klassisch" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Hochladen" STR_BOOK_S_STYLE: "Buch-Stil" STR_EMBEDDED_STYLE: "Eingebetteter Stil" STR_OPDS_SERVER_URL: "OPDS-Server-URL" -STR_SCREENSHOT_BUTTON: "Screenshot aufnehmen" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Screenshot aufnehmen" diff --git a/lib/I18n/translations/portuguese.yaml b/lib/I18n/translations/portuguese.yaml index 8ba7defa..4f694048 100644 --- a/lib/I18n/translations/portuguese.yaml +++ b/lib/I18n/translations/portuguese.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[LIGADO]" STR_SLEEP_COVER_FILTER: "Filtro capa tela repouso" STR_FILTER_CONTRAST: "Contraste" -STR_STATUS_BAR_FULL_PERCENT: "Completa c/ porcentagem" -STR_STATUS_BAR_FULL_BOOK: "Completa c/ barra livro" -STR_STATUS_BAR_BOOK_ONLY: "Só barra do livro" -STR_STATUS_BAR_FULL_CHAPTER: "Completa c/ barra capítulo" STR_UI_THEME: "Tema da interface" STR_THEME_CLASSIC: "Clássico" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Enviar" STR_BOOK_S_STYLE: "Estilo do livro" STR_EMBEDDED_STYLE: "Estilo embutido" STR_OPDS_SERVER_URL: "URL do servidor OPDS" -STR_SCREENSHOT_BUTTON: "Capturar tela" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Capturar tela" diff --git a/lib/I18n/translations/romanian.yaml b/lib/I18n/translations/romanian.yaml index f4c781be..76b669b8 100644 --- a/lib/I18n/translations/romanian.yaml +++ b/lib/I18n/translations/romanian.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ON]" STR_SLEEP_COVER_FILTER: "Filtru ecran de repaus" STR_FILTER_CONTRAST: "Contrast" -STR_STATUS_BAR_FULL_PERCENT: "Complet cu procentaj" -STR_STATUS_BAR_FULL_BOOK: "Complet cu bara de carte" -STR_STATUS_BAR_BOOK_ONLY: "Doar bara de carte" -STR_STATUS_BAR_FULL_CHAPTER: "Complet cu bara de capitol" STR_UI_THEME: "Tema UI" STR_THEME_CLASSIC: "Clasic" STR_THEME_LYRA: "Lyra" diff --git a/lib/I18n/translations/russian.yaml b/lib/I18n/translations/russian.yaml index ecbda70f..7096f9b8 100644 --- a/lib/I18n/translations/russian.yaml +++ b/lib/I18n/translations/russian.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[ВКЛ]" STR_SLEEP_COVER_FILTER: "Фильтр экрана сна" STR_FILTER_CONTRAST: "Контраст" -STR_STATUS_BAR_FULL_PERCENT: "Полная + %" -STR_STATUS_BAR_FULL_BOOK: "Полная + шкала книги" -STR_STATUS_BAR_BOOK_ONLY: "Только шкала книги" -STR_STATUS_BAR_FULL_CHAPTER: "Полная + шкала главы" STR_UI_THEME: "Тема интерфейса" STR_THEME_CLASSIC: "Классическая" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Отправить" STR_BOOK_S_STYLE: "Стиль книги" STR_EMBEDDED_STYLE: "Встроенный стиль" STR_OPDS_SERVER_URL: "URL OPDS сервера" -STR_SCREENSHOT_BUTTON: "Сделать снимок экрана" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Сделать снимок экрана" diff --git a/lib/I18n/translations/spanish.yaml b/lib/I18n/translations/spanish.yaml index 5a76e3be..fd7dc3cb 100644 --- a/lib/I18n/translations/spanish.yaml +++ b/lib/I18n/translations/spanish.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[Activo]" STR_SLEEP_COVER_FILTER: "Filtro de pantalla de suspensión" STR_FILTER_CONTRAST: "Contraste" -STR_STATUS_BAR_FULL_PERCENT: "Completa con %" -STR_STATUS_BAR_FULL_BOOK: "Completa con progreso lect." -STR_STATUS_BAR_BOOK_ONLY: "Solo progreso" -STR_STATUS_BAR_FULL_CHAPTER: "Completa con progreso cap." STR_UI_THEME: "Interfaz" STR_THEME_CLASSIC: "Clásico" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Subir" STR_BOOK_S_STYLE: "Estilo del libro" STR_EMBEDDED_STYLE: "Estilo integrado" STR_OPDS_SERVER_URL: "URL del servidor OPDS" -STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla" diff --git a/lib/I18n/translations/swedish.yaml b/lib/I18n/translations/swedish.yaml index 95cb5764..8f434e88 100644 --- a/lib/I18n/translations/swedish.yaml +++ b/lib/I18n/translations/swedish.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "Okej" STR_ON_MARKER: "[PÅ]" STR_SLEEP_COVER_FILTER: "Viloskärmens omslagsfilter" STR_FILTER_CONTRAST: "Kontrast" -STR_STATUS_BAR_FULL_PERCENT: "Full w/ Procent" -STR_STATUS_BAR_FULL_BOOK: "Full w/ Boklist" -STR_STATUS_BAR_BOOK_ONLY: "Boklist enbart" -STR_STATUS_BAR_FULL_CHAPTER: "Full w/ Kapitellist" STR_UI_THEME: "Användargränssnittstema" STR_THEME_CLASSIC: "Klassisk" STR_THEME_LYRA: "Lyra" @@ -317,4 +313,4 @@ STR_UPLOAD: "Uppladdning" STR_BOOK_S_STYLE: "Bokstil" STR_EMBEDDED_STYLE: "Inbäddad stil" STR_OPDS_SERVER_URL: "OPDS-serveradress" -STR_SCREENSHOT_BUTTON: "Ta en skärmdump" \ No newline at end of file +STR_SCREENSHOT_BUTTON: "Ta en skärmdump" diff --git a/lib/I18n/translations/ukrainian.yaml b/lib/I18n/translations/ukrainian.yaml index 80889914..a187cb58 100644 --- a/lib/I18n/translations/ukrainian.yaml +++ b/lib/I18n/translations/ukrainian.yaml @@ -249,10 +249,6 @@ STR_OK_BUTTON: "OK" STR_ON_MARKER: "[УВІМК]" STR_SLEEP_COVER_FILTER: "Фільтр обкладинки екрана сну" STR_FILTER_CONTRAST: "Контраст" -STR_STATUS_BAR_FULL_PERCENT: "Повна з відсотками" -STR_STATUS_BAR_FULL_BOOK: "Повна з прогресом книги" -STR_STATUS_BAR_BOOK_ONLY: "Тільки прогрес книги" -STR_STATUS_BAR_FULL_CHAPTER: "Повна з панеллю розділу" STR_UI_THEME: "Тема інтерфейсу" STR_THEME_CLASSIC: "Класична" STR_THEME_LYRA: "Lyra" diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index 0b9bbb25..aca87bdc 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -57,6 +57,7 @@ void applyLegacyFrontButtonLayout(CrossPointSettings& settings) { break; } } + } // namespace void CrossPointSettings::validateFrontButtonMapping(CrossPointSettings& settings) { @@ -141,7 +142,7 @@ bool CrossPointSettings::loadFromBinaryFile() { if (++settingsRead >= fileSettingsCount) break; readAndValidate(inputFile, shortPwrBtn, SHORT_PWRBTN_COUNT); if (++settingsRead >= fileSettingsCount) break; - readAndValidate(inputFile, statusBar, STATUS_BAR_MODE_COUNT); + readAndValidate(inputFile, statusBar, STATUS_BAR_MODE_COUNT); // legacy if (++settingsRead >= fileSettingsCount) break; readAndValidate(inputFile, orientation, ORIENTATION_COUNT); if (++settingsRead >= fileSettingsCount) break; diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 8d341b0c..996ffb0f 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -35,7 +35,7 @@ class CrossPointSettings { SLEEP_SCREEN_COVER_FILTER_COUNT }; - // Status bar display type enum + // Status bar enum - legacy enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, @@ -45,6 +45,19 @@ class CrossPointSettings { CHAPTER_PROGRESS_BAR = 5, STATUS_BAR_MODE_COUNT }; + enum STATUS_BAR_PROGRESS_BAR { + BOOK_PROGRESS = 0, + CHAPTER_PROGRESS = 1, + HIDE_PROGRESS = 2, + STATUS_BAR_PROGRESS_BAR_COUNT + }; + enum STATUS_BAR_PROGRESS_BAR_THICKNESS { + PROGRESS_BAR_THIN = 0, + PROGRESS_BAR_NORMAL = 1, + PROGRESS_BAR_THICK = 2, + STATUS_BAR_PROGRESS_BAR_THICKNESS_COUNT + }; + enum STATUS_BAR_TITLE { BOOK_TITLE = 0, CHAPTER_TITLE = 1, HIDE_TITLE = 2, STATUS_BAR_TITLE_COUNT }; enum ORIENTATION { PORTRAIT = 0, // 480x800 logical coordinates (current default) @@ -128,8 +141,14 @@ class CrossPointSettings { uint8_t sleepScreenCoverMode = FIT; // Sleep screen cover filter uint8_t sleepScreenCoverFilter = NO_FILTER; - // Status bar settings + // Status bar settings (statusBar retained for migration only) uint8_t statusBar = FULL; + uint8_t statusBarChapterPageCount = 1; + uint8_t statusBarBookProgressPercentage = 1; + uint8_t statusBarProgressBar = HIDE_PROGRESS; + uint8_t statusBarProgressBarThickness = PROGRESS_BAR_NORMAL; + uint8_t statusBarTitle = CHAPTER_TITLE; + uint8_t statusBarBattery = 1; // Text rendering settings uint8_t extraParagraphSpacing = 1; uint8_t textAntiAliasing = 1; diff --git a/src/JsonSettingsIO.cpp b/src/JsonSettingsIO.cpp index 827952f1..ce9df3bc 100644 --- a/src/JsonSettingsIO.cpp +++ b/src/JsonSettingsIO.cpp @@ -13,6 +13,55 @@ #include "RecentBooksStore.h" #include "WifiCredentialStore.h" +// Convert legacy settings. +void applyLegacyStatusBarSettings(CrossPointSettings& settings) { + switch (static_cast(settings.statusBar)) { + case CrossPointSettings::NONE: + settings.statusBarChapterPageCount = 0; + settings.statusBarBookProgressPercentage = 0; + settings.statusBarProgressBar = CrossPointSettings::HIDE_PROGRESS; + settings.statusBarTitle = CrossPointSettings::HIDE_TITLE; + settings.statusBarBattery = 0; + break; + case CrossPointSettings::NO_PROGRESS: + settings.statusBarChapterPageCount = 0; + settings.statusBarBookProgressPercentage = 0; + settings.statusBarProgressBar = CrossPointSettings::HIDE_PROGRESS; + settings.statusBarTitle = CrossPointSettings::CHAPTER_TITLE; + settings.statusBarBattery = 1; + break; + case CrossPointSettings::BOOK_PROGRESS_BAR: + settings.statusBarChapterPageCount = 1; + settings.statusBarBookProgressPercentage = 0; + settings.statusBarProgressBar = CrossPointSettings::BOOK_PROGRESS; + settings.statusBarTitle = CrossPointSettings::CHAPTER_TITLE; + settings.statusBarBattery = 1; + break; + case CrossPointSettings::ONLY_BOOK_PROGRESS_BAR: + settings.statusBarChapterPageCount = 1; + settings.statusBarBookProgressPercentage = 0; + settings.statusBarProgressBar = CrossPointSettings::BOOK_PROGRESS; + settings.statusBarTitle = CrossPointSettings::HIDE_TITLE; + settings.statusBarBattery = 0; + break; + case CrossPointSettings::CHAPTER_PROGRESS_BAR: + settings.statusBarChapterPageCount = 0; + settings.statusBarBookProgressPercentage = 1; + settings.statusBarProgressBar = CrossPointSettings::CHAPTER_PROGRESS; + settings.statusBarTitle = CrossPointSettings::CHAPTER_TITLE; + settings.statusBarBattery = 1; + break; + case CrossPointSettings::FULL: + default: + settings.statusBarChapterPageCount = 1; + settings.statusBarBookProgressPercentage = 1; + settings.statusBarProgressBar = CrossPointSettings::HIDE_PROGRESS; + settings.statusBarTitle = CrossPointSettings::CHAPTER_TITLE; + settings.statusBarBattery = 1; + break; + } +} + // ---- CrossPointState ---- bool JsonSettingsIO::saveState(const CrossPointState& s, const char* path) { @@ -76,6 +125,12 @@ bool JsonSettingsIO::saveSettings(const CrossPointSettings& s, const char* path) doc["uiTheme"] = s.uiTheme; doc["fadingFix"] = s.fadingFix; doc["embeddedStyle"] = s.embeddedStyle; + doc["statusBarChapterPageCount"] = s.statusBarChapterPageCount; + doc["statusBarBookProgressPercentage"] = s.statusBarBookProgressPercentage; + doc["statusBarProgressBar"] = s.statusBarProgressBar; + doc["statusBarTitle"] = s.statusBarTitle; + doc["statusBarBattery"] = s.statusBarBattery; + doc["statusBarProgressBarThickness"] = s.statusBarProgressBarThickness; String json; serializeJson(doc, json); @@ -149,6 +204,19 @@ bool JsonSettingsIO::loadSettings(CrossPointSettings& s, const char* json, bool* strncpy(s.opdsPassword, pass.c_str(), sizeof(s.opdsPassword) - 1); s.opdsPassword[sizeof(s.opdsPassword) - 1] = '\0'; LOG_DBG("CPS", "Settings loaded from file"); + + if (doc.containsKey("statusBarChapterPageCount")) { + s.statusBarChapterPageCount = doc["statusBarChapterPageCount"]; + s.statusBarBookProgressPercentage = doc["statusBarBookProgressPercentage"]; + s.statusBarProgressBar = doc["statusBarProgressBar"]; + s.statusBarTitle = doc["statusBarTitle"]; + s.statusBarBattery = doc["statusBarBattery"]; + } else { + applyLegacyStatusBarSettings(s); + } + + s.statusBarProgressBarThickness = doc["statusBarProgressBarThickness"] | (uint8_t)S::PROGRESS_BAR_NORMAL; + return true; } diff --git a/src/SettingsList.h b/src/SettingsList.h index bf2ed201..dac00035 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -23,11 +23,6 @@ inline 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_STATUS_BAR, &CrossPointSettings::statusBar, - {StrId::STR_NONE_OPT, StrId::STR_NO_PROGRESS, StrId::STR_STATUS_BAR_FULL_PERCENT, - StrId::STR_STATUS_BAR_FULL_BOOK, StrId::STR_STATUS_BAR_BOOK_ONLY, StrId::STR_STATUS_BAR_FULL_CHAPTER}, - "statusBar", 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), @@ -67,7 +62,6 @@ inline std::vector getSettingsList() { StrId::STR_CAT_READER), SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing", 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), @@ -120,5 +114,21 @@ inline std::vector getSettingsList() { StrId::STR_OPDS_BROWSER), SettingInfo::String(StrId::STR_PASSWORD, SETTINGS.opdsPassword, sizeof(SETTINGS.opdsPassword), "opdsPassword", StrId::STR_OPDS_BROWSER), + + // --- Status Bar Settings (web-only, uses StatusBarSettingsActivity) --- + SettingInfo::Toggle(StrId::STR_CHAPTER_PAGE_COUNT, &CrossPointSettings::statusBarChapterPageCount, + "statusBarChapterPageCount", StrId::STR_CUSTOMISE_STATUS_BAR), + SettingInfo::Toggle(StrId::STR_BOOK_PROGRESS_PERCENTAGE, &CrossPointSettings::statusBarBookProgressPercentage, + "statusBarBookProgressPercentage", StrId::STR_CUSTOMISE_STATUS_BAR), + SettingInfo::Enum(StrId::STR_PROGRESS_BAR, &CrossPointSettings::statusBarProgressBar, + {StrId::STR_BOOK, StrId::STR_CHAPTER, StrId::STR_HIDE}, "statusBarProgressBar", + StrId::STR_CUSTOMISE_STATUS_BAR), + SettingInfo::Enum(StrId::STR_PROGRESS_BAR_THICKNESS, &CrossPointSettings::statusBarProgressBarThickness, + {StrId::STR_PROGRESS_BAR_THIN, StrId::STR_PROGRESS_BAR_MEDIUM, StrId::STR_PROGRESS_BAR_THICK}), + SettingInfo::Enum(StrId::STR_TITLE, &CrossPointSettings::statusBarTitle, + {StrId::STR_BOOK, StrId::STR_CHAPTER, StrId::STR_HIDE}, "statusBarTitle", + StrId::STR_CUSTOMISE_STATUS_BAR), + SettingInfo::Toggle(StrId::STR_BATTERY, &CrossPointSettings::statusBarBattery, "statusBarBattery", + StrId::STR_CUSTOMISE_STATUS_BAR), }; -} \ No newline at end of file +} diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 357e1501..00cff712 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -25,8 +25,6 @@ namespace { // pagesPerRefresh now comes from SETTINGS.getRefreshFrequency() constexpr unsigned long skipChapterMs = 700; constexpr unsigned long goHomeMs = 1000; -constexpr int statusBarMargin = 19; -constexpr int progressBarMarginTop = 1; int clampPercent(int percent) { if (percent < 0) { @@ -558,19 +556,8 @@ void EpubReaderActivity::render(Activity::RenderLock&& lock) { orientedMarginTop += SETTINGS.screenMargin; orientedMarginLeft += SETTINGS.screenMargin; orientedMarginRight += SETTINGS.screenMargin; - orientedMarginBottom += SETTINGS.screenMargin; - - const auto& metrics = UITheme::getInstance().getMetrics(); - - // Add status bar margin - if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) { - // Add additional margin for status bar if progress bar is shown - const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - orientedMarginBottom += statusBarMargin - SETTINGS.screenMargin + - (showProgressBar ? (metrics.bookProgressBarHeight + progressBarMarginTop) : 0); - } + orientedMarginBottom += + std::max(SETTINGS.screenMargin, static_cast(UITheme::getInstance().getStatusBarHeight())); if (!section) { const auto filepath = epub->getSpineItem(currentSpineIndex).href; @@ -631,7 +618,7 @@ void EpubReaderActivity::render(Activity::RenderLock&& lock) { if (section->pageCount == 0) { LOG_DBG("ERS", "No pages to render"); renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_EMPTY_CHAPTER), true, EpdFontFamily::BOLD); - renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderStatusBar(); renderer.displayBuffer(); return; } @@ -639,7 +626,7 @@ void EpubReaderActivity::render(Activity::RenderLock&& lock) { if (section->currentPage < 0 || section->currentPage >= section->pageCount) { LOG_DBG("ERS", "Page out of bounds: %d (max %d)", section->currentPage, section->pageCount); renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_OUT_OF_BOUNDS), true, EpdFontFamily::BOLD); - renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderStatusBar(); renderer.displayBuffer(); return; } @@ -691,7 +678,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or bool imagePageWithAA = page->hasImages() && SETTINGS.textAntiAliasing; page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); - renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderStatusBar(); if (imagePageWithAA) { // Double FAST_REFRESH with selective image blanking (pablohc's technique): // HALF_REFRESH sets particles too firmly for the grayscale LUT to adjust. @@ -705,7 +692,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or // Re-render page content to restore images into the blanked area page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); - renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderStatusBar(); renderer.displayBuffer(HalDisplay::FAST_REFRESH); } else { renderer.displayBuffer(HalDisplay::HALF_REFRESH); @@ -745,111 +732,28 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or renderer.restoreBwBuffer(); } -void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom, - const int orientedMarginLeft) const { - const auto& metrics = UITheme::getInstance().getMetrics(); - - // determine visible status bar elements - const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; - const bool showBookProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_BOOK_PROGRESS_BAR; - const bool showChapterProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR; - const bool showBookPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showChapterTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showBatteryPercentage = - SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; - - // Position status bar near the bottom of the logical screen, regardless of orientation - const auto screenHeight = renderer.getScreenHeight(); - const auto textY = screenHeight - orientedMarginBottom - 4; - int progressTextWidth = 0; - +void EpubReaderActivity::renderStatusBar() const { // Calculate progress in book - const float sectionChapterProg = static_cast(section->currentPage) / section->pageCount; + const int currentPage = section->currentPage + 1; + const float pageCount = section->pageCount; + const float sectionChapterProg = (pageCount > 0) ? (static_cast(currentPage) / pageCount) : 0; const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100; - if (showProgressText || showProgressPercentage || showBookPercentage) { - // Right aligned text for progress counter - char progressStr[32]; + const int tocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); + std::string title; - // Hide percentage when progress bar is shown to reduce clutter - if (showProgressPercentage) { - snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", section->currentPage + 1, section->pageCount, - bookProgress); - } else if (showBookPercentage) { - snprintf(progressStr, sizeof(progressStr), "%.0f%%", bookProgress); - } else { - snprintf(progressStr, sizeof(progressStr), "%d/%d", section->currentPage + 1, section->pageCount); - } - - progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr); - renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, - progressStr); - } - - if (showBookProgressBar) { - // Draw progress bar at the very bottom of the screen, from edge to edge of viewable area - GUI.drawReadingProgressBar(renderer, static_cast(bookProgress)); - } - - if (showChapterProgressBar) { - // Draw chapter progress bar at the very bottom of the screen, from edge to edge of viewable area - const float chapterProgress = - (section->pageCount > 0) ? (static_cast(section->currentPage + 1) / section->pageCount) * 100 : 0; - GUI.drawReadingProgressBar(renderer, static_cast(chapterProgress)); - } - - if (showBattery) { - GUI.drawBatteryLeft(renderer, Rect{orientedMarginLeft + 1, textY, metrics.batteryWidth, metrics.batteryHeight}, - showBatteryPercentage); - } - - if (showChapterTitle) { - // Centered chatper title text - // Page width minus existing content with 30px padding on each side - const int rendererableScreenWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; - - const int batterySize = showBattery ? (showBatteryPercentage ? 50 : 20) : 0; - const int titleMarginLeft = batterySize + 30; - const int titleMarginRight = progressTextWidth + 30; - - // Attempt to center title on the screen, but if title is too wide then later we will center it within the - // available space. - int titleMarginLeftAdjusted = std::max(titleMarginLeft, titleMarginRight); - int availableTitleSpace = rendererableScreenWidth - 2 * titleMarginLeftAdjusted; - const int tocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); - - std::string title; - int titleWidth; + if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::CHAPTER_TITLE) { if (tocIndex == -1) { title = tr(STR_UNNAMED); - titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); } else { const auto tocItem = epub->getTocItem(tocIndex); title = tocItem.title; - titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); - if (titleWidth > availableTitleSpace) { - // Not enough space to center on the screen, center it within the remaining space instead - availableTitleSpace = rendererableScreenWidth - titleMarginLeft - titleMarginRight; - titleMarginLeftAdjusted = titleMarginLeft; - } - if (titleWidth > availableTitleSpace) { - title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTitleSpace); - titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); - } } - - renderer.drawText(SMALL_FONT_ID, - titleMarginLeftAdjusted + orientedMarginLeft + (availableTitleSpace - titleWidth) / 2, textY, - title.c_str()); + } else if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::BOOK_TITLE) { + title = epub->getTitle(); + } else { + title = ""; } + + GUI.drawStatusBar(renderer, bookProgress, currentPage, pageCount, title); } diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 861e590a..0805ef20 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -27,7 +27,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity { void renderContents(std::unique_ptr page, int orientedMarginTop, int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft); - void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const; + void renderStatusBar() const; void saveProgress(int spineIndex, int currentPage, int pageCount); // Jump to a percentage of the book (0-100), mapping it to spine and page. void jumpToPercent(int percent); diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 1f535c97..6535069c 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -15,8 +15,6 @@ namespace { constexpr unsigned long goHomeMs = 1000; -constexpr int statusBarMargin = 25; -constexpr int progressBarMarginTop = 1; constexpr size_t CHUNK_SIZE = 8 * 1024; // 8KB chunk for reading // Cache file magic and version @@ -131,28 +129,16 @@ void TxtReaderActivity::initializeReader() { cachedParagraphAlignment = SETTINGS.paragraphAlignment; // Calculate viewport dimensions - int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft; - renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom, - &orientedMarginLeft); - orientedMarginTop += cachedScreenMargin; - orientedMarginLeft += cachedScreenMargin; - orientedMarginRight += cachedScreenMargin; - orientedMarginBottom += cachedScreenMargin; + renderer.getOrientedViewableTRBL(&cachedOrientedMarginTop, &cachedOrientedMarginRight, &cachedOrientedMarginBottom, + &cachedOrientedMarginLeft); + cachedOrientedMarginTop += cachedScreenMargin; + cachedOrientedMarginLeft += cachedScreenMargin; + cachedOrientedMarginRight += cachedScreenMargin; + cachedOrientedMarginBottom += + std::max(cachedScreenMargin, static_cast(UITheme::getInstance().getStatusBarHeight())); - const auto& metrics = UITheme::getInstance().getMetrics(); - - // Add status bar margin - if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) { - // Add additional margin for status bar if progress bar is shown - const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - orientedMarginBottom += statusBarMargin - cachedScreenMargin + - (showProgressBar ? (metrics.bookProgressBarHeight + progressBarMarginTop) : 0); - } - - viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; - const int viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom; + viewportWidth = renderer.getScreenWidth() - cachedOrientedMarginLeft - cachedOrientedMarginRight; + const int viewportHeight = renderer.getScreenHeight() - cachedOrientedMarginTop - cachedOrientedMarginBottom; const int lineHeight = renderer.getLineHeight(cachedFontId); linesPerPage = viewportHeight / lineHeight; @@ -375,23 +361,15 @@ void TxtReaderActivity::render(Activity::RenderLock&&) { } void TxtReaderActivity::renderPage() { - int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft; - renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom, - &orientedMarginLeft); - orientedMarginTop += cachedScreenMargin; - orientedMarginLeft += cachedScreenMargin; - orientedMarginRight += cachedScreenMargin; - orientedMarginBottom += statusBarMargin; - const int lineHeight = renderer.getLineHeight(cachedFontId); const int contentWidth = viewportWidth; // Render text lines with alignment auto renderLines = [&]() { - int y = orientedMarginTop; + int y = cachedOrientedMarginTop; for (const auto& line : currentPageLines) { if (!line.empty()) { - int x = orientedMarginLeft; + int x = cachedOrientedMarginLeft; // Apply text alignment switch (cachedParagraphAlignment) { @@ -401,12 +379,12 @@ void TxtReaderActivity::renderPage() { break; case CrossPointSettings::CENTER_ALIGN: { int textWidth = renderer.getTextWidth(cachedFontId, line.c_str()); - x = orientedMarginLeft + (contentWidth - textWidth) / 2; + x = cachedOrientedMarginLeft + (contentWidth - textWidth) / 2; break; } case CrossPointSettings::RIGHT_ALIGN: { int textWidth = renderer.getTextWidth(cachedFontId, line.c_str()); - x = orientedMarginLeft + contentWidth - textWidth; + x = cachedOrientedMarginLeft + contentWidth - textWidth; break; } case CrossPointSettings::JUSTIFIED: @@ -423,7 +401,7 @@ void TxtReaderActivity::renderPage() { // First pass: BW rendering renderLines(); - renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderStatusBar(); if (pagesUntilFullRefresh <= 1) { renderer.displayBuffer(HalDisplay::HALF_REFRESH); @@ -456,78 +434,11 @@ void TxtReaderActivity::renderPage() { } } -void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom, - const int orientedMarginLeft) const { - const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; - const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_BOOK_PROGRESS_BAR; - const bool showChapterProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR; - const bool showBookPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::BOOK_PROGRESS_BAR || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR; - const bool showBatteryPercentage = - SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; - - const auto& metrics = UITheme::getInstance().getMetrics(); - const auto screenHeight = renderer.getScreenHeight(); - // Adjust text position upward when progress bar is shown to avoid overlap - const auto textY = screenHeight - orientedMarginBottom - 4; - int progressTextWidth = 0; - +void TxtReaderActivity::renderStatusBar() const { const float progress = totalPages > 0 ? (currentPage + 1) * 100.0f / totalPages : 0; + std::string title = txt->getTitle(); - if (showProgressText || showProgressPercentage || showBookPercentage) { - char progressStr[32]; - if (showProgressPercentage) { - snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", currentPage + 1, totalPages, progress); - } else if (showBookPercentage) { - snprintf(progressStr, sizeof(progressStr), "%.0f%%", progress); - } else { - snprintf(progressStr, sizeof(progressStr), "%d/%d", currentPage + 1, totalPages); - } - - progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr); - renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, - progressStr); - } - - if (showProgressBar) { - // Draw progress bar at the very bottom of the screen, from edge to edge of viewable area - GUI.drawReadingProgressBar(renderer, static_cast(progress)); - } - - if (showChapterProgressBar) { - // For text mode, treat the entire book as one chapter, so chapter progress == book progress - GUI.drawReadingProgressBar(renderer, static_cast(progress)); - } - - if (showBattery) { - GUI.drawBatteryLeft(renderer, Rect{orientedMarginLeft, textY, metrics.batteryWidth, metrics.batteryHeight}, - showBatteryPercentage); - } - - if (showTitle) { - const int titleMarginLeft = 50 + 30 + orientedMarginLeft; - const int titleMarginRight = progressTextWidth + 30 + orientedMarginRight; - const int availableTextWidth = renderer.getScreenWidth() - titleMarginLeft - titleMarginRight; - - std::string title = txt->getTitle(); - int titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); - if (titleWidth > availableTextWidth) { - title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTextWidth); - titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); - } - - renderer.drawText(SMALL_FONT_ID, titleMarginLeft + (availableTextWidth - titleWidth) / 2, textY, title.c_str()); - } + GUI.drawStatusBar(renderer, progress, currentPage + 1, totalPages, title); } void TxtReaderActivity::saveProgress() const { diff --git a/src/activities/reader/TxtReaderActivity.h b/src/activities/reader/TxtReaderActivity.h index c63009d2..c3b2ad7f 100644 --- a/src/activities/reader/TxtReaderActivity.h +++ b/src/activities/reader/TxtReaderActivity.h @@ -26,11 +26,15 @@ class TxtReaderActivity final : public ActivityWithSubactivity { // Cached settings for cache validation (different fonts/margins require re-indexing) int cachedFontId = 0; - int cachedScreenMargin = 0; + uint8_t cachedScreenMargin = 0; uint8_t cachedParagraphAlignment = CrossPointSettings::LEFT_ALIGN; + int cachedOrientedMarginTop = 0; + int cachedOrientedMarginRight = 0; + int cachedOrientedMarginBottom = 0; + int cachedOrientedMarginLeft = 0; void renderPage(); - void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const; + void renderStatusBar() const; void initializeReader(); bool loadPageAtOffset(size_t offset, std::vector& outLines, size_t& nextOffset); diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 2ffa2b2f..eab84cbb 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -12,6 +12,7 @@ #include "MappedInputManager.h" #include "OtaUpdateActivity.h" #include "SettingsList.h" +#include "StatusBarSettingsActivity.h" #include "activities/network/WifiSelectionActivity.h" #include "components/UITheme.h" #include "fontIds.h" @@ -51,6 +52,7 @@ void SettingsActivity::onEnter() { systemSettings.push_back(SettingInfo::Action(StrId::STR_CLEAR_READING_CACHE, SettingAction::ClearCache)); systemSettings.push_back(SettingInfo::Action(StrId::STR_CHECK_UPDATES, SettingAction::CheckForUpdates)); systemSettings.push_back(SettingInfo::Action(StrId::STR_LANGUAGE, SettingAction::Language)); + readerSettings.push_back(SettingInfo::Action(StrId::STR_CUSTOMISE_STATUS_BAR, SettingAction::CustomiseStatusBar)); // Reset selection to first category selectedCategoryIndex = 0; @@ -181,6 +183,9 @@ void SettingsActivity::toggleCurrentSetting() { case SettingAction::RemapFrontButtons: enterSubActivity(new ButtonRemapActivity(renderer, mappedInput, onComplete)); break; + case SettingAction::CustomiseStatusBar: + enterSubActivity(new StatusBarSettingsActivity(renderer, mappedInput, onComplete)); + break; case SettingAction::KOReaderSync: enterSubActivity(new KOReaderSettingsActivity(renderer, mappedInput, onComplete)); break; @@ -259,4 +264,4 @@ void SettingsActivity::render(Activity::RenderLock&&) { // Always use standard refresh for settings screen renderer.displayBuffer(); -} \ No newline at end of file +} diff --git a/src/activities/settings/SettingsActivity.h b/src/activities/settings/SettingsActivity.h index 802060e9..62f98dc5 100644 --- a/src/activities/settings/SettingsActivity.h +++ b/src/activities/settings/SettingsActivity.h @@ -15,6 +15,7 @@ enum class SettingType { TOGGLE, ENUM, ACTION, VALUE, STRING }; enum class SettingAction { None, RemapFrontButtons, + CustomiseStatusBar, KOReaderSync, OPDSBrowser, Network, diff --git a/src/activities/settings/StatusBarSettingsActivity.cpp b/src/activities/settings/StatusBarSettingsActivity.cpp new file mode 100644 index 00000000..675f73dc --- /dev/null +++ b/src/activities/settings/StatusBarSettingsActivity.cpp @@ -0,0 +1,174 @@ +#include "StatusBarSettingsActivity.h" + +#include +#include + +#include + +#include "CrossPointSettings.h" +#include "MappedInputManager.h" +#include "components/UITheme.h" +#include "fontIds.h" + +namespace { +constexpr int MENU_ITEMS = 6; +const StrId menuNames[MENU_ITEMS] = {StrId::STR_CHAPTER_PAGE_COUNT, + StrId::STR_BOOK_PROGRESS_PERCENTAGE, + StrId::STR_PROGRESS_BAR, + StrId::STR_PROGRESS_BAR_THICKNESS, + StrId::STR_TITLE, + StrId::STR_BATTERY}; +constexpr int PROGRESS_BAR_ITEMS = 3; +const StrId progressBarNames[PROGRESS_BAR_ITEMS] = {StrId::STR_BOOK, StrId::STR_CHAPTER, StrId::STR_HIDE}; + +constexpr int PROGRESS_BAR_THICKNESS_ITEMS = 3; +const StrId progressBarThicknessNames[PROGRESS_BAR_THICKNESS_ITEMS] = { + StrId::STR_PROGRESS_BAR_THIN, StrId::STR_PROGRESS_BAR_MEDIUM, StrId::STR_PROGRESS_BAR_THICK}; + +constexpr int TITLE_ITEMS = 3; +const StrId titleNames[TITLE_ITEMS] = {StrId::STR_BOOK, StrId::STR_CHAPTER, StrId::STR_HIDE}; + +const char* translatedShow = tr(STR_SHOW); +const char* translatedHide = tr(STR_HIDE); + +const int widthMargin = 10; +const int verticalPreviewPadding = 50; +const int verticalPreviewTextPadding = 40; +} // namespace + +void StatusBarSettingsActivity::onEnter() { + Activity::onEnter(); + + selectedIndex = 0; + + // Clamp statusBarProgressBar and statusBarTitle in case of corrupt/migrated data + if (SETTINGS.statusBarProgressBar >= PROGRESS_BAR_ITEMS) { + SETTINGS.statusBarProgressBar = CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS; + } + + if (SETTINGS.statusBarTitle >= PROGRESS_BAR_THICKNESS_ITEMS) { + SETTINGS.statusBarTitle = CrossPointSettings::STATUS_BAR_PROGRESS_BAR_THICKNESS::PROGRESS_BAR_NORMAL; + } + + if (SETTINGS.statusBarTitle >= TITLE_ITEMS) { + SETTINGS.statusBarTitle = CrossPointSettings::STATUS_BAR_TITLE::HIDE_TITLE; + } + + requestUpdate(); +} + +void StatusBarSettingsActivity::onExit() { Activity::onExit(); } + +void StatusBarSettingsActivity::loop() { + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onBack(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + handleSelection(); + requestUpdate(); + return; + } + + // Handle navigation + buttonNavigator.onNextRelease([this] { + selectedIndex = ButtonNavigator::nextIndex(selectedIndex, MENU_ITEMS); + requestUpdate(); + }); + + buttonNavigator.onPreviousRelease([this] { + selectedIndex = ButtonNavigator::previousIndex(selectedIndex, MENU_ITEMS); + requestUpdate(); + }); + + buttonNavigator.onNextContinuous([this] { + selectedIndex = ButtonNavigator::nextIndex(selectedIndex, MENU_ITEMS); + requestUpdate(); + }); + + buttonNavigator.onPreviousContinuous([this] { + selectedIndex = ButtonNavigator::previousIndex(selectedIndex, MENU_ITEMS); + requestUpdate(); + }); +} + +void StatusBarSettingsActivity::handleSelection() { + if (selectedIndex == 0) { + // Chapter Page Count + SETTINGS.statusBarChapterPageCount = (SETTINGS.statusBarChapterPageCount + 1) % 2; + } else if (selectedIndex == 1) { + // Book Progress % + SETTINGS.statusBarBookProgressPercentage = (SETTINGS.statusBarBookProgressPercentage + 1) % 2; + } else if (selectedIndex == 2) { + // Progress Bar + SETTINGS.statusBarProgressBar = (SETTINGS.statusBarProgressBar + 1) % PROGRESS_BAR_ITEMS; + } else if (selectedIndex == 3) { + // Progress Bar Thickness + SETTINGS.statusBarProgressBarThickness = + (SETTINGS.statusBarProgressBarThickness + 1) % PROGRESS_BAR_THICKNESS_ITEMS; + } else if (selectedIndex == 4) { + // Chapter Title + SETTINGS.statusBarTitle = (SETTINGS.statusBarTitle + 1) % TITLE_ITEMS; + } else if (selectedIndex == 5) { + // Show Battery + SETTINGS.statusBarBattery = (SETTINGS.statusBarBattery + 1) % 2; + } + SETTINGS.saveToFile(); +} + +void StatusBarSettingsActivity::render(Activity::RenderLock&&) { + renderer.clearScreen(); + + auto metrics = UITheme::getInstance().getMetrics(); + const auto pageWidth = renderer.getScreenWidth(); + const auto pageHeight = renderer.getScreenHeight(); + + GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_CUSTOMISE_STATUS_BAR)); + + const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; + const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2; + GUI.drawList( + renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast(MENU_ITEMS), + static_cast(selectedIndex), [](int index) { return std::string(I18N.get(menuNames[index])); }, nullptr, + nullptr, + [this](int index) { + // Draw status for each setting + if (index == 0) { + return SETTINGS.statusBarChapterPageCount ? translatedShow : translatedHide; + } else if (index == 1) { + return SETTINGS.statusBarBookProgressPercentage ? translatedShow : translatedHide; + } else if (index == 2) { + return I18N.get(progressBarNames[SETTINGS.statusBarProgressBar]); + } else if (index == 3) { + return I18N.get(progressBarThicknessNames[SETTINGS.statusBarProgressBarThickness]); + } else if (index == 4) { + return I18N.get(titleNames[SETTINGS.statusBarTitle]); + } else if (index == 5) { + return SETTINGS.statusBarBattery ? translatedShow : translatedHide; + } else { + return translatedHide; + } + }, + true); + + // Draw button hints + const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_TOGGLE), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + std::string title; + if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::BOOK_TITLE) { + title = tr(STR_EXAMPLE_BOOK); + } else { + title = tr(STR_EXAMPLE_CHAPTER); + } + + GUI.drawStatusBar(renderer, 75, 8, 32, title, verticalPreviewPadding); + + renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, + renderer.getScreenHeight() - UITheme::getInstance().getStatusBarHeight() - verticalPreviewPadding - + verticalPreviewTextPadding, + tr(STR_PREVIEW)); + + renderer.displayBuffer(); +} diff --git a/src/activities/settings/StatusBarSettingsActivity.h b/src/activities/settings/StatusBarSettingsActivity.h new file mode 100644 index 00000000..4c7e4ed0 --- /dev/null +++ b/src/activities/settings/StatusBarSettingsActivity.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include + +#include "activities/Activity.h" +#include "util/ButtonNavigator.h" + +// Reader status bar configuration activity +class StatusBarSettingsActivity final : public Activity { + public: + explicit StatusBarSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onBack) + : Activity("StatusBarSettings", renderer, mappedInput), onBack(onBack) {} + + void onEnter() override; + void onExit() override; + void loop() override; + void render(Activity::RenderLock&&) override; + + private: + ButtonNavigator buttonNavigator; + + int selectedIndex = 0; + + const std::function onBack; + + static void taskTrampoline(void* param); + void handleSelection(); +}; diff --git a/src/components/UITheme.cpp b/src/components/UITheme.cpp index 6555c09f..8a8a559e 100644 --- a/src/components/UITheme.cpp +++ b/src/components/UITheme.cpp @@ -90,3 +90,16 @@ UIIcon UITheme::getFileIcon(std::string filename) { } return File; } + +int UITheme::getStatusBarHeight() { + const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); + + // Add status bar margin + const bool showStatusBar = SETTINGS.statusBarChapterPageCount || SETTINGS.statusBarBookProgressPercentage || + SETTINGS.statusBarTitle != CrossPointSettings::STATUS_BAR_TITLE::HIDE_TITLE || + SETTINGS.statusBarBattery; + const bool showProgressBar = + SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS; + return (showStatusBar ? (metrics.statusBarVerticalMargin) : 0) + + (showProgressBar ? (((SETTINGS.statusBarProgressBarThickness + 1) * 2) + metrics.progressBarMarginTop) : 0); +} diff --git a/src/components/UITheme.h b/src/components/UITheme.h index 054ee89e..0478fd3e 100644 --- a/src/components/UITheme.h +++ b/src/components/UITheme.h @@ -22,6 +22,7 @@ class UITheme { bool hasSubtitle); static std::string getCoverThumbPath(std::string coverBmpPath, int coverHeight); static UIIcon getFileIcon(std::string filename); + static int getStatusBarHeight(); private: const ThemeMetrics* currentMetrics; diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index a3766ba0..1020117b 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -628,16 +628,98 @@ void BaseTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layou renderer.displayBuffer(HalDisplay::FAST_REFRESH); } -void BaseTheme::drawReadingProgressBar(const GfxRenderer& renderer, const size_t bookProgress) const { - int vieweableMarginTop, vieweableMarginRight, vieweableMarginBottom, vieweableMarginLeft; - renderer.getOrientedViewableTRBL(&vieweableMarginTop, &vieweableMarginRight, &vieweableMarginBottom, - &vieweableMarginLeft); +void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage, + const int pageCount, std::string title, const int paddingBottom) const { + auto metrics = UITheme::getInstance().getMetrics(); + int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft; + renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom, + &orientedMarginLeft); - const int progressBarMaxWidth = renderer.getScreenWidth() - vieweableMarginLeft - vieweableMarginRight; - const int progressBarY = - renderer.getScreenHeight() - vieweableMarginBottom - BaseMetrics::values.bookProgressBarHeight; - const int barWidth = progressBarMaxWidth * bookProgress / 100; - renderer.fillRect(vieweableMarginLeft, progressBarY, barWidth, BaseMetrics::values.bookProgressBarHeight, true); + // Draw Progress Text + const auto screenHeight = renderer.getScreenHeight(); + const auto textY = + screenHeight - UITheme::getInstance().getStatusBarHeight() - orientedMarginBottom - paddingBottom - 4; + int progressTextWidth = 0; + + if (SETTINGS.statusBarBookProgressPercentage || SETTINGS.statusBarChapterPageCount) { + // Right aligned text for progress counter + char progressStr[32]; + + if (SETTINGS.statusBarBookProgressPercentage && SETTINGS.statusBarChapterPageCount) { + snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", currentPage, pageCount, bookProgress); + } else if (SETTINGS.statusBarBookProgressPercentage) { + snprintf(progressStr, sizeof(progressStr), "%.0f%%", bookProgress); + } else { + snprintf(progressStr, sizeof(progressStr), "%d/%d", currentPage, pageCount); + } + + progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr); + renderer.drawText( + SMALL_FONT_ID, + renderer.getScreenWidth() - metrics.statusBarHorizontalMargin - orientedMarginRight - progressTextWidth, textY, + progressStr); + } + + // Draw Progress Bar + if (SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS) { + const int progressBarMaxWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; + const int progressBarY = renderer.getScreenHeight() - orientedMarginBottom - + ((SETTINGS.statusBarProgressBarThickness + 1) * 2) - paddingBottom; + size_t progress; + if (SETTINGS.statusBarProgressBar == CrossPointSettings::STATUS_BAR_PROGRESS_BAR::BOOK_PROGRESS) { + progress = static_cast(bookProgress); + } else { + // Chapter progress + progress = (pageCount > 0) ? (static_cast(currentPage) / pageCount) * 100 : 0; + } + const int barWidth = progressBarMaxWidth * progress / 100; + renderer.fillRect(orientedMarginLeft, progressBarY, barWidth, ((SETTINGS.statusBarProgressBarThickness + 1) * 2), + true); + } + + // Draw Battery + const bool showBatteryPercentage = + SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; + if (SETTINGS.statusBarBattery) { + GUI.drawBatteryLeft(renderer, + Rect{metrics.statusBarHorizontalMargin + orientedMarginLeft + 1, textY, metrics.batteryWidth, + metrics.batteryHeight}, + showBatteryPercentage); + } + + // Draw Title + if (SETTINGS.statusBarTitle != CrossPointSettings::STATUS_BAR_TITLE::HIDE_TITLE) { + // Centered chapter title text + // Page width minus existing content with 30px padding on each side + const int rendererableScreenWidth = + renderer.getScreenWidth() - (metrics.statusBarHorizontalMargin * 2) - orientedMarginLeft - orientedMarginRight; + + const int batterySize = SETTINGS.statusBarBattery ? (showBatteryPercentage ? 50 : 20) : 0; + const int titleMarginLeft = batterySize + 30; + const int titleMarginRight = progressTextWidth + 30; + + // Attempt to center title on the screen, but if title is too wide then later we will center it within the + // available space. + int titleMarginLeftAdjusted = std::max(titleMarginLeft, titleMarginRight); + int availableTitleSpace = rendererableScreenWidth - 2 * titleMarginLeftAdjusted; + + int titleWidth; + titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); + if (titleWidth > availableTitleSpace) { + // Not enough space to center on the screen, center it within the remaining space instead + availableTitleSpace = rendererableScreenWidth - titleMarginLeft - titleMarginRight; + titleMarginLeftAdjusted = titleMarginLeft; + } + if (titleWidth > availableTitleSpace) { + title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTitleSpace); + titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); + } + + renderer.drawText(SMALL_FONT_ID, + titleMarginLeftAdjusted + metrics.statusBarHorizontalMargin + orientedMarginLeft + + (availableTitleSpace - titleWidth) / 2, + textY, title.c_str()); + } } void BaseTheme::drawHelpText(const GfxRenderer& renderer, Rect rect, const char* label) const { diff --git a/src/components/themes/BaseTheme.h b/src/components/themes/BaseTheme.h index 5c70d4d2..f11ce104 100644 --- a/src/components/themes/BaseTheme.h +++ b/src/components/themes/BaseTheme.h @@ -53,7 +53,9 @@ struct ThemeMetrics { int sideButtonHintsWidth; int progressBarHeight; - int bookProgressBarHeight; + int progressBarMarginTop; + int statusBarHorizontalMargin; + int statusBarVerticalMargin; int keyboardKeyWidth; int keyboardKeyHeight; @@ -90,7 +92,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 15, .buttonHintsHeight = 40, .sideButtonHintsWidth = 30, .progressBarHeight = 16, - .bookProgressBarHeight = 4, + .progressBarMarginTop = 1, + .statusBarHorizontalMargin = 5, + .statusBarVerticalMargin = 19, .keyboardKeyWidth = 22, .keyboardKeyHeight = 30, .keyboardKeySpacing = 10, @@ -131,7 +135,8 @@ class BaseTheme { const std::function& rowIcon) const; virtual Rect drawPopup(const GfxRenderer& renderer, const char* message) const; virtual void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const; - virtual void drawReadingProgressBar(const GfxRenderer& renderer, const size_t bookProgress) const; + virtual void drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage, + const int pageCount, std::string title, const int paddingBottom = 0) const; virtual void drawHelpText(const GfxRenderer& renderer, Rect rect, const char* label) const; virtual void drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth) const; virtual void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected) const; diff --git a/src/components/themes/lyra/Lyra3CoversTheme.h b/src/components/themes/lyra/Lyra3CoversTheme.h index a9177d3f..dde92001 100644 --- a/src/components/themes/lyra/Lyra3CoversTheme.h +++ b/src/components/themes/lyra/Lyra3CoversTheme.h @@ -30,7 +30,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 16, .buttonHintsHeight = 40, .sideButtonHintsWidth = 30, .progressBarHeight = 16, - .bookProgressBarHeight = 4, + .progressBarMarginTop = 1, + .statusBarHorizontalMargin = 5, + .statusBarVerticalMargin = 19, .keyboardKeyWidth = 31, .keyboardKeyHeight = 50, .keyboardKeySpacing = 0, diff --git a/src/components/themes/lyra/LyraTheme.h b/src/components/themes/lyra/LyraTheme.h index 3fc451a8..1e953a81 100644 --- a/src/components/themes/lyra/LyraTheme.h +++ b/src/components/themes/lyra/LyraTheme.h @@ -28,7 +28,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 16, .buttonHintsHeight = 40, .sideButtonHintsWidth = 30, .progressBarHeight = 16, - .bookProgressBarHeight = 4, + .progressBarMarginTop = 1, + .statusBarHorizontalMargin = 5, + .statusBarVerticalMargin = 19, .keyboardKeyWidth = 31, .keyboardKeyHeight = 50, .keyboardKeySpacing = 0,