Brings ~55 mod-exclusive files to the upstream-based mod/master-resync branch: Activities (migrated to new ActivityManager pattern): - Clock/Time: SetTimeActivity, SetTimezoneOffsetActivity, NtpSyncActivity - Dictionary: DictionaryDefinitionActivity, DictionarySuggestionsActivity, DictionaryWordSelectActivity, LookedUpWordsActivity - Bookmark: EpubReaderBookmarkSelectionActivity - Book management: BookManageMenuActivity, EndOfBookMenuActivity - OPDS: OpdsServerListActivity, OpdsSettingsActivity - Utility: DirectoryPickerActivity, NumericStepperActivity Utilities (unchanged): - BookManager, BookSettings, BookmarkStore, BootNtpSync - Dictionary, LookupHistory, TimeSync, OpdsServerStore Libraries: PlaceholderCover, TableData, ChapterXPathIndexer Scripts: inject_mod_version, generate_book_icon, preview_placeholder_cover Docs: KOReader sync XPath mapping Migration changes: - ActivityWithSubactivity -> Activity base class - Callback constructors -> finish()/setResult() pattern - enterNewActivity() -> startActivityForResult() - Activity::RenderLock&& -> RenderLock&& These files won't compile yet - they reference mod settings and I18n strings that will be added in subsequent phases. Made-with: Cursor
48 lines
3.5 KiB
Markdown
48 lines
3.5 KiB
Markdown
# Dictionary Feature Bug Fixes (Round 3)
|
||
|
||
**Date:** 2026-02-12
|
||
**Branch:** mod/add-dictionary
|
||
|
||
## Task
|
||
|
||
Fix three issues reported after round 2 of dictionary fixes.
|
||
|
||
## Changes Made
|
||
|
||
### 1. Fix: Definitions truncated for some words (Dictionary.cpp)
|
||
|
||
**Root cause:** The `asciiCaseCmp` case-insensitive match introduced in round 2 returns the *first* case variant found in the index. In StarDict order, "Professor" (capitalized) sorts before "professor" (lowercase). If the dictionary has separate entries for each — e.g., "Professor" as a title (short definition) and "professor" as the common noun (full multi-page definition) — the shorter entry is returned.
|
||
|
||
**Fix:** The linear scan in `searchIndex` now remembers the first case-insensitive match as a fallback, but continues scanning adjacent entries (case variants are always adjacent in StarDict order). If an exact case-sensitive match is found, it's used immediately. Otherwise, the first case-insensitive match is used. This ensures `cleanWord("professor")` → `"professor"` finds the full lowercase entry, not the shorter capitalized one.
|
||
|
||
**Files:** `src/util/Dictionary.cpp`
|
||
|
||
### 2. Fix: Non-renderable foreign script characters in definitions (DictionaryDefinitionActivity)
|
||
|
||
**Root cause:** Dictionary definitions include text from other languages (Chinese, Greek, Arabic, Cyrillic, etc.) as etymological references or examples. These characters aren't in the e-ink bitmap font and render as empty boxes. This is the same class of issue as the IPA pronunciation fix from round 2, but affecting inline content within definitions.
|
||
|
||
**Fix:**
|
||
- Added `isRenderableCodepoint(uint32_t cp)` static helper that whitelists character ranges the e-ink font supports:
|
||
- U+0000–U+024F: Basic Latin through Latin Extended-B (ASCII + accented chars)
|
||
- U+0300–U+036F: Combining Diacritical Marks
|
||
- U+2000–U+206F: General Punctuation (dashes, quotes, bullets, ellipsis)
|
||
- U+20A0–U+20CF: Currency Symbols
|
||
- U+2100–U+214F: Letterlike Symbols
|
||
- U+2190–U+21FF: Arrows
|
||
- Replaced the byte-by-byte character append in `parseHtml()` with a UTF-8-aware decoder that reads multi-byte sequences, decodes the codepoint, and only appends renderable characters. Invalid or non-renderable characters are silently skipped.
|
||
|
||
**Files:** `src/activities/reader/DictionaryDefinitionActivity.h`, `src/activities/reader/DictionaryDefinitionActivity.cpp`
|
||
|
||
### 3. Fix: Revert to standard-height hints, keep overlap hiding (DictionaryWordSelectActivity)
|
||
|
||
**What changed:** Reverted from 22px thin custom hints back to the standard 40px theme-style buttons (rounded corners with `cornerRadius=6`, `SMALL_FONT_ID` text, matching `LyraTheme::drawButtonHints` exactly). The overlap detection is preserved.
|
||
|
||
**Key design choice:** Instead of calling `GUI.drawButtonHints()` (which always clears all 4 button areas, erasing page content even for hidden buttons), the method draws each button individually in portrait mode. Hidden buttons are skipped entirely (`continue`), so the page content and word highlight underneath remain visible. Non-hidden buttons get the full theme treatment: white fill + rounded rect border + centered text.
|
||
|
||
**Files:** `src/activities/reader/DictionaryWordSelectActivity.cpp`
|
||
|
||
## Follow-up Items
|
||
|
||
- The `isRenderableCodepoint` whitelist is conservative — if the font gains additional glyph coverage (e.g., Greek letters for math), the whitelist can be extended
|
||
- Entity-decoded characters bypass the codepoint filter since they're appended as raw bytes; this is fine for the current entity set (all produce ASCII or General Punctuation characters)
|