@devo-bmad-custom/agent-orchestration 1.0.1 → 1.0.3
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/lib/installer.js +44 -11
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/bmad-track-compact.md +1 -1
- package/src/.claude/commands/bmad-track-extended.md +1 -1
- package/src/.claude/commands/bmad-track-large.md +1 -1
- package/src/.claude/commands/bmad-track-medium.md +1 -1
- package/src/.claude/commands/bmad-track-nano.md +1 -1
- package/src/.claude/commands/bmad-track-rv.md +1 -1
- package/src/.claude/commands/bmad-track-small.md +1 -1
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/review-agent.md +1 -1
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/agents/master-orchestrator.md +3 -3
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,516 +1,516 @@
|
|
|
1
|
-
# Jetpack Compose Side Effects Reference
|
|
2
|
-
|
|
3
|
-
Compose is declarative, but apps must interact with the imperative world: launch coroutines, register listeners, manage resources. Side effects are the bridge. Understanding when and how to use them is essential for correctness.
|
|
4
|
-
|
|
5
|
-
## The Effect Mental Model
|
|
6
|
-
|
|
7
|
-
Compose recomposes when state changes. Effects are blocks of code that run outside the normal composition and recomposition cycle:
|
|
8
|
-
|
|
9
|
-
- **Composition**: Calculate the UI tree
|
|
10
|
-
- **Side effects**: Run imperative code (coroutines, callbacks, lifecycle events)
|
|
11
|
-
- **Layout**: Measure and position elements
|
|
12
|
-
- **Drawing**: Render to screen
|
|
13
|
-
|
|
14
|
-
Effects run *after* composition succeeds. If composition fails, the effect doesn't run.
|
|
15
|
-
|
|
16
|
-
```kotlin
|
|
17
|
-
@Composable
|
|
18
|
-
fun MyScreen() {
|
|
19
|
-
// This runs during composition
|
|
20
|
-
val state = remember { mutableStateOf("initial") }
|
|
21
|
-
|
|
22
|
-
// This runs AFTER composition, and only when 'state.value' changes
|
|
23
|
-
LaunchedEffect(state.value) {
|
|
24
|
-
println("State changed to: ${state.value}")
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// This runs after every composition (use sparingly)
|
|
28
|
-
SideEffect {
|
|
29
|
-
println("Recomposition happened")
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// This runs when composable leaves composition
|
|
33
|
-
DisposableEffect(Unit) {
|
|
34
|
-
onDispose {
|
|
35
|
-
println("Composable is leaving composition")
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
Button(onClick = { state.value = "updated" }) {
|
|
40
|
-
Text(state.value)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## SideEffect — After Every Successful Composition
|
|
46
|
-
|
|
47
|
-
`SideEffect` runs after *every* successful composition. It has no cleanup, no keys, and always executes.
|
|
48
|
-
|
|
49
|
-
```kotlin
|
|
50
|
-
@Composable
|
|
51
|
-
fun MyComposable() {
|
|
52
|
-
var clickCount by remember { mutableStateOf(0) }
|
|
53
|
-
|
|
54
|
-
// Runs after every recomposition
|
|
55
|
-
SideEffect {
|
|
56
|
-
println("Recomposed! Click count: $clickCount")
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
Button(onClick = { clickCount++ }) {
|
|
60
|
-
Text("Clicks: $clickCount")
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Use Cases
|
|
66
|
-
|
|
67
|
-
- Synchronizing Compose state with external systems (e.g., Analytics logging)
|
|
68
|
-
- Updating non-Compose UI elements
|
|
69
|
-
- One-way synchronization where cleanup isn't needed
|
|
70
|
-
|
|
71
|
-
```kotlin
|
|
72
|
-
@Composable
|
|
73
|
-
fun TrackScreenView(screenName: String) {
|
|
74
|
-
SideEffect {
|
|
75
|
-
Analytics.logScreenView(screenName)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**Do:** Use for simple, stateless synchronization.
|
|
81
|
-
**Don't:** Use for resource allocation (use `DisposableEffect` instead).
|
|
82
|
-
|
|
83
|
-
Source: `compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt`
|
|
84
|
-
|
|
85
|
-
## LaunchedEffect(key) — Coroutines Scoped to Composition
|
|
86
|
-
|
|
87
|
-
`LaunchedEffect` launches a coroutine in a scope tied to the composable's lifecycle. The coroutine is cancelled if the key changes or the composable leaves composition.
|
|
88
|
-
|
|
89
|
-
```kotlin
|
|
90
|
-
@Composable
|
|
91
|
-
fun DataLoader(userId: String) {
|
|
92
|
-
var data by remember { mutableStateOf<String?>(null) }
|
|
93
|
-
|
|
94
|
-
// Coroutine runs when userId changes or composable enters composition
|
|
95
|
-
LaunchedEffect(userId) {
|
|
96
|
-
data = loadData(userId) // suspend function
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
Text(data ?: "Loading...")
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Key Selection
|
|
104
|
-
|
|
105
|
-
```kotlin
|
|
106
|
-
// Key = Unit: runs once when composable enters composition, never cancels/restarts
|
|
107
|
-
LaunchedEffect(Unit) {
|
|
108
|
-
setupOnce()
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Key = specific value: reruns whenever the value changes
|
|
112
|
-
var userId by remember { mutableStateOf("user1") }
|
|
113
|
-
LaunchedEffect(userId) {
|
|
114
|
-
loadUserData(userId) // reruns when userId changes
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Multiple keys: reruns if ANY key changes
|
|
118
|
-
LaunchedEffect(userId, postId) {
|
|
119
|
-
loadUserAndPost(userId, postId)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// No key parameter (not recommended): equivalent to Unit
|
|
123
|
-
LaunchedEffect {
|
|
124
|
-
setupOnce()
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Common Mistake: Wrong Key Selection
|
|
129
|
-
|
|
130
|
-
```kotlin
|
|
131
|
-
// Don't: Key changes every recomposition (creates infinite loop)
|
|
132
|
-
@Composable
|
|
133
|
-
fun BadKeySelection() {
|
|
134
|
-
var count by remember { mutableStateOf(0) }
|
|
135
|
-
val randomKey = Random.nextInt() // Changes every recomposition!
|
|
136
|
-
|
|
137
|
-
LaunchedEffect(randomKey) {
|
|
138
|
-
count++ // This launches infinitely
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
Text("Count: $count")
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Do: Use stable keys that represent the data you depend on
|
|
145
|
-
@Composable
|
|
146
|
-
fun GoodKeySelection(userId: String) {
|
|
147
|
-
var userData by remember { mutableStateOf<User?>(null) }
|
|
148
|
-
|
|
149
|
-
LaunchedEffect(userId) {
|
|
150
|
-
userData = fetchUser(userId)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
Text(userData?.name ?: "Loading...")
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Cancellation Behavior
|
|
158
|
-
|
|
159
|
-
```kotlin
|
|
160
|
-
@Composable
|
|
161
|
-
fun ResourceUser(shouldLoad: Boolean) {
|
|
162
|
-
LaunchedEffect(shouldLoad) {
|
|
163
|
-
if (shouldLoad) {
|
|
164
|
-
val resource = acquireResource()
|
|
165
|
-
try {
|
|
166
|
-
delay(5000) // Long operation
|
|
167
|
-
processResource(resource)
|
|
168
|
-
} finally {
|
|
169
|
-
resource.close() // Runs even if cancelled
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// If shouldLoad becomes false, the LaunchedEffect coroutine is cancelled.
|
|
176
|
-
// The finally block ensures cleanup.
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## DisposableEffect(key) — For Cleanup
|
|
180
|
-
|
|
181
|
-
`DisposableEffect` runs after composition and requires a cleanup function (onDispose). Use for listeners, registrations, and resources.
|
|
182
|
-
|
|
183
|
-
```kotlin
|
|
184
|
-
@Composable
|
|
185
|
-
fun LocationListener(context: Context) {
|
|
186
|
-
DisposableEffect(context) {
|
|
187
|
-
val listener = LocationListener { location ->
|
|
188
|
-
println("Location: $location")
|
|
189
|
-
}
|
|
190
|
-
// Register listener
|
|
191
|
-
locationManager.requestLocationUpdates(
|
|
192
|
-
LocationManager.GPS_PROVIDER,
|
|
193
|
-
0,
|
|
194
|
-
0f,
|
|
195
|
-
listener
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
// Cleanup: unregister listener
|
|
199
|
-
onDispose {
|
|
200
|
-
locationManager.removeUpdates(listener)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Common Pattern: Lifecycle Events
|
|
207
|
-
|
|
208
|
-
```kotlin
|
|
209
|
-
@Composable
|
|
210
|
-
fun ScreenWithLifecycle() {
|
|
211
|
-
val lifecycle = LocalLifecycleOwner.current.lifecycle
|
|
212
|
-
|
|
213
|
-
DisposableEffect(lifecycle) {
|
|
214
|
-
val observer = LifecycleEventObserver { _, event ->
|
|
215
|
-
when (event) {
|
|
216
|
-
Lifecycle.Event.ON_RESUME -> println("Screen resumed")
|
|
217
|
-
Lifecycle.Event.ON_PAUSE -> println("Screen paused")
|
|
218
|
-
else -> {}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
lifecycle.addObserver(observer)
|
|
222
|
-
|
|
223
|
-
onDispose {
|
|
224
|
-
lifecycle.removeObserver(observer)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
**Do:** Use `DisposableEffect` for every resource you allocate.
|
|
231
|
-
**Don't:** Forget the `onDispose` block (resource leaks result).
|
|
232
|
-
|
|
233
|
-
Source: `compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt`
|
|
234
|
-
|
|
235
|
-
## rememberCoroutineScope — Launching from Event Handlers
|
|
236
|
-
|
|
237
|
-
`rememberCoroutineScope` provides a coroutine scope tied to the composable. Use it to launch coroutines from event handlers (clicks, gestures).
|
|
238
|
-
|
|
239
|
-
```kotlin
|
|
240
|
-
@Composable
|
|
241
|
-
fun ButtonWithAsync() {
|
|
242
|
-
val scope = rememberCoroutineScope()
|
|
243
|
-
var result by remember { mutableStateOf("") }
|
|
244
|
-
|
|
245
|
-
Button(
|
|
246
|
-
onClick = {
|
|
247
|
-
// Launch coroutine from click handler
|
|
248
|
-
scope.launch {
|
|
249
|
-
result = fetchData()
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
) {
|
|
253
|
-
Text("Fetch")
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
Text(result)
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Do vs Don't
|
|
261
|
-
|
|
262
|
-
```kotlin
|
|
263
|
-
// Don't: regular function scope doesn't work
|
|
264
|
-
@Composable
|
|
265
|
-
fun BadAsync() {
|
|
266
|
-
var result by remember { mutableStateOf("") }
|
|
267
|
-
|
|
268
|
-
Button(
|
|
269
|
-
onClick = {
|
|
270
|
-
runBlocking { // Blocks UI thread!
|
|
271
|
-
result = fetchData()
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
) {
|
|
275
|
-
Text("Fetch")
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Do: use rememberCoroutineScope
|
|
280
|
-
@Composable
|
|
281
|
-
fun GoodAsync() {
|
|
282
|
-
val scope = rememberCoroutineScope()
|
|
283
|
-
var result by remember { mutableStateOf("") }
|
|
284
|
-
|
|
285
|
-
Button(
|
|
286
|
-
onClick = {
|
|
287
|
-
scope.launch {
|
|
288
|
-
result = fetchData()
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
) {
|
|
292
|
-
Text("Fetch")
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## rememberUpdatedState — Capturing Latest Values
|
|
298
|
-
|
|
299
|
-
Long-running effects need the latest value of frequently-changing state, but you don't want to restart the effect on every change.
|
|
300
|
-
|
|
301
|
-
```kotlin
|
|
302
|
-
// Don't: effect restarts when callback changes
|
|
303
|
-
@Composable
|
|
304
|
-
fun BadCallback(onSuccess: (String) -> Unit) {
|
|
305
|
-
LaunchedEffect(onSuccess) { // Restarts whenever onSuccess changes!
|
|
306
|
-
val result = expensiveOperation()
|
|
307
|
-
onSuccess(result)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Do: use rememberUpdatedState to capture latest without restarting
|
|
312
|
-
@Composable
|
|
313
|
-
fun GoodCallback(onSuccess: (String) -> Unit) {
|
|
314
|
-
val updatedOnSuccess = rememberUpdatedState(onSuccess)
|
|
315
|
-
|
|
316
|
-
LaunchedEffect(Unit) {
|
|
317
|
-
val result = expensiveOperation()
|
|
318
|
-
updatedOnSuccess.value(result)
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Another Example: Animations
|
|
324
|
-
|
|
325
|
-
```kotlin
|
|
326
|
-
@Composable
|
|
327
|
-
fun AnimateWithCallback(
|
|
328
|
-
shouldAnimate: Boolean,
|
|
329
|
-
onAnimationEnd: () -> Unit
|
|
330
|
-
) {
|
|
331
|
-
val updatedCallback = rememberUpdatedState(onAnimationEnd)
|
|
332
|
-
var progress by remember { mutableStateOf(0f) }
|
|
333
|
-
|
|
334
|
-
LaunchedEffect(shouldAnimate) {
|
|
335
|
-
if (shouldAnimate) {
|
|
336
|
-
while (progress < 1f) {
|
|
337
|
-
progress += 0.1f
|
|
338
|
-
delay(16)
|
|
339
|
-
}
|
|
340
|
-
updatedCallback.value() // Call latest callback without restarting
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
## produceState — Converting Non-Compose State to Compose State
|
|
347
|
-
|
|
348
|
-
`produceState` converts imperative state sources (callbacks, flows, coroutines) into Compose state.
|
|
349
|
-
|
|
350
|
-
```kotlin
|
|
351
|
-
@Composable
|
|
352
|
-
fun UserData(userId: String): State<User?> = produceState<User?>(initialValue = null) {
|
|
353
|
-
value = fetchUser(userId)
|
|
354
|
-
|
|
355
|
-
// Optional: for lifecycle cleanup
|
|
356
|
-
snapshotFlow { userId }.collect { newUserId ->
|
|
357
|
-
value = fetchUser(newUserId)
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Usage
|
|
362
|
-
@Composable
|
|
363
|
-
fun UserScreen(userId: String) {
|
|
364
|
-
val user by UserData(userId)
|
|
365
|
-
Text(user?.name ?: "Loading...")
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### Integration with Flows
|
|
370
|
-
|
|
371
|
-
```kotlin
|
|
372
|
-
@Composable
|
|
373
|
-
fun <T> Flow<T>.collectAsState(initial: T): State<T> = produceState(initial) {
|
|
374
|
-
collect { value = it }
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Usage
|
|
378
|
-
@Composable
|
|
379
|
-
fun ObserveFlow(dataFlow: Flow<String>) {
|
|
380
|
-
val data by dataFlow.collectAsState(initial = "")
|
|
381
|
-
Text(data)
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## Effect Ordering and Lifecycle
|
|
386
|
-
|
|
387
|
-
Effects execute in declaration order after composition:
|
|
388
|
-
|
|
389
|
-
```kotlin
|
|
390
|
-
@Composable
|
|
391
|
-
fun EffectOrder() {
|
|
392
|
-
println("1. Composition")
|
|
393
|
-
|
|
394
|
-
SideEffect {
|
|
395
|
-
println("4. Side effect (after every composition)")
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
LaunchedEffect(Unit) {
|
|
399
|
-
println("3. Launched effect (async, but scheduled)")
|
|
400
|
-
delay(100)
|
|
401
|
-
println("5. After delay in launched effect")
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
DisposableEffect(Unit) {
|
|
405
|
-
println("2. Disposable effect setup (after composition)")
|
|
406
|
-
|
|
407
|
-
onDispose {
|
|
408
|
-
println("6. Cleanup when leaving composition")
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
println("End of composition body")
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Output order (approximate):
|
|
416
|
-
// 1. Composition
|
|
417
|
-
// End of composition body
|
|
418
|
-
// 2. Disposable effect setup (after composition)
|
|
419
|
-
// 3. Launched effect (async, but scheduled)
|
|
420
|
-
// 4. Side effect (after every composition)
|
|
421
|
-
// 5. After delay in launched effect
|
|
422
|
-
// [... later when composable leaves ...]
|
|
423
|
-
// 6. Cleanup when leaving composition
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
## Common Mistakes
|
|
427
|
-
|
|
428
|
-
### Using LaunchedEffect(Unit) When Key Should Change
|
|
429
|
-
|
|
430
|
-
```kotlin
|
|
431
|
-
// Don't: effect runs once, never updates
|
|
432
|
-
@Composable
|
|
433
|
-
fun BadSearch(query: String) {
|
|
434
|
-
var results by remember { mutableStateOf<List<String>>(emptyList()) }
|
|
435
|
-
|
|
436
|
-
LaunchedEffect(Unit) {
|
|
437
|
-
results = search(query) // Only runs once!
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
Text("Results: ${results.size}")
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Do: use query as key
|
|
444
|
-
@Composable
|
|
445
|
-
fun GoodSearch(query: String) {
|
|
446
|
-
var results by remember { mutableStateOf<List<String>>(emptyList()) }
|
|
447
|
-
|
|
448
|
-
LaunchedEffect(query) {
|
|
449
|
-
results = search(query) // Reruns when query changes
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
Text("Results: ${results.size}")
|
|
453
|
-
}
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Forgetting Cleanup in DisposableEffect
|
|
457
|
-
|
|
458
|
-
```kotlin
|
|
459
|
-
// Don't: memory leak
|
|
460
|
-
@Composable
|
|
461
|
-
fun BadListener(context: Context) {
|
|
462
|
-
DisposableEffect(Unit) {
|
|
463
|
-
val listener = MyListener()
|
|
464
|
-
context.registerListener(listener)
|
|
465
|
-
// Missing: onDispose { context.unregisterListener(listener) }
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// Do: always clean up
|
|
470
|
-
@Composable
|
|
471
|
-
fun GoodListener(context: Context) {
|
|
472
|
-
DisposableEffect(Unit) {
|
|
473
|
-
val listener = MyListener()
|
|
474
|
-
context.registerListener(listener)
|
|
475
|
-
|
|
476
|
-
onDispose {
|
|
477
|
-
context.unregisterListener(listener)
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
### Capturing Mutable State Directly
|
|
484
|
-
|
|
485
|
-
```kotlin
|
|
486
|
-
// Don't: stale state in effect
|
|
487
|
-
@Composable
|
|
488
|
-
fun BadCapture() {
|
|
489
|
-
var count by remember { mutableStateOf(0) }
|
|
490
|
-
|
|
491
|
-
LaunchedEffect(Unit) {
|
|
492
|
-
delay(1000)
|
|
493
|
-
println(count) // May be stale!
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
Button(onClick = { count++ }) { Text("Click") }
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// Do: use rememberUpdatedState or include in key
|
|
500
|
-
@Composable
|
|
501
|
-
fun GoodCapture() {
|
|
502
|
-
var count by remember { mutableStateOf(0) }
|
|
503
|
-
|
|
504
|
-
val updatedCount = rememberUpdatedState(count)
|
|
505
|
-
LaunchedEffect(Unit) {
|
|
506
|
-
delay(1000)
|
|
507
|
-
println(updatedCount.value) // Always current
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
Button(onClick = { count++ }) { Text("Click") }
|
|
511
|
-
}
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
---
|
|
515
|
-
|
|
516
|
-
**Summary:** Effects bridge declarative Compose with imperative systems. Master key selection in `LaunchedEffect`, always cleanup in `DisposableEffect`, use `rememberUpdatedState` for long-running effects that need fresh values, and prefer effect-based patterns over manual lifecycle management.
|
|
1
|
+
# Jetpack Compose Side Effects Reference
|
|
2
|
+
|
|
3
|
+
Compose is declarative, but apps must interact with the imperative world: launch coroutines, register listeners, manage resources. Side effects are the bridge. Understanding when and how to use them is essential for correctness.
|
|
4
|
+
|
|
5
|
+
## The Effect Mental Model
|
|
6
|
+
|
|
7
|
+
Compose recomposes when state changes. Effects are blocks of code that run outside the normal composition and recomposition cycle:
|
|
8
|
+
|
|
9
|
+
- **Composition**: Calculate the UI tree
|
|
10
|
+
- **Side effects**: Run imperative code (coroutines, callbacks, lifecycle events)
|
|
11
|
+
- **Layout**: Measure and position elements
|
|
12
|
+
- **Drawing**: Render to screen
|
|
13
|
+
|
|
14
|
+
Effects run *after* composition succeeds. If composition fails, the effect doesn't run.
|
|
15
|
+
|
|
16
|
+
```kotlin
|
|
17
|
+
@Composable
|
|
18
|
+
fun MyScreen() {
|
|
19
|
+
// This runs during composition
|
|
20
|
+
val state = remember { mutableStateOf("initial") }
|
|
21
|
+
|
|
22
|
+
// This runs AFTER composition, and only when 'state.value' changes
|
|
23
|
+
LaunchedEffect(state.value) {
|
|
24
|
+
println("State changed to: ${state.value}")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// This runs after every composition (use sparingly)
|
|
28
|
+
SideEffect {
|
|
29
|
+
println("Recomposition happened")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// This runs when composable leaves composition
|
|
33
|
+
DisposableEffect(Unit) {
|
|
34
|
+
onDispose {
|
|
35
|
+
println("Composable is leaving composition")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Button(onClick = { state.value = "updated" }) {
|
|
40
|
+
Text(state.value)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## SideEffect — After Every Successful Composition
|
|
46
|
+
|
|
47
|
+
`SideEffect` runs after *every* successful composition. It has no cleanup, no keys, and always executes.
|
|
48
|
+
|
|
49
|
+
```kotlin
|
|
50
|
+
@Composable
|
|
51
|
+
fun MyComposable() {
|
|
52
|
+
var clickCount by remember { mutableStateOf(0) }
|
|
53
|
+
|
|
54
|
+
// Runs after every recomposition
|
|
55
|
+
SideEffect {
|
|
56
|
+
println("Recomposed! Click count: $clickCount")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Button(onClick = { clickCount++ }) {
|
|
60
|
+
Text("Clicks: $clickCount")
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Use Cases
|
|
66
|
+
|
|
67
|
+
- Synchronizing Compose state with external systems (e.g., Analytics logging)
|
|
68
|
+
- Updating non-Compose UI elements
|
|
69
|
+
- One-way synchronization where cleanup isn't needed
|
|
70
|
+
|
|
71
|
+
```kotlin
|
|
72
|
+
@Composable
|
|
73
|
+
fun TrackScreenView(screenName: String) {
|
|
74
|
+
SideEffect {
|
|
75
|
+
Analytics.logScreenView(screenName)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Do:** Use for simple, stateless synchronization.
|
|
81
|
+
**Don't:** Use for resource allocation (use `DisposableEffect` instead).
|
|
82
|
+
|
|
83
|
+
Source: `compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt`
|
|
84
|
+
|
|
85
|
+
## LaunchedEffect(key) — Coroutines Scoped to Composition
|
|
86
|
+
|
|
87
|
+
`LaunchedEffect` launches a coroutine in a scope tied to the composable's lifecycle. The coroutine is cancelled if the key changes or the composable leaves composition.
|
|
88
|
+
|
|
89
|
+
```kotlin
|
|
90
|
+
@Composable
|
|
91
|
+
fun DataLoader(userId: String) {
|
|
92
|
+
var data by remember { mutableStateOf<String?>(null) }
|
|
93
|
+
|
|
94
|
+
// Coroutine runs when userId changes or composable enters composition
|
|
95
|
+
LaunchedEffect(userId) {
|
|
96
|
+
data = loadData(userId) // suspend function
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Text(data ?: "Loading...")
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Key Selection
|
|
104
|
+
|
|
105
|
+
```kotlin
|
|
106
|
+
// Key = Unit: runs once when composable enters composition, never cancels/restarts
|
|
107
|
+
LaunchedEffect(Unit) {
|
|
108
|
+
setupOnce()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Key = specific value: reruns whenever the value changes
|
|
112
|
+
var userId by remember { mutableStateOf("user1") }
|
|
113
|
+
LaunchedEffect(userId) {
|
|
114
|
+
loadUserData(userId) // reruns when userId changes
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Multiple keys: reruns if ANY key changes
|
|
118
|
+
LaunchedEffect(userId, postId) {
|
|
119
|
+
loadUserAndPost(userId, postId)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// No key parameter (not recommended): equivalent to Unit
|
|
123
|
+
LaunchedEffect {
|
|
124
|
+
setupOnce()
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Common Mistake: Wrong Key Selection
|
|
129
|
+
|
|
130
|
+
```kotlin
|
|
131
|
+
// Don't: Key changes every recomposition (creates infinite loop)
|
|
132
|
+
@Composable
|
|
133
|
+
fun BadKeySelection() {
|
|
134
|
+
var count by remember { mutableStateOf(0) }
|
|
135
|
+
val randomKey = Random.nextInt() // Changes every recomposition!
|
|
136
|
+
|
|
137
|
+
LaunchedEffect(randomKey) {
|
|
138
|
+
count++ // This launches infinitely
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Text("Count: $count")
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Do: Use stable keys that represent the data you depend on
|
|
145
|
+
@Composable
|
|
146
|
+
fun GoodKeySelection(userId: String) {
|
|
147
|
+
var userData by remember { mutableStateOf<User?>(null) }
|
|
148
|
+
|
|
149
|
+
LaunchedEffect(userId) {
|
|
150
|
+
userData = fetchUser(userId)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Text(userData?.name ?: "Loading...")
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Cancellation Behavior
|
|
158
|
+
|
|
159
|
+
```kotlin
|
|
160
|
+
@Composable
|
|
161
|
+
fun ResourceUser(shouldLoad: Boolean) {
|
|
162
|
+
LaunchedEffect(shouldLoad) {
|
|
163
|
+
if (shouldLoad) {
|
|
164
|
+
val resource = acquireResource()
|
|
165
|
+
try {
|
|
166
|
+
delay(5000) // Long operation
|
|
167
|
+
processResource(resource)
|
|
168
|
+
} finally {
|
|
169
|
+
resource.close() // Runs even if cancelled
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// If shouldLoad becomes false, the LaunchedEffect coroutine is cancelled.
|
|
176
|
+
// The finally block ensures cleanup.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## DisposableEffect(key) — For Cleanup
|
|
180
|
+
|
|
181
|
+
`DisposableEffect` runs after composition and requires a cleanup function (onDispose). Use for listeners, registrations, and resources.
|
|
182
|
+
|
|
183
|
+
```kotlin
|
|
184
|
+
@Composable
|
|
185
|
+
fun LocationListener(context: Context) {
|
|
186
|
+
DisposableEffect(context) {
|
|
187
|
+
val listener = LocationListener { location ->
|
|
188
|
+
println("Location: $location")
|
|
189
|
+
}
|
|
190
|
+
// Register listener
|
|
191
|
+
locationManager.requestLocationUpdates(
|
|
192
|
+
LocationManager.GPS_PROVIDER,
|
|
193
|
+
0,
|
|
194
|
+
0f,
|
|
195
|
+
listener
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
// Cleanup: unregister listener
|
|
199
|
+
onDispose {
|
|
200
|
+
locationManager.removeUpdates(listener)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Common Pattern: Lifecycle Events
|
|
207
|
+
|
|
208
|
+
```kotlin
|
|
209
|
+
@Composable
|
|
210
|
+
fun ScreenWithLifecycle() {
|
|
211
|
+
val lifecycle = LocalLifecycleOwner.current.lifecycle
|
|
212
|
+
|
|
213
|
+
DisposableEffect(lifecycle) {
|
|
214
|
+
val observer = LifecycleEventObserver { _, event ->
|
|
215
|
+
when (event) {
|
|
216
|
+
Lifecycle.Event.ON_RESUME -> println("Screen resumed")
|
|
217
|
+
Lifecycle.Event.ON_PAUSE -> println("Screen paused")
|
|
218
|
+
else -> {}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
lifecycle.addObserver(observer)
|
|
222
|
+
|
|
223
|
+
onDispose {
|
|
224
|
+
lifecycle.removeObserver(observer)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Do:** Use `DisposableEffect` for every resource you allocate.
|
|
231
|
+
**Don't:** Forget the `onDispose` block (resource leaks result).
|
|
232
|
+
|
|
233
|
+
Source: `compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt`
|
|
234
|
+
|
|
235
|
+
## rememberCoroutineScope — Launching from Event Handlers
|
|
236
|
+
|
|
237
|
+
`rememberCoroutineScope` provides a coroutine scope tied to the composable. Use it to launch coroutines from event handlers (clicks, gestures).
|
|
238
|
+
|
|
239
|
+
```kotlin
|
|
240
|
+
@Composable
|
|
241
|
+
fun ButtonWithAsync() {
|
|
242
|
+
val scope = rememberCoroutineScope()
|
|
243
|
+
var result by remember { mutableStateOf("") }
|
|
244
|
+
|
|
245
|
+
Button(
|
|
246
|
+
onClick = {
|
|
247
|
+
// Launch coroutine from click handler
|
|
248
|
+
scope.launch {
|
|
249
|
+
result = fetchData()
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
) {
|
|
253
|
+
Text("Fetch")
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Text(result)
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Do vs Don't
|
|
261
|
+
|
|
262
|
+
```kotlin
|
|
263
|
+
// Don't: regular function scope doesn't work
|
|
264
|
+
@Composable
|
|
265
|
+
fun BadAsync() {
|
|
266
|
+
var result by remember { mutableStateOf("") }
|
|
267
|
+
|
|
268
|
+
Button(
|
|
269
|
+
onClick = {
|
|
270
|
+
runBlocking { // Blocks UI thread!
|
|
271
|
+
result = fetchData()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
) {
|
|
275
|
+
Text("Fetch")
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Do: use rememberCoroutineScope
|
|
280
|
+
@Composable
|
|
281
|
+
fun GoodAsync() {
|
|
282
|
+
val scope = rememberCoroutineScope()
|
|
283
|
+
var result by remember { mutableStateOf("") }
|
|
284
|
+
|
|
285
|
+
Button(
|
|
286
|
+
onClick = {
|
|
287
|
+
scope.launch {
|
|
288
|
+
result = fetchData()
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
) {
|
|
292
|
+
Text("Fetch")
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## rememberUpdatedState — Capturing Latest Values
|
|
298
|
+
|
|
299
|
+
Long-running effects need the latest value of frequently-changing state, but you don't want to restart the effect on every change.
|
|
300
|
+
|
|
301
|
+
```kotlin
|
|
302
|
+
// Don't: effect restarts when callback changes
|
|
303
|
+
@Composable
|
|
304
|
+
fun BadCallback(onSuccess: (String) -> Unit) {
|
|
305
|
+
LaunchedEffect(onSuccess) { // Restarts whenever onSuccess changes!
|
|
306
|
+
val result = expensiveOperation()
|
|
307
|
+
onSuccess(result)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Do: use rememberUpdatedState to capture latest without restarting
|
|
312
|
+
@Composable
|
|
313
|
+
fun GoodCallback(onSuccess: (String) -> Unit) {
|
|
314
|
+
val updatedOnSuccess = rememberUpdatedState(onSuccess)
|
|
315
|
+
|
|
316
|
+
LaunchedEffect(Unit) {
|
|
317
|
+
val result = expensiveOperation()
|
|
318
|
+
updatedOnSuccess.value(result)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Another Example: Animations
|
|
324
|
+
|
|
325
|
+
```kotlin
|
|
326
|
+
@Composable
|
|
327
|
+
fun AnimateWithCallback(
|
|
328
|
+
shouldAnimate: Boolean,
|
|
329
|
+
onAnimationEnd: () -> Unit
|
|
330
|
+
) {
|
|
331
|
+
val updatedCallback = rememberUpdatedState(onAnimationEnd)
|
|
332
|
+
var progress by remember { mutableStateOf(0f) }
|
|
333
|
+
|
|
334
|
+
LaunchedEffect(shouldAnimate) {
|
|
335
|
+
if (shouldAnimate) {
|
|
336
|
+
while (progress < 1f) {
|
|
337
|
+
progress += 0.1f
|
|
338
|
+
delay(16)
|
|
339
|
+
}
|
|
340
|
+
updatedCallback.value() // Call latest callback without restarting
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## produceState — Converting Non-Compose State to Compose State
|
|
347
|
+
|
|
348
|
+
`produceState` converts imperative state sources (callbacks, flows, coroutines) into Compose state.
|
|
349
|
+
|
|
350
|
+
```kotlin
|
|
351
|
+
@Composable
|
|
352
|
+
fun UserData(userId: String): State<User?> = produceState<User?>(initialValue = null) {
|
|
353
|
+
value = fetchUser(userId)
|
|
354
|
+
|
|
355
|
+
// Optional: for lifecycle cleanup
|
|
356
|
+
snapshotFlow { userId }.collect { newUserId ->
|
|
357
|
+
value = fetchUser(newUserId)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Usage
|
|
362
|
+
@Composable
|
|
363
|
+
fun UserScreen(userId: String) {
|
|
364
|
+
val user by UserData(userId)
|
|
365
|
+
Text(user?.name ?: "Loading...")
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Integration with Flows
|
|
370
|
+
|
|
371
|
+
```kotlin
|
|
372
|
+
@Composable
|
|
373
|
+
fun <T> Flow<T>.collectAsState(initial: T): State<T> = produceState(initial) {
|
|
374
|
+
collect { value = it }
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Usage
|
|
378
|
+
@Composable
|
|
379
|
+
fun ObserveFlow(dataFlow: Flow<String>) {
|
|
380
|
+
val data by dataFlow.collectAsState(initial = "")
|
|
381
|
+
Text(data)
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Effect Ordering and Lifecycle
|
|
386
|
+
|
|
387
|
+
Effects execute in declaration order after composition:
|
|
388
|
+
|
|
389
|
+
```kotlin
|
|
390
|
+
@Composable
|
|
391
|
+
fun EffectOrder() {
|
|
392
|
+
println("1. Composition")
|
|
393
|
+
|
|
394
|
+
SideEffect {
|
|
395
|
+
println("4. Side effect (after every composition)")
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
LaunchedEffect(Unit) {
|
|
399
|
+
println("3. Launched effect (async, but scheduled)")
|
|
400
|
+
delay(100)
|
|
401
|
+
println("5. After delay in launched effect")
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
DisposableEffect(Unit) {
|
|
405
|
+
println("2. Disposable effect setup (after composition)")
|
|
406
|
+
|
|
407
|
+
onDispose {
|
|
408
|
+
println("6. Cleanup when leaving composition")
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
println("End of composition body")
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Output order (approximate):
|
|
416
|
+
// 1. Composition
|
|
417
|
+
// End of composition body
|
|
418
|
+
// 2. Disposable effect setup (after composition)
|
|
419
|
+
// 3. Launched effect (async, but scheduled)
|
|
420
|
+
// 4. Side effect (after every composition)
|
|
421
|
+
// 5. After delay in launched effect
|
|
422
|
+
// [... later when composable leaves ...]
|
|
423
|
+
// 6. Cleanup when leaving composition
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Common Mistakes
|
|
427
|
+
|
|
428
|
+
### Using LaunchedEffect(Unit) When Key Should Change
|
|
429
|
+
|
|
430
|
+
```kotlin
|
|
431
|
+
// Don't: effect runs once, never updates
|
|
432
|
+
@Composable
|
|
433
|
+
fun BadSearch(query: String) {
|
|
434
|
+
var results by remember { mutableStateOf<List<String>>(emptyList()) }
|
|
435
|
+
|
|
436
|
+
LaunchedEffect(Unit) {
|
|
437
|
+
results = search(query) // Only runs once!
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
Text("Results: ${results.size}")
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Do: use query as key
|
|
444
|
+
@Composable
|
|
445
|
+
fun GoodSearch(query: String) {
|
|
446
|
+
var results by remember { mutableStateOf<List<String>>(emptyList()) }
|
|
447
|
+
|
|
448
|
+
LaunchedEffect(query) {
|
|
449
|
+
results = search(query) // Reruns when query changes
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
Text("Results: ${results.size}")
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Forgetting Cleanup in DisposableEffect
|
|
457
|
+
|
|
458
|
+
```kotlin
|
|
459
|
+
// Don't: memory leak
|
|
460
|
+
@Composable
|
|
461
|
+
fun BadListener(context: Context) {
|
|
462
|
+
DisposableEffect(Unit) {
|
|
463
|
+
val listener = MyListener()
|
|
464
|
+
context.registerListener(listener)
|
|
465
|
+
// Missing: onDispose { context.unregisterListener(listener) }
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Do: always clean up
|
|
470
|
+
@Composable
|
|
471
|
+
fun GoodListener(context: Context) {
|
|
472
|
+
DisposableEffect(Unit) {
|
|
473
|
+
val listener = MyListener()
|
|
474
|
+
context.registerListener(listener)
|
|
475
|
+
|
|
476
|
+
onDispose {
|
|
477
|
+
context.unregisterListener(listener)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Capturing Mutable State Directly
|
|
484
|
+
|
|
485
|
+
```kotlin
|
|
486
|
+
// Don't: stale state in effect
|
|
487
|
+
@Composable
|
|
488
|
+
fun BadCapture() {
|
|
489
|
+
var count by remember { mutableStateOf(0) }
|
|
490
|
+
|
|
491
|
+
LaunchedEffect(Unit) {
|
|
492
|
+
delay(1000)
|
|
493
|
+
println(count) // May be stale!
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
Button(onClick = { count++ }) { Text("Click") }
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Do: use rememberUpdatedState or include in key
|
|
500
|
+
@Composable
|
|
501
|
+
fun GoodCapture() {
|
|
502
|
+
var count by remember { mutableStateOf(0) }
|
|
503
|
+
|
|
504
|
+
val updatedCount = rememberUpdatedState(count)
|
|
505
|
+
LaunchedEffect(Unit) {
|
|
506
|
+
delay(1000)
|
|
507
|
+
println(updatedCount.value) // Always current
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
Button(onClick = { count++ }) { Text("Click") }
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
**Summary:** Effects bridge declarative Compose with imperative systems. Master key selection in `LaunchedEffect`, always cleanup in `DisposableEffect`, use `rememberUpdatedState` for long-running effects that need fresh values, and prefer effect-based patterns over manual lifecycle management.
|