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,296 @@
1
+ ---
2
+ name: compose
3
+ description: >
4
+ Jetpack Compose fundamentals, patterns, and best practices for Android UI.
5
+ Load this skill when building any Compose UI, designing composable functions,
6
+ managing state in Compose, or optimizing recomposition.
7
+ ---
8
+
9
+ # Compose
10
+
11
+ ## Overview
12
+ Jetpack Compose is Android's modern declarative UI toolkit. UI is described as functions of state — when state changes, the UI recomposes automatically. Understanding recomposition, state hoisting, and composable design is essential for correct and performant Compose code.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - UI is a **function of state** — never imperatively mutate UI
19
+ - **Hoist state** to the lowest common ancestor that needs it
20
+ - Keep composables **small and focused** — one responsibility per composable
21
+ - **Stateless composables** are easier to test, preview, and reuse
22
+ - Avoid side effects inside composable functions — use `LaunchedEffect`, `SideEffect`, `DisposableEffect`
23
+
24
+ ---
25
+
26
+ ## Composable Function Design
27
+
28
+ ```kotlin
29
+ // ✅ Stateless composable — accepts state, emits events
30
+ @Composable
31
+ fun UserCard(
32
+ user: User,
33
+ onUserClick: (String) -> Unit,
34
+ modifier: Modifier = Modifier // always include modifier parameter
35
+ ) {
36
+ Card(
37
+ modifier = modifier.clickable { onUserClick(user.id) }
38
+ ) {
39
+ Column(modifier = Modifier.padding(16.dp)) {
40
+ Text(text = user.name, style = MaterialTheme.typography.titleMedium)
41
+ Text(text = user.email, style = MaterialTheme.typography.bodySmall)
42
+ }
43
+ }
44
+ }
45
+
46
+ // ✅ Stateful composable — owns state, delegates to stateless
47
+ @Composable
48
+ fun UserCardScreen(viewModel: UserViewModel = hiltViewModel()) {
49
+ val state by viewModel.state.collectAsStateWithLifecycle()
50
+ UserCard(
51
+ user = state.user,
52
+ onUserClick = viewModel::onUserClicked
53
+ )
54
+ }
55
+ ```
56
+
57
+ ---
58
+
59
+ ## State Management in Compose
60
+
61
+ ```kotlin
62
+ // ✅ Local UI state — remember
63
+ @Composable
64
+ fun ExpandableCard(title: String, content: String) {
65
+ var isExpanded by remember { mutableStateOf(false) }
66
+
67
+ Card(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
68
+ Column {
69
+ Text(title)
70
+ if (isExpanded) Text(content)
71
+ }
72
+ }
73
+ }
74
+
75
+ // ✅ State that survives rotation — rememberSaveable
76
+ @Composable
77
+ fun SearchBar(onSearch: (String) -> Unit) {
78
+ var query by rememberSaveable { mutableStateOf("") }
79
+ TextField(
80
+ value = query,
81
+ onValueChange = { query = it },
82
+ trailingIcon = {
83
+ IconButton(onClick = { onSearch(query) }) {
84
+ Icon(Icons.Default.Search, contentDescription = null)
85
+ }
86
+ }
87
+ )
88
+ }
89
+
90
+ // ✅ Complex state — hoist to ViewModel
91
+ @Composable
92
+ fun ProductScreen(viewModel: ProductViewModel = hiltViewModel()) {
93
+ val state by viewModel.state.collectAsStateWithLifecycle()
94
+ ProductContent(
95
+ state = state,
96
+ onAddToCart = viewModel::onAddToCart,
97
+ onQuantityChange = viewModel::onQuantityChange
98
+ )
99
+ }
100
+ ```
101
+
102
+ ---
103
+
104
+ ## State Hoisting Pattern
105
+
106
+ ```kotlin
107
+ // ✅ Hoist state up — pass value and onValueChange
108
+ @Composable
109
+ fun EmailField(
110
+ value: String,
111
+ onValueChange: (String) -> Unit,
112
+ modifier: Modifier = Modifier
113
+ ) {
114
+ OutlinedTextField(
115
+ value = value,
116
+ onValueChange = onValueChange,
117
+ label = { Text("Email") },
118
+ modifier = modifier
119
+ )
120
+ }
121
+
122
+ // ✅ Owner of state composes and passes down
123
+ @Composable
124
+ fun RegisterForm() {
125
+ var email by rememberSaveable { mutableStateOf("") }
126
+ var password by rememberSaveable { mutableStateOf("") }
127
+
128
+ EmailField(value = email, onValueChange = { email = it })
129
+ PasswordField(value = password, onValueChange = { password = it })
130
+ }
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Side Effects
136
+
137
+ ```kotlin
138
+ // ✅ LaunchedEffect — coroutine tied to composition
139
+ @Composable
140
+ fun UserScreen(userId: String, viewModel: UserViewModel = hiltViewModel()) {
141
+ LaunchedEffect(userId) {
142
+ viewModel.loadUser(userId) // re-runs when userId changes
143
+ }
144
+ }
145
+
146
+ // ✅ DisposableEffect — non-coroutine cleanup
147
+ @Composable
148
+ fun LifecycleAwareScreen(onResume: () -> Unit) {
149
+ val lifecycleOwner = LocalLifecycleOwner.current
150
+ DisposableEffect(lifecycleOwner) {
151
+ val observer = LifecycleEventObserver { _, event ->
152
+ if (event == Lifecycle.Event.ON_RESUME) onResume()
153
+ }
154
+ lifecycleOwner.lifecycle.addObserver(observer)
155
+ onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
156
+ }
157
+ }
158
+
159
+ // ✅ SideEffect — sync Compose state to non-Compose code
160
+ @Composable
161
+ fun AnalyticsScreen(screenName: String) {
162
+ SideEffect {
163
+ analytics.logScreenView(screenName) // runs on every successful recomposition
164
+ }
165
+ }
166
+
167
+ // ✅ One-time events from ViewModel
168
+ @Composable
169
+ fun OrderScreen(viewModel: OrderViewModel = hiltViewModel()) {
170
+ val lifecycleOwner = LocalLifecycleOwner.current
171
+
172
+ LaunchedEffect(Unit) {
173
+ viewModel.events
174
+ .flowWithLifecycle(lifecycleOwner.lifecycle)
175
+ .collect { event ->
176
+ when (event) {
177
+ is OrderEvent.NavigateToConfirmation -> navController.navigate(...)
178
+ is OrderEvent.ShowError -> snackbarHostState.showSnackbar(event.message)
179
+ }
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Modifier Best Practices
188
+
189
+ ```kotlin
190
+ // ✅ Always accept modifier as parameter — last before lambdas
191
+ @Composable
192
+ fun MyComponent(
193
+ text: String,
194
+ modifier: Modifier = Modifier, // default to Modifier (empty)
195
+ onClick: () -> Unit
196
+ ) {
197
+ Box(modifier = modifier.clickable { onClick() }) {
198
+ Text(text)
199
+ }
200
+ }
201
+
202
+ // ✅ Order matters — padding before clickable = larger touch target
203
+ Box(modifier = Modifier
204
+ .padding(8.dp)
205
+ .clickable { } // touch area includes padding
206
+ )
207
+
208
+ // ✅ Clickable before padding = smaller touch target
209
+ Box(modifier = Modifier
210
+ .clickable { }
211
+ .padding(8.dp) // padding is outside the touch area
212
+ )
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Lists
218
+
219
+ ```kotlin
220
+ // ✅ LazyColumn for long lists — only renders visible items
221
+ @Composable
222
+ fun UserList(users: List<User>, onUserClick: (String) -> Unit) {
223
+ LazyColumn(
224
+ contentPadding = PaddingValues(16.dp),
225
+ verticalArrangement = Arrangement.spacedBy(8.dp)
226
+ ) {
227
+ items(
228
+ items = users,
229
+ key = { user -> user.id } // ✅ always provide stable key
230
+ ) { user ->
231
+ UserCard(user = user, onUserClick = onUserClick)
232
+ }
233
+ }
234
+ }
235
+
236
+ // ✅ Column only for short/fixed lists (< ~10 items)
237
+ @Composable
238
+ fun SettingsMenu(items: List<SettingItem>) {
239
+ Column {
240
+ items.forEach { item ->
241
+ SettingRow(item = item)
242
+ }
243
+ }
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Previews
250
+
251
+ ```kotlin
252
+ // ✅ Preview stateless composables
253
+ @Preview(showBackground = true)
254
+ @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
255
+ @Composable
256
+ private fun UserCardPreview() {
257
+ AppTheme {
258
+ UserCard(
259
+ user = User(id = "1", name = "Ali Rezaei", email = "ali@example.com"),
260
+ onUserClick = {}
261
+ )
262
+ }
263
+ }
264
+
265
+ // ✅ Preview with multiple states
266
+ @Preview(name = "Loading")
267
+ @Preview(name = "Success")
268
+ @Composable
269
+ private fun UserScreenPreview() {
270
+ AppTheme {
271
+ UserContent(state = previewState)
272
+ }
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Anti-Patterns
279
+
280
+ - Side effects directly in composable body — use `LaunchedEffect`/`DisposableEffect`
281
+ - Reading `viewModel.state.value` directly — use `collectAsStateWithLifecycle()`
282
+ - Not providing `key` in `items {}` — causes incorrect animations and recomposition
283
+ - Deeply nested composables — extract to named functions
284
+ - Not passing `modifier` parameter — prevents callers from customizing layout
285
+ - Creating remember/state inside loops or conditions — violates rules of hooks
286
+ - Using `Column` for long scrollable lists — use `LazyColumn`
287
+
288
+ ---
289
+
290
+ ## Related Skills
291
+ - `compose-navigation` — navigation between screens
292
+ - `compose-performance` — recomposition optimization
293
+ - `compose-animation` — animation in Compose
294
+ - `material3` — Material 3 components and theming
295
+ - `state-management` — state patterns with ViewModel
296
+ - `reactive-state-management` — collecting flows in Compose
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: compose-animation
3
+ description: >
4
+ Compose animation APIs and patterns for Android UI.
5
+ Load this skill when adding transitions, animated visibility,
6
+ motion between screens, or any time-based UI change in Compose.
7
+ ---
8
+
9
+ # Compose Animation
10
+
11
+ ## Overview
12
+ Compose provides a rich animation system ranging from simple animated value changes to complex physics-based motion. Animations improve UX by providing visual continuity and feedback. Choose the simplest API that meets the need.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - Choose the **simplest API** for the job — don't use `Animatable` when `animateFloatAsState` works
19
+ - Animations should **respect user accessibility settings** — check `reduceMotion`
20
+ - Never block the main thread — all Compose animations are coroutine-based
21
+ - Animate **state transitions**, not imperative sequences
22
+ - Use `AnimatedVisibility` and `AnimatedContent` before reaching for custom animations
23
+
24
+ ---
25
+
26
+ ## Animation API Hierarchy
27
+
28
+ ```
29
+ Simple value change → animateXxxAsState
30
+ Visibility show/hide → AnimatedVisibility
31
+ Content swap → AnimatedContent
32
+ Screen transitions → NavHost transitions
33
+ Multi-value / sequenced → updateTransition
34
+ Full control / physics → Animatable
35
+ Infinite → rememberInfiniteTransition
36
+ ```
37
+
38
+ ---
39
+
40
+ ## animateXxxAsState — Simple Value Animation
41
+
42
+ ```kotlin
43
+ // ✅ Animate a single value when state changes
44
+ @Composable
45
+ fun LikeButton(isLiked: Boolean, onToggle: () -> Unit) {
46
+ val scale by animateFloatAsState(
47
+ targetValue = if (isLiked) 1.2f else 1f,
48
+ animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy),
49
+ label = "like_scale" // ✅ always provide label for tooling
50
+ )
51
+ val color by animateColorAsState(
52
+ targetValue = if (isLiked) Color.Red else Color.Gray,
53
+ label = "like_color"
54
+ )
55
+
56
+ Icon(
57
+ imageVector = Icons.Default.Favorite,
58
+ contentDescription = null,
59
+ tint = color,
60
+ modifier = Modifier
61
+ .scale(scale)
62
+ .clickable { onToggle() }
63
+ )
64
+ }
65
+
66
+ // ✅ Animate size
67
+ val size by animateDpAsState(
68
+ targetValue = if (isExpanded) 200.dp else 100.dp,
69
+ animationSpec = tween(durationMillis = 300),
70
+ label = "card_size"
71
+ )
72
+ ```
73
+
74
+ ---
75
+
76
+ ## AnimatedVisibility
77
+
78
+ ```kotlin
79
+ // ✅ Show/hide with animation
80
+ @Composable
81
+ fun FilterPanel(isVisible: Boolean, content: @Composable () -> Unit) {
82
+ AnimatedVisibility(
83
+ visible = isVisible,
84
+ enter = slideInVertically() + fadeIn(),
85
+ exit = slideOutVertically() + fadeOut()
86
+ ) {
87
+ content()
88
+ }
89
+ }
90
+
91
+ // ✅ List item appearance
92
+ LazyColumn {
93
+ items(users, key = { it.id }) { user ->
94
+ AnimatedVisibility(
95
+ visible = true,
96
+ enter = fadeIn() + expandVertically()
97
+ ) {
98
+ UserCard(user = user)
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## AnimatedContent
107
+
108
+ ```kotlin
109
+ // ✅ Animate between different content states
110
+ @Composable
111
+ fun CounterDisplay(count: Int) {
112
+ AnimatedContent(
113
+ targetState = count,
114
+ transitionSpec = {
115
+ if (targetState > initialState) {
116
+ slideInVertically { -it } + fadeIn() togetherWith
117
+ slideOutVertically { it } + fadeOut()
118
+ } else {
119
+ slideInVertically { it } + fadeIn() togetherWith
120
+ slideOutVertically { -it } + fadeOut()
121
+ }
122
+ },
123
+ label = "counter"
124
+ ) { targetCount ->
125
+ Text(text = "$targetCount", style = MaterialTheme.typography.displayLarge)
126
+ }
127
+ }
128
+
129
+ // ✅ Switch between loading/content/error states
130
+ @Composable
131
+ fun ScreenContent(state: UiState) {
132
+ AnimatedContent(
133
+ targetState = state,
134
+ label = "screen_content"
135
+ ) { currentState ->
136
+ when (currentState) {
137
+ is UiState.Loading -> LoadingView()
138
+ is UiState.Success -> ContentView(currentState.data)
139
+ is UiState.Error -> ErrorView(currentState.message)
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ ---
146
+
147
+ ## updateTransition — Coordinated Multi-Value Animation
148
+
149
+ ```kotlin
150
+ // ✅ Animate multiple values tied to the same state
151
+ @Composable
152
+ fun ExpandableCard(isExpanded: Boolean) {
153
+ val transition = updateTransition(targetState = isExpanded, label = "card_transition")
154
+
155
+ val cornerRadius by transition.animateDp(label = "corner") {
156
+ if (it) 0.dp else 16.dp
157
+ }
158
+ val elevation by transition.animateDp(label = "elevation") {
159
+ if (it) 8.dp else 2.dp
160
+ }
161
+ val backgroundColor by transition.animateColor(label = "bg") {
162
+ if (it) MaterialTheme.colorScheme.primaryContainer
163
+ else MaterialTheme.colorScheme.surface
164
+ }
165
+
166
+ Card(
167
+ shape = RoundedCornerShape(cornerRadius),
168
+ colors = CardDefaults.cardColors(containerColor = backgroundColor)
169
+ ) { ... }
170
+ }
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Screen Transitions (Compose Navigation)
176
+
177
+ ```kotlin
178
+ // ✅ Global transitions in NavHost
179
+ NavHost(
180
+ navController = navController,
181
+ startDestination = HomeRoute,
182
+ enterTransition = { slideInHorizontally { it } + fadeIn() },
183
+ exitTransition = { slideOutHorizontally { -it } + fadeOut() },
184
+ popEnterTransition = { slideInHorizontally { -it } + fadeIn() },
185
+ popExitTransition = { slideOutHorizontally { it } + fadeOut() }
186
+ ) {
187
+ composable<HomeRoute> { HomeScreen() }
188
+ composable<DetailRoute> { DetailScreen() }
189
+ }
190
+
191
+ // ✅ Per-route transitions
192
+ composable<DetailRoute>(
193
+ enterTransition = { fadeIn(tween(300)) },
194
+ exitTransition = { fadeOut(tween(300)) }
195
+ ) { DetailScreen() }
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Animation Specs
201
+
202
+ ```kotlin
203
+ // tween — linear/eased time-based
204
+ tween(durationMillis = 300, easing = FastOutSlowInEasing)
205
+
206
+ // spring — physics-based, natural feel
207
+ spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessMedium)
208
+
209
+ // keyframes — precise time-value control
210
+ keyframes {
211
+ durationMillis = 400
212
+ 0f at 0
213
+ 1.2f at 200
214
+ 1f at 400
215
+ }
216
+
217
+ // snap — instant, no animation
218
+ snap()
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Accessibility — Reduced Motion
224
+
225
+ ```kotlin
226
+ // ✅ Respect user's reduce motion setting
227
+ @Composable
228
+ fun AccessibleAnimation(isVisible: Boolean) {
229
+ val reduceMotion = LocalReduceMotion.current // not yet in stable — use workaround
230
+
231
+ // Workaround until LocalReduceMotion is stable
232
+ val animationDuration = if (isSystemInDarkTheme()) 0 else 300
233
+
234
+ AnimatedVisibility(
235
+ visible = isVisible,
236
+ enter = fadeIn(tween(animationDuration)),
237
+ exit = fadeOut(tween(animationDuration))
238
+ ) { ... }
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Infinite Animation
245
+
246
+ ```kotlin
247
+ // ✅ Loading shimmer / pulse
248
+ @Composable
249
+ fun PulsingDot() {
250
+ val infiniteTransition = rememberInfiniteTransition(label = "pulse")
251
+ val scale by infiniteTransition.animateFloat(
252
+ initialValue = 0.8f,
253
+ targetValue = 1.2f,
254
+ animationSpec = infiniteRepeatable(
255
+ animation = tween(600),
256
+ repeatMode = RepeatMode.Reverse
257
+ ),
258
+ label = "scale"
259
+ )
260
+ Box(modifier = Modifier.scale(scale).size(12.dp).background(Color.Blue, CircleShape))
261
+ }
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Anti-Patterns
267
+
268
+ - Animating on every recomposition — animation state must be stable
269
+ - Missing `label` parameter — breaks Animation Inspector in Android Studio
270
+ - Using `Thread.sleep()` or `delay()` for animation timing — use animation specs
271
+ - Animating too many properties simultaneously — causes jank
272
+ - Not testing with reduced motion — accessibility oversight
273
+ - Using `LaunchedEffect` + manual delay for show/hide — use `AnimatedVisibility`
274
+
275
+ ---
276
+
277
+ ## Related Skills
278
+ - `compose` — Compose fundamentals and state
279
+ - `compose-performance` — avoiding recomposition during animation
280
+ - `material3` — Material 3 motion system
281
+ - `loading-strategy` — animated loading states