mod: Phase 3 — Re-port unmerged upstream PRs

Re-applied upstream PRs not yet merged to upstream/master:

- #1055: Byte-level framebuffer writes (fillPhysicalHSpan*,
  optimized fillRect/drawLine/fillRectDither/fillPolygon)
- #1027: Word-width cache (FNV-1a, 128-entry) and hyphenation
  early exit in ParsedText for 7-9% layout speedup
- #1068: Already present in upstream — URL hyphenation fix
- #1019: Already present in upstream — file extensions in browser
- #1090/#1185/#1217: KOReader sync improvements — binary credential
  store, document hash caching, ChapterXPathIndexer integration
- #1209: OPDS multi-server — OpdsBookBrowserActivity accepts
  OpdsServer, directory picker for downloads, download-complete
  prompt with open/back options
- #857: Dictionary activities already ported in Phase 1/2
- #1003: Placeholder cover already integrated in Phase 2

Also fixed: STR_OFF i18n string, include paths, replaced
Epub::isValidThumbnailBmp with Storage.exists, replaced
StringUtils::checkFileExtension with FsHelpers equivalents.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-07 16:15:42 -05:00
parent 30473c27d3
commit 60a3e21c0e
25 changed files with 811 additions and 295 deletions

View File

@@ -213,44 +213,6 @@ bool JsonSettingsIO::loadSettings(CrossPointSettings& s, const char* json, bool*
return true;
}
// ---- KOReaderCredentialStore ----
bool JsonSettingsIO::saveKOReader(const KOReaderCredentialStore& store, const char* path) {
JsonDocument doc;
doc["username"] = store.getUsername();
doc["password_obf"] = obfuscation::obfuscateToBase64(store.getPassword());
doc["serverUrl"] = store.getServerUrl();
doc["matchMethod"] = static_cast<uint8_t>(store.getMatchMethod());
String json;
serializeJson(doc, json);
return Storage.writeFile(path, json);
}
bool JsonSettingsIO::loadKOReader(KOReaderCredentialStore& store, const char* json, bool* needsResave) {
if (needsResave) *needsResave = false;
JsonDocument doc;
auto error = deserializeJson(doc, json);
if (error) {
LOG_ERR("KRS", "JSON parse error: %s", error.c_str());
return false;
}
store.username = doc["username"] | std::string("");
bool ok = false;
store.password = obfuscation::deobfuscateFromBase64(doc["password_obf"] | "", &ok);
if (!ok || store.password.empty()) {
store.password = doc["password"] | std::string("");
if (!store.password.empty() && needsResave) *needsResave = true;
}
store.serverUrl = doc["serverUrl"] | std::string("");
uint8_t method = doc["matchMethod"] | (uint8_t)0;
store.matchMethod = static_cast<DocumentMatchMethod>(method);
LOG_DBG("KRS", "Loaded KOReader credentials for user: %s", store.username.c_str());
return true;
}
// ---- WifiCredentialStore ----
bool JsonSettingsIO::saveWifi(const WifiCredentialStore& store, const char* path) {