mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
Split the monolithic :composeApp into :core, :app:shared, :app:ui-components, and :app:androidApp. The old module is still present and remains the source of truth until the next commits remove it; both compile in parallel to keep iOS/Android builds green during the cut-over. Highlights: - :core - SQLDelight schema + LedgerStore + Repository (now an injectable class, not a singleton object). Methods are suspend to match generateAsync = true. - :app:ui-components - design system primitives. IconButton/AppButton APIs revised: label = real contentDescription, testTag = stable selector. Drops the data-carrier description argument. - :app:shared - per-screen ViewModels colocated with screens; pure composables on (state, onEvent); LocalAppComponent CompositionLocal for hand-rolled DI; @Serializable Route. Hosts the iOS framework (baseName Shared). - :app:androidApp - thin Android entry that constructs the DriverFactory and hands it to App(). - gradle/libs.versions.toml centralises versions; settings.gradle.kts enables type-safe project accessors. Deferred to follow-up PRs (per the design discussion): - Metro DI: hand-rolled AppComponent for now; Metro graphs are mostly ceremony for an app this size and add KSP/version risk. - Navigation3: kept the existing Navigator-as-backstack class, injected rather than singleton; nav3 isn't shipping a stable multiplatform artifact for commonMain consumption yet. - :app:webApp + OPFS sqlite worker: web persistence is real new wiring (custom worker on @sqlite.org/sqlite-wasm). Master's WebLedgerStore + Snapshot is being removed by this PR; web stays buildable as a klib but no app-level wasm binary lands here.
Folio
A minimal Kotlin Multiplatform personal-ledger app: login with demo credentials, create accounts, add credits and debits. Shared UI across Android, iOS, and Web via Compose Multiplatform. Doubles as the example sanderling runs its property-based specs against.
Stack
- Kotlin Multiplatform + Compose Multiplatform (shared UI)
- kotlinx.serialization for file-backed persistence
- kotlinx.coroutines for state flows
Prerequisites
just- JDK 17
- Android SDK (auto-discovered under
$ANDROID_HOME,~/Library/Android/sdk, or the Homebrew cask) - Xcode 16+ and
xcodegen(brew install xcodegen) for iOS
Android
just install # build + install on a booted emulator / device
just uninstall
just clean
iOS
just ios # default device: iPhone 17 Pro
IOS_DEVICE="iPhone 15" just ios # pick a different simulator
just ios regenerates iosApp/iosApp.xcodeproj from iosApp/project.yml,
builds the KMP framework, links it into the SwiftUI host, installs, and
launches.
Demo credentials
email: [email protected]
password: ledger123
Run a sanderling test (Android)
just test
If no device is connected, sanderling boots the single AVD it finds. With multiple AVDs, pick one:
AVD=Pixel_7 just test
Persistent settings can live in .env alongside the justfile:
AVD=Pixel_7
DURATION=5m
Traces land in ./sanderling/runs/<timestamp>/.
How it connects to sanderling
- UI elements expose state via content descriptions (
account:$id:$balance,ledger_row:$id:$signed,ledger_balance:$cents,active_account:$id,focused_input:$field) sanderling/spec.tsimports@sanderling/spec, reads state vias.ax.*, asserts properties, and weights the actions the fuzzer picks fromjust testinvokessanderling testagainst the installed APK