|
| 1 | +# Working in this repo |
| 2 | + |
| 3 | +Notes for anyone, human or otherwise, changing this codebase. Things the code |
| 4 | +itself does not say. |
| 5 | + |
| 6 | +## Layout |
| 7 | + |
| 8 | + shared/ domain model, repositories, SQLDelight schema, most of the tests |
| 9 | + composeApp/ Android app: UI, widget, notifications, camera, migration |
| 10 | + config/ detekt configuration |
| 11 | + store-assets/ Play listing assets, with the scripts that generate them |
| 12 | + |
| 13 | +`shared` is multiplatform-shaped but only Android is wired up. Nothing outside |
| 14 | +`androidMain` may depend on Android. |
| 15 | + |
| 16 | +## Commands |
| 17 | + |
| 18 | + ./gradlew :composeApp:assembleDebug |
| 19 | + ./gradlew ciCheck # ktlint, detekt, Android Lint, unit tests, debug build |
| 20 | + ./gradlew ciCheckDevice # the above plus instrumented tests |
| 21 | + |
| 22 | +`ciCheck` and `.github/workflows/ci.yml` must stay in step. CI runs one task per |
| 23 | +job step so failures are attributable; adding a task to `ciCheck` means adding a |
| 24 | +step there too. |
| 25 | + |
| 26 | +Run the formatter and linter after changing code, and fix what they flag. |
| 27 | + |
| 28 | +## Conventions |
| 29 | + |
| 30 | +- ktlint is wired through the CLI, not the Gradle plugin. AGP 9 supplies its own |
| 31 | + Kotlin plugin, so `org.jetbrains.kotlin.android` is never applied and |
| 32 | + ktlint-gradle registers no source-set tasks. Style comes from `.editorconfig`. |
| 33 | +- American English throughout, including comments and strings. The pre-2.0 code |
| 34 | + was British. |
| 35 | +- Radii come from `EdrShapes`. No one-off `RoundedCornerShape` values. |
| 36 | +- Comments explain why, not what. A rule or a workaround with no stated reason is |
| 37 | + one nobody can safely delete later. |
| 38 | + |
| 39 | +## Things that have already gone wrong |
| 40 | + |
| 41 | +- **`LegacyImporter`** is the only path that can lose data users cannot get back. |
| 42 | + It reads the 1.5 database and image cache on first launch, once, and leaves the |
| 43 | + original files alone. Treat changes here as the highest-risk edits in the repo. |
| 44 | +- **R8 strips ML Kit's reflective constructors.** The failure is silent: the app |
| 45 | + starts, logs `NoSuchMethodException` at WARN, and scanning never works. Keep |
| 46 | + rules and their reasoning are in `composeApp/proguard-rules.pro`. A debug build |
| 47 | + cannot show this, so exercise `assembleRelease` before shipping. |
| 48 | +- **Widget sizing** lives in `WidgetSizing.kt` as plain Kotlin, deliberately, so |
| 49 | + it is testable without Glance. It still leaves dead space and drops its overflow |
| 50 | + line at tall sizes. |
| 51 | +- **Schema defaults and `AppSettings()` must agree.** They silently disagreed |
| 52 | + once; `SettingsDefaultsTest` is the guard. |
| 53 | +- **Instrumented test method names cannot contain commas.** Dex will not represent |
| 54 | + them. JVM tests can keep backticked sentences. |
| 55 | +- **Robolectric boots the real `EdrApplication`** and Koin then refuses to start |
| 56 | + twice. Use `@Config(application = Application::class)`. |
| 57 | + |
| 58 | +## Signing |
| 59 | + |
| 60 | +Release builds are signed only when `keystore.properties` exists in the project |
| 61 | +root, holding `storeFile`, `storePassword`, `keyAlias` and `keyPassword`. It is |
| 62 | +gitignored, along with `*.jks` and `*.keystore`, and must stay that way. Without |
| 63 | +it the build produces an unsigned artifact rather than failing configuration, so |
| 64 | +CI needs no secrets. |
| 65 | + |
| 66 | +Upload `mapping.txt` with every bundle or Play Console crash reports are |
| 67 | +unreadable. |
| 68 | + |
| 69 | +## Known gaps |
| 70 | + |
| 71 | +- The eight translations are machine generated and unreviewed. |
| 72 | +- OCR and the GenAI path have only ever run on an emulator. |
| 73 | +- Install-over-1.5 has never been tested through a real Play install. |
0 commit comments