2.10.2: Performance mega-boost, search is now measured in the tens of milliseconds on large multi-language setups, down from seconds in 2.10.1 and earlier
v2.10.2 — Dictionary search rewrite + reader polish
Two themes: dictionary search is now effectively instant on any library size — the per-session in-memory term index closes the last slow path that the 2.10.1 schema work left exposed — and a pass over the reader chrome cleans up the TTU toolbar regression, reworks the no-audio bottom bar, and adds a global confirm-on-exit toggle plus a one-tap language switcher on the home page.
🚀 Dictionary search — an in-memory term index
Search on large multi-language setups (tens of thousands of entries per dictionary, several dictionaries per language) is now measured in the tens of milliseconds end-to-end. In 2.10.1 it could stretch into seconds whenever the Isar cursor had to walk a language with many non-applicable dictionaries.
- In-memory term index. The first search in a language pages the per-dictionary index into a packed byte array and keeps it for the session. Every subsequent query on that language skips the per-dictionary cursor walks entirely and binary-searches memory.
- Build-progress overlay. The first build for a language takes a few seconds on large libraries. A top-of-screen "Indexing: N / M" overlay reports progress and, crucially, renders from
MaterialApp.builderso it stays visible above routes, dialogs, and the reader's half-screen dict — no more "is it frozen?" moments. - Persistent search-worker isolate. The background worker that runs searches now stays alive between queries instead of being spawned and torn down each time. Removes several tens of ms of per-search overhead that was hard to see in a single query but visible when scrolling-tapping through a paragraph.
- Perf logging off by default. The
[WORKER-PERF]emitter is dead-coded in release builds. Flip_kSearchPerfLoggingtotrueinapp_model.dartto re-enable for diagnostics.
Together with the 2.10.1 schema-v3 work (per-dictionary primaryLanguage tag, bloom skip-gate, language-scoped searches), the only time you should see a perceptible delay now is the first search after opening the app in a given language.
📖 Reader chrome
- TTU toolbar access restored, no more dark strip. The 2.10.0 yellow-on-black theme painted TTU's invisible 32 px tap-target button as a solid dark strip that covered the first line of book text when the toolbar was collapsed. A prior fix hid the toolbar entirely, which also cost access to TTU's Cog (font size, its own settings). Net result in this release: toolbar behaves normally — tap the top of the page to show/hide — and the 32 px tap-target is now transparent.
- No-audio bottom bar keeps the right-hand controls. Previously when no audio file was set, the bar collapsed to a centered "Set audiobook" prompt that hid the translation-book toggle and the three-dot menu. Now the bar stays full-height: the left half is a tappable "Select audio file" prompt, and translation-book + settings stay on the right where they are when audio is set.
- Universal "Ask for confirmation on book exit" toggle. Lives in the reader's three-dot bottom sheet and in the book-list Tune dialog; both bind to the same preference. Default on. Unlike TTU's own
confirmClosekey — which turns out to be scoped per book and so never honored cross-library — this one applies to every book in the reader. - Three-dot bottom sheet is now scrollable, so the last options are reachable on shorter screens regardless of how many rows live in the sheet.
🌐 Home app bar — language switcher
- Globe icon between the app-icon and the card-creator button. One tap on the globe, one tap on a language, target language changed — applies across the reader, dictionary search, and UI text direction in one step. Hidden when fewer than two languages are eligible. Eligibility uses the same inclusion logic as the search pipeline, so dictionaries imported before the schema-v3
primaryLanguagetag (via the legacyhiddenLanguagesfallback) still count toward qualifying their language.
📝 Known issue
Pressing Android back while the half-screen dictionary popup is visible still exits the book instead of dismissing only the popup. A fix attempt was deferred from this release — the straightforward isDictionaryShown guard in the base page's onWillPop didn't take effect on-device, and the proper diagnosis needs more investigation than this release window allowed. Workaround: tap anywhere outside the popup to dismiss it first, then press back.
Full diff: v2.10.1...v2.10.2