Skip to content

Clean up bugs, threading, and build config#8

Merged
baz8080 merged 1 commit intomasterfrom
baz8080/cleanup-pass-1
May 5, 2026
Merged

Clean up bugs, threading, and build config#8
baz8080 merged 1 commit intomasterfrom
baz8080/cleanup-pass-1

Conversation

@baz8080
Copy link
Copy Markdown
Owner

@baz8080 baz8080 commented May 5, 2026

First of several cleanup PRs based on the analysis of the codebase. Net −15 LOC despite adding the version catalog and Mode/state plumbing.

Summary

Real bugs

  • File I/O and SQLite reads/writes moved off the UI thread to Dispatchers.IO (search, favourite reads/writes, clear-all).
  • isFavourited() was a SQLite COUNT(*) per row in onBindViewHolder — replaced with a single getFavouriteKeys() upfront and a Set lookup in the adapter.
  • MIME typo "plain/text""text/plain" on the email-favourites intent.
  • onNewIntent now handles INITIAL_WORD for the singleTask activity (previously only the first intent was used).
  • Cursor leaks in FavouritesDbHelper fixed with cursor.use { }.
  • Per-launch CRC32 over the entire bundled dictionary replaced with a data_version flag in SharedPreferences — re-extract only when bumped.
  • linkifyDefinition now trims the cleaned word so onWordClick gets a usable query; linkifySynonyms guards against a missing leading space.

Code smells

  • EditText "special:favourites" sentinel replaced with a Mode enum + PreviousState on SearchViewModel; toolbar title now reflects mode.
  • Hardcoded English strings (Send mail..., Share word, Shared by Arcus Dictionary, Synonyms:, My Favourites from Arcus Dictionary) moved to strings.xml.
  • All app code now lives under com.arcuscomputing.dictionary — the orphan com.arcuscomputing package is gone.
  • @Synchronized dropped from FavouritesDbHelper (SQLite handles internal locking); the eager compileStatement cache went with it.
  • closeFileHandles() teardown removed from the activity — ArcusApplication owns the dictionary; OS reclaims handles on process death.

Modern paradigms

  • <fragment> tag in activity_preferences.xml replaced with FragmentContainerView; the fragment is added programmatically.
  • Top-level apply plugin: form replaced with a plugins {} block.
  • New gradle/libs.versions.toml version catalog.
  • Switched dictionary data dir from getExternalFilesDir to filesDir; removed the now-obsolete "no SD card" dialog and strings.
  • TextWatcher interface impl replaced with doAfterTextChanged.

Out of scope (deferred to follow-up PRs)

  • Real bug 7 (exit-warning reset in onResume) — left as-is per request.
  • Code smell 4 (OFFSET_INDEX / TAGCOUNT_INDEX redundant constants) — left as-is per request.
  • Modern paradigm 1 (ViewBinding), 5 (mmap dictionary), 7 (ListAdapter + DiffUtil) — separate PRs.

Test plan

  • ./gradlew assembleDebug — passing locally.
  • Cold launch: progress dialog briefly shows then dismisses; search works.
  • Type "cat" → results appear without ANR; tap a linkified word → searches that word; press back → restores prior query.
  • Tap Favourites menu → toolbar title shows "Favourites", list of saved favourites loads. Press back → restores previous search and toolbar.
  • Tap a star to (un)favourite — UI flips immediately, persists across re-search.
  • In Favourites, sort by date asc/desc and word asc/desc — list reorders.
  • Email favourites — intent chooser shows email apps (the text/plain fix).
  • Settings activity — preferences screen renders with toolbar + back arrow.
  • Reinstall (data wiped) — first launch extracts dictionary into internal storage; second launch skips extraction.

🤖 Generated with Claude Code

* Move dictionary search and SQLite reads/writes off the UI thread to
  Dispatchers.IO; precompute the favourites set once per result list
  rather than running a COUNT query in onBindViewHolder per row.
* Fix MIME typo "plain/text" → "text/plain" on the email favourites
  intent so more clients respond.
* Override onNewIntent so a singleTask launch with INITIAL_WORD picks
  up subsequent intents.
* Use cursor.use { } for SQLite reads to release on exception, and
  drop the eager compileStatement / @synchronized in favour of the
  internal SQLiteDatabase locking.
* Drop the per-launch CRC32 of the bundled dictionary; replace with a
  data version flag in SharedPreferences and re-extract only when it
  bumps.
* Switch dictionary data dir from getExternalFilesDir to filesDir and
  remove the obsolete "no SD card" dialog and strings.
* Trim the cleaned word in linkifyDefinition so spans fire onWordClick
  with a usable query, and guard linkifySynonyms against missing space.
* Replace the EditText "special:favourites" sentinel with a Mode enum
  + PreviousState in SearchViewModel; toolbar title reflects mode.
* Replace the TextWatcher impl with doAfterTextChanged; drop the
  isFavourited / inFavouritesMode callbacks on the adapter.
* Replace the legacy <fragment> tag with FragmentContainerView and
  add the preferences fragment programmatically.
* Drop closeFileHandles teardown in the activity — ArcusApplication
  owns the dictionary and the OS reclaims handles on process death.
* Move share / email / synonym hardcoded strings into strings.xml.
* Consolidate everything into the com.arcuscomputing.dictionary
  package so there is only one root.
* Migrate to plugins {} blocks + libs.versions.toml.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@baz8080 baz8080 merged commit 3270816 into master May 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant