agy-superpowers 5.0.7 → 5.0.9
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.
- package/package.json +1 -1
- package/template/agent/rules/superpowers.md +54 -0
- package/template/agent/skills/api-design/SKILL.md +193 -0
- package/template/agent/skills/app-store-optimizer/SKILL.md +127 -0
- package/template/agent/skills/auth-and-identity/SKILL.md +167 -0
- package/template/agent/skills/backend-developer/SKILL.md +148 -0
- package/template/agent/skills/community-manager/SKILL.md +115 -0
- package/template/agent/skills/content-marketer/SKILL.md +111 -0
- package/template/agent/skills/conversion-optimizer/SKILL.md +142 -0
- package/template/agent/skills/copywriter/SKILL.md +114 -0
- package/template/agent/skills/cto-architect/SKILL.md +133 -0
- package/template/agent/skills/customer-success-manager/SKILL.md +126 -0
- package/template/agent/skills/data-analyst/SKILL.md +147 -0
- package/template/agent/skills/devops-engineer/SKILL.md +117 -0
- package/template/agent/skills/email-infrastructure/SKILL.md +164 -0
- package/template/agent/skills/frontend-developer/SKILL.md +172 -0
- package/template/agent/skills/frontend-developer/references/react-nextjs.md +343 -0
- package/template/agent/skills/frontend-developer/references/react-rules/_sections.md +46 -0
- package/template/agent/skills/frontend-developer/references/react-rules/_template.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-event-handler-refs.md +55 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-init-once.md +42 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-use-latest.md +39 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-api-routes.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-defer-await.md +80 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-dependencies.md +51 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-parallel.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-suspense-boundaries.md +99 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-barrel-imports.md +59 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-conditional.md +31 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-defer-third-party.md +49 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-dynamic-imports.md +35 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-preload.md +50 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-event-listeners.md +74 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-localstorage-schema.md +71 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-passive-event-listeners.md +48 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-swr-dedup.md +56 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-batch-dom-css.md +107 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-function-results.md +80 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-property-access.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-storage.md +70 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-combine-iterations.md +32 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-early-exit.md +50 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-flatmap-filter.md +60 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-hoist-regexp.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-index-maps.md +37 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-length-check-first.md +49 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-min-max-loop.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-set-map-lookups.md +24 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-tosorted-immutable.md +57 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-activity.md +26 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-animate-svg-wrapper.md +47 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-conditional-render.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-content-visibility.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hoist-jsx.md +46 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hydration-no-flicker.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hydration-suppress-warning.md +30 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-resource-hints.md +85 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-script-defer-async.md +68 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-svg-precision.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-usetransition-loading.md +75 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-defer-reads.md +39 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-dependencies.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-derived-state-no-effect.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-derived-state.md +29 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-functional-setstate.md +74 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-lazy-state-init.md +58 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-memo-with-default-value.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-memo.md +44 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-move-effect-to-event.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-no-inline-components.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-simple-expression-in-memo.md +35 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-split-combined-hooks.md +64 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-transitions.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-use-deferred-value.md +59 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-use-ref-transient-values.md +73 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-after-nonblocking.md +73 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-auth-actions.md +96 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-cache-lru.md +41 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-cache-react.md +76 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-dedup-props.md +65 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-hoist-static-io.md +142 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-parallel-fetching.md +83 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-serialization.md +38 -0
- package/template/agent/skills/frontend-developer/references/svelte-sveltekit.md +220 -0
- package/template/agent/skills/frontend-developer/references/vanilla.md +275 -0
- package/template/agent/skills/frontend-developer/references/vue-nuxt.md +289 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/_index.md +154 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/animation-class-based-technique.md +254 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/animation-state-driven-technique.md +291 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-async.md +97 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-data-flow.md +307 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-fallthrough-attrs.md +174 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-keep-alive.md +137 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-slots.md +216 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-suspense.md +228 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-teleport.md +108 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-transition-group.md +128 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-transition.md +125 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/composables.md +290 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/directives.md +162 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-v-once-v-memo-directives.md +182 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-virtualize-large-lists.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/plugins.md +166 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/reactivity.md +344 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/render-functions.md +201 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/sfc.md +310 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/state-management.md +135 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/updated-hook-performance.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/_index.md +23 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-beforeenter-no-param-trigger.md +167 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-beforerouteenter-no-this.md +176 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-guard-async-await-pattern.md +227 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-navigation-guard-infinite-loop.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-navigation-guard-next-deprecated.md +150 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-param-change-no-lifecycle.md +181 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-simple-routing-cleanup.md +209 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-use-vue-router-for-production.md +183 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/_index.md +29 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/async-component-testing.md +163 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/teleport-testing-complexity.md +158 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-async-await-flushpromises.md +175 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-browser-vs-node-runners.md +208 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-component-blackbox-approach.md +144 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-composables-helper-wrapper.md +238 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-e2e-playwright-recommended.md +242 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-no-snapshot-only.md +197 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-pinia-store-setup.md +228 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-suspense-async-components.md +229 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-vitest-recommended-for-vue.md +204 -0
- package/template/agent/skills/game-design/SKILL.md +194 -0
- package/template/agent/skills/game-developer/SKILL.md +175 -0
- package/template/agent/skills/growth-hacker/SKILL.md +122 -0
- package/template/agent/skills/i18n-localization/SKILL.md +126 -0
- package/template/agent/skills/influencer-marketer/SKILL.md +141 -0
- package/template/agent/skills/mobile-developer/SKILL.md +194 -0
- package/template/agent/skills/mobile-developer/references/android-native.md +396 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-accessibility.md +36 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-architecture.md +52 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-coroutines.md +139 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-data-layer.md +51 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-emulator-skill.md +108 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-gradle-logic.md +126 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-retrofit.md +142 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-testing.md +102 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-viewmodel.md +43 -0
- package/template/agent/skills/mobile-developer/references/android-rules/coil-compose.md +74 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-navigation.md +422 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-performance-audit.md +199 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-ui.md +49 -0
- package/template/agent/skills/mobile-developer/references/android-rules/gradle-build-performance.md +346 -0
- package/template/agent/skills/mobile-developer/references/android-rules/kotlin-concurrency-expert.md +169 -0
- package/template/agent/skills/mobile-developer/references/android-rules/rxjava-to-coroutines-migration.md +101 -0
- package/template/agent/skills/mobile-developer/references/android-rules/xml-to-compose-migration.md +338 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-best-practices.md +52 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-checks-migration.md +134 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-cli-app-best-practices.md +123 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-doc-validation.md +45 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-matcher-best-practices.md +106 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-modern-features.md +241 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-package-maintenance.md +75 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-test-fundamentals.md +124 -0
- package/template/agent/skills/mobile-developer/references/flutter.md +291 -0
- package/template/agent/skills/mobile-developer/references/ios-native.md +358 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/accessibility-patterns.md +215 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-advanced.md +403 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-basics.md +284 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-transitions.md +326 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/charts-accessibility.md +135 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/charts.md +602 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/image-optimization.md +203 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/latest-apis.md +464 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/layout-best-practices.md +266 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/liquid-glass.md +416 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/list-patterns.md +394 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-scenes.md +318 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-views.md +357 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-window-styling.md +303 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/performance-patterns.md +403 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/scroll-patterns.md +293 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/sheet-navigation-patterns.md +363 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/state-management.md +417 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/view-structure.md +389 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/_sections.md +86 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/_template.md +28 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-derived-value.md +53 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-gesture-detector-press.md +95 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-gpu-properties.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/design-system-compound-components.md +66 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/fonts-config-plugin.md +71 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/imports-design-system-folder.md +68 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/js-hoist-intl.md +61 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-callbacks.md +44 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-function-references.md +132 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-images.md +53 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-inline-objects.md +97 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-expensive.md +94 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-memo.md +82 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-types.md +104 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-virtualize.md +67 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/monorepo-native-deps-in-app.md +46 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/monorepo-single-dependency-versions.md +63 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/navigation-native-navigators.md +188 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-compiler-destructure-functions.md +50 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-compiler-reanimated-shared-values.md +48 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-dispatcher.md +91 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-fallback.md +56 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-minimize.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/rendering-no-falsy-and.md +74 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/rendering-text-in-text-component.md +36 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/scroll-position-no-state.md +82 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/state-ground-truth.md +80 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-expo-image.md +66 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-image-gallery.md +104 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-measure-views.md +78 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-menus.md +174 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-native-modals.md +77 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-pressable.md +61 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-safe-area-scroll.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-scrollview-content-inset.md +45 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-styling.md +87 -0
- package/template/agent/skills/mobile-developer/references/react-native.md +345 -0
- package/template/agent/skills/monetization-strategist/SKILL.md +119 -0
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +119 -0
- package/template/agent/skills/product-manager/SKILL.md +105 -0
- package/template/agent/skills/real-time-features/SKILL.md +194 -0
- package/template/agent/skills/retention-specialist/SKILL.md +123 -0
- package/template/agent/skills/saas-architect/SKILL.md +139 -0
- package/template/agent/skills/security-engineer/SKILL.md +133 -0
- package/template/agent/skills/seo-specialist/SKILL.md +130 -0
- package/template/agent/skills/subscription-billing/SKILL.md +179 -0
- package/template/agent/skills/ux-designer/SKILL.md +128 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# Android Native (Kotlin / Jetpack Compose) Reference
|
|
2
|
+
|
|
3
|
+
> **Philosophy:** Material Design, Kotlin-first, Compose-first.
|
|
4
|
+
> Lifecycle-aware, configuration-change-safe, backwards-compatible.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Project Setup & Detection
|
|
9
|
+
|
|
10
|
+
**Stack indicators:** `build.gradle.kts` or `build.gradle`, `AndroidManifest.xml`, `settings.gradle.kts`.
|
|
11
|
+
|
|
12
|
+
**Key config files:**
|
|
13
|
+
|
|
14
|
+
| File | Purpose |
|
|
15
|
+
|------|---------|
|
|
16
|
+
| `build.gradle.kts` (app module) | App dependencies, minSdk, targetSdk, signing |
|
|
17
|
+
| `build.gradle.kts` (project) | Plugin versions, repositories |
|
|
18
|
+
| `settings.gradle.kts` | Module declarations, version catalog |
|
|
19
|
+
| `gradle/libs.versions.toml` | Gradle Version Catalog (centralized dependency versions) |
|
|
20
|
+
| `AndroidManifest.xml` | Permissions, components, intent filters |
|
|
21
|
+
| `proguard-rules.pro` | R8/ProGuard minification rules |
|
|
22
|
+
|
|
23
|
+
**Recommended project structure (feature-based, multi-module):**
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
app/
|
|
27
|
+
src/main/
|
|
28
|
+
java/com/example/myapp/
|
|
29
|
+
MyApp.kt # Application class
|
|
30
|
+
MainActivity.kt # Single Activity
|
|
31
|
+
navigation/
|
|
32
|
+
AppNavigation.kt # NavHost setup
|
|
33
|
+
res/
|
|
34
|
+
values/themes.xml
|
|
35
|
+
feature/
|
|
36
|
+
auth/
|
|
37
|
+
src/main/java/.../auth/
|
|
38
|
+
ui/LoginScreen.kt
|
|
39
|
+
LoginViewModel.kt
|
|
40
|
+
data/AuthRepository.kt
|
|
41
|
+
home/
|
|
42
|
+
src/main/java/.../home/
|
|
43
|
+
ui/HomeScreen.kt
|
|
44
|
+
HomeViewModel.kt
|
|
45
|
+
core/
|
|
46
|
+
data/ # Shared data layer
|
|
47
|
+
ui/ # Shared Compose components
|
|
48
|
+
network/ # Retrofit setup, API definitions
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Architecture Patterns
|
|
54
|
+
|
|
55
|
+
### MVVM with ViewModel + StateFlow
|
|
56
|
+
|
|
57
|
+
```kotlin
|
|
58
|
+
class ProfileViewModel @Inject constructor(
|
|
59
|
+
private val userRepository: UserRepository,
|
|
60
|
+
) : ViewModel() {
|
|
61
|
+
|
|
62
|
+
private val _uiState = MutableStateFlow<ProfileUiState>(ProfileUiState.Loading)
|
|
63
|
+
val uiState: StateFlow<ProfileUiState> = _uiState.asStateFlow()
|
|
64
|
+
|
|
65
|
+
init { loadProfile() }
|
|
66
|
+
|
|
67
|
+
private fun loadProfile() {
|
|
68
|
+
viewModelScope.launch {
|
|
69
|
+
_uiState.value = ProfileUiState.Loading
|
|
70
|
+
userRepository.getProfile()
|
|
71
|
+
.onSuccess { _uiState.value = ProfileUiState.Success(it) }
|
|
72
|
+
.onFailure { _uiState.value = ProfileUiState.Error(it.message) }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
sealed interface ProfileUiState {
|
|
78
|
+
data object Loading : ProfileUiState
|
|
79
|
+
data class Success(val user: User) : ProfileUiState
|
|
80
|
+
data class Error(val message: String?) : ProfileUiState
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Dependency Injection
|
|
85
|
+
|
|
86
|
+
| Framework | Use When |
|
|
87
|
+
|-----------|----------|
|
|
88
|
+
| **Hilt** (recommended) | Most apps — Google-supported, integrates with ViewModel, WorkManager |
|
|
89
|
+
| **Koin** | Lightweight, no annotation processing, multiplatform support |
|
|
90
|
+
|
|
91
|
+
```kotlin
|
|
92
|
+
// Hilt module
|
|
93
|
+
@Module
|
|
94
|
+
@InstallIn(SingletonComponent::class)
|
|
95
|
+
object NetworkModule {
|
|
96
|
+
@Provides @Singleton
|
|
97
|
+
fun provideRetrofit(): Retrofit = Retrofit.Builder()
|
|
98
|
+
.baseUrl("https://api.example.com/")
|
|
99
|
+
.addConverterFactory(MoshiConverterFactory.create())
|
|
100
|
+
.build()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ViewModel injection
|
|
104
|
+
@HiltViewModel
|
|
105
|
+
class HomeViewModel @Inject constructor(
|
|
106
|
+
private val repository: ItemRepository,
|
|
107
|
+
) : ViewModel()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Navigation
|
|
111
|
+
|
|
112
|
+
**Navigation Compose** — type-safe with Kotlin serialization:
|
|
113
|
+
|
|
114
|
+
```kotlin
|
|
115
|
+
@Serializable data class Profile(val id: String)
|
|
116
|
+
|
|
117
|
+
NavHost(navController, startDestination = Home) {
|
|
118
|
+
composable<Home> { HomeScreen(onNavigate = { navController.navigate(Profile(it)) }) }
|
|
119
|
+
composable<Profile> { backStackEntry ->
|
|
120
|
+
val profile: Profile = backStackEntry.toRoute()
|
|
121
|
+
ProfileScreen(id = profile.id)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- Use **single-Activity** architecture with Compose Navigation
|
|
127
|
+
- Use `NavBackStackEntry.toRoute()` for type-safe argument extraction
|
|
128
|
+
- Handle deep links via `deepLinks` parameter in `composable()`
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Performance Optimization
|
|
133
|
+
|
|
134
|
+
### Critical Thresholds
|
|
135
|
+
|
|
136
|
+
| Metric | Target | Investigate |
|
|
137
|
+
|--------|--------|-------------|
|
|
138
|
+
| Cold start | < 1s | > 2s |
|
|
139
|
+
| Frame rendering | 16ms (60fps) | > 32ms |
|
|
140
|
+
| APK/AAB size | < 20MB | > 50MB |
|
|
141
|
+
| Memory (foreground) | < 150MB | > 300MB |
|
|
142
|
+
|
|
143
|
+
### Compose Performance
|
|
144
|
+
|
|
145
|
+
1. **Stability matters** — Compose skips recomposition for stable parameters. Unstable types (lists, lambdas) prevent skipping.
|
|
146
|
+
|
|
147
|
+
```kotlin
|
|
148
|
+
// ❌ Bad: List<Item> is unstable, recomposes every time
|
|
149
|
+
@Composable fun ItemList(items: List<Item>) { ... }
|
|
150
|
+
|
|
151
|
+
// ✅ Good: ImmutableList is stable, skips recomposition when data unchanged
|
|
152
|
+
@Composable fun ItemList(items: ImmutableList<Item>) { ... }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. **`@Stable` and `@Immutable` annotations** — tell Compose your types are stable.
|
|
156
|
+
|
|
157
|
+
```kotlin
|
|
158
|
+
@Immutable
|
|
159
|
+
data class UserProfile(val id: String, val name: String, val avatarUrl: String)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
3. **`LazyColumn` with stable keys** — always provide unique keys for correct recomposition and animation.
|
|
163
|
+
|
|
164
|
+
```kotlin
|
|
165
|
+
LazyColumn {
|
|
166
|
+
items(items, key = { it.id }) { item ->
|
|
167
|
+
ItemRow(item = item)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
4. **`remember` wisely** — use `remember` for expensive computations, not simple derivations. Don't use `remember` with unstable keys.
|
|
173
|
+
|
|
174
|
+
5. **Baseline Profiles** — pre-compile hot paths at install time, reducing cold start time by 30-50%.
|
|
175
|
+
|
|
176
|
+
```kotlin
|
|
177
|
+
// benchmark/src/main/java/BaselineProfileGenerator.kt
|
|
178
|
+
@RunWith(AndroidJUnit4::class)
|
|
179
|
+
class BaselineProfileGenerator {
|
|
180
|
+
@get:Rule val rule = BaselineProfileRule()
|
|
181
|
+
|
|
182
|
+
@Test
|
|
183
|
+
fun generate() {
|
|
184
|
+
rule.collect("com.example.myapp") {
|
|
185
|
+
pressHome()
|
|
186
|
+
startActivityAndWait()
|
|
187
|
+
// Navigate through critical flows
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
6. **R8 minification** — always enable for release builds. Removes unused code and obfuscates.
|
|
194
|
+
|
|
195
|
+
7. **StrictMode** — enable in debug to catch disk/network on main thread:
|
|
196
|
+
|
|
197
|
+
```kotlin
|
|
198
|
+
if (BuildConfig.DEBUG) {
|
|
199
|
+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
|
|
200
|
+
.detectAll().penaltyLog().build())
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Common Libraries Ecosystem
|
|
207
|
+
|
|
208
|
+
| Category | Recommended | Alternative |
|
|
209
|
+
|----------|-------------|-------------|
|
|
210
|
+
| **Networking** | `Retrofit` + `OkHttp` | `Ktor` |
|
|
211
|
+
| **JSON** | `Moshi` / `Kotlin Serialization` | `Gson` (legacy) |
|
|
212
|
+
| **Database** | `Room` | `SQLDelight` |
|
|
213
|
+
| **Preferences** | `DataStore` | `SharedPreferences` (legacy) |
|
|
214
|
+
| **Secure Storage** | `EncryptedSharedPreferences` | `Tink` |
|
|
215
|
+
| **Images** | `Coil` (Compose-native) | `Glide` |
|
|
216
|
+
| **DI** | `Hilt` | `Koin` |
|
|
217
|
+
| **UI** | Material 3 (`material3`) | — |
|
|
218
|
+
| **Async** | Kotlin `Flow` + `Coroutines` | RxJava (legacy) |
|
|
219
|
+
| **Paging** | `Paging 3` | — |
|
|
220
|
+
| **Work** | `WorkManager` | — |
|
|
221
|
+
| **Testing** | `JUnit 5` + `MockK` | `Mockito-Kotlin` |
|
|
222
|
+
| **Compose Testing** | `compose-test` | — |
|
|
223
|
+
| **Analytics** | Firebase Analytics | Amplitude |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Anti-Patterns & Gotchas
|
|
228
|
+
|
|
229
|
+
| ❌ Don't | Why | ✅ Do Instead |
|
|
230
|
+
|----------|-----|---------------|
|
|
231
|
+
| Unstable lambdas in Compose | Prevents recomposition skipping | Extract to ViewModel, hoist to caller, or use `remember` |
|
|
232
|
+
| `MutableList`/`List` parameters | Unstable in Compose, always recomposes | `ImmutableList` from `kotlinx.collections.immutable` |
|
|
233
|
+
| `remember { mutableStateOf() }` for ViewModel state | ViewModel outlives Compose, wrong lifecycle | `StateFlow` in ViewModel, `collectAsStateWithLifecycle` in UI |
|
|
234
|
+
| Blocking main thread | ANR (Application Not Responding) | Coroutines with `Dispatchers.IO` |
|
|
235
|
+
| Missing ProGuard rules | Crashes in release (reflection-based libs) | Add keep rules for Retrofit, Moshi, Room models |
|
|
236
|
+
| Hardcoded dp/sp values everywhere | Inconsistent across screens | Design tokens / theme values |
|
|
237
|
+
| `GlobalScope.launch` | Lifecycle leak, no cancellation | `viewModelScope`, `lifecycleScope`, or custom scope |
|
|
238
|
+
| `SharedPreferences` for complex data | Race conditions, no type safety | `DataStore` with Proto or Preferences |
|
|
239
|
+
| Multiple Activities for navigation | Complex backstack, state loss | Single Activity + Compose Navigation |
|
|
240
|
+
| `@Preview` without sample data | Previews are useless | Use `@PreviewParameter` with sample providers |
|
|
241
|
+
|
|
242
|
+
### Compose-Specific Pitfalls
|
|
243
|
+
|
|
244
|
+
- **`derivedStateOf`** — use for expensive computations that depend on state. Don't use for simple reads.
|
|
245
|
+
- **`LaunchedEffect` vs `SideEffect`** — `LaunchedEffect` for suspend functions (runs once per key), `SideEffect` for every recomposition.
|
|
246
|
+
- **`rememberSaveable`** — survives configuration changes and process death. Use for user input, scroll position.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Testing
|
|
251
|
+
|
|
252
|
+
| Layer | Tool | Purpose |
|
|
253
|
+
|-------|------|---------|
|
|
254
|
+
| **Unit** | JUnit 5 + MockK | ViewModel, Repository, UseCase |
|
|
255
|
+
| **Compose UI** | `createComposeRule()` | Component rendering and interaction |
|
|
256
|
+
| **Integration** | Espresso (+ Compose) | Full screen flows |
|
|
257
|
+
| **Robolectric** | JVM-based Android tests | Fast feedback, no emulator needed |
|
|
258
|
+
| **Screenshot** | Compose Preview Screenshot Testing | Visual regression |
|
|
259
|
+
|
|
260
|
+
**Testing Compose:**
|
|
261
|
+
|
|
262
|
+
```kotlin
|
|
263
|
+
@get:Rule val composeTestRule = createComposeRule()
|
|
264
|
+
|
|
265
|
+
@Test
|
|
266
|
+
fun showsLoginButton() {
|
|
267
|
+
composeTestRule.setContent { LoginScreen() }
|
|
268
|
+
composeTestRule.onNodeWithText("Log In").assertIsDisplayed()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@Test
|
|
272
|
+
fun submitForm() {
|
|
273
|
+
composeTestRule.setContent { LoginScreen() }
|
|
274
|
+
composeTestRule.onNodeWithTag("email_input").performTextInput("test@example.com")
|
|
275
|
+
composeTestRule.onNodeWithText("Log In").performClick()
|
|
276
|
+
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**ViewModel testing:**
|
|
281
|
+
|
|
282
|
+
```kotlin
|
|
283
|
+
@Test
|
|
284
|
+
fun loadProfile_success() = runTest {
|
|
285
|
+
val repo = mockk<UserRepository> {
|
|
286
|
+
coEvery { getProfile() } returns Result.success(testUser)
|
|
287
|
+
}
|
|
288
|
+
val vm = ProfileViewModel(repo)
|
|
289
|
+
vm.uiState.test {
|
|
290
|
+
assertThat(awaitItem()).isEqualTo(ProfileUiState.Loading)
|
|
291
|
+
assertThat(awaitItem()).isEqualTo(ProfileUiState.Success(testUser))
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Deployment & Distribution
|
|
299
|
+
|
|
300
|
+
### Build Commands
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Debug build
|
|
304
|
+
./gradlew assembleDebug
|
|
305
|
+
|
|
306
|
+
# Release APK
|
|
307
|
+
./gradlew assembleRelease
|
|
308
|
+
|
|
309
|
+
# Release AAB (Play Store required format)
|
|
310
|
+
./gradlew bundleRelease
|
|
311
|
+
|
|
312
|
+
# Run tests
|
|
313
|
+
./gradlew test # Unit tests
|
|
314
|
+
./gradlew connectedAndroidTest # Instrumented tests
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Distribution Channels
|
|
318
|
+
|
|
319
|
+
| Channel | Use When |
|
|
320
|
+
|---------|----------|
|
|
321
|
+
| **Google Play Internal Testing** | Fast internal feedback (up to 100 testers) |
|
|
322
|
+
| **Google Play Closed Testing** | Beta testing with larger groups |
|
|
323
|
+
| **Google Play Production** | Public release (staged rollout recommended) |
|
|
324
|
+
| **Firebase App Distribution** | Ad hoc testing, no Play Store needed |
|
|
325
|
+
|
|
326
|
+
### Signing Configuration
|
|
327
|
+
|
|
328
|
+
```kotlin
|
|
329
|
+
// build.gradle.kts
|
|
330
|
+
android {
|
|
331
|
+
signingConfigs {
|
|
332
|
+
create("release") {
|
|
333
|
+
storeFile = file(System.getenv("KEYSTORE_PATH"))
|
|
334
|
+
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
|
335
|
+
keyAlias = System.getenv("KEY_ALIAS")
|
|
336
|
+
keyPassword = System.getenv("KEY_PASSWORD")
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
buildTypes {
|
|
340
|
+
release {
|
|
341
|
+
signingConfig = signingConfigs.getByName("release")
|
|
342
|
+
isMinifyEnabled = true
|
|
343
|
+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### App Size Optimization
|
|
350
|
+
- Enable R8 minification (`isMinifyEnabled = true`)
|
|
351
|
+
- Use Android App Bundle (`.aab`) — Google Play delivers optimized APK per device
|
|
352
|
+
- Remove unused resources with `shrinkResources = true`
|
|
353
|
+
- Use WebP for images (30% smaller than PNG)
|
|
354
|
+
- Split APKs by ABI if distributing outside Play Store
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Quick Reference — Granular Rules
|
|
359
|
+
|
|
360
|
+
Individual skill files in `android-rules/` with detailed patterns, code
|
|
361
|
+
examples, and audit workflows for Android/Kotlin/Compose development.
|
|
362
|
+
|
|
363
|
+
> Source: [awesome-android-agent-skills](https://github.com/new-silvermoon/awesome-android-agent-skills)
|
|
364
|
+
|
|
365
|
+
### Architecture & Core
|
|
366
|
+
|
|
367
|
+
- [android-architecture.md](android-rules/android-architecture.md) — Clean Architecture, modularization, Hilt DI
|
|
368
|
+
- [android-viewmodel.md](android-rules/android-viewmodel.md) — ViewModel + StateFlow/SharedFlow patterns
|
|
369
|
+
- [android-data-layer.md](android-rules/android-data-layer.md) — Repository pattern, offline-first sync
|
|
370
|
+
- [kotlin-concurrency-expert.md](android-rules/kotlin-concurrency-expert.md) — Coroutines triage & structured concurrency
|
|
371
|
+
- [android-coroutines.md](android-rules/android-coroutines.md) — Coroutines patterns
|
|
372
|
+
|
|
373
|
+
### Compose UI & Performance
|
|
374
|
+
|
|
375
|
+
- [compose-ui.md](android-rules/compose-ui.md) — Stateless composables, state hoisting, theming
|
|
376
|
+
- [compose-performance-audit.md](android-rules/compose-performance-audit.md) — Recomposition storms, unstable keys audit
|
|
377
|
+
- [compose-navigation.md](android-rules/compose-navigation.md) — Type-safe navigation, deep links, nested graphs
|
|
378
|
+
- [coil-compose.md](android-rules/coil-compose.md) — Coil image loading in Compose
|
|
379
|
+
|
|
380
|
+
### Networking & Data
|
|
381
|
+
|
|
382
|
+
- [android-retrofit.md](android-rules/android-retrofit.md) — Retrofit, OkHttp, serialization, interceptors
|
|
383
|
+
- [android-accessibility.md](android-rules/android-accessibility.md) — Content descriptions, touch targets, contrast
|
|
384
|
+
|
|
385
|
+
### Testing & Build
|
|
386
|
+
|
|
387
|
+
- [android-testing.md](android-rules/android-testing.md) — Unit, Hilt, screenshot testing (Roborazzi)
|
|
388
|
+
- [android-gradle-logic.md](android-rules/android-gradle-logic.md) — Convention plugins, version catalogs
|
|
389
|
+
- [gradle-build-performance.md](android-rules/gradle-build-performance.md) — Build time optimization (12 patterns)
|
|
390
|
+
- [android-emulator-skill.md](android-rules/android-emulator-skill.md) — ADB, emulator automation
|
|
391
|
+
|
|
392
|
+
### Migration
|
|
393
|
+
|
|
394
|
+
- [xml-to-compose-migration.md](android-rules/xml-to-compose-migration.md) — XML to Compose mapping tables
|
|
395
|
+
- [rxjava-to-coroutines-migration.md](android-rules/rxjava-to-coroutines-migration.md) — RxJava to Coroutines/Flow
|
|
396
|
+
|
package/template/agent/skills/mobile-developer/references/android-rules/android-accessibility.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-accessibility
|
|
3
|
+
description: Expert checklist and prompts for auditing and fixing Android accessibility issues, especially in Jetpack Compose.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Accessibility Checklist
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
Analyze the provided component or screen for the following accessibility aspects.
|
|
11
|
+
|
|
12
|
+
### 1. Content Descriptions
|
|
13
|
+
* **Check**: Do `Image` and `Icon` composables have a meaningful `contentDescription`?
|
|
14
|
+
* **Decorative**: If an image is purely decorative, use `contentDescription = null`.
|
|
15
|
+
* **Actionable**: If an element is clickable, the description should describe the *action* (e.g., "Play music"), not the icon (e.g., "Triangle").
|
|
16
|
+
|
|
17
|
+
### 2. Touch Target Size
|
|
18
|
+
* **Standard**: Minimum **48x48dp** for all interactive elements.
|
|
19
|
+
* **Fix**: Use `MinTouchTargetSize` or wrap in `Box` with appropriate padding if the visual icon is smaller.
|
|
20
|
+
|
|
21
|
+
### 3. Color Contrast
|
|
22
|
+
* **Standard**: WCAG AA requires **4.5:1** for normal text and **3.0:1** for large text/icons.
|
|
23
|
+
* **Tool**: Verify colors against backgrounds using contrast logic.
|
|
24
|
+
|
|
25
|
+
### 4. Focus & Semantics
|
|
26
|
+
* **Focus Order**: Ensure keyboard/screen-reader focus moves logically (e.g., Top-Start to Bottom-End).
|
|
27
|
+
* **Grouping**: Use `Modifier.semantics(mergeDescendants = true)` for complex items (like a row with text and icon) so they are announced as a single item.
|
|
28
|
+
* **State descriptions**: Use `stateDescription` to describe custom states (e.g., "Selected", "Checked") if standard semantics aren't enough.
|
|
29
|
+
|
|
30
|
+
### 5. Headings
|
|
31
|
+
* **Traversal**: Mark title texts with `Modifier.semantics { heading() }` to allow screen reader users to jump between sections.
|
|
32
|
+
|
|
33
|
+
## Example Prompts for Agent Usage
|
|
34
|
+
* "Analyze the content description of this Image. Is it appropriate?"
|
|
35
|
+
* "Check if the touch target size of this button is at least 48dp."
|
|
36
|
+
* "Does this custom toggle button report its 'Checked' state to TalkBack?"
|
package/template/agent/skills/mobile-developer/references/android-rules/android-architecture.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-architecture
|
|
3
|
+
description: Expert guidance on setting up and maintaining a modern Android application architecture using Clean Architecture and Hilt. Use this when asked about project structure, module setup, or dependency injection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Modern Architecture & Modularization
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
When designing or refactoring an Android application, adhere to the **Guide to App Architecture** and **Clean Architecture** principles.
|
|
11
|
+
|
|
12
|
+
### 1. High-Level Layers
|
|
13
|
+
Structure the application into three primary layers. Dependencies must strictly flow **inwards** (or downwards) to the core logic.
|
|
14
|
+
|
|
15
|
+
* **UI Layer (Presentation)**:
|
|
16
|
+
* **Responsibility**: Displaying data and handling user interactions.
|
|
17
|
+
* **Components**: Activities, Fragments, Composables, ViewModels.
|
|
18
|
+
* **Dependencies**: Depends on the Domain Layer (or Data Layer if simple). **Never** depends on the Data Layer implementation details directly.
|
|
19
|
+
* **Domain Layer (Business Logic) [Optional but Recommended]**:
|
|
20
|
+
* **Responsibility**: Encapsulating complex business rules and reuse.
|
|
21
|
+
* **Components**: Use Cases (e.g., `GetLatestNewsUseCase`), Domain Models (pure Kotlin data classes).
|
|
22
|
+
* **Pure Kotlin**: Must NOT contain any Android framework dependencies (no `android.*` imports).
|
|
23
|
+
* **Dependencies**: Depends on Repository Interfaces.
|
|
24
|
+
* **Data Layer**:
|
|
25
|
+
* **Responsibility**: Managing application data (fetching, caching, saving).
|
|
26
|
+
* **Components**: Repositories (implementations), Data Sources (Retrofit APIs, Room DAOs).
|
|
27
|
+
* **Dependencies**: Depends only on external sources and libraries.
|
|
28
|
+
|
|
29
|
+
### 2. Dependency Injection with Hilt
|
|
30
|
+
Use **Hilt** for all dependency injection.
|
|
31
|
+
|
|
32
|
+
* **@HiltAndroidApp**: Annotate the `Application` class.
|
|
33
|
+
* **@AndroidEntryPoint**: Annotate Activities and Fragments.
|
|
34
|
+
* **@HiltViewModel**: Annotate ViewModels; use standard `constructor` injection.
|
|
35
|
+
* **Modules**:
|
|
36
|
+
* Use `@Module` and `@InstallIn(SingletonComponent::class)` for app-wide singletons (e.g., Network, Database).
|
|
37
|
+
* Use `@Binds` in an abstract class to bind interface implementations (cleaner than `@Provides`).
|
|
38
|
+
|
|
39
|
+
### 3. Modularization Strategy
|
|
40
|
+
For production apps, use a multi-module strategy to improve build times and separation of concerns.
|
|
41
|
+
|
|
42
|
+
* **:app**: The main entry point, connects features.
|
|
43
|
+
* **:core:model**: Shared domain models (Pure Kotlin).
|
|
44
|
+
* **:core:data**: Repositories, Data Sources, Database, Network.
|
|
45
|
+
* **:core:domain**: Use Cases and Repository Interfaces.
|
|
46
|
+
* **:core:ui**: Shared Composables, Theme, Resources.
|
|
47
|
+
* **:feature:[name]**: Standalone feature modules containing their own UI and ViewModels. Depends on `:core:domain` and `:core:ui`.
|
|
48
|
+
|
|
49
|
+
### 4. Checklist for implementation
|
|
50
|
+
- [ ] Ensure `Domain` layer has no Android dependencies.
|
|
51
|
+
- [ ] Repositories should default to main-safe suspend functions (use `Dispatchers.IO` internally if needed).
|
|
52
|
+
- [ ] ViewModels should interact with the UI layer via `StateFlow` (see `android-viewmodel` skill).
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-coroutines
|
|
3
|
+
description: Authoritative rules and patterns for production-quality Kotlin Coroutines onto Android. Covers structured concurrency, lifecycle integration, and reactive streams.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Coroutines Expert Skill
|
|
7
|
+
|
|
8
|
+
This skill provides authoritative rules and patterns for writing production-quality Kotlin Coroutines code on Android. It enforces structured concurrency, lifecycle safety, and modern best practices (2025 standards).
|
|
9
|
+
|
|
10
|
+
## Responsibilities
|
|
11
|
+
|
|
12
|
+
* **Asynchronous Logic**: Implementing suspend functions, Dispatcher management, and parallel execution.
|
|
13
|
+
* **Reactive Streams**: Implementing `Flow`, `StateFlow`, `SharedFlow`, and `callbackFlow`.
|
|
14
|
+
* **Lifecycle Integration**: Managing scopes (`viewModelScope`, `lifecycleScope`) and safe collection (`repeatOnLifecycle`).
|
|
15
|
+
* **Error Handling**: Implementing `CoroutineExceptionHandler`, `SupervisorJob`, and proper `try-catch` hierarchies.
|
|
16
|
+
* **Cancellability**: Ensuring long-running operations are cooperative using `ensureActive()`.
|
|
17
|
+
* **Testing**: Setting up `TestDispatcher` and `runTest`.
|
|
18
|
+
|
|
19
|
+
## Applicability
|
|
20
|
+
|
|
21
|
+
Activate this skill when the user asks to:
|
|
22
|
+
* "Fetch data from an API/Database."
|
|
23
|
+
* "Perform background processing."
|
|
24
|
+
* "Fix a memory leak" related to threads/tasks.
|
|
25
|
+
* "Convert a listener/callback to Coroutines."
|
|
26
|
+
* "Implement a ViewModel."
|
|
27
|
+
* "Handle UI state updates."
|
|
28
|
+
|
|
29
|
+
## Critical Rules & Constraints
|
|
30
|
+
|
|
31
|
+
### 1. Dispatcher Injection (Testability)
|
|
32
|
+
* **NEVER** hardcode Dispatchers (e.g., `Dispatchers.IO`, `Dispatchers.Default`) inside classes.
|
|
33
|
+
* **ALWAYS** inject a `CoroutineDispatcher` via the constructor.
|
|
34
|
+
* **DEFAULT** to `Dispatchers.IO` in the constructor argument for convenience, but allow it to be overridden.
|
|
35
|
+
|
|
36
|
+
```kotlin
|
|
37
|
+
// CORRECT
|
|
38
|
+
class UserRepository(
|
|
39
|
+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
|
40
|
+
) { ... }
|
|
41
|
+
|
|
42
|
+
// INCORRECT
|
|
43
|
+
class UserRepository {
|
|
44
|
+
fun getData() = withContext(Dispatchers.IO) { ... }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Main-Safety
|
|
49
|
+
* All suspend functions defined in the Data or Domain layer must be **main-safe**.
|
|
50
|
+
* **One-shot calls** should be exposed as `suspend` functions.
|
|
51
|
+
* **Data changes** should be exposed as `Flow`.
|
|
52
|
+
* The caller (ViewModel) should be able to call them from `Dispatchers.Main` without blocking the UI.
|
|
53
|
+
* Use `withContext(dispatcher)` inside the repository implementation to move execution to the background.
|
|
54
|
+
|
|
55
|
+
### 3. Lifecycle-Aware Collection
|
|
56
|
+
* **NEVER** collect a flow directly in `lifecycleScope.launch` or `launchWhenStarted` (deprecated/unsafe).
|
|
57
|
+
* **ALWAYS** use `repeatOnLifecycle(Lifecycle.State.STARTED)` for collecting flows in Activities or Fragments.
|
|
58
|
+
|
|
59
|
+
```kotlin
|
|
60
|
+
// CORRECT
|
|
61
|
+
viewLifecycleOwner.lifecycleScope.launch {
|
|
62
|
+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
63
|
+
viewModel.uiState.collect { ... }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. ViewModel Scope Usage
|
|
69
|
+
* Use `viewModelScope` for initiating coroutines in ViewModels.
|
|
70
|
+
* Do not expose suspend functions from the ViewModel to the View. The ViewModel should expose `StateFlow` or `SharedFlow` that the View observes.
|
|
71
|
+
|
|
72
|
+
### 5. Mutable State Encapsulation
|
|
73
|
+
* **NEVER** expose `MutableStateFlow` or `MutableSharedFlow` publicly.
|
|
74
|
+
* Expose them as read-only `StateFlow` or `Flow` using `.asStateFlow()` or upcasting.
|
|
75
|
+
|
|
76
|
+
### 6. GlobalScope Prohibition
|
|
77
|
+
* **NEVER** use `GlobalScope`. It breaks structured concurrency and leads to leaks.
|
|
78
|
+
* If a task must survive the current scope, use an injected `applicationScope` (a custom scope tied to the Application lifecycle).
|
|
79
|
+
|
|
80
|
+
### 7. Exception Handling
|
|
81
|
+
* **NEVER** catch `CancellationException` in a generic `catch (e: Exception)` block without rethrowing it.
|
|
82
|
+
* Use `runCatching` only if you explicitly rethrow `CancellationException`.
|
|
83
|
+
* Use `CoroutineExceptionHandler` only for top-level coroutines (inside `launch`). It has no effect inside `async` or child coroutines.
|
|
84
|
+
|
|
85
|
+
### 8. Cancellability
|
|
86
|
+
* Coroutines feature **cooperative cancellation**. They don't stop immediately unless they check for cancellation.
|
|
87
|
+
* **ALWAYS** call `ensureActive()` or `yield()` in tight loops (e.g., processing a large list, reading files) to check for cancellation.
|
|
88
|
+
* Standard functions like `delay()` and `withContext()` are already cancellable.
|
|
89
|
+
|
|
90
|
+
### 9. Callback Conversion
|
|
91
|
+
* Use `callbackFlow` to convert callback-based APIs to Flow.
|
|
92
|
+
* **ALWAYS** use `awaitClose` at the end of the `callbackFlow` block to unregister listeners.
|
|
93
|
+
|
|
94
|
+
## Code Patterns
|
|
95
|
+
|
|
96
|
+
### Repository Pattern with Flow
|
|
97
|
+
|
|
98
|
+
```kotlin
|
|
99
|
+
class NewsRepository(
|
|
100
|
+
private val remoteDataSource: NewsRemoteDataSource,
|
|
101
|
+
private val externalScope: CoroutineScope, // For app-wide events
|
|
102
|
+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
|
103
|
+
) {
|
|
104
|
+
val newsUpdates: Flow<List<News>> = flow {
|
|
105
|
+
val news = remoteDataSource.fetchLatestNews()
|
|
106
|
+
emit(news)
|
|
107
|
+
}.flowOn(ioDispatcher) // Upstream executes on IO
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Parallel Execution
|
|
112
|
+
|
|
113
|
+
```kotlin
|
|
114
|
+
suspend fun loadDashboardData() = coroutineScope {
|
|
115
|
+
val userDeferred = async { userRepo.getUser() }
|
|
116
|
+
val feedDeferred = async { feedRepo.getFeed() }
|
|
117
|
+
|
|
118
|
+
// Wait for both
|
|
119
|
+
DashboardData(
|
|
120
|
+
user = userDeferred.await(),
|
|
121
|
+
feed = feedDeferred.await()
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Testing with runTest
|
|
127
|
+
|
|
128
|
+
```kotlin
|
|
129
|
+
@Test
|
|
130
|
+
fun testViewModel() = runTest {
|
|
131
|
+
val testDispatcher = StandardTestDispatcher(testScheduler)
|
|
132
|
+
val viewModel = MyViewModel(testDispatcher)
|
|
133
|
+
|
|
134
|
+
viewModel.loadData()
|
|
135
|
+
advanceUntilIdle() // Process coroutines
|
|
136
|
+
|
|
137
|
+
assertEquals(expectedState, viewModel.uiState.value)
|
|
138
|
+
}
|
|
139
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-data-layer
|
|
3
|
+
description: Guidance on implementing the Data Layer using Repository pattern, Room (Local), and Retrofit (Remote) with offline-first synchronization.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Data Layer & Offline-First
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
The Data Layer coordinates data from multiple sources.
|
|
11
|
+
|
|
12
|
+
### 1. Repository Pattern
|
|
13
|
+
* **Role**: Single Source of Truth (SSOT).
|
|
14
|
+
* **Logic**: The repository decides whether to return cached data or fetch fresh data.
|
|
15
|
+
* **Implementation**:
|
|
16
|
+
```kotlin
|
|
17
|
+
class NewsRepository @Inject constructor(
|
|
18
|
+
private val newsDao: NewsDao,
|
|
19
|
+
private val newsApi: NewsApi
|
|
20
|
+
) {
|
|
21
|
+
// Expose data from Local DB as the source of truth
|
|
22
|
+
val newsStream: Flow<List<News>> = newsDao.getAllNews()
|
|
23
|
+
|
|
24
|
+
// Sync operation
|
|
25
|
+
suspend fun refreshNews() {
|
|
26
|
+
val remoteNews = newsApi.fetchLatest()
|
|
27
|
+
newsDao.insertAll(remoteNews)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Local Persistence (Room)
|
|
33
|
+
* **Usage**: Primary cache and offline storage.
|
|
34
|
+
* **Entities**: Define `@Entity` data classes.
|
|
35
|
+
* **DAOs**: Return `Flow<T>` for observable data.
|
|
36
|
+
|
|
37
|
+
### 3. Remote Data (Retrofit)
|
|
38
|
+
* **Usage**: Fetching data from backend.
|
|
39
|
+
* **Response**: Use `suspend` functions in interfaces.
|
|
40
|
+
* **Error Handling**: Wrap network calls in `try-catch` blocks or a `Result` wrapper to handle exceptions (NoInternet, 404, etc.) gracefully.
|
|
41
|
+
|
|
42
|
+
### 4. Synchronization
|
|
43
|
+
* **Read**: "Stale-While-Revalidate". Show local data immediately, trigger a background refresh.
|
|
44
|
+
* **Write**: "Outbox Pattern" (Advanced). Save local change immediately, mark as "unsynced", use `WorkManager` to push changes to server.
|
|
45
|
+
|
|
46
|
+
### 5. Dependency Injection
|
|
47
|
+
* Bind Repository interfaces to implementations in a Hilt Module.
|
|
48
|
+
```kotlin
|
|
49
|
+
@Binds
|
|
50
|
+
abstract fun bindNewsRepository(impl: OfflineFirstNewsRepository): NewsRepository
|
|
51
|
+
```
|