refactor(folio): introduce nested KotlinConf-style modules

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.
This commit is contained in:
pj committed 2026-04-26 14:30:59 +07:00
1 parent df44012d3e
commit 5121f777f2
61 files changed
+2492 -6

No files matched your search

@@ -0,0 +1,44 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.plugin.compose)
alias(libs.plugins.compose.multiplatform)
}
val sanderlingVersion = findProperty("sanderling.version") as String? ?: "0.0.0-dev"
kotlin {
compilerOptions { jvmTarget.set(JvmTarget.JVM_17) }
}
android {
namespace = "app.folio"
compileSdk = 36
defaultConfig {
applicationId = "app.folio"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = sanderlingVersion
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildTypes { debug { isDebuggable = true } }
sourceSets["main"].apply {
manifest.srcFile("src/main/AndroidManifest.xml")
res.srcDirs("src/main/res")
}
}
dependencies {
implementation(projects.app.shared)
implementation(libs.androidx.activity.compose)
}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="Folio"
android:allowBackup="false"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|uiMode|fontScale">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,14 @@
package app.folio
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import app.folio.core.data.DriverFactory
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val driverFactory = DriverFactory(applicationContext)
setContent { App(driverFactory) }
}
}