agy-superpowers 5.0.8 → 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/frontend-developer/SKILL.md +39 -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/mobile-developer/SKILL.md +52 -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
|
@@ -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
|
+
```
|
package/template/agent/skills/mobile-developer/references/android-rules/android-emulator-skill.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-emulator-skill
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Production-ready scripts for Android app testing, building, and automation. Provides semantic UI navigation, build automation, log monitoring, and emulator lifecycle management. Optimized for AI agents with minimal token output.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Android Emulator Skill
|
|
8
|
+
|
|
9
|
+
Build, test, and automate Android applications using accessibility-driven navigation and structured data instead of pixel coordinates.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Check environment
|
|
15
|
+
bash scripts/emu_health_check.sh
|
|
16
|
+
|
|
17
|
+
# 2. Launch app
|
|
18
|
+
python scripts/app_launcher.py --launch com.example.app
|
|
19
|
+
|
|
20
|
+
# 3. Map screen to see elements
|
|
21
|
+
python scripts/screen_mapper.py
|
|
22
|
+
|
|
23
|
+
# 4. Tap button
|
|
24
|
+
python scripts/navigator.py --find-text "Login" --tap
|
|
25
|
+
|
|
26
|
+
# 5. Enter text
|
|
27
|
+
python scripts/navigator.py --find-type EditText --enter-text "user@example.com"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
All scripts support `--help` for detailed options and `--json` for machine-readable output.
|
|
31
|
+
|
|
32
|
+
## Production Scripts
|
|
33
|
+
|
|
34
|
+
### Build & Development
|
|
35
|
+
|
|
36
|
+
1. **build_and_test.py** - Build Android projects, run tests, parse results
|
|
37
|
+
- Wrapper around Gradle
|
|
38
|
+
- Support for assemble, install, and connectedCheck
|
|
39
|
+
- Parse build errors and test results
|
|
40
|
+
- Options: `--task`, `--clean`, `--json`
|
|
41
|
+
|
|
42
|
+
2. **log_monitor.py** - Real-time log monitoring with intelligent filtering
|
|
43
|
+
- Wrapper around `adb logcat`
|
|
44
|
+
- Filter by tag, priority, or PID
|
|
45
|
+
- Deduplicate repeated messages
|
|
46
|
+
- Options: `--package`, `--tag`, `--priority`, `--duration`, `--json`
|
|
47
|
+
|
|
48
|
+
### Navigation & Interaction
|
|
49
|
+
|
|
50
|
+
3. **screen_mapper.py** - Analyze current screen and list interactive elements
|
|
51
|
+
- Dump UI hierarchy using `uiautomator`
|
|
52
|
+
- Parse XML to identify buttons, text fields, etc.
|
|
53
|
+
- Options: `--verbose`, `--json`
|
|
54
|
+
|
|
55
|
+
4. **navigator.py** - Find and interact with elements semantically
|
|
56
|
+
- Find by text (fuzzy matching), resource-id, or class name
|
|
57
|
+
- Interactive tapping and text entry
|
|
58
|
+
- Options: `--find-text`, `--find-id`, `--tap`, `--enter-text`, `--json`
|
|
59
|
+
|
|
60
|
+
5. **gesture.py** - Perform swipes, scrolls, and other gestures
|
|
61
|
+
- Swipe up/down/left/right
|
|
62
|
+
- Scroll lists
|
|
63
|
+
- Options: `--swipe`, `--scroll`, `--duration`, `--json`
|
|
64
|
+
|
|
65
|
+
6. **keyboard.py** - Key events and hardware buttons
|
|
66
|
+
- Input key events (Home, Back, Enter, Tab)
|
|
67
|
+
- Type text via ADB
|
|
68
|
+
- Options: `--key`, `--text`, `--json`
|
|
69
|
+
|
|
70
|
+
7. **app_launcher.py** - App lifecycle management
|
|
71
|
+
- Launch apps (`adb shell am start`)
|
|
72
|
+
- Terminate apps (`adb shell am force-stop`)
|
|
73
|
+
- Install/Uninstall APKs
|
|
74
|
+
- List installed packages
|
|
75
|
+
- Options: `--launch`, `--terminate`, `--install`, `--uninstall`, `--list`, `--json`
|
|
76
|
+
|
|
77
|
+
### Emulator Lifecycle Management
|
|
78
|
+
|
|
79
|
+
8. **emulator_manage.py** - Manage Android Virtual Devices (AVDs)
|
|
80
|
+
- List available AVDs
|
|
81
|
+
- Boot emulators
|
|
82
|
+
- Shutdown emulators
|
|
83
|
+
- Options: `--list`, `--boot`, `--shutdown`, `--json`
|
|
84
|
+
|
|
85
|
+
9. **emu_health_check.sh** - Verify environment is properly configured
|
|
86
|
+
- Check ADB, Emulator, Java, Gradle, ANDROID_HOME
|
|
87
|
+
- List connected devices
|
|
88
|
+
|
|
89
|
+
## Common Patterns
|
|
90
|
+
|
|
91
|
+
**Auto-Device Detection**: Scripts target the single connected device/emulator if only one is present, or require `-s <serial>` if multiple are connected.
|
|
92
|
+
|
|
93
|
+
**Output Formats**: Default is concise human-readable output. Use `--json` for machine-readable output.
|
|
94
|
+
|
|
95
|
+
## Requirements
|
|
96
|
+
|
|
97
|
+
- Android SDK Platform-Tools (adb, fastboot)
|
|
98
|
+
- Android Emulator
|
|
99
|
+
- Java / OpenJDK
|
|
100
|
+
- Python 3
|
|
101
|
+
|
|
102
|
+
## Key Design Principles
|
|
103
|
+
|
|
104
|
+
**Semantic Navigation**: Find elements by text, resource-id, or content-description.
|
|
105
|
+
|
|
106
|
+
**Token Efficiency**: Concise default output with optional verbose and JSON modes.
|
|
107
|
+
|
|
108
|
+
**Zero Configuration**: Works with standard Android SDK installation.
|
package/template/agent/skills/mobile-developer/references/android-rules/android-gradle-logic.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-gradle-logic
|
|
3
|
+
description: Expert guidance on setting up scalable Gradle build logic using Convention Plugins and Version Catalogs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Gradle Build Logic & Convention Plugins
|
|
7
|
+
|
|
8
|
+
This skill helps you configure a scalable, maintainable build system for Android apps using **Gradle Convention Plugins** and **Version Catalogs**, following the "Now in Android" (NiA) architecture.
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
Stop copy-pasting code between `build.gradle.kts` files. Centralize build logic (Compose setup, Kotlin options, Hilt, etc.) in reusable plugins.
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
14
|
+
|
|
15
|
+
Ensure your project has a `build-logic` directory included in `settings.gradle.kts` as a composite build.
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
root/
|
|
19
|
+
├── build-logic/
|
|
20
|
+
│ ├── convention/
|
|
21
|
+
│ │ ├── src/main/kotlin/
|
|
22
|
+
│ │ │ └── AndroidApplicationConventionPlugin.kt
|
|
23
|
+
│ │ └── build.gradle.kts
|
|
24
|
+
│ ├── build.gradle.kts
|
|
25
|
+
│ └── settings.gradle.kts
|
|
26
|
+
├── gradle/
|
|
27
|
+
│ └── libs.versions.toml
|
|
28
|
+
├── app/
|
|
29
|
+
│ └── build.gradle.kts
|
|
30
|
+
└── settings.gradle.kts
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Step 1: Configure `settings.gradle.kts`
|
|
34
|
+
|
|
35
|
+
Include the `build-logic` as a plugin management source.
|
|
36
|
+
|
|
37
|
+
```kotlin
|
|
38
|
+
// settings.gradle.kts
|
|
39
|
+
pluginManagement {
|
|
40
|
+
includeBuild("build-logic")
|
|
41
|
+
repositories {
|
|
42
|
+
google()
|
|
43
|
+
mavenCentral()
|
|
44
|
+
gradlePluginPortal()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
dependencyResolutionManagement {
|
|
48
|
+
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
|
49
|
+
repositories {
|
|
50
|
+
google()
|
|
51
|
+
mavenCentral()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Step 2: Define Dependencies in `libs.versions.toml`
|
|
57
|
+
|
|
58
|
+
Use the Version Catalog for both libraries *and* plugins.
|
|
59
|
+
|
|
60
|
+
```toml
|
|
61
|
+
[versions]
|
|
62
|
+
androidGradlePlugin = "8.2.0"
|
|
63
|
+
kotlin = "1.9.20"
|
|
64
|
+
|
|
65
|
+
[libraries]
|
|
66
|
+
# ...
|
|
67
|
+
|
|
68
|
+
[plugins]
|
|
69
|
+
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
|
70
|
+
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
|
|
71
|
+
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
|
72
|
+
# Define your own plugins here
|
|
73
|
+
nowinandroid-android-application = { id = "nowinandroid.android.application", version = "unspecified" }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Step 3: Create a Convention Plugin
|
|
77
|
+
|
|
78
|
+
Inside `build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt`:
|
|
79
|
+
|
|
80
|
+
```kotlin
|
|
81
|
+
import com.android.build.api.dsl.ApplicationExtension
|
|
82
|
+
import org.gradle.api.Plugin
|
|
83
|
+
import org.gradle.api.Project
|
|
84
|
+
import org.gradle.kotlin.dsl.configure
|
|
85
|
+
|
|
86
|
+
class AndroidApplicationConventionPlugin : Plugin<Project> {
|
|
87
|
+
override fun apply(target: Project) {
|
|
88
|
+
with(target) {
|
|
89
|
+
with(pluginManager) {
|
|
90
|
+
apply("com.android.application")
|
|
91
|
+
apply("org.jetbrains.kotlin.android")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
extensions.configure<ApplicationExtension> {
|
|
95
|
+
defaultConfig.targetSdk = 34
|
|
96
|
+
// Configure common options here
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Don't forget to register it in `build-logic/convention/build.gradle.kts`:
|
|
104
|
+
|
|
105
|
+
```kotlin
|
|
106
|
+
gradlePlugin {
|
|
107
|
+
plugins {
|
|
108
|
+
register("androidApplication") {
|
|
109
|
+
id = "nowinandroid.android.application"
|
|
110
|
+
implementationClass = "AndroidApplicationConventionPlugin"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Usage
|
|
117
|
+
|
|
118
|
+
Apply your custom plugin in your modules (e.g., `app/build.gradle.kts`):
|
|
119
|
+
|
|
120
|
+
```kotlin
|
|
121
|
+
plugins {
|
|
122
|
+
alias(libs.plugins.nowinandroid.android.application)
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This drastically cleans up module-level build files.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-retrofit
|
|
3
|
+
description: Expert guidance on setting up and using Retrofit for type-safe HTTP networking in Android. Covers service definitions, coroutines, OkHttp configuration, and Hilt integration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Networking with Retrofit
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
When implementing network layers using **Retrofit**, follow these modern Android best practices (2025).
|
|
11
|
+
|
|
12
|
+
### 1. URL Manipulation
|
|
13
|
+
Retrofit allows dynamic URL updates through replacement blocks and query parameters.
|
|
14
|
+
|
|
15
|
+
* **Dynamic Paths**: Use `{name}` in the relative URL and `@Path("name")` in parameters.
|
|
16
|
+
* **Query Parameters**: Use `@Query("key")` for individual parameters.
|
|
17
|
+
* **Complex Queries**: Use `@QueryMap Map<String, String>` for dynamic sets of parameters.
|
|
18
|
+
|
|
19
|
+
```kotlin
|
|
20
|
+
interface SearchService {
|
|
21
|
+
@GET("group/{id}/users")
|
|
22
|
+
suspend fun groupList(
|
|
23
|
+
@Path("id") groupId: Int,
|
|
24
|
+
@Query("sort") sort: String?,
|
|
25
|
+
@QueryMap options: Map<String, String> = emptyMap()
|
|
26
|
+
): List<User>
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Request Body & Form Data
|
|
31
|
+
You can send objects as JSON bodies or use form-encoded/multipart formats.
|
|
32
|
+
|
|
33
|
+
* **@Body**: Serializes an object using the configured converter (JSON).
|
|
34
|
+
* **@FormUrlEncoded**: Sends data as `application/x-www-form-urlencoded`. Use `@Field`.
|
|
35
|
+
* **@Multipart**: Sends data as `multipart/form-data`. Use `@Part`.
|
|
36
|
+
|
|
37
|
+
```kotlin
|
|
38
|
+
interface UserService {
|
|
39
|
+
@POST("users/new")
|
|
40
|
+
suspend fun createUser(@Body user: User): User
|
|
41
|
+
|
|
42
|
+
@FormUrlEncoded
|
|
43
|
+
@POST("user/edit")
|
|
44
|
+
suspend fun updateUser(
|
|
45
|
+
@Field("first_name") first: String,
|
|
46
|
+
@Field("last_name") last: String
|
|
47
|
+
): User
|
|
48
|
+
|
|
49
|
+
@Multipart
|
|
50
|
+
@PUT("user/photo")
|
|
51
|
+
suspend fun uploadPhoto(
|
|
52
|
+
@Part("description") description: RequestBody,
|
|
53
|
+
@Part photo: MultipartBody.Part
|
|
54
|
+
): User
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Header Manipulation
|
|
59
|
+
Headers can be set statically for a method or dynamically via parameters.
|
|
60
|
+
|
|
61
|
+
* **Static Headers**: Use `@Headers`.
|
|
62
|
+
* **Dynamic Headers**: Use `@Header`.
|
|
63
|
+
* **Header Maps**: Use `@HeaderMap`.
|
|
64
|
+
* **Global Headers**: Use an OkHttp **Interceptor**.
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
interface WidgetService {
|
|
68
|
+
@Headers("Cache-Control: max-age=640000")
|
|
69
|
+
@GET("widget/list")
|
|
70
|
+
suspend fun widgetList(): List<Widget>
|
|
71
|
+
|
|
72
|
+
@GET("user")
|
|
73
|
+
suspend fun getUser(@Header("Authorization") token: String): User
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 4. Kotlin Support & Response Handling
|
|
78
|
+
When using `suspend` functions, you have two choices for return types:
|
|
79
|
+
|
|
80
|
+
1. **Direct Body (`User`)**: Returns the deserialized body. Throws `HttpException` for non-2xx responses.
|
|
81
|
+
2. **`Response<User>`**: Provides access to the status code, headers, and error body. Does NOT throw on non-2xx results.
|
|
82
|
+
|
|
83
|
+
```kotlin
|
|
84
|
+
@GET("users")
|
|
85
|
+
suspend fun getUsers(): List<User> // Throws on error
|
|
86
|
+
|
|
87
|
+
@GET("users")
|
|
88
|
+
suspend fun getUsersResponse(): Response<List<User>> // Manual check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 5. Hilt & Serialization Configuration
|
|
92
|
+
Provide your Retrofit instances as singletons in a Hilt module.
|
|
93
|
+
|
|
94
|
+
```kotlin
|
|
95
|
+
@Module
|
|
96
|
+
@InstallIn(SingletonComponent::class)
|
|
97
|
+
object NetworkModule {
|
|
98
|
+
|
|
99
|
+
@Provides
|
|
100
|
+
@Singleton
|
|
101
|
+
fun provideJson(): Json = Json {
|
|
102
|
+
ignoreUnknownKeys = true
|
|
103
|
+
coerceInputValues = true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@Provides
|
|
107
|
+
@Singleton
|
|
108
|
+
fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder()
|
|
109
|
+
.addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY })
|
|
110
|
+
.connectTimeout(30, TimeUnit.SECONDS)
|
|
111
|
+
.build()
|
|
112
|
+
|
|
113
|
+
@Provides
|
|
114
|
+
@Singleton
|
|
115
|
+
fun provideRetrofit(okHttpClient: OkHttpClient, json: Json): Retrofit = Retrofit.Builder()
|
|
116
|
+
.baseUrl("https://api.github.com/")
|
|
117
|
+
.client(okHttpClient)
|
|
118
|
+
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
|
119
|
+
.build()
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 6. Error Handling in Repositories
|
|
124
|
+
Always handle network exceptions in the Repository layer to keep the UI state clean.
|
|
125
|
+
|
|
126
|
+
```kotlin
|
|
127
|
+
class GitHubRepository @Inject constructor(private val service: GitHubService) {
|
|
128
|
+
suspend fun getRepos(username: String): Result<List<Repo>> = runCatching {
|
|
129
|
+
// Direct body call throws HttpException on 4xx/5xx
|
|
130
|
+
service.listRepos(username)
|
|
131
|
+
}.onFailure { exception ->
|
|
132
|
+
// Handle specific exceptions like UnknownHostException or SocketTimeoutException
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 7. Checklist
|
|
138
|
+
- [ ] Use `suspend` functions for all network calls.
|
|
139
|
+
- [ ] Prefer `Response<T>` if you need to handle specific status codes (e.g., 401 Unauthorized).
|
|
140
|
+
- [ ] Use `@Path` and `@Query` instead of manual string concatenation for URLs.
|
|
141
|
+
- [ ] Configure `OkHttpClient` with logging (for debug) and sensible timeouts.
|
|
142
|
+
- [ ] Map API DTOs to Domain models to decouple layers.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-testing
|
|
3
|
+
description: Comprehensive testing strategy involving Unit, Integration, Hilt, and Screenshot tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Testing Strategies
|
|
7
|
+
|
|
8
|
+
This skill provides expert guidance on testing modern Android applications, inspired by "Now in Android". It covers **Unit Tests**, **Hilt Integration Tests**, and **Screenshot Testing**.
|
|
9
|
+
|
|
10
|
+
## Testing Pyramid
|
|
11
|
+
|
|
12
|
+
1. **Unit Tests**: Fast, isolate logic (ViewModels, Repositories).
|
|
13
|
+
2. **Integration Tests**: Test interactions (Room DAOs, Retrofit vs MockWebServer).
|
|
14
|
+
3. **UI/Screenshot Tests**: Verify UI correctness (Compose).
|
|
15
|
+
|
|
16
|
+
## Dependencies (`libs.versions.toml`)
|
|
17
|
+
|
|
18
|
+
Ensure you have the right testing dependencies.
|
|
19
|
+
|
|
20
|
+
```toml
|
|
21
|
+
[libraries]
|
|
22
|
+
junit4 = { module = "junit:junit", version = "4.13.2" }
|
|
23
|
+
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }
|
|
24
|
+
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version = "1.1.5" }
|
|
25
|
+
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version = "3.5.1" }
|
|
26
|
+
compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
|
27
|
+
hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
|
|
28
|
+
roborazzi = { group = "io.github.takahirom.roborazzi", name = "roborazzi", version.ref = "roborazzi" }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Screenshot Testing with Roborazzi
|
|
32
|
+
|
|
33
|
+
Screenshot tests ensure your UI doesn't regress visually. NiA uses **Roborazzi** because it runs on the JVM (fast) without needing an emulator.
|
|
34
|
+
|
|
35
|
+
### Setup
|
|
36
|
+
|
|
37
|
+
1. Add the plugin to `libs.versions.toml`:
|
|
38
|
+
```toml
|
|
39
|
+
[plugins]
|
|
40
|
+
roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" }
|
|
41
|
+
```
|
|
42
|
+
2. Apply it in your module's `build.gradle.kts`:
|
|
43
|
+
```kotlin
|
|
44
|
+
plugins {
|
|
45
|
+
alias(libs.plugins.roborazzi)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Writing a Screenshot Test
|
|
50
|
+
|
|
51
|
+
```kotlin
|
|
52
|
+
@RunWith(AndroidJUnit4::class)
|
|
53
|
+
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
|
54
|
+
@Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel5)
|
|
55
|
+
class MyScreenScreenshotTest {
|
|
56
|
+
|
|
57
|
+
@get:Rule
|
|
58
|
+
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
|
|
59
|
+
|
|
60
|
+
@Test
|
|
61
|
+
fun captureMyScreen() {
|
|
62
|
+
composeTestRule.setContent {
|
|
63
|
+
MyTheme {
|
|
64
|
+
MyScreen()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
composeTestRule.onRoot()
|
|
69
|
+
.captureRoboImage()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Hilt Testing
|
|
75
|
+
|
|
76
|
+
Use `HiltAndroidRule` to inject dependencies in tests.
|
|
77
|
+
|
|
78
|
+
```kotlin
|
|
79
|
+
@HiltAndroidTest
|
|
80
|
+
class MyDaoTest {
|
|
81
|
+
|
|
82
|
+
@get:Rule
|
|
83
|
+
var hiltRule = HiltAndroidRule(this)
|
|
84
|
+
|
|
85
|
+
@Inject
|
|
86
|
+
lateinit var database: MyDatabase
|
|
87
|
+
private lateinit var dao: MyDao
|
|
88
|
+
|
|
89
|
+
@Before
|
|
90
|
+
fun init() {
|
|
91
|
+
hiltRule.inject()
|
|
92
|
+
dao = database.myDao()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ... tests
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Running Tests
|
|
100
|
+
|
|
101
|
+
* **Unit**: `./gradlew test`
|
|
102
|
+
* **Screenshots**: `./gradlew recordRoborazziDebug` (to record) / `./gradlew verifyRoborazziDebug` (to verify)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-viewmodel
|
|
3
|
+
description: Best practices for implementing Android ViewModels, specifically focused on StateFlow for UI state and SharedFlow for one-off events.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android ViewModel & State Management
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
Use `ViewModel` to hold state and business logic. It must outlive configuration changes.
|
|
11
|
+
|
|
12
|
+
### 1. UI State (StateFlow)
|
|
13
|
+
* **What**: Represents the persistent state of the UI (e.g., `Loading`, `Success(data)`, `Error`).
|
|
14
|
+
* **Type**: `StateFlow<UiState>`.
|
|
15
|
+
* **Initialization**: Must have an initial value.
|
|
16
|
+
* **Exposure**: Expose as a read-only `StateFlow` backing a private `MutableStateFlow`.
|
|
17
|
+
```kotlin
|
|
18
|
+
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
|
|
19
|
+
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
|
20
|
+
```
|
|
21
|
+
* **Updates**: Update state using `.update { oldState -> ... }` for thread safety.
|
|
22
|
+
|
|
23
|
+
### 2. One-Off Events (SharedFlow)
|
|
24
|
+
* **What**: Transient events like "Show Toast", "Navigate to Screen", "Show Snackbar".
|
|
25
|
+
* **Type**: `SharedFlow<UiEvent>`.
|
|
26
|
+
* **Configuration**: Must use `replay = 0` to prevent events from re-triggering on screen rotation.
|
|
27
|
+
```kotlin
|
|
28
|
+
private val _uiEvent = MutableSharedFlow<UiEvent>(replay = 0)
|
|
29
|
+
val uiEvent: SharedFlow<UiEvent> = _uiEvent.asSharedFlow()
|
|
30
|
+
```
|
|
31
|
+
* **Sending**: Use `.emit(event)` (suspend) or `.tryEmit(event)`.
|
|
32
|
+
|
|
33
|
+
### 3. Collecting in UI
|
|
34
|
+
* **Compose**: Use `collectAsStateWithLifecycle()` for `StateFlow`.
|
|
35
|
+
```kotlin
|
|
36
|
+
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
|
37
|
+
```
|
|
38
|
+
For `SharedFlow`, use `LaunchedEffect` with `LocalLifecycleOwner`.
|
|
39
|
+
* **Views (XML)**: Use `repeatOnLifecycle(Lifecycle.State.STARTED)` within a coroutine.
|
|
40
|
+
|
|
41
|
+
### 4. Scope
|
|
42
|
+
* Use `viewModelScope` for all coroutines started by the ViewModel.
|
|
43
|
+
* Ideally, specific operations should be delegated to UseCases or Repositories.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coil-compose
|
|
3
|
+
description: Expert guidance on using Coil for image loading in Jetpack Compose. Use this when asked about loading images from URLs, handling image states, or optimizing image performance in Compose.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Coil for Jetpack Compose
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
When implementing image loading in Jetpack Compose, use **Coil** (Coroutines Image Loader). It is the recommended library for Compose due to its efficiency and seamless integration.
|
|
11
|
+
|
|
12
|
+
### 1. Primary Composable: `AsyncImage`
|
|
13
|
+
Use `AsyncImage` for most use cases. It handles size resolution automatically and supports standard `Image` parameters.
|
|
14
|
+
|
|
15
|
+
```kotlin
|
|
16
|
+
AsyncImage(
|
|
17
|
+
model = ImageRequest.Builder(LocalContext.current)
|
|
18
|
+
.data("https://example.com/image.jpg")
|
|
19
|
+
.crossfade(true)
|
|
20
|
+
.build(),
|
|
21
|
+
placeholder = painterResource(R.drawable.placeholder),
|
|
22
|
+
error = painterResource(R.drawable.error),
|
|
23
|
+
contentDescription = stringResource(R.string.description),
|
|
24
|
+
contentScale = ContentScale.Crop,
|
|
25
|
+
modifier = Modifier.clip(CircleShape)
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Low-Level Control: `rememberAsyncImagePainter`
|
|
30
|
+
Use `rememberAsyncImagePainter` only when you need a `Painter` instead of a composable (e.g., for `Canvas` or `Icon`) or when you need to observe the loading state manually.
|
|
31
|
+
|
|
32
|
+
> [!WARNING]
|
|
33
|
+
> `rememberAsyncImagePainter` does not detect the size your image is loaded at on screen and always loads the image with its original dimensions by default. Use `AsyncImage` unless a `Painter` is strictly required.
|
|
34
|
+
|
|
35
|
+
```kotlin
|
|
36
|
+
val painter = rememberAsyncImagePainter(
|
|
37
|
+
model = ImageRequest.Builder(LocalContext.current)
|
|
38
|
+
.data("https://example.com/image.jpg")
|
|
39
|
+
.size(Size.ORIGINAL) // Explicitly define size if needed
|
|
40
|
+
.build()
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Slot API: `SubcomposeAsyncImage`
|
|
45
|
+
Use `SubcomposeAsyncImage` when you need a custom slot API for different states (Loading, Success, Error).
|
|
46
|
+
|
|
47
|
+
> [!CAUTION]
|
|
48
|
+
> Subcomposition is slower than regular composition. Avoid using `SubcomposeAsyncImage` in performance-critical areas like `LazyColumn` or `LazyRow`.
|
|
49
|
+
|
|
50
|
+
```kotlin
|
|
51
|
+
SubcomposeAsyncImage(
|
|
52
|
+
model = "https://example.com/image.jpg",
|
|
53
|
+
contentDescription = null,
|
|
54
|
+
loading = {
|
|
55
|
+
CircularProgressIndicator()
|
|
56
|
+
},
|
|
57
|
+
error = {
|
|
58
|
+
Icon(Icons.Default.Error, contentDescription = null)
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. Performance & Best Practices
|
|
64
|
+
* **Singleton ImageLoader**: Use a single `ImageLoader` instance for the entire app to share the disk/memory cache.
|
|
65
|
+
* **Main-Safe**: Coil executes image requests on a background thread automatically.
|
|
66
|
+
* **Crossfade**: Always enable `crossfade(true)` in `ImageRequest` for a smoother transition from placeholder to success.
|
|
67
|
+
* **Sizing**: Ensure `contentScale` is set appropriately to avoid loading larger images than necessary.
|
|
68
|
+
|
|
69
|
+
### 5. Checklist for implementation
|
|
70
|
+
- [ ] Prefer `AsyncImage` over other variants.
|
|
71
|
+
- [ ] Always provide a meaningful `contentDescription` or set it to `null` for decorative images.
|
|
72
|
+
- [ ] Use `crossfade(true)` for better UX.
|
|
73
|
+
- [ ] Avoid `SubcomposeAsyncImage` in lists.
|
|
74
|
+
- [ ] Configure `ImageRequest` for specific needs like transformations (e.g., `CircleCropTransformation`).
|