android-sdd 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +27 -0
  3. package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
  4. package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
  5. package/skills/Android Platform/Configuration/SKILL.md +201 -0
  6. package/skills/Android Platform/Filesystem/SKILL.md +216 -0
  7. package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
  8. package/skills/Android Platform/Manifest/SKILL.md +226 -0
  9. package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
  10. package/skills/Android Platform/Resources/SKILL.md +234 -0
  11. package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
  12. package/skills/Android Platform/State Restoration/SKILL.md +210 -0
  13. package/skills/Architecture/Bounded Context/SKILL.md +207 -0
  14. package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
  15. package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
  16. package/skills/Architecture/Entity Design/SKILL.md +243 -0
  17. package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
  18. package/skills/Architecture/MVI/SKILL.md +224 -0
  19. package/skills/Architecture/MVVM/SKILL.md +198 -0
  20. package/skills/Architecture/Modularization/SKILL.md +194 -0
  21. package/skills/Architecture/Offline First/SKILL.md +249 -0
  22. package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
  23. package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
  24. package/skills/Architecture/State Management/SKILL.md +229 -0
  25. package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
  26. package/skills/Architecture/Use Case Design/SKILL.md +244 -0
  27. package/skills/Architecture/Value Object/SKILL.md +226 -0
  28. package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
  29. package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
  30. package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
  31. package/skills/Build System/Build Cache/SKILL.md +233 -0
  32. package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
  33. package/skills/Build System/Build Variant/SKILL.md +215 -0
  34. package/skills/Build System/Convention Plugin/SKILL.md +288 -0
  35. package/skills/Build System/Dependency Management/SKILL.md +261 -0
  36. package/skills/Build System/Gradle/SKILL.md +284 -0
  37. package/skills/Build System/Incremental Build/SKILL.md +199 -0
  38. package/skills/Build System/KAPT/SKILL.md +198 -0
  39. package/skills/Build System/KSP/SKILL.md +263 -0
  40. package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
  41. package/skills/Build System/Specialized/C++/SKILL.md +308 -0
  42. package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
  43. package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
  44. package/skills/Build System/Version Catalog/SKILL.md +304 -0
  45. package/skills/Concurrency/Background Processing/SKILL.md +185 -0
  46. package/skills/Concurrency/Channel/SKILL.md +207 -0
  47. package/skills/Concurrency/Coroutine/SKILL.md +200 -0
  48. package/skills/Concurrency/Flow/SKILL.md +179 -0
  49. package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
  50. package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
  51. package/skills/Concurrency/StateFlow/SKILL.md +175 -0
  52. package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
  53. package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
  54. package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
  55. package/skills/Core Language/DSL/SKILL.md +186 -0
  56. package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
  57. package/skills/Core Language/Immutability/SKILL.md +156 -0
  58. package/skills/Core Language/KMP/SKILL.md +182 -0
  59. package/skills/Core Language/Kotlin/SKILL.md +187 -0
  60. package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
  61. package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
  62. package/skills/Core Language/Serialization/SKILL.md +191 -0
  63. package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
  64. package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
  65. package/skills/Data Layer/DAO/SKILL.md +225 -0
  66. package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
  67. package/skills/Data Layer/DataStore/SKILL.md +264 -0
  68. package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
  69. package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
  70. package/skills/Data Layer/File Storage/SKILL.md +247 -0
  71. package/skills/Data Layer/Indexing/SKILL.md +184 -0
  72. package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
  73. package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
  74. package/skills/Data Layer/Migration/SKILL.md +243 -0
  75. package/skills/Data Layer/Paging/SKILL.md +264 -0
  76. package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
  77. package/skills/Data Layer/Room/SKILL.md +244 -0
  78. package/skills/Data Layer/SQLite/SKILL.md +255 -0
  79. package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
  80. package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
  81. package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
  82. package/skills/Dependency Injection/Koin/SKILL.md +282 -0
  83. package/skills/Developer Experience/Detekt/SKILL.md +272 -0
  84. package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
  85. package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
  86. package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
  87. package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
  88. package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
  89. package/skills/Media/Audio/SKILL.md +257 -0
  90. package/skills/Media/Camera/SKILL.md +229 -0
  91. package/skills/Media/CameraX/SKILL.md +295 -0
  92. package/skills/Media/ExoPlayer/SKILL.md +258 -0
  93. package/skills/Media/Video/SKILL.md +228 -0
  94. package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
  95. package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
  96. package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
  97. package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
  98. package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
  99. package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
  100. package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
  101. package/skills/Navigation/Navigation/SKILL.md +215 -0
  102. package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
  103. package/skills/Networking/API Contract/SKILL.md +220 -0
  104. package/skills/Networking/Authentication/SKILL.md +210 -0
  105. package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
  106. package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
  107. package/skills/Networking/Ktor/SKILL.md +219 -0
  108. package/skills/Networking/Multipart Upload/SKILL.md +213 -0
  109. package/skills/Networking/OkHttp/SKILL.md +193 -0
  110. package/skills/Networking/REST/SKILL.md +178 -0
  111. package/skills/Networking/Rate Limiting/SKILL.md +170 -0
  112. package/skills/Networking/Retrofit/SKILL.md +241 -0
  113. package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
  114. package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
  115. package/skills/Networking/WebSocket/SKILL.md +224 -0
  116. package/skills/Observability/Crash Reporting/SKILL.md +219 -0
  117. package/skills/Observability/Logging/SKILL.md +168 -0
  118. package/skills/Observability/Metrics/SKILL.md +227 -0
  119. package/skills/Observability/Structured Logging/SKILL.md +234 -0
  120. package/skills/Performance/ANR Prevention/SKILL.md +192 -0
  121. package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
  122. package/skills/Performance/App Startup/SKILL.md +183 -0
  123. package/skills/Performance/Baseline Profile/SKILL.md +205 -0
  124. package/skills/Performance/Battery Optimization/SKILL.md +192 -0
  125. package/skills/Performance/Benchmark/SKILL.md +182 -0
  126. package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
  127. package/skills/Performance/Compose Optimization/SKILL.md +187 -0
  128. package/skills/Performance/Heap Management/SKILL.md +184 -0
  129. package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
  130. package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
  131. package/skills/Performance/Rendering Performance/SKILL.md +205 -0
  132. package/skills/Performance/Startup Optimization/SKILL.md +219 -0
  133. package/skills/Security/Biometric/SKILL.md +224 -0
  134. package/skills/Security/Certificate Transparency/SKILL.md +158 -0
  135. package/skills/Security/Cryptography/SKILL.md +244 -0
  136. package/skills/Security/Encrypted Storage/SKILL.md +273 -0
  137. package/skills/Security/Frida Detection/SKILL.md +230 -0
  138. package/skills/Security/Hook Detection/SKILL.md +197 -0
  139. package/skills/Security/Keystore/SKILL.md +272 -0
  140. package/skills/Security/Network Security Config/SKILL.md +186 -0
  141. package/skills/Security/Obfuscation/SKILL.md +226 -0
  142. package/skills/Security/Proguard/SKILL.md +202 -0
  143. package/skills/Security/R8/SKILL.md +234 -0
  144. package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
  145. package/skills/Security/Root Detection/SKILL.md +220 -0
  146. package/skills/Security/Secure Networking/SKILL.md +220 -0
  147. package/skills/System Integration/AlarmManager/SKILL.md +182 -0
  148. package/skills/System Integration/App Widget/SKILL.md +182 -0
  149. package/skills/System Integration/Deep Link/SKILL.md +187 -0
  150. package/skills/System Integration/Foreground Service/SKILL.md +212 -0
  151. package/skills/System Integration/Notification/SKILL.md +237 -0
  152. package/skills/System Integration/WorkManager/SKILL.md +256 -0
  153. package/skills/System Integration/clipboard/SKILL.md +155 -0
  154. package/skills/System Integration/share-intent/SKILL.md +182 -0
  155. package/skills/Testing/Compose Testing/SKILL.md +296 -0
  156. package/skills/Testing/Espresso/SKILL.md +292 -0
  157. package/skills/Testing/Fake Data/SKILL.md +245 -0
  158. package/skills/Testing/Integration Testing/SKILL.md +288 -0
  159. package/skills/Testing/Mocking/SKILL.md +229 -0
  160. package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
  161. package/skills/Testing/UI Testing/SKILL.md +293 -0
  162. package/skills/Testing/Unit Testing/SKILL.md +309 -0
  163. package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
  164. package/skills/UI System/Compose/SKILL.md +296 -0
  165. package/skills/UI System/Compose Animation/SKILL.md +281 -0
  166. package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
  167. package/skills/UI System/Compose Navigation/SKILL.md +255 -0
  168. package/skills/UI System/Compose Performance/SKILL.md +274 -0
  169. package/skills/UI System/Design System/SKILL.md +217 -0
  170. package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
  171. package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
  172. package/skills/UI System/Loading Strategy/SKILL.md +254 -0
  173. package/skills/UI System/Material 3/SKILL.md +279 -0
  174. package/skills/UI System/RTL/SKILL.md +179 -0
  175. package/src/index.ts +182 -0
  176. package/tsconfig.json +19 -0
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: deep-navigation
3
+ description: >
4
+ Deep link handling in Android with Jetpack Compose Navigation.
5
+ Load this skill when implementing URI-based deep links, handling
6
+ incoming intents from notifications or external apps, defining
7
+ deep link patterns, or testing deep link navigation.
8
+ ---
9
+
10
+ # Deep Navigation
11
+
12
+ ## Overview
13
+ Deep links allow the app to navigate directly to a specific screen from an external source — a notification, a web URL, another app, or an NFC tag. Navigation Compose supports deep links via `deepLinks` parameter on composable destinations.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Define deep link URIs in a central constants object — never inline strings
20
+ - Always verify deep links in the manifest with `android:autoVerify="true"` for App Links
21
+ - Handle deep link arguments the same way as regular nav arguments — via `toRoute()`
22
+ - Deep links must be **tested with adb** before release
23
+ - Provide fallback navigation when a deep link destination requires authentication
24
+
25
+ ---
26
+
27
+ ## Manifest Setup
28
+
29
+ ```xml
30
+ <!-- AndroidManifest.xml -->
31
+ <activity
32
+ android:name=".MainActivity"
33
+ android:exported="true">
34
+
35
+ <intent-filter android:autoVerify="true">
36
+ <action android:name="android.intent.action.VIEW" />
37
+ <category android:name="android.intent.category.DEFAULT" />
38
+ <category android:name="android.intent.category.BROWSABLE" />
39
+ <data android:scheme="https"
40
+ android:host="example.com"
41
+ android:pathPrefix="/users" />
42
+ </intent-filter>
43
+
44
+ <!-- Custom scheme for internal deep links -->
45
+ <intent-filter>
46
+ <action android:name="android.intent.action.VIEW" />
47
+ <category android:name="android.intent.category.DEFAULT" />
48
+ <category android:name="android.intent.category.BROWSABLE" />
49
+ <data android:scheme="myapp" />
50
+ </intent-filter>
51
+
52
+ </activity>
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Route with Deep Link
58
+
59
+ ```kotlin
60
+ // ✅ Define deep link URIs centrally
61
+ object DeepLinks {
62
+ const val BASE = "https://example.com"
63
+ const val USER_DETAIL = "$BASE/users/{userId}"
64
+ const val ORDER_DETAIL = "$BASE/orders/{orderId}"
65
+
66
+ // Custom scheme
67
+ const val NOTIFICATION_BASE = "myapp://notification"
68
+ const val NOTIFICATION_DETAIL = "$NOTIFICATION_BASE/{notificationId}"
69
+ }
70
+
71
+ // ✅ Attach deep links to composable destination
72
+ composable<UserDetailRoute>(
73
+ deepLinks = listOf(
74
+ navDeepLink<UserDetailRoute>(
75
+ basePath = "https://example.com/users"
76
+ )
77
+ )
78
+ ) { backStackEntry ->
79
+ val route: UserDetailRoute = backStackEntry.toRoute()
80
+ UserDetailScreen(userId = route.userId)
81
+ }
82
+
83
+ // ✅ Legacy string-based deep link (if not using type-safe routes)
84
+ composable(
85
+ route = "user/{userId}",
86
+ deepLinks = listOf(
87
+ navDeepLink {
88
+ uriPattern = DeepLinks.USER_DETAIL
89
+ }
90
+ ),
91
+ arguments = listOf(navArgument("userId") { type = NavType.StringType })
92
+ ) { backStackEntry ->
93
+ val userId = backStackEntry.arguments?.getString("userId") ?: return@composable
94
+ UserDetailScreen(userId = userId)
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Handling Incoming Intent in Activity
101
+
102
+ ```kotlin
103
+ // ✅ Pass intent to NavHost for deep link handling
104
+ class MainActivity : ComponentActivity() {
105
+ override fun onCreate(savedInstanceState: Bundle?) {
106
+ super.onCreate(savedInstanceState)
107
+ setContent {
108
+ AppTheme {
109
+ val navController = rememberNavController()
110
+ AppNavHost(navController = navController)
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ // Navigation Compose handles intent automatically when
117
+ // NavHost is set up — no manual intent parsing needed
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Notification Deep Links
123
+
124
+ ```kotlin
125
+ // ✅ Build PendingIntent with deep link URI
126
+ fun buildNotificationIntent(context: Context, userId: String): PendingIntent {
127
+ val deepLinkUri = Uri.parse("https://example.com/users/$userId")
128
+
129
+ val intent = Intent(Intent.ACTION_VIEW, deepLinkUri).apply {
130
+ setPackage(context.packageName)
131
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
132
+ }
133
+
134
+ return TaskStackBuilder.create(context).run {
135
+ addNextIntentWithParentStack(intent)
136
+ getPendingIntent(
137
+ userId.hashCode(),
138
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
139
+ )!!
140
+ }
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Auth Guard for Deep Links
147
+
148
+ ```kotlin
149
+ // ✅ Redirect unauthenticated deep link to login
150
+ @Composable
151
+ fun AppNavHost(navController: NavHostController) {
152
+ val authState by authViewModel.state.collectAsStateWithLifecycle()
153
+
154
+ NavHost(navController = navController, startDestination = HomeRoute) {
155
+
156
+ composable<UserDetailRoute> { backStackEntry ->
157
+ if (authState !is AuthState.Authenticated) {
158
+ LaunchedEffect(Unit) {
159
+ navController.navigate(LoginRoute) {
160
+ // store original destination for post-login redirect
161
+ navController.currentBackStackEntry
162
+ ?.savedStateHandle
163
+ ?.set("pending_route", "user_detail")
164
+ }
165
+ }
166
+ } else {
167
+ val route: UserDetailRoute = backStackEntry.toRoute()
168
+ UserDetailScreen(userId = route.userId)
169
+ }
170
+ }
171
+ }
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Testing Deep Links with ADB
178
+
179
+ ```bash
180
+ # Test HTTPS deep link
181
+ adb shell am start \
182
+ -W -a android.intent.action.VIEW \
183
+ -d "https://example.com/users/123" \
184
+ com.example.app
185
+
186
+ # Test custom scheme
187
+ adb shell am start \
188
+ -W -a android.intent.action.VIEW \
189
+ -d "myapp://notification/456" \
190
+ com.example.app
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Anti-Patterns
196
+
197
+ - Inline URI strings in `navDeepLink {}` — define in a constants object
198
+ - Not adding `autoVerify="true"` for HTTPS App Links — won't be verified by Google
199
+ - Parsing the intent URI manually in `onCreate` — Navigation Compose handles this
200
+ - Not handling the unauthenticated deep link case — sends user to a broken state
201
+ - Using deep links for in-app navigation between features — use regular routes
202
+
203
+ ---
204
+
205
+ ## Related Skills
206
+ - `navigation` — core navigation setup
207
+ - `nested-navigation` — deep links into nested graphs
208
+ - `notification` — building notifications with deep link intents
209
+ - `manifest` — intent filter configuration
@@ -0,0 +1,215 @@
1
+ ---
2
+ name: navigation
3
+ description: >
4
+ Navigation setup and patterns in Jetpack Compose using Navigation Compose.
5
+ Load this skill when setting up the NavHost, defining routes, passing
6
+ arguments between screens, handling back stack, or structuring navigation
7
+ in a single-activity architecture.
8
+ ---
9
+
10
+ # Navigation
11
+
12
+ ## Overview
13
+ Navigation Compose is the standard navigation library for Jetpack Compose. It manages the back stack, screen transitions, and argument passing within a single-activity architecture. Routes are defined as type-safe objects using Kotlin serialization.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - One `NavHost` per app — never nest multiple NavHosts at the top level
20
+ - Routes must be **type-safe** using `@Serializable` data objects/classes — never string literals
21
+ - Navigation logic belongs in the **ViewModel or event callbacks** — never inside composables directly
22
+ - Pass only **IDs** between screens — never full objects
23
+ - Always use `launchSingleTop = true` for bottom navigation items
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```toml
30
+ # libs.versions.toml
31
+ [versions]
32
+ navigation-compose = "2.8.0"
33
+
34
+ [libraries]
35
+ navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" }
36
+ ```
37
+
38
+ ```kotlin
39
+ // build.gradle.kts
40
+ dependencies {
41
+ implementation(libs.navigation.compose)
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Type-Safe Routes
48
+
49
+ ```kotlin
50
+ // ✅ Define routes as serializable objects/classes
51
+ @Serializable
52
+ data object HomeRoute
53
+
54
+ @Serializable
55
+ data object SettingsRoute
56
+
57
+ @Serializable
58
+ data class UserDetailRoute(val userId: String)
59
+
60
+ @Serializable
61
+ data class EditUserRoute(val userId: String, val mode: String = "edit")
62
+ ```
63
+
64
+ ---
65
+
66
+ ## NavHost Setup
67
+
68
+ ```kotlin
69
+ // ✅ NavHost at the app root
70
+ @Composable
71
+ fun AppNavHost(
72
+ navController: NavHostController = rememberNavController()
73
+ ) {
74
+ NavHost(
75
+ navController = navController,
76
+ startDestination = HomeRoute
77
+ ) {
78
+ composable<HomeRoute> {
79
+ HomeScreen(
80
+ onNavigateToUser = { userId ->
81
+ navController.navigate(UserDetailRoute(userId))
82
+ }
83
+ )
84
+ }
85
+
86
+ composable<UserDetailRoute> { backStackEntry ->
87
+ val route: UserDetailRoute = backStackEntry.toRoute()
88
+ UserDetailScreen(
89
+ userId = route.userId,
90
+ onNavigateBack = { navController.popBackStack() },
91
+ onNavigateToEdit = {
92
+ navController.navigate(EditUserRoute(route.userId))
93
+ }
94
+ )
95
+ }
96
+
97
+ composable<EditUserRoute> { backStackEntry ->
98
+ val route: EditUserRoute = backStackEntry.toRoute()
99
+ EditUserScreen(
100
+ userId = route.userId,
101
+ onNavigateBack = { navController.popBackStack() }
102
+ )
103
+ }
104
+
105
+ composable<SettingsRoute> {
106
+ SettingsScreen(
107
+ onNavigateBack = { navController.popBackStack() }
108
+ )
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Bottom Navigation
117
+
118
+ ```kotlin
119
+ // ✅ Bottom navigation with launchSingleTop
120
+ @Composable
121
+ fun AppScaffold(navController: NavHostController) {
122
+ val navBackStackEntry by navController.currentBackStackEntryAsState()
123
+ val currentDestination = navBackStackEntry?.destination
124
+
125
+ Scaffold(
126
+ bottomBar = {
127
+ NavigationBar {
128
+ bottomNavItems.forEach { item ->
129
+ NavigationBarItem(
130
+ icon = { Icon(item.icon, contentDescription = null) },
131
+ label = { Text(item.label) },
132
+ selected = currentDestination?.hierarchy?.any {
133
+ it.hasRoute(item.route::class)
134
+ } == true,
135
+ onClick = {
136
+ navController.navigate(item.route) {
137
+ popUpTo(navController.graph.findStartDestination().id) {
138
+ saveState = true
139
+ }
140
+ launchSingleTop = true // ✅ avoid duplicates
141
+ restoreState = true // ✅ restore tab state
142
+ }
143
+ }
144
+ )
145
+ }
146
+ }
147
+ }
148
+ ) { padding ->
149
+ AppNavHost(
150
+ navController = navController,
151
+ modifier = Modifier.padding(padding)
152
+ )
153
+ }
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Passing Results Back
160
+
161
+ ```kotlin
162
+ // ✅ Pass result back via SavedStateHandle
163
+ // In destination screen
164
+ navController.previousBackStackEntry
165
+ ?.savedStateHandle
166
+ ?.set("selected_item_id", selectedItemId)
167
+ navController.popBackStack()
168
+
169
+ // ✅ Observe in source screen's ViewModel
170
+ class SourceViewModel(
171
+ savedStateHandle: SavedStateHandle
172
+ ) : ViewModel() {
173
+ val selectedItemId = savedStateHandle
174
+ .getStateFlow<String?>("selected_item_id", null)
175
+ }
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Navigation Extensions
181
+
182
+ ```kotlin
183
+ // ✅ Extension to reduce boilerplate
184
+ fun NavController.navigateSingleTop(route: Any) {
185
+ navigate(route) {
186
+ launchSingleTop = true
187
+ }
188
+ }
189
+
190
+ fun NavController.navigateAndClearStack(route: Any) {
191
+ navigate(route) {
192
+ popUpTo(0) { inclusive = true }
193
+ launchSingleTop = true
194
+ }
195
+ }
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Anti-Patterns
201
+
202
+ - Using raw string routes — loses type safety and refactoring support
203
+ - Passing full objects (Parcelable/Serializable) as nav arguments — pass IDs only
204
+ - Calling `navController.navigate()` directly inside a composable body — use callbacks or events
205
+ - Nesting `NavHost` inside another `NavHost` at the top level — use nested graphs instead
206
+ - Not using `launchSingleTop` for bottom nav — creates duplicate back stack entries
207
+ - Holding `NavController` reference in ViewModel — pass navigation events as lambdas
208
+
209
+ ---
210
+
211
+ ## Related Skills
212
+ - `compose-navigation` — advanced NavHost patterns and animations
213
+ - `deep-navigation` — deep links and external navigation
214
+ - `nested-navigation` — nested graphs and feature module navigation
215
+ - `savedstatehandle` — passing data between screens
@@ -0,0 +1,214 @@
1
+ ---
2
+ name: nested-navigation
3
+ description: >
4
+ Nested navigation graphs in Jetpack Compose Navigation.
5
+ Load this skill when organizing routes into feature-scoped graphs,
6
+ implementing tab-based navigation with independent back stacks,
7
+ isolating feature module navigation, or structuring auth vs main flows.
8
+ ---
9
+
10
+ # Nested Navigation
11
+
12
+ ## Overview
13
+ Nested navigation graphs group related destinations into a sub-graph with its own start destination. This enables feature isolation, independent back stacks per tab, and clean separation between flows (e.g. auth flow vs main flow).
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Each feature or flow gets its own nested graph — never dump all routes into one flat NavHost
20
+ - Nested graphs have their own `startDestination` — the entry point is the only public route
21
+ - Tab-based navigation uses `saveState`/`restoreState` to preserve independent back stacks
22
+ - Auth flow and main flow must be separate nested graphs — not mixed in the same graph
23
+ - Never navigate directly to an internal route of another feature's graph
24
+
25
+ ---
26
+
27
+ ## Basic Nested Graph
28
+
29
+ ```kotlin
30
+ // ✅ Define feature graph routes
31
+ @Serializable data object UserGraph
32
+ @Serializable data object UserListRoute
33
+ @Serializable data class UserDetailRoute(val userId: String)
34
+ @Serializable data class UserEditRoute(val userId: String)
35
+
36
+ // ✅ Register nested graph in NavHost
37
+ NavHost(navController = navController, startDestination = UserGraph) {
38
+
39
+ navigation<UserGraph>(startDestination = UserListRoute) {
40
+
41
+ composable<UserListRoute> {
42
+ UserListScreen(
43
+ onNavigateToDetail = { userId ->
44
+ navController.navigate(UserDetailRoute(userId))
45
+ }
46
+ )
47
+ }
48
+
49
+ composable<UserDetailRoute> { backStackEntry ->
50
+ val route: UserDetailRoute = backStackEntry.toRoute()
51
+ UserDetailScreen(
52
+ userId = route.userId,
53
+ onNavigateToEdit = {
54
+ navController.navigate(UserEditRoute(route.userId))
55
+ },
56
+ onNavigateBack = { navController.popBackStack() }
57
+ )
58
+ }
59
+
60
+ composable<UserEditRoute> { backStackEntry ->
61
+ val route: UserEditRoute = backStackEntry.toRoute()
62
+ UserEditScreen(
63
+ userId = route.userId,
64
+ onNavigateBack = { navController.popBackStack() }
65
+ )
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Auth vs Main Flow
74
+
75
+ ```kotlin
76
+ // ✅ Separate auth and main flows as nested graphs
77
+ @Serializable data object AuthGraph
78
+ @Serializable data object LoginRoute
79
+ @Serializable data object RegisterRoute
80
+
81
+ @Serializable data object MainGraph
82
+ @Serializable data object HomeRoute
83
+ @Serializable data object SettingsRoute
84
+
85
+ @Composable
86
+ fun AppNavHost(
87
+ navController: NavHostController,
88
+ isAuthenticated: Boolean
89
+ ) {
90
+ NavHost(
91
+ navController = navController,
92
+ startDestination = if (isAuthenticated) MainGraph else AuthGraph
93
+ ) {
94
+
95
+ navigation<AuthGraph>(startDestination = LoginRoute) {
96
+ composable<LoginRoute> {
97
+ LoginScreen(
98
+ onLoginSuccess = {
99
+ navController.navigate(MainGraph) {
100
+ popUpTo(AuthGraph) { inclusive = true } // ✅ clear auth stack
101
+ }
102
+ },
103
+ onNavigateToRegister = {
104
+ navController.navigate(RegisterRoute)
105
+ }
106
+ )
107
+ }
108
+ composable<RegisterRoute> {
109
+ RegisterScreen(
110
+ onRegisterSuccess = {
111
+ navController.navigate(MainGraph) {
112
+ popUpTo(AuthGraph) { inclusive = true }
113
+ }
114
+ },
115
+ onNavigateBack = { navController.popBackStack() }
116
+ )
117
+ }
118
+ }
119
+
120
+ navigation<MainGraph>(startDestination = HomeRoute) {
121
+ composable<HomeRoute> { HomeScreen() }
122
+ composable<SettingsRoute> { SettingsScreen() }
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Tab Navigation with Independent Back Stacks
131
+
132
+ ```kotlin
133
+ // ✅ Each tab is a nested graph with its own back stack
134
+ @Serializable data object HomeGraph
135
+ @Serializable data object HomeRootRoute
136
+
137
+ @Serializable data object SearchGraph
138
+ @Serializable data object SearchRootRoute
139
+
140
+ @Serializable data object ProfileGraph
141
+ @Serializable data object ProfileRootRoute
142
+
143
+ @Composable
144
+ fun MainScreen() {
145
+ val navController = rememberNavController()
146
+
147
+ Scaffold(
148
+ bottomBar = {
149
+ BottomNavBar(navController = navController)
150
+ }
151
+ ) { padding ->
152
+ NavHost(
153
+ navController = navController,
154
+ startDestination = HomeGraph,
155
+ modifier = Modifier.padding(padding)
156
+ ) {
157
+ navigation<HomeGraph>(startDestination = HomeRootRoute) {
158
+ composable<HomeRootRoute> { HomeScreen() }
159
+ // more home destinations...
160
+ }
161
+
162
+ navigation<SearchGraph>(startDestination = SearchRootRoute) {
163
+ composable<SearchRootRoute> { SearchScreen() }
164
+ // more search destinations...
165
+ }
166
+
167
+ navigation<ProfileGraph>(startDestination = ProfileRootRoute) {
168
+ composable<ProfileRootRoute> { ProfileScreen() }
169
+ // more profile destinations...
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ // ✅ Bottom nav switching with state save/restore
176
+ fun NavController.switchTab(route: Any) {
177
+ navigate(route) {
178
+ popUpTo(graph.findStartDestination().id) {
179
+ saveState = true // ✅ save current tab's back stack
180
+ }
181
+ launchSingleTop = true
182
+ restoreState = true // ✅ restore destination tab's back stack
183
+ }
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Popping to Graph Start
190
+
191
+ ```kotlin
192
+ // ✅ Pop back to the start of a nested graph
193
+ navController.popBackStack(route = UserListRoute, inclusive = false)
194
+
195
+ // ✅ Pop the entire graph off the stack
196
+ navController.popBackStack(route = UserGraph, inclusive = true)
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Anti-Patterns
202
+
203
+ - Flat NavHost with all routes at the same level — hard to maintain and reason about
204
+ - Navigating directly to an internal route of another feature graph from outside it
205
+ - Not using `saveState`/`restoreState` for tab navigation — back stack lost on tab switch
206
+ - Not clearing the auth graph when navigating to main — user can back-navigate to login
207
+ - Sharing a single `NavController` across nested `NavHost` composables
208
+
209
+ ---
210
+
211
+ ## Related Skills
212
+ - `navigation` — core navigation setup and route definitions
213
+ - `deep-navigation` — deep links into nested graphs
214
+ - `compose-navigation` — transitions and animations between graphs