The Ethiopian Orthodox Tewahedo Book of Hours (ሰዓታት) for Android — Amharic-first, fully offline, built and shipped solo. 241 Kotlin files, 47k lines, and exactly one network call in the whole app.
- added
Homophone-tolerant Amharic search as Unicode block arithmetic, not a lookup table: each Ge’ez syllable family (ሠ→ሰ, ሐ/ኀ/ኸ→ሀ, ዐ→አ, ፀ→ጸ) folds to one canonical consonant by codepoint offset, preserving the vowel order, so query and index collapse to the same form.
- added
ባሕረ ሓሳብ implemented from the classical tables rather than shipped as a date list — Fasika via the Alexandrian paschal cycle (Julian computus, shifted to Gregorian), every movable feast a Tewsak offset from ጾመ ነነዌ, with Wenber, Abekte and Metqi exposed and pinned by unit tests against known Easter dates.
- added
441 unit tests across 71 files — the computus, ግጻዌ link coverage, Ge’ez numerals, the backup format and Ethiopian date arithmetic, which is where a calendar app actually breaks.
- added
Three GitHub Actions workflows. Release is gated in order — bundled-content validation, unit tests, release-blocking lint — then builds a signed APK and a Play AAB from the same commit.
- added
The self-update notice is a Gradle flag (-PupdateNotice) wired so the failure mode is safe: forget it and GitHub loses a notice; it cannot ship an update prompt into a Play build, which would breach policy.
- added
The corpus itself: seven canonical hours plus the Veil, the 150-psalm Psalter, the full Amharic 1980 canon, ግጻዌ across all 366 fixed dates, ስንክሳር, አጽዋማት, and ሥርዓተ ማኅሌት’s 190 feasts — each searchable and cross-linked.
- changed
28 MB of liturgical text ships in a 10.4 MB APK — R8 with resource shrinking, manifest-driven asset loading, and a 24-script Python pipeline that is the corpus’s only writer. Nothing in assets/ is hand-edited.
- changed
Kotlin and Jetpack Compose throughout, Material 3, Room for the journal, DataStore for preferences, kotlinx.serialization for the bundled corpus. Reaches Android 6.0 (API 23) through core library desugaring, which backports java.time across 61 files — the lower floor cost no source changes.
- changed
That check is gated inside the repository object rather than at its call sites, so a Play build compiles it dark by construction instead of by discipline — pointing a Play install at a page of APKs is exactly what the store forbids.
- fixed
Exactly one network call exists: a once-a-day GitHub releases check on the hand-installed build, opt-out, carrying no content and no identifiers. It fails silently — a person praying offline should not learn about it from an error.