#pragma once #include #include #include "CrossPointSettings.h" #include "KOReaderCredentialStore.h" #include "activities/settings/SettingsActivity.h" // Compile-time table of available font families and their enum values. // Used by the DynamicEnum getter/setter to map between list indices and stored FONT_FAMILY values. struct FontFamilyMapping { const char* name; uint8_t value; }; inline constexpr FontFamilyMapping kFontFamilyMappings[] = { #ifndef OMIT_BOOKERLY {"Bookerly", CrossPointSettings::BOOKERLY}, #endif #ifndef OMIT_NOTOSANS {"Noto Sans", CrossPointSettings::NOTOSANS}, #endif #ifndef OMIT_OPENDYSLEXIC {"Open Dyslexic", CrossPointSettings::OPENDYSLEXIC}, #endif }; inline constexpr size_t kFontFamilyMappingCount = sizeof(kFontFamilyMappings) / sizeof(kFontFamilyMappings[0]); static_assert(kFontFamilyMappingCount > 0, "At least one font family must be available"); // Shared settings list used by both the device settings UI and the web settings API. // Each entry has a key (for JSON API) and category (for grouping). // ACTION-type entries and entries without a key are device-only. inline std::vector getSettingsList() { // Build font family StrId options from the compile-time mapping table constexpr StrId kFontFamilyStrIds[] = { #ifndef OMIT_BOOKERLY StrId::STR_BOOKERLY, #endif #ifndef OMIT_NOTOSANS StrId::STR_NOTO_SANS, #endif #ifndef OMIT_OPENDYSLEXIC StrId::STR_OPEN_DYSLEXIC, #endif }; std::vector fontFamilyStrIds(std::begin(kFontFamilyStrIds), std::end(kFontFamilyStrIds)); return { // --- Display --- SettingInfo::Enum(StrId::STR_SLEEP_SCREEN, &CrossPointSettings::sleepScreen, {StrId::STR_DARK, StrId::STR_LIGHT, StrId::STR_CUSTOM, StrId::STR_COVER, StrId::STR_NONE_OPT, StrId::STR_COVER_CUSTOM}, "sleepScreen", StrId::STR_CAT_DISPLAY), SettingInfo::Enum(StrId::STR_SLEEP_COVER_MODE, &CrossPointSettings::sleepScreenCoverMode, {StrId::STR_FIT, StrId::STR_CROP}, "sleepScreenCoverMode", StrId::STR_CAT_DISPLAY), 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_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_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), SettingInfo::Enum( StrId::STR_REFRESH_FREQ, &CrossPointSettings::refreshFrequency, {StrId::STR_PAGES_1, StrId::STR_PAGES_5, StrId::STR_PAGES_10, StrId::STR_PAGES_15, StrId::STR_PAGES_30}, "refreshFrequency", StrId::STR_CAT_DISPLAY), SettingInfo::Enum(StrId::STR_UI_THEME, &CrossPointSettings::uiTheme, {StrId::STR_THEME_CLASSIC, StrId::STR_THEME_LYRA, StrId::STR_THEME_LYRA_EXTENDED}, "uiTheme", StrId::STR_CAT_DISPLAY), SettingInfo::Toggle(StrId::STR_SUNLIGHT_FADING_FIX, &CrossPointSettings::fadingFix, "fadingFix", StrId::STR_CAT_DISPLAY), // --- Clock --- SettingInfo::Enum(StrId::STR_CLOCK, &CrossPointSettings::clockFormat, {StrId::STR_STATE_OFF, StrId::STR_CLOCK_AMPM, StrId::STR_CLOCK_24H}, "clockFormat", StrId::STR_CAT_CLOCK), SettingInfo::Enum(StrId::STR_CLOCK_SIZE, &CrossPointSettings::clockSize, {StrId::STR_CLOCK_SIZE_SMALL, StrId::STR_CLOCK_SIZE_MEDIUM, StrId::STR_CLOCK_SIZE_LARGE}, "clockSize", StrId::STR_CAT_CLOCK), SettingInfo::Enum(StrId::STR_TIMEZONE, &CrossPointSettings::timezone, {StrId::STR_TZ_UTC, StrId::STR_TZ_EASTERN, StrId::STR_TZ_CENTRAL, StrId::STR_TZ_MOUNTAIN, StrId::STR_TZ_PACIFIC, StrId::STR_TZ_ALASKA, StrId::STR_TZ_HAWAII, StrId::STR_TZ_CUSTOM}, "timezone", StrId::STR_CAT_CLOCK), // --- Reader --- SettingInfo::DynamicEnum( StrId::STR_FONT_FAMILY, std::move(fontFamilyStrIds), []() -> uint8_t { for (uint8_t i = 0; i < kFontFamilyMappingCount; i++) { if (kFontFamilyMappings[i].value == SETTINGS.fontFamily) return i; } return 0; // fallback to first available family }, [](uint8_t idx) { if (idx < kFontFamilyMappingCount) { SETTINGS.fontFamily = kFontFamilyMappings[idx].value; } }, "fontFamily", StrId::STR_CAT_READER), SettingInfo::Enum(StrId::STR_FONT_SIZE, &CrossPointSettings::fontSize, {StrId::STR_SMALL, StrId::STR_MEDIUM, StrId::STR_LARGE, StrId::STR_X_LARGE}, "fontSize", StrId::STR_CAT_READER), SettingInfo::Enum(StrId::STR_LINE_SPACING, &CrossPointSettings::lineSpacing, {StrId::STR_TIGHT, StrId::STR_NORMAL, StrId::STR_WIDE}, "lineSpacing", StrId::STR_CAT_READER), SettingInfo::Value(StrId::STR_SCREEN_MARGIN, &CrossPointSettings::screenMargin, {5, 40, 5}, "screenMargin", StrId::STR_CAT_READER), SettingInfo::Enum(StrId::STR_PARA_ALIGNMENT, &CrossPointSettings::paragraphAlignment, {StrId::STR_JUSTIFY, StrId::STR_ALIGN_LEFT, StrId::STR_CENTER, StrId::STR_ALIGN_RIGHT, StrId::STR_BOOK_S_STYLE}, "paragraphAlignment", StrId::STR_CAT_READER), SettingInfo::Toggle(StrId::STR_EMBEDDED_STYLE, &CrossPointSettings::embeddedStyle, "embeddedStyle", StrId::STR_CAT_READER), SettingInfo::Toggle(StrId::STR_HYPHENATION, &CrossPointSettings::hyphenationEnabled, "hyphenationEnabled", StrId::STR_CAT_READER), SettingInfo::Enum(StrId::STR_ORIENTATION, &CrossPointSettings::orientation, {StrId::STR_PORTRAIT, StrId::STR_LANDSCAPE_CW, StrId::STR_INVERTED, StrId::STR_LANDSCAPE_CCW}, "orientation", StrId::STR_CAT_READER), SettingInfo::DynamicEnum( StrId::STR_PREFERRED_PORTRAIT, {StrId::STR_PORTRAIT, StrId::STR_INVERTED}, [] { return static_cast(SETTINGS.preferredPortrait == CrossPointSettings::INVERTED ? 1 : 0); }, [](uint8_t idx) { SETTINGS.preferredPortrait = (idx == 1) ? CrossPointSettings::INVERTED : CrossPointSettings::PORTRAIT; }, "preferredPortrait", StrId::STR_CAT_READER), SettingInfo::DynamicEnum( StrId::STR_PREFERRED_LANDSCAPE, {StrId::STR_LANDSCAPE_CW, StrId::STR_LANDSCAPE_CCW}, [] { return static_cast(SETTINGS.preferredLandscape == CrossPointSettings::LANDSCAPE_CCW ? 1 : 0); }, [](uint8_t idx) { SETTINGS.preferredLandscape = (idx == 1) ? CrossPointSettings::LANDSCAPE_CCW : CrossPointSettings::LANDSCAPE_CW; }, "preferredLandscape", StrId::STR_CAT_READER), SettingInfo::Toggle(StrId::STR_EXTRA_SPACING, &CrossPointSettings::extraParagraphSpacing, "extraParagraphSpacing", 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), SettingInfo::Toggle(StrId::STR_LONG_PRESS_SKIP, &CrossPointSettings::longPressChapterSkip, "longPressChapterSkip", StrId::STR_CAT_CONTROLS), SettingInfo::Enum(StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn, {StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN}, "shortPwrBtn", StrId::STR_CAT_CONTROLS), // --- System --- SettingInfo::Enum(StrId::STR_TIME_TO_SLEEP, &CrossPointSettings::sleepTimeout, {StrId::STR_MIN_1, StrId::STR_MIN_5, StrId::STR_MIN_10, StrId::STR_MIN_15, StrId::STR_MIN_30}, "sleepTimeout", StrId::STR_CAT_SYSTEM), // --- KOReader Sync (web-only, uses KOReaderCredentialStore) --- SettingInfo::DynamicString( StrId::STR_KOREADER_USERNAME, [] { return KOREADER_STORE.getUsername(); }, [](const std::string& v) { KOREADER_STORE.setCredentials(v, KOREADER_STORE.getPassword()); KOREADER_STORE.saveToFile(); }, "koUsername", StrId::STR_KOREADER_SYNC), SettingInfo::DynamicString( StrId::STR_KOREADER_PASSWORD, [] { return KOREADER_STORE.getPassword(); }, [](const std::string& v) { KOREADER_STORE.setCredentials(KOREADER_STORE.getUsername(), v); KOREADER_STORE.saveToFile(); }, "koPassword", StrId::STR_KOREADER_SYNC), SettingInfo::DynamicString( StrId::STR_SYNC_SERVER_URL, [] { return KOREADER_STORE.getServerUrl(); }, [](const std::string& v) { KOREADER_STORE.setServerUrl(v); KOREADER_STORE.saveToFile(); }, "koServerUrl", StrId::STR_KOREADER_SYNC), SettingInfo::DynamicEnum( StrId::STR_DOCUMENT_MATCHING, {StrId::STR_FILENAME, StrId::STR_BINARY}, [] { return static_cast(KOREADER_STORE.getMatchMethod()); }, [](uint8_t v) { KOREADER_STORE.setMatchMethod(static_cast(v)); KOREADER_STORE.saveToFile(); }, "koMatchMethod", StrId::STR_KOREADER_SYNC), // --- OPDS Browser (web-only, uses CrossPointSettings char arrays) --- SettingInfo::String(StrId::STR_OPDS_SERVER_URL, SETTINGS.opdsServerUrl, sizeof(SETTINGS.opdsServerUrl), "opdsServerUrl", StrId::STR_OPDS_BROWSER), SettingInfo::String(StrId::STR_USERNAME, SETTINGS.opdsUsername, sizeof(SETTINGS.opdsUsername), "opdsUsername", StrId::STR_OPDS_BROWSER), SettingInfo::String(StrId::STR_PASSWORD, SETTINGS.opdsPassword, sizeof(SETTINGS.opdsPassword), "opdsPassword", StrId::STR_OPDS_BROWSER), }; }