Cover the startup path, per-keystroke search with index reads and
ranking, the dictzip article read, block merge and text warm-up,
and dictionary indexing; they previously ran as JIT-warmed or
interpreted code.
The screen merges small parser blocks into larger render blocks,
while the warm-up measured the unmerged parser blocks. Merge once in
the view model and keep the merged blocks in the article state, so
the screen and the warm-up share exactly what will be drawn.
The warm-up ran only above a block-count threshold, so an article
that parses into one large block never qualified. Trigger on the
total character count as well.
The final ranking tie-break compared headwords lexicographically,
so entries numbered with digits or CJK numerals sorted by text
instead of by number. Compare runs of digits or numeral characters
by their numeric value, saturating on very long runs.
- Added search history
- The search bar can be placed at the top or bottom of the screen
- Fixed headwords with stress marks displaying truncated in search results
- Improved download, indexing and navigation stability
- The About screen opens faster
- Updated build tooling and code cleanup
HistoryEntryClicked in wide mode only called SearchAndLoadArticle,
which never updates searchQuery, so the field stayed empty and the
results pager took the query.isBlank() branch with PagingData.empty().
Now dispatch onSearchQueryChanged first, then SearchAndLoadArticle.
The display form was truncated at the first formatting tag, so headwords
with a mid-word stress mark displayed as their prefix only. Build the
display from the full text with tags stripped and render stress marks as
a combining acute accent. Bump the index version so existing indexes
rebuild.
Drop the v prefix so the version shows as a plain version name, and
align it by baseline with the app name instead of the bottom edge of
the headline line box.
Pasting several URLs separated by spaces, newlines or commas into one
field now distributes them across separate fields when every token is a
valid source template. Previously the joined text passed validation as a
single URL and failed at download time.
Remove unused imports and an unused spacing constant, drop redundant if
checks and redundant opt-in markers, replace loop variables with
destructuring, convert a string concatenation to a template, use
Configuration.screenHeightDp instead of LocalWindowInfo.containerSize, and
opt in to ExperimentalSerializationApi for decodeFromStream.
Background metadata loading rewrote the dictionaries flow several times
after startup, and every emission recreated the Pager: the results list
visibly collapsed and refilled. Distinct on the index paths that paging
actually uses, and seed the state synchronously instead of an empty list.
A second activity instance (PROCESS_TEXT) ran the full directory scan
again, and the main screen stayed blank until the scan finished. The
repository is a process-wide singleton: when it already holds
dictionaries, mark them up to date and load preferences immediately.
handleExternalSearch auto-opened the article on an exact match, so the main
screen with the search bar flashed before the article covered it. Only set
the query; the article now opens from the results list.
TextStyle.copy() returned a new instance on every recomposition, so the
remember() cache for the rendered blocks never hit. A text selection re-ran
block merging and recreated all article text nodes, rebuilding their
StaticLayouts repeatedly. Hoist the theme values and remember the style.
Stream the bundled license catalog straight into the JSON decoder
instead of buffering the whole resource as a string first, halving
parse time and peak allocation when the About screen loads.
A racing SettingsViewModel whose scan short-circuits with an in-progress
error persisted hadNoDictionaries from a still-empty list, forcing the
Settings screen on the next cold start despite existing dictionaries.
With many fields, the Add Source sheet could keep re-triggering its
settle animation: animated window insets reached the container while
its height followed the content. Keep only the static status bar
inset on the sheet container; the content already pads itself for
the navigation bar and IME.
Record queries on explicit search and keep up to 100 entries.
Show them in a bottom sheet opened from the search bar, with
per-entry removal and clear-all.
Top-align the title row in compact layouts, align the back button
with the first title line using the shared back button, make the
title start padding depend on whether the back button is shown,
and drop the spacing constant the old arrow buttons used.
Read the theme, locale, empty-library seed and section expansion
once in the application and collect them as state, instead of
blocking the UI thread with synchronous reads before setContent.
On restart the update-available state was restored purely from the
saved date. Also compare the installed payload file names against
dated sources, and re-check when they no longer match.
An already-consumed down change is part of another gesture, not a
reason to cancel the link press. Only treat movement past touch
slop as cancellation.
A just-deleted index file can still be held by the system, so
createNewFile() may fail right after deletion. Retry a few times
with a short delay, waiting for the old file to disappear first.
The platform blocks cleartext traffic by default, so an http:// source
passed validation but could never download and failed with a misleading
network error. The validator now rejects http:// upfront.
areDictionariesUpToDate() mapped every exception to NeedsUpdate, and
the post-update recheck ran after the first indexed source of a batch,
before later sources finished downloading; the interim NeedsUpdate
persisted for the day. Treat unexpected errors as up to date, rethrow
cancellation, and recheck once when the download batch completes.
Unnecessary safe call on a non-null File receiver; unused catch parameters renamed to _; constructor parameter used only in init no longer held as a property; deprecated Configuration.screenHeightDp replaced with LocalWindowInfo.containerSize; redundant filterNotNull on Paging items; deprecated invisibleToUser() replaced with hideFromAccessibility(); redundant alias variable inlined; redundant else in an exhaustive when removed; paging snapshot read moved into the SideEffect that consumes it.
On back navigation the article state was cleared before the exit animation ran, so the panel animated out empty except for the back arrow. The overlay now retains the last shown article state until the exit transition completes.
Article was an AnimatedContent target: opening it disposed Home, and returning from it recreated the whole results list in a single frame. The article screen now renders as a full-screen AnimatedVisibility overlay above Home, which stays composed for the whole article session.
- The app starts faster
- Smooth screen transition animations
- Articles render DSL line breaks, indentation and named colors correctly
- Tabs and extra spaces inside articles no longer break the layout
- The article title can be copied, tapping the article clears the selection
- Source URLs accept host:port addresses
- Dictionary downloads retry automatically when the network switches
- Download progress notifications are more reliable
- Search results clear instantly when the query is erased
- Leftover files from cancelled downloads are now removed automatically
- Improved app stability
- Faster dictionary indexing
- Updated build tooling and documentation
- Long link-heavy articles no longer freeze while scrolling
- Large search result lists render faster
- Dark article colors are readable in the dark theme
The title SelectionContainer covered only the text, so a tap on the empty bar area or the article body never cleared the highlight. A tap anywhere on the article screen now recreates the container and drops the selection.
Colors set by dictionaries such as navy, dark red and brown are nearly invisible on the dark background. Swap the dark named colors for lighter tones when rendering in the dark theme; the light theme keeps the original colors.
Link-heavy articles split every line into its own list item, so a
fast fling composed a dozen items in one frame and froze. Merge small
blocks into multi-paragraph items: indent via em space and a uniform
line pitch via LineHeightStyle(Proportional, Trim.Both).
Keep showing the last results while a new search generation loads,
and guard list access: the paging snapshot can shrink mid-layout,
which threw and crashed on an empty result set.
Blocks stayed open until the next character arrived, so following text
merged into them and trailing escapes dropped. Close each block right
at its tag and append escaped characters unconditionally.
Style and grammar labels printed upright while sources mark the same
words in different ways, so identical labels rendered inconsistently.
Every [p] block now uses the label color with italic posture, and the
text scan for specific label words is removed.
A literal tab advanced text to the next platform tab stop, which pushed
the rest of the line far enough to wrap it mid-phrase.
Replace each tab with an en space so the separator keeps a fixed, modest
width and the line breaks like ordinary text.