diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 63d4afe..fd105f7 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -16,10 +16,16 @@ dependencies {
implementation(project(":core:data"))
implementation(project(":core:design-system"))
+ // Characters feature: data + presentation (Koin modules) + Compose renderer (nav graph).
+ implementation(project(":feature:characters:data"))
+ implementation(project(":feature:characters:presentation"))
+ implementation(project(":feature:characters:presentation-compose"))
+
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.bundles.lifecycle.compose)
+ implementation(libs.androidx.navigation.compose)
// Material Components — required for the Material3 XML Activity theme.
implementation(libs.material)
// Logging — the DebugTree is planted here; other modules log via Timber's static API.
diff --git a/app/src/main/kotlin/com/example/architecture/ArchitectureApp.kt b/app/src/main/kotlin/com/example/architecture/ArchitectureApp.kt
index 3005658..6842088 100644
--- a/app/src/main/kotlin/com/example/architecture/ArchitectureApp.kt
+++ b/app/src/main/kotlin/com/example/architecture/ArchitectureApp.kt
@@ -2,14 +2,16 @@ package com.example.architecture
import android.app.Application
import com.example.architecture.core.data.di.coreDataModule
+import com.example.architecture.feature.characters.data.di.charactersDataModule
+import com.example.architecture.feature.characters.presentation.di.charactersPresentationModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import timber.log.Timber
/**
- * Single Koin entry point. Feature modules append their own `*DataModule` / `*PresentationModule`
- * to the [modules] list — assembly happens only here, never inside feature modules.
+ * Single Koin entry point. Every feature's `*DataModule` / `*PresentationModule` is assembled here,
+ * never inside feature modules.
*/
class ArchitectureApp : Application() {
override fun onCreate() {
@@ -24,7 +26,11 @@ class ArchitectureApp : Application() {
androidLogger()
androidContext(this@ArchitectureApp)
modules(
+ // core
coreDataModule,
+ // characters feature
+ charactersDataModule,
+ charactersPresentationModule,
)
}
}
diff --git a/app/src/main/kotlin/com/example/architecture/MainActivity.kt b/app/src/main/kotlin/com/example/architecture/MainActivity.kt
index abbb074..bbeab40 100644
--- a/app/src/main/kotlin/com/example/architecture/MainActivity.kt
+++ b/app/src/main/kotlin/com/example/architecture/MainActivity.kt
@@ -4,31 +4,26 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Text
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import com.example.architecture.core.design.system.component.AppScaffold
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.rememberNavController
import com.example.architecture.core.design.system.theme.AppTheme
+import com.example.architecture.feature.characters.presentation.compose.CharacterListRoute
+import com.example.architecture.feature.characters.presentation.compose.charactersGraph
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
- // Compose themes via AppTheme; the navigation host lands in a later milestone.
AppTheme {
- AppScaffold { innerPadding ->
- Box(
- modifier = Modifier
- .fillMaxSize()
- .padding(innerPadding),
- contentAlignment = Alignment.Center,
- ) {
- Text(text = "Android Architecture Showcase")
- }
+ val navController = rememberNavController()
+ NavHost(
+ navController = navController,
+ startDestination = CharacterListRoute,
+ ) {
+ charactersGraph(
+ onCharacterClick = { /* Detail navigation is wired in the next milestone. */ },
+ )
}
}
}
diff --git a/core/data/src/main/AndroidManifest.xml b/core/data/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f15e066
--- /dev/null
+++ b/core/data/src/main/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/feature/characters/presentation-compose/build.gradle.kts b/feature/characters/presentation-compose/build.gradle.kts
index c9981f0..016b9c0 100644
--- a/feature/characters/presentation-compose/build.gradle.kts
+++ b/feature/characters/presentation-compose/build.gradle.kts
@@ -1,5 +1,7 @@
plugins {
alias(libs.plugins.architecture.android.feature)
+ // For @Serializable type-safe navigation routes.
+ alias(libs.plugins.architecture.kotlinx.serialization)
}
android {
diff --git a/feature/characters/presentation-compose/src/main/kotlin/com/example/architecture/feature/characters/presentation/compose/CharactersNavigation.kt b/feature/characters/presentation-compose/src/main/kotlin/com/example/architecture/feature/characters/presentation/compose/CharactersNavigation.kt
new file mode 100644
index 0000000..3ae9849
--- /dev/null
+++ b/feature/characters/presentation-compose/src/main/kotlin/com/example/architecture/feature/characters/presentation/compose/CharactersNavigation.kt
@@ -0,0 +1,21 @@
+package com.example.architecture.feature.characters.presentation.compose
+
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.compose.composable
+import kotlinx.serialization.Serializable
+
+/** Type-safe route for the characters list screen. */
+@Serializable
+data object CharacterListRoute
+
+/**
+ * The characters feature nav graph. `:app` only calls this and supplies cross-screen navigation as
+ * a callback. The detail destination is added here in a later milestone.
+ */
+fun NavGraphBuilder.charactersGraph(
+ onCharacterClick: (Int) -> Unit,
+) {
+ composable {
+ CharacterListRoot(onCharacterClick = onCharacterClick)
+ }
+}
diff --git a/feature/characters/presentation/src/main/kotlin/com/example/architecture/feature/characters/presentation/di/CharactersPresentationModule.kt b/feature/characters/presentation/src/main/kotlin/com/example/architecture/feature/characters/presentation/di/CharactersPresentationModule.kt
new file mode 100644
index 0000000..466b610
--- /dev/null
+++ b/feature/characters/presentation/src/main/kotlin/com/example/architecture/feature/characters/presentation/di/CharactersPresentationModule.kt
@@ -0,0 +1,10 @@
+package com.example.architecture.feature.characters.presentation.di
+
+import com.example.architecture.feature.characters.presentation.CharacterListViewModel
+import org.koin.core.module.dsl.viewModelOf
+import org.koin.dsl.module
+
+/** Presentation DI for the characters feature. Lives with the (UI-agnostic) ViewModel it provides. */
+val charactersPresentationModule = module {
+ viewModelOf(::CharacterListViewModel)
+}