Skip to content

Commit 19dbe82

Browse files
author
Ahmed Mohamed
committed
v2.0.0-b1: clean architecture refactor, 5-tab nav, expanded power-user surface
Architecture spine: core/dispatchers (DispatcherProvider) + core/result (Outcome + AppError) + Konsist suite enforcing layer purity (domain Android-free, no Dispatchers outside core/, repository contract). Four UseCases (Install / Synthesize / RefreshCatalog / RecommendTier). DeviceTierEstimator and UpdateChannel moved into their proper layers. Navigation: NavigationBar with five tabs (Library / Browse / Studio / Activity / Settings) replaces single-stack Library entry. Each tab keeps its own back stack. New surfaces: - Activity tab: Downloads, Extractions, Live Generations (RTF telemetry via SynthesisTelemetryRepository), Request log, Cache stats. - Studio tab: entry point for the Playground knobs + voice profiles + WAV export + SSML preprocessor (subset: prosody, break, say-as). - Speak Selection: ACTION_PROCESS_TEXT activity for system-wide TTS. - HayaiTtsNudge: foreground "speaking" notification with Stop action. - UpdateCheckWorker: 12h periodic GitHub Releases poll. - AltRuntime: pluggable seam for non-sherpa families. - SherpaTtsRuntime.synthesizeBlend: Kokoro multi-speaker mixing. Catalog: tools/catalog/build_catalog.py infers Piper voice gender from a hand-curated table; Speaker carries genderConfidence (declared / inferred / unknown) so Browse filters have real data. Filters: domain-side BrowseFilters with seven dimensions (gender, languages, families, tiers, licenses, sample-rate buckets, size buckets) plus multi-speaker, available-only, requireKnownGender toggles. Loosen() helper for the "no results" CTA. Database: Room v3 -> v4. Three new tables: voice_profiles, pronunciations, app_routes. MIGRATION_3_4 hand-written, empty on first run. Library: family-tinted accent border on cards. Drag reorder no longer collapses on a single fast frame. Dead 4th FAB button, hit-test bleed, 20-bar waveform mismatch, orphaned Help route, dead AnimatedVisibility, JVM 17/21 toolchain skew all fixed. Docs: CLAUDE.md (build + conventions) + docs/ARCHITECTURE.md (12-section contract: layers, boundaries, DI, threading, errors, naming, testing, forbidden patterns, finished migration table). Tests: OutcomeTest (5 cases), BrowseFiltersTest (6 cases), Konsist ArchitectureTest (7 rules). All green on testDebugUnitTest. Version: 1.2.0-b1 -> 2.0.0-b1 (versionCode 200).
1 parent 642adad commit 19dbe82

66 files changed

Lines changed: 3315 additions & 236 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# CLAUDE.md — HayaiTTS
2+
3+
Quick-reference for working in this repo. Detailed history and architecture
4+
live in [`ONBOARDING.md`](ONBOARDING.md) and
5+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
6+
7+
## Build
8+
9+
```powershell
10+
.\gradlew assembleDebug -Dorg.gradle.java.home="C:\Program Files\Android\Android Studio\jbr"
11+
adb install -r app/build/outputs/apk/debug/app-debug.apk
12+
```
13+
14+
JDK 21 (JBR shipped with Android Studio). Gradle toolchain is pinned, so any
15+
JDK 21 install works. Lint clean — keep it that way. `:app:test` runs the
16+
Konsist architecture suite; treat failures as build errors, not warnings.
17+
18+
## Repo orientation
19+
20+
- `app/` — single Gradle module, all production code.
21+
- `catalog/v1/models.json` — voice manifest, regenerated weekly by
22+
[`tools/catalog/build_catalog.py`](tools/catalog/build_catalog.py) via the
23+
[`catalog-refresh`](.github/workflows/catalog-refresh.yml) workflow.
24+
- `docs/ARCHITECTURE.md` — layering, naming, threading, error handling,
25+
testing, forbidden patterns. **Read before adding a feature.**
26+
- `ONBOARDING.md` — build phase history, signing, CI architecture,
27+
on-device smoke test.
28+
29+
## Architecture in one paragraph
30+
31+
UI → UseCase → Repository → Data source → sherpa-onnx runtime. Dependencies
32+
point one way. `domain/` is pure Kotlin (no `android.*`, no `androidx.*`
33+
except `androidx.annotation`); `data/` may import `domain` but not `ui`;
34+
`ui/` may import both. Threading goes through the injected
35+
[`DispatcherProvider`](app/src/main/java/dev/ahmedmohamed/hayaitts/core/dispatchers/DispatcherProvider.kt),
36+
not `Dispatchers.*` directly. Repository returns flow through
37+
[`Outcome<T>`](app/src/main/java/dev/ahmedmohamed/hayaitts/core/result/Outcome.kt)
38+
rather than thrown exceptions. Konsist tests in
39+
`app/src/test/java/.../core/konsist/` enforce these rules — break a rule and
40+
CI goes red.
41+
42+
## Conventions
43+
44+
- No `Co-Authored-By: Claude` trailers on commits, no robot emoji in PR
45+
bodies. Just write the change.
46+
- Strings ship in all 10 supported locales. CI diffs the key sets across
47+
`res/values-*/strings.xml`.
48+
- Voice teal (`#0E7C86`) is the brand color. Don't override the M3 Expressive
49+
scheme; extend it.
50+
- For UI changes attach a screenshot or short recording — Compose previews
51+
don't capture motion/haptics, which is most of where the UX lives.
52+
53+
## Forbidden
54+
55+
- Importing `kotlinx.coroutines.Dispatchers` outside `core/` (Workers and
56+
Receivers excepted — they are framework-constructed).
57+
- Returning Room `*Entity` types from a `domain/` repo or referencing them
58+
from a `@Composable`.
59+
- Throwing exceptions from a repository or use case — return `Outcome.Failure`.
60+
- Adding a `build.gradle` version literal — every version lives in
61+
`gradle/libs.versions.toml`.

app/build.gradle.kts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ plugins {
1515
kotlin {
1616
jvmToolchain(21)
1717
compilerOptions {
18-
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
18+
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
1919
freeCompilerArgs.addAll(
2020
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
2121
"-opt-in=androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
@@ -31,8 +31,8 @@ android {
3131
applicationId = "dev.ahmedmohamed.hayaitts"
3232
minSdk = 26
3333
targetSdk = 36
34-
versionCode = 120
35-
versionName = "1.2.0-b1"
34+
versionCode = 200
35+
versionName = "2.0.0-b1"
3636

3737
// Room schema export. KSP picks this up via the `room` argument and
3838
// writes JSON snapshots of each entity into app/schemas/. Schemas are
@@ -109,8 +109,8 @@ android {
109109
}
110110

111111
compileOptions {
112-
sourceCompatibility = JavaVersion.VERSION_17
113-
targetCompatibility = JavaVersion.VERSION_17
112+
sourceCompatibility = JavaVersion.VERSION_21
113+
targetCompatibility = JavaVersion.VERSION_21
114114
}
115115

116116
// Note: kotlinOptions DSL was deprecated in Kotlin 2.2 — switched to the
@@ -207,6 +207,7 @@ dependencies {
207207
testImplementation(libs.junit4)
208208
testImplementation(libs.coroutines.test)
209209
testImplementation(libs.androidx.test.core)
210+
testImplementation(libs.konsist)
210211

211212
androidTestImplementation(libs.androidx.test.ext.junit)
212213
androidTestImplementation(libs.androidx.test.runner)

0 commit comments

Comments
 (0)