reis-mobile 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +175 -168
- package/THIRD_PARTY_NOTICES.md +224 -4
- package/agents/android-architect.md +89 -0
- package/agents/android-performance-engineer.md +92 -0
- package/agents/android-test-engineer.md +97 -0
- package/agents/flutter-test-engineer.md +2 -0
- package/agents/ios-architect.md +93 -0
- package/agents/ios-performance-engineer.md +92 -0
- package/agents/ios-test-engineer.md +95 -0
- package/agents/lead-mobile.md +10 -1
- package/agents/mobile-staff-engineer.md +1 -1
- package/agents/rn-architect.md +94 -0
- package/agents/rn-performance-engineer.md +92 -0
- package/agents/rn-test-engineer.md +98 -0
- package/bin/reis-mobile.mjs +59 -17
- package/commands/debate.md +10 -1
- package/commands/debug.md +60 -0
- package/commands/reis-mobile.md +7 -2
- package/core/config/project.mjs +59 -0
- package/core/registry/frontmatter.mjs +15 -4
- package/core/registry/registry.mjs +21 -1
- package/core/router/intents.mjs +2 -0
- package/core/router/router.mjs +10 -5
- package/package.json +1 -1
- package/skills/android-adaptive/SKILL.md +304 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/container-behavior.md +112 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/get-started.md +69 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/index.md +81 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/item-behavior.md +170 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/container-properties.md +415 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/get-started.md +51 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/index.md +73 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/item-properties.md +170 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/mediaquery/index.md +333 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/tooling/debug.md +114 -0
- package/skills/android-adaptive/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
- package/skills/android-agp-9-upgrade/SKILL.md +106 -0
- package/skills/android-agp-9-upgrade/references/android/build/migrate-to-built-in-kotlin.md +416 -0
- package/skills/android-agp-9-upgrade/references/android/build/releases/agp-9-0-0-release-notes.md +554 -0
- package/skills/android-agp-9-upgrade/references/buildconfig.md +54 -0
- package/skills/android-agp-9-upgrade/references/ksp-kapt.md +39 -0
- package/skills/android-agp-9-upgrade/references/paparazzi-gradle-9.md +30 -0
- package/skills/android-agp-9-upgrade/references/recipes.md +62 -0
- package/skills/android-appfunctions/SKILL.md +74 -0
- package/skills/android-appfunctions/references/adb-interaction-testing.md +95 -0
- package/skills/android-appfunctions/references/context.md +26 -0
- package/skills/android-appfunctions/references/feature-discovery-analysis.md +71 -0
- package/skills/android-appfunctions/references/implementation-configuration.md +282 -0
- package/skills/android-appfunctions/references/kdoc-refinement-optimization.md +75 -0
- package/skills/android-appfunctions/references/migrate-to-service-entry-point.md +226 -0
- package/skills/android-camerax/SKILL.md +135 -0
- package/skills/android-camerax/references/camera1-to-camerax.md +198 -0
- package/skills/android-camerax/references/camera2-to-camerax.md +193 -0
- package/skills/android-camerax/references/expert-blueprints.md +58 -0
- package/skills/android-camerax/references/foldables.md +83 -0
- package/skills/android-camerax/references/immutability.md +60 -0
- package/skills/android-camerax/references/low-light.md +124 -0
- package/skills/android-camerax/references/mlkit-spatial.md +75 -0
- package/skills/android-camerax/references/modern-apis.md +42 -0
- package/skills/android-camerax/references/testing.md +69 -0
- package/skills/android-camerax/references/thermals.md +85 -0
- package/skills/android-camerax/references/wear-os.md +76 -0
- package/skills/android-camerax/references/xr.md +54 -0
- package/skills/android-cli/SKILL.md +474 -0
- package/skills/android-cli/references/interact.md +113 -0
- package/skills/android-cli/references/journeys.md +120 -0
- package/skills/android-code-review/SKILL.md +58 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/SKILL.md +340 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/design/ui/ai-glasses/guides/interaction/inputs.md +67 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/access-hardware-projected-context.md +388 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/buttons.md +139 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/cards.md +148 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/focus.md +107 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/icons.md +90 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/text.md +69 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/title-chips.md +82 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/request-hardware-permissions.md +213 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/button-samples-source.md +176 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/button-source.md +203 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/card-samples-source.md +296 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/card-source.md +515 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/deptheffect-source.md +224 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/deptheffectlevels-source.md +105 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/glimmersansflextypography-source.md +270 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/glimmertheme-source.md +182 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/icon-source.md +388 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/iconbutton-source.md +126 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/iconsizes-source.md +78 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/list-source.md +27 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/listitem-source.md +272 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/liststate-source.md +427 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/material-hct-source.md +217 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/projectedcontext-source.md +265 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stack-source.md +368 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stackitemscope-source.md +440 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stackstate-source.md +325 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/surface-source.md +1211 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/titlechip-samples-source.md +101 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/titlechip-source.md +131 -0
- package/skills/android-edge-to-edge/SKILL.md +429 -0
- package/skills/android-engage-sdk-integration/SKILL.md +130 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/faq.md +439 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/food.md +1149 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/healthandfitness.md +1055 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/listen.md +1050 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/otherverticals.md +1301 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/read.md +910 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/shopping.md +1224 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/social.md +719 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/travel.md +1413 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/continue-watching/index.md +19 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/entitlements.md +353 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/getting-started.md +202 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/recommendations.md +471 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/watch.md +1081 -0
- package/skills/android-engage-sdk-integration/references/clusters.md +154 -0
- package/skills/android-engage-sdk-integration/references/common.md +519 -0
- package/skills/android-engage-sdk-integration/references/patterns.md +527 -0
- package/skills/android-engage-sdk-integration/references/requests.md +260 -0
- package/skills/android-engage-sdk-integration/references/schemas/food.md +509 -0
- package/skills/android-engage-sdk-integration/references/schemas/listen.md +842 -0
- package/skills/android-engage-sdk-integration/references/schemas/other.md +220 -0
- package/skills/android-engage-sdk-integration/references/schemas/read.md +412 -0
- package/skills/android-engage-sdk-integration/references/schemas/shopping.md +357 -0
- package/skills/android-engage-sdk-integration/references/schemas/social.md +228 -0
- package/skills/android-engage-sdk-integration/references/schemas/travel.md +923 -0
- package/skills/android-engage-sdk-integration/references/schemas/tv.md +1226 -0
- package/skills/android-engage-sdk-integration/references/schemas/watch.md +1137 -0
- package/skills/android-engage-sdk-integration/references/troubleshooting.md +39 -0
- package/skills/android-gradle-build-debug/SKILL.md +71 -0
- package/skills/android-intent-security/SKILL.md +550 -0
- package/skills/android-leanback-to-compose-tv-migration/SKILL.md +743 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/get-started/navigation.md +372 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/playback/compose/browse.md +243 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/playback/compose/index.md +153 -0
- package/skills/android-media3-cast-integration/SKILL.md +236 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/create-castplayer.md +390 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/customize-castoptions.md +93 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/index.md +21 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/SKILL.md +127 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/analysis-of-the-project-and-layout.md +42 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +171 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/migrate/interoperability-apis/compose-in-views.md +299 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/migrate/interoperability-apis/views-in-compose.md +286 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +197 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/identify-optimal-xml-candidate.md +31 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/xml-layout-migration.md +86 -0
- package/skills/android-ml-kit-genai-prompt-api/SKILL.md +124 -0
- package/skills/android-ml-kit-genai-prompt-api/references/get-started.md +272 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prefix-caching.md +146 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prompt-design.md +55 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prompt-optimization.md +74 -0
- package/skills/android-ml-kit-genai-prompt-api/references/structured-output.md +219 -0
- package/skills/android-ml-kit-genai-prompt-api/references/system-instructions.md +71 -0
- package/skills/android-navigation-3/SKILL.md +122 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/index.md +51 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/migration-guide.md +670 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/animations.md +147 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basic.md +89 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basicdsl.md +85 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basicsaveable.md +90 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/bottomsheet.md +195 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/common-ui.md +200 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/conditional-transitions.md +182 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/conditional.md +230 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-custommatcher.md +176 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-staticuri.md +140 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-syntheticbackstack.md +184 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/dialog.md +107 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/lifecycle-owner.md +185 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/material-supportingpane.md +145 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-hilt.md +283 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-koin.md +287 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/multiple-backstacks.md +468 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/passingarguments.md +371 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/results-event.md +273 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/results-state.md +266 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-listdetail.md +435 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-twopane.md +244 -0
- package/skills/android-navigation-3/references/android/guide/navigation/type-safe-destinations.md +129 -0
- package/skills/android-navigation-event/SKILL.md +312 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/dispatcher.md +134 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/handle-back.md +217 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/index.md +83 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/setup.md +32 -0
- package/skills/android-play-billing-library-version-upgrade/SKILL.md +96 -0
- package/skills/android-play-billing-library-version-upgrade/references/android/google/play/billing/release-notes.md +1240 -0
- package/skills/android-play-billing-library-version-upgrade/references/migration-logic.md +78 -0
- package/skills/android-play-billing-library-version-upgrade/references/version-checklist.md +54 -0
- package/skills/android-play-policy-insights/SKILL.md +172 -0
- package/skills/android-play-policy-insights/resources/common_mandates.md +100 -0
- package/skills/android-play-policy-insights/resources/compliance_report_template.md +59 -0
- package/skills/android-play-policy-insights/resources/critic.md +86 -0
- package/skills/android-play-policy-insights/resources/goal_data_safety.md +212 -0
- package/skills/android-play-policy-insights/resources/goal_permissions_and_apis.md +459 -0
- package/skills/android-play-policy-insights/resources/goal_user_account.md +106 -0
- package/skills/android-play-policy-insights/resources/policies.json +321 -0
- package/skills/android-play-policy-insights/resources/scanner_config.json +843 -0
- package/skills/android-play-policy-insights/scripts/generate_report.py +860 -0
- package/skills/android-play-policy-insights/scripts/orchestrator.py +1313 -0
- package/skills/android-play-policy-insights/scripts/play_store_scraper.py +410 -0
- package/skills/android-play-policy-insights/scripts/scanner.py +261 -0
- package/skills/android-play-policy-insights/scripts/template_engine.py +243 -0
- package/skills/android-profiler/SKILL.md +60 -0
- package/skills/android-profiler/analysis/analysis_orchestrator.md +32 -0
- package/skills/android-profiler/analysis/workflows/perfetto-sql/perfetto_sql.md +28 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/perfetto_trace_analysis.md +121 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/guiding_principles.md +51 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/domain_hints_template.md +7 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_cpu.md +56 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_graphics.md +51 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_io.md +46 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_ipc.md +41 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_memory.md +55 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_power.md +33 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/per_candidate_analysis.md +172 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/triage.md +94 -0
- package/skills/android-profiler/recording/recording_orchestrator.md +36 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/perfetto_trace_recording.md +148 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/app_jank.pftxt +43 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/cpu_profile.pftxt +35 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/java_heap_dump.pftxt +21 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/long_background.pftxt +37 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/memory_counters.pftxt +45 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/native_heap.pftxt +21 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/sched_cpu.pftxt +33 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/trace_config_reference.md +102 -0
- package/skills/android-profiler/references/env_setup.md +15 -0
- package/skills/android-profiler/references/perfetto/setup.md +29 -0
- package/skills/android-profiler/references/perfetto/sql.md +327 -0
- package/skills/android-r8-analyzer/SKILL.md +72 -0
- package/skills/android-r8-analyzer/references/CONFIGURATION-ANALYZER.md +287 -0
- package/skills/android-r8-analyzer/references/CONFIGURATION.md +44 -0
- package/skills/android-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
- package/skills/android-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
- package/skills/android-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
- package/skills/android-r8-analyzer/references/REPORT_FORMAT.md +51 -0
- package/skills/android-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +252 -0
- package/skills/android-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
- package/skills/android-restore-credentials/SKILL.md +359 -0
- package/skills/android-restore-credentials/references/android/guide/topics/manifest/application-element.md +832 -0
- package/skills/android-restore-credentials/references/android/identity/passkeys/create-passkeys.md +327 -0
- package/skills/android-restore-credentials/references/android/identity/passkeys/sign-in-with-passkeys.md +219 -0
- package/skills/android-styles/SKILL.md +229 -0
- package/skills/android-styles/references/android/develop/ui/compose/designsystems/custom.md +459 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/fundamentals.md +421 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/state-animations.md +461 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/styles-vs-modifiers.md +48 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/theming.md +269 -0
- package/skills/android-verified-email/SKILL.md +432 -0
- package/skills/android-verified-email/references/android/identity/credential-manager/index.md +67 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/credential-verifier.md +166 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/email-verification-implementation.md +313 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/email-verification.md +158 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/index.md +112 -0
- package/skills/android-verified-email/references/android/identity/passkeys/create-passkeys.md +327 -0
- package/skills/android-verified-email/references/android/identity/sign-in/credential-manager-webview.md +84 -0
- package/skills/android-wear-compose-m3/SKILL.md +365 -0
- package/skills/android-wear-compose-m3/references/android/training/wearables/compose/migrate-to-material3.md +677 -0
- package/skills/android-wear-compose-m3/references/foundation/AmbientModeSample.kt.md +123 -0
- package/skills/android-wear-compose-m3/references/foundation/AmbientModeSample.kt.md.txt +123 -0
- package/skills/android-wear-compose-m3/references/foundation/CurvedWorldSample.kt.md +430 -0
- package/skills/android-wear-compose-m3/references/foundation/CurvedWorldSample.kt.md.txt +430 -0
- package/skills/android-wear-compose-m3/references/foundation/ExpandableSample.kt.md +99 -0
- package/skills/android-wear-compose-m3/references/foundation/ExpandableSample.kt.md.txt +99 -0
- package/skills/android-wear-compose-m3/references/foundation/HierarchicalFocusSample.kt.md +141 -0
- package/skills/android-wear-compose-m3/references/foundation/HierarchicalFocusSample.kt.md.txt +141 -0
- package/skills/android-wear-compose-m3/references/foundation/PagerSamples.kt.md +56 -0
- package/skills/android-wear-compose-m3/references/foundation/PagerSamples.kt.md.txt +56 -0
- package/skills/android-wear-compose-m3/references/foundation/RotarySamples.kt.md +153 -0
- package/skills/android-wear-compose-m3/references/foundation/RotarySamples.kt.md.txt +153 -0
- package/skills/android-wear-compose-m3/references/foundation/ScalingLazyColumnSample.kt.md +131 -0
- package/skills/android-wear-compose-m3/references/foundation/ScalingLazyColumnSample.kt.md.txt +131 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToDismissBoxSample.kt.md +169 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToDismissBoxSample.kt.md.txt +169 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToRevealSample.kt.md +282 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToRevealSample.kt.md.txt +282 -0
- package/skills/android-wear-compose-m3/references/foundation/TransformingLazyColumnSample.kt.md +335 -0
- package/skills/android-wear-compose-m3/references/foundation/TransformingLazyColumnSample.kt.md.txt +335 -0
- package/skills/android-wear-compose-m3/references/material3/AlertDialogSample.kt.md +377 -0
- package/skills/android-wear-compose-m3/references/material3/AlertDialogSample.kt.md.txt +377 -0
- package/skills/android-wear-compose-m3/references/material3/AnimatedTextSample.kt.md +165 -0
- package/skills/android-wear-compose-m3/references/material3/AnimatedTextSample.kt.md.txt +165 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonGroupSample.kt.md +91 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonGroupSample.kt.md.txt +91 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonSample.kt.md +496 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonSample.kt.md.txt +496 -0
- package/skills/android-wear-compose-m3/references/material3/CardSample.kt.md +470 -0
- package/skills/android-wear-compose-m3/references/material3/CardSample.kt.md.txt +470 -0
- package/skills/android-wear-compose-m3/references/material3/CheckboxButtonSample.kt.md +67 -0
- package/skills/android-wear-compose-m3/references/material3/CheckboxButtonSample.kt.md.txt +67 -0
- package/skills/android-wear-compose-m3/references/material3/ConfirmationDialogSample.kt.md +162 -0
- package/skills/android-wear-compose-m3/references/material3/ConfirmationDialogSample.kt.md.txt +162 -0
- package/skills/android-wear-compose-m3/references/material3/CurvedTextSamples.kt.md +78 -0
- package/skills/android-wear-compose-m3/references/material3/CurvedTextSamples.kt.md.txt +78 -0
- package/skills/android-wear-compose-m3/references/material3/DatePickerSample.kt.md +131 -0
- package/skills/android-wear-compose-m3/references/material3/DatePickerSample.kt.md.txt +131 -0
- package/skills/android-wear-compose-m3/references/material3/DynamicColorSchemeSample.kt.md +74 -0
- package/skills/android-wear-compose-m3/references/material3/DynamicColorSchemeSample.kt.md.txt +74 -0
- package/skills/android-wear-compose-m3/references/material3/EdgeButtonSample.kt.md +63 -0
- package/skills/android-wear-compose-m3/references/material3/EdgeButtonSample.kt.md.txt +63 -0
- package/skills/android-wear-compose-m3/references/material3/FadingExpandingLabelSample.kt.md +60 -0
- package/skills/android-wear-compose-m3/references/material3/FadingExpandingLabelSample.kt.md.txt +60 -0
- package/skills/android-wear-compose-m3/references/material3/IconButtonSample.kt.md +125 -0
- package/skills/android-wear-compose-m3/references/material3/IconButtonSample.kt.md.txt +125 -0
- package/skills/android-wear-compose-m3/references/material3/IconToggleButtonSample.kt.md +116 -0
- package/skills/android-wear-compose-m3/references/material3/IconToggleButtonSample.kt.md.txt +116 -0
- package/skills/android-wear-compose-m3/references/material3/LevelIndicatorSample.kt.md +68 -0
- package/skills/android-wear-compose-m3/references/material3/LevelIndicatorSample.kt.md.txt +68 -0
- package/skills/android-wear-compose-m3/references/material3/LinearProgressIndicatorSample.kt.md +50 -0
- package/skills/android-wear-compose-m3/references/material3/LinearProgressIndicatorSample.kt.md.txt +50 -0
- package/skills/android-wear-compose-m3/references/material3/ListHeaderSample.kt.md +177 -0
- package/skills/android-wear-compose-m3/references/material3/ListHeaderSample.kt.md.txt +177 -0
- package/skills/android-wear-compose-m3/references/material3/OneHandedGestureSamples.kt.md +651 -0
- package/skills/android-wear-compose-m3/references/material3/OneHandedGestureSamples.kt.md.txt +651 -0
- package/skills/android-wear-compose-m3/references/material3/OpenOnPhoneDialogSample.kt.md +57 -0
- package/skills/android-wear-compose-m3/references/material3/OpenOnPhoneDialogSample.kt.md.txt +57 -0
- package/skills/android-wear-compose-m3/references/material3/PageIndicatorSample.kt.md +110 -0
- package/skills/android-wear-compose-m3/references/material3/PageIndicatorSample.kt.md.txt +110 -0
- package/skills/android-wear-compose-m3/references/material3/PagerScaffoldSample.kt.md +204 -0
- package/skills/android-wear-compose-m3/references/material3/PagerScaffoldSample.kt.md.txt +204 -0
- package/skills/android-wear-compose-m3/references/material3/PickerGroupSample.kt.md +139 -0
- package/skills/android-wear-compose-m3/references/material3/PickerGroupSample.kt.md.txt +139 -0
- package/skills/android-wear-compose-m3/references/material3/PickerSample.kt.md +111 -0
- package/skills/android-wear-compose-m3/references/material3/PickerSample.kt.md.txt +111 -0
- package/skills/android-wear-compose-m3/references/material3/PlaceholderSample.kt.md +184 -0
- package/skills/android-wear-compose-m3/references/material3/PlaceholderSample.kt.md.txt +184 -0
- package/skills/android-wear-compose-m3/references/material3/ProgressIndicatorSample.kt.md +263 -0
- package/skills/android-wear-compose-m3/references/material3/ProgressIndicatorSample.kt.md.txt +263 -0
- package/skills/android-wear-compose-m3/references/material3/RadioButtonSample.kt.md +105 -0
- package/skills/android-wear-compose-m3/references/material3/RadioButtonSample.kt.md.txt +105 -0
- package/skills/android-wear-compose-m3/references/material3/ScaffoldSample.kt.md +146 -0
- package/skills/android-wear-compose-m3/references/material3/ScaffoldSample.kt.md.txt +146 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollAwaySample.kt.md +97 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollAwaySample.kt.md.txt +97 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollIndicatorSample.kt.md +66 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollIndicatorSample.kt.md.txt +66 -0
- package/skills/android-wear-compose-m3/references/material3/SliderSample.kt.md +86 -0
- package/skills/android-wear-compose-m3/references/material3/SliderSample.kt.md.txt +86 -0
- package/skills/android-wear-compose-m3/references/material3/StepperSample.kt.md +148 -0
- package/skills/android-wear-compose-m3/references/material3/StepperSample.kt.md.txt +148 -0
- package/skills/android-wear-compose-m3/references/material3/SurfaceTransformationSample.kt.md +166 -0
- package/skills/android-wear-compose-m3/references/material3/SurfaceTransformationSample.kt.md.txt +166 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToDismissBoxSample.kt.md +172 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToDismissBoxSample.kt.md.txt +172 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToRevealSample.kt.md +367 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToRevealSample.kt.md.txt +367 -0
- package/skills/android-wear-compose-m3/references/material3/SwitchButtonSample.kt.md +66 -0
- package/skills/android-wear-compose-m3/references/material3/SwitchButtonSample.kt.md.txt +66 -0
- package/skills/android-wear-compose-m3/references/material3/TextButtonSample.kt.md +115 -0
- package/skills/android-wear-compose-m3/references/material3/TextButtonSample.kt.md.txt +115 -0
- package/skills/android-wear-compose-m3/references/material3/TextToggleButtonSample.kt.md +71 -0
- package/skills/android-wear-compose-m3/references/material3/TextToggleButtonSample.kt.md.txt +71 -0
- package/skills/android-wear-compose-m3/references/material3/TimePickerSample.kt.md +151 -0
- package/skills/android-wear-compose-m3/references/material3/TimePickerSample.kt.md.txt +151 -0
- package/skills/android-wear-compose-m3/references/material3/TimeTextSample.kt.md +65 -0
- package/skills/android-wear-compose-m3/references/material3/TimeTextSample.kt.md.txt +65 -0
- package/skills/android-wear-compose-m3/references/material3/TransformationSpecSample.kt.md +246 -0
- package/skills/android-wear-compose-m3/references/material3/TransformationSpecSample.kt.md.txt +246 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnNotificationsSample.kt.md +89 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnNotificationsSample.kt.md.txt +89 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnSample.kt.md +309 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnSample.kt.md.txt +309 -0
- package/skills/android-wear-compose-m3/references/navigation3/SwipeDismissableSceneStrategySample.kt.md +205 -0
- package/skills/android-wear-compose-m3/references/navigation3/SwipeDismissableSceneStrategySample.kt.md.txt +205 -0
- package/skills/{architecture-feature-first → flutter-architecture-feature-first}/SKILL.md +1 -1
- package/skills/{bloc → flutter-bloc}/SKILL.md +1 -1
- package/skills/flutter-build-debug/SKILL.md +66 -0
- package/skills/{code-review → flutter-code-review}/SKILL.md +1 -1
- package/skills/{dart-3-updates → flutter-dart-3-updates}/SKILL.md +1 -1
- package/skills/{dart-fix-runtime-errors → flutter-dart-fix-runtime-errors}/SKILL.md +1 -1
- package/skills/{dart-resolve-package-conflicts → flutter-dart-resolve-package-conflicts}/SKILL.md +1 -1
- package/skills/{dart-run-static-analysis → flutter-dart-run-static-analysis}/SKILL.md +1 -1
- package/skills/{dart-use-pattern-matching → flutter-dart-use-pattern-matching}/SKILL.md +1 -1
- package/skills/{effective-dart → flutter-effective-dart}/SKILL.md +1 -1
- package/skills/{provider → flutter-provider}/SKILL.md +1 -1
- package/skills/{riverpod → flutter-riverpod}/SKILL.md +1 -1
- package/skills/ios-cocoapods-debug/SKILL.md +65 -0
- package/skills/ios-code-review/SKILL.md +56 -0
- package/skills/ios-xcode-build-debug/SKILL.md +66 -0
- package/skills/{detect-mobile-stack → mobile-detect-stack}/SKILL.md +1 -1
- package/skills/mobile-firebase/SKILL.md +54 -0
- package/skills/mobile-firebase/references/android/ai-logic.md +31 -0
- package/skills/mobile-firebase/references/android/analytics.md +33 -0
- package/skills/mobile-firebase/references/android/app-check.md +36 -0
- package/skills/mobile-firebase/references/android/auth.md +44 -0
- package/skills/mobile-firebase/references/android/crashlytics.md +31 -0
- package/skills/mobile-firebase/references/android/firestore.md +44 -0
- package/skills/mobile-firebase/references/android/functions.md +33 -0
- package/skills/mobile-firebase/references/android/in-app-messaging.md +28 -0
- package/skills/mobile-firebase/references/android/messaging.md +41 -0
- package/skills/mobile-firebase/references/android/realtime-database.md +50 -0
- package/skills/mobile-firebase/references/android/remote-config.md +43 -0
- package/skills/mobile-firebase/references/android/sql-connect.md +31 -0
- package/skills/mobile-firebase/references/android/storage.md +39 -0
- package/skills/mobile-firebase/references/android.md +30 -0
- package/skills/{firebase-ai/SKILL.md → mobile-firebase/references/flutter/ai-logic.md} +2 -8
- package/skills/{firebase-analytics/SKILL.md → mobile-firebase/references/flutter/analytics.md} +2 -8
- package/skills/{firebase-app-check/SKILL.md → mobile-firebase/references/flutter/app-check.md} +2 -8
- package/skills/{firebase-auth/SKILL.md → mobile-firebase/references/flutter/auth.md} +2 -8
- package/skills/{firebase-crashlytics/SKILL.md → mobile-firebase/references/flutter/crashlytics.md} +2 -8
- package/skills/{firebase-cloud-firestore/SKILL.md → mobile-firebase/references/flutter/firestore.md} +2 -8
- package/skills/{firebase-cloud-functions/SKILL.md → mobile-firebase/references/flutter/functions.md} +2 -8
- package/skills/{firebase-in-app-messaging/SKILL.md → mobile-firebase/references/flutter/in-app-messaging.md} +2 -8
- package/skills/{firebase-messaging/SKILL.md → mobile-firebase/references/flutter/messaging.md} +2 -8
- package/skills/{firebase-database/SKILL.md → mobile-firebase/references/flutter/realtime-database.md} +2 -8
- package/skills/{firebase-remote-config/SKILL.md → mobile-firebase/references/flutter/remote-config.md} +2 -8
- package/skills/{flutterfire-configure/SKILL.md → mobile-firebase/references/flutter/setup-flutterfire.md} +1 -8
- package/skills/{firebase-data-connect/SKILL.md → mobile-firebase/references/flutter/sql-connect.md} +2 -8
- package/skills/{firebase-storage/SKILL.md → mobile-firebase/references/flutter/storage.md} +2 -8
- package/skills/mobile-firebase/references/flutter.md +36 -0
- package/skills/mobile-firebase/references/ios/ai-logic.md +30 -0
- package/skills/mobile-firebase/references/ios/analytics.md +33 -0
- package/skills/mobile-firebase/references/ios/app-check.md +36 -0
- package/skills/mobile-firebase/references/ios/auth.md +48 -0
- package/skills/mobile-firebase/references/ios/crashlytics.md +34 -0
- package/skills/mobile-firebase/references/ios/firestore.md +53 -0
- package/skills/mobile-firebase/references/ios/functions.md +35 -0
- package/skills/mobile-firebase/references/ios/in-app-messaging.md +26 -0
- package/skills/mobile-firebase/references/ios/messaging.md +45 -0
- package/skills/mobile-firebase/references/ios/realtime-database.md +49 -0
- package/skills/mobile-firebase/references/ios/remote-config.md +44 -0
- package/skills/mobile-firebase/references/ios/sql-connect.md +33 -0
- package/skills/mobile-firebase/references/ios/storage.md +36 -0
- package/skills/mobile-firebase/references/ios.md +28 -0
- package/skills/mobile-firebase/references/react-native/ai-logic.md +32 -0
- package/skills/mobile-firebase/references/react-native/analytics.md +43 -0
- package/skills/mobile-firebase/references/react-native/app-check.md +35 -0
- package/skills/mobile-firebase/references/react-native/auth.md +50 -0
- package/skills/mobile-firebase/references/react-native/crashlytics.md +36 -0
- package/skills/mobile-firebase/references/react-native/firestore.md +45 -0
- package/skills/mobile-firebase/references/react-native/functions.md +28 -0
- package/skills/mobile-firebase/references/react-native/in-app-messaging.md +27 -0
- package/skills/mobile-firebase/references/react-native/messaging.md +46 -0
- package/skills/mobile-firebase/references/react-native/realtime-database.md +46 -0
- package/skills/mobile-firebase/references/react-native/remote-config.md +32 -0
- package/skills/mobile-firebase/references/react-native/sql-connect.md +11 -0
- package/skills/mobile-firebase/references/react-native/storage.md +30 -0
- package/skills/mobile-firebase/references/react-native.md +29 -0
- package/skills/mobile-test/SKILL.md +63 -0
- package/skills/mobile-test/references/android/setup/GUIDE.md +183 -0
- package/skills/mobile-test/references/android/setup/references/android/develop/ui/compose/testing/common-patterns.md +181 -0
- package/skills/mobile-test/references/android/setup/references/android/studio/preview/compose-screenshot-testing.md +255 -0
- package/skills/mobile-test/references/android/setup/references/android/training/dependency-injection/hilt-testing.md +447 -0
- package/skills/mobile-test/references/android.md +83 -0
- package/skills/{dart-collect-coverage/SKILL.md → mobile-test/references/flutter/coverage.md} +2 -11
- package/skills/{dart-generate-test-mocks/SKILL.md → mobile-test/references/flutter/generate-mocks.md} +2 -11
- package/skills/{flutter-add-integration-test/SKILL.md → mobile-test/references/flutter/integration-tests.md} +2 -11
- package/skills/{dart-migrate-to-checks-package/SKILL.md → mobile-test/references/flutter/migrate-to-checks.md} +2 -13
- package/skills/{mockito/SKILL.md → mobile-test/references/flutter/mockito.md} +1 -8
- package/skills/{mocktail/SKILL.md → mobile-test/references/flutter/mocktail.md} +1 -8
- package/skills/{patrol-e2e-testing/SKILL.md → mobile-test/references/flutter/patrol.md} +1 -8
- package/skills/{testing/SKILL.md → mobile-test/references/flutter/testing-guidelines.md} +1 -8
- package/skills/{dart-add-unit-test/SKILL.md → mobile-test/references/flutter/unit-tests.md} +2 -11
- package/skills/{flutter-add-widget-test/SKILL.md → mobile-test/references/flutter/widget-tests.md} +2 -11
- package/skills/mobile-test/references/flutter.md +44 -0
- package/skills/mobile-test/references/ios.md +79 -0
- package/skills/mobile-test/references/react-native.md +62 -0
- /package/skills/{dart-use-pattern-matching → flutter-dart-use-pattern-matching}/examples/json_patterns.dart +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Two-Pane Scene Recipe
|
|
2
|
+
|
|
3
|
+
This example shows how to create a two pane layout using the Scenes API.
|
|
4
|
+
|
|
5
|
+
A `TwoPaneSceneStrategy` will return a `TwoPaneScene` if:
|
|
6
|
+
|
|
7
|
+
- the window width is over 600dp
|
|
8
|
+
- the last two nav entries on the back stack have indicated that they support being displayed in a `TwoPaneScene` in their metadata.
|
|
9
|
+
|
|
10
|
+
See `TwoPaneScene.kt` for more implementation details.
|
|
11
|
+
[ Explore View the full recipe on GitHub.](https://github.com/android/nav3-recipes/tree/main/app/src/main/java/com/example/nav3recipes/scenes/twopane)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
package com.example.nav3recipes.scenes.twopane
|
|
15
|
+
|
|
16
|
+
import androidx.compose.foundation.layout.Column
|
|
17
|
+
import androidx.compose.foundation.layout.Row
|
|
18
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
19
|
+
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
|
|
20
|
+
import androidx.compose.runtime.Composable
|
|
21
|
+
import androidx.compose.runtime.remember
|
|
22
|
+
import androidx.compose.ui.Modifier
|
|
23
|
+
import androidx.navigation3.runtime.NavEntry
|
|
24
|
+
import androidx.navigation3.runtime.NavMetadataKey
|
|
25
|
+
import androidx.navigation3.runtime.contains
|
|
26
|
+
import androidx.navigation3.runtime.metadata
|
|
27
|
+
import androidx.navigation3.scene.Scene
|
|
28
|
+
import androidx.navigation3.scene.SceneStrategy
|
|
29
|
+
import androidx.navigation3.scene.SceneStrategyScope
|
|
30
|
+
import androidx.window.core.layout.WindowSizeClass
|
|
31
|
+
import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND
|
|
32
|
+
|
|
33
|
+
// --- TwoPaneScene ---
|
|
34
|
+
/**
|
|
35
|
+
* A custom [Scene] that displays two [NavEntry]s side-by-side in a 50/50 split.
|
|
36
|
+
*/
|
|
37
|
+
data class TwoPaneScene<T : Any>(
|
|
38
|
+
override val key: Any,
|
|
39
|
+
override val previousEntries: List<NavEntry<T>>,
|
|
40
|
+
val firstEntry: NavEntry<T>,
|
|
41
|
+
val secondEntry: NavEntry<T>
|
|
42
|
+
) : Scene<T> {
|
|
43
|
+
override val entries: List<NavEntry<T>> = listOf(firstEntry, secondEntry)
|
|
44
|
+
override val content: @Composable (() -> Unit) = {
|
|
45
|
+
Row(modifier = Modifier.fillMaxSize()) {
|
|
46
|
+
Column(modifier = Modifier.weight(0.5f)) {
|
|
47
|
+
firstEntry.Content()
|
|
48
|
+
}
|
|
49
|
+
Column(modifier = Modifier.weight(0.5f)) {
|
|
50
|
+
secondEntry.Content()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
companion object {
|
|
56
|
+
/**
|
|
57
|
+
* Helper function to add metadata to a [NavEntry] indicating it can be displayed
|
|
58
|
+
* in a two-pane layout.
|
|
59
|
+
*/
|
|
60
|
+
fun twoPane() = metadata {
|
|
61
|
+
put(TwoPaneKey, true)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
object TwoPaneKey : NavMetadataKey<Boolean>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Composable
|
|
69
|
+
fun <T : Any> rememberTwoPaneSceneStrategy(): TwoPaneSceneStrategy<T> {
|
|
70
|
+
val windowSizeClass = currentWindowAdaptiveInfoV2().windowSizeClass
|
|
71
|
+
|
|
72
|
+
return remember(windowSizeClass) {
|
|
73
|
+
TwoPaneSceneStrategy(windowSizeClass)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// --- TwoPaneSceneStrategy ---
|
|
79
|
+
/**
|
|
80
|
+
* A [SceneStrategy] that activates a [TwoPaneScene] if the window is wide enough
|
|
81
|
+
* and the top two back stack entries declare support for two-pane display.
|
|
82
|
+
*/
|
|
83
|
+
class TwoPaneSceneStrategy<T : Any>(val windowSizeClass: WindowSizeClass) : SceneStrategy<T> {
|
|
84
|
+
|
|
85
|
+
override fun SceneStrategyScope<T>.calculateScene(entries: List<NavEntry<T>>): Scene<T>? {
|
|
86
|
+
|
|
87
|
+
// Condition 1: Only return a Scene if the window is sufficiently wide to render two panes.
|
|
88
|
+
// We use isWidthAtLeastBreakpoint with WIDTH_DP_MEDIUM_LOWER_BOUND (600dp).
|
|
89
|
+
if (!windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND)) {
|
|
90
|
+
return null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
val lastTwoEntries = entries.takeLast(2)
|
|
94
|
+
|
|
95
|
+
// Condition 2: Only return a Scene if there are two entries, and both have declared
|
|
96
|
+
// they can be displayed in a two pane scene.
|
|
97
|
+
return if (lastTwoEntries.size == 2
|
|
98
|
+
&& lastTwoEntries.all { it.metadata.contains(TwoPaneScene.TwoPaneKey) }
|
|
99
|
+
) {
|
|
100
|
+
val firstEntry = lastTwoEntries.first()
|
|
101
|
+
val secondEntry = lastTwoEntries.last()
|
|
102
|
+
|
|
103
|
+
// The scene key must uniquely represent the state of the scene.
|
|
104
|
+
// A Pair of the first and second entry keys ensures uniqueness.
|
|
105
|
+
val sceneKey = Pair(firstEntry.contentKey, secondEntry.contentKey)
|
|
106
|
+
|
|
107
|
+
TwoPaneScene(
|
|
108
|
+
key = sceneKey,
|
|
109
|
+
// Where we go back to is a UX decision. In this case, we only remove the top
|
|
110
|
+
// entry from the back stack, despite displaying two entries in this scene.
|
|
111
|
+
// This is because in this app we only ever add one entry to the
|
|
112
|
+
// back stack at a time. It would therefore be confusing to the user to add one
|
|
113
|
+
// when navigating forward, but remove two when navigating back.
|
|
114
|
+
previousEntries = entries.dropLast(1),
|
|
115
|
+
firstEntry = firstEntry,
|
|
116
|
+
secondEntry = secondEntry
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
} else {
|
|
120
|
+
null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
/*
|
|
130
|
+
* Copyright 2025 The Android Open Source Project
|
|
131
|
+
*
|
|
132
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
133
|
+
* you may not use this file except in compliance with the License.
|
|
134
|
+
* You may obtain a copy of the License at
|
|
135
|
+
*
|
|
136
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
137
|
+
*
|
|
138
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
139
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
140
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
141
|
+
* See the License for the specific language governing permissions and
|
|
142
|
+
* limitations under the License.
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
package com.example.nav3recipes.scenes.twopane
|
|
146
|
+
|
|
147
|
+
import android.os.Bundle
|
|
148
|
+
import androidx.activity.ComponentActivity
|
|
149
|
+
import androidx.activity.compose.setContent
|
|
150
|
+
import androidx.compose.animation.SharedTransitionLayout
|
|
151
|
+
import androidx.compose.foundation.background
|
|
152
|
+
import androidx.compose.foundation.layout.Column
|
|
153
|
+
import androidx.compose.material3.Button
|
|
154
|
+
import androidx.compose.material3.Text
|
|
155
|
+
import androidx.compose.ui.Alignment
|
|
156
|
+
import androidx.compose.ui.Modifier
|
|
157
|
+
import androidx.lifecycle.compose.dropUnlessResumed
|
|
158
|
+
import androidx.navigation3.runtime.NavBackStack
|
|
159
|
+
import androidx.navigation3.runtime.NavKey
|
|
160
|
+
import androidx.navigation3.runtime.entryProvider
|
|
161
|
+
import androidx.navigation3.runtime.rememberNavBackStack
|
|
162
|
+
import androidx.navigation3.ui.NavDisplay
|
|
163
|
+
import com.example.nav3recipes.content.ContentBase
|
|
164
|
+
import com.example.nav3recipes.content.ContentGreen
|
|
165
|
+
import com.example.nav3recipes.content.ContentRed
|
|
166
|
+
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
|
|
167
|
+
import com.example.nav3recipes.ui.theme.colors
|
|
168
|
+
import kotlinx.serialization.Serializable
|
|
169
|
+
|
|
170
|
+
@Serializable
|
|
171
|
+
private object Home : NavKey
|
|
172
|
+
|
|
173
|
+
@Serializable
|
|
174
|
+
private data class Product(val id: Int) : NavKey
|
|
175
|
+
|
|
176
|
+
@Serializable
|
|
177
|
+
private data object Profile : NavKey
|
|
178
|
+
|
|
179
|
+
class TwoPaneActivity : ComponentActivity() {
|
|
180
|
+
|
|
181
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
182
|
+
setEdgeToEdgeConfig()
|
|
183
|
+
super.onCreate(savedInstanceState)
|
|
184
|
+
|
|
185
|
+
setContent {
|
|
186
|
+
val backStack = rememberNavBackStack(Home)
|
|
187
|
+
val twoPaneStrategy = rememberTwoPaneSceneStrategy<NavKey>()
|
|
188
|
+
|
|
189
|
+
SharedTransitionLayout {
|
|
190
|
+
NavDisplay(
|
|
191
|
+
backStack = backStack,
|
|
192
|
+
onBack = { backStack.removeLastOrNull() },
|
|
193
|
+
sceneStrategies = listOf(twoPaneStrategy),
|
|
194
|
+
sharedTransitionScope = this,
|
|
195
|
+
entryProvider = entryProvider {
|
|
196
|
+
entry<Home>(
|
|
197
|
+
metadata = TwoPaneScene.twoPane()
|
|
198
|
+
) {
|
|
199
|
+
ContentRed("Welcome to Nav3") {
|
|
200
|
+
Button(onClick = { backStack.addProductRoute(1) }) {
|
|
201
|
+
Text("View the first product")
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
entry<Product>(
|
|
206
|
+
metadata = TwoPaneScene.twoPane()
|
|
207
|
+
) { product ->
|
|
208
|
+
ContentBase(
|
|
209
|
+
"Product ${product.id} ",
|
|
210
|
+
Modifier.background(colors[product.id % colors.size])
|
|
211
|
+
) {
|
|
212
|
+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
213
|
+
Button(onClick = dropUnlessResumed {
|
|
214
|
+
backStack.addProductRoute(product.id + 1)
|
|
215
|
+
}) {
|
|
216
|
+
Text("View the next product")
|
|
217
|
+
}
|
|
218
|
+
Button(onClick = dropUnlessResumed {
|
|
219
|
+
backStack.add(Profile)
|
|
220
|
+
}) {
|
|
221
|
+
Text("View profile")
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
entry<Profile> {
|
|
227
|
+
ContentGreen("Profile (single pane only)")
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private fun NavBackStack<NavKey>.addProductRoute(productId: Int) {
|
|
237
|
+
val productRoute =
|
|
238
|
+
Product(productId)
|
|
239
|
+
// Avoid adding the same product route to the back stack twice.
|
|
240
|
+
if (!contains(productRoute)) {
|
|
241
|
+
add(productRoute)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
package/skills/android-navigation-3/references/android/guide/navigation/type-safe-destinations.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
This guide outlines the process of replacing string-based routes with
|
|
2
|
+
serializable Kotlin types to achieve compile-time safety and eliminate runtime
|
|
3
|
+
crashes caused by typos or incorrect argument types.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before starting the migration, verify that your project meets the following
|
|
8
|
+
requirements:
|
|
9
|
+
|
|
10
|
+
1. **Navigation version**: Update to Jetpack Navigation 2.8.0 or higher
|
|
11
|
+
2. **Kotlin serialization plugin**:
|
|
12
|
+
3. Add the plugin to `libs.versions.toml`:
|
|
13
|
+
|
|
14
|
+
[libraries]
|
|
15
|
+
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
|
16
|
+
|
|
17
|
+
[plugins]
|
|
18
|
+
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
|
19
|
+
|
|
20
|
+
- Add the dependencies to your top-level `build.gradle.kts` and module-level `build.gradle.kts`.
|
|
21
|
+
|
|
22
|
+
## Step 1: Define Your Destinations
|
|
23
|
+
|
|
24
|
+
Replace your constant route strings with `@Serializable` objects and classes.
|
|
25
|
+
|
|
26
|
+
- **For screens without arguments** : Use a `data object`
|
|
27
|
+
- **For screens with arguments** : Use a `data class`
|
|
28
|
+
|
|
29
|
+
**Before (string based):**
|
|
30
|
+
|
|
31
|
+
const val ROUTE_HOME = "home"
|
|
32
|
+
const val ROUTE_PROFILE = "profile/{userId}"
|
|
33
|
+
|
|
34
|
+
**After (type safe):**
|
|
35
|
+
|
|
36
|
+
import kotlinx.serialization.Serializable
|
|
37
|
+
|
|
38
|
+
@Serializable
|
|
39
|
+
object Home
|
|
40
|
+
|
|
41
|
+
@Serializable
|
|
42
|
+
data class Profile(val userId: String)
|
|
43
|
+
|
|
44
|
+
## Step 2: Update the NavHost Configuration
|
|
45
|
+
|
|
46
|
+
Update your `NavHost` to use the new generic types in the `composable` and
|
|
47
|
+
`dialog` function.
|
|
48
|
+
|
|
49
|
+
**Before:**
|
|
50
|
+
|
|
51
|
+
NavHost(navController, startDestination = "home") {
|
|
52
|
+
composable("home") { HomeScreen(...) }
|
|
53
|
+
composable("profile/{userId}") { backStackEntry ->
|
|
54
|
+
val userId = backStackEntry.arguments?.getString("userId")
|
|
55
|
+
ProfileScreen(userId)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
**After:**
|
|
60
|
+
|
|
61
|
+
NavHost(navController, startDestination = Home) {
|
|
62
|
+
composable<Home> {
|
|
63
|
+
HomeScreen(...)
|
|
64
|
+
}
|
|
65
|
+
composable<Profile> { backStackEntry ->
|
|
66
|
+
// The library automatically handles argument extraction
|
|
67
|
+
val profile: Profile = backStackEntry.toRoute()
|
|
68
|
+
ProfileScreen(profile.userId)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
## Step 3: Implement Type-Safe Navigation Calls
|
|
73
|
+
|
|
74
|
+
Replace string-interpolated navigation calls with class instances.
|
|
75
|
+
|
|
76
|
+
**Before:**
|
|
77
|
+
|
|
78
|
+
navController.navigate("profile/user123")
|
|
79
|
+
|
|
80
|
+
**After:**
|
|
81
|
+
|
|
82
|
+
navController.navigate(Profile(userId = "user123"))
|
|
83
|
+
|
|
84
|
+
## Step 4: Accessing Arguments in ViewModels
|
|
85
|
+
|
|
86
|
+
If you use a `ViewModel`, you can now extract the route object directly from the
|
|
87
|
+
`SavedStateHandle`.
|
|
88
|
+
|
|
89
|
+
**Implementation:**
|
|
90
|
+
|
|
91
|
+
class ProfileViewModel(
|
|
92
|
+
savedStateHandle: SavedStateHandle
|
|
93
|
+
) : ViewModel() {
|
|
94
|
+
// Automatically parses arguments into the Profile class
|
|
95
|
+
private val profile = savedStateHandle.toRoute<Profile>()
|
|
96
|
+
val userId = profile.userId
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
## Step 5: (Advanced) Handling Custom Types
|
|
100
|
+
|
|
101
|
+
If you need to pass complex data classes (not just primitives), you must define
|
|
102
|
+
a custom `NavType`.
|
|
103
|
+
|
|
104
|
+
1. **Create the Custom Type** : \`\`\`kotlin val SearchFilterType = object : NavType(isNullableAllowed = false) { override fun get(bundle: Bundle, key: String): SearchFilter? = Json.decodeFromString(bundle.getString(key) ?: return null)
|
|
105
|
+
|
|
106
|
+
override fun parseValue(value: String): SearchFilter =
|
|
107
|
+
Json.decodeFromString(Uri.decode(value))
|
|
108
|
+
|
|
109
|
+
override fun put(bundle: Bundle, key: String, value: SearchFilter) {
|
|
110
|
+
bundle.putString(key, Json.encodeToString(value))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
2. **Register it in the Graph**:
|
|
118
|
+
```kotlin
|
|
119
|
+
composable<Search>(
|
|
120
|
+
typeMap = mapOf(typeOf<SearchFilter>() to SearchFilterType)
|
|
121
|
+
) { ... }
|
|
122
|
+
|
|
123
|
+
## Best practices and tips
|
|
124
|
+
|
|
125
|
+
- **Sealed Hierarchies**: For large apps, group your routes using a sealed interface or class to keep the navigation structure organized
|
|
126
|
+
- **Object Instances** : For routes without parameters, always use `object` instead of `class` to avoid unnecessary allocations
|
|
127
|
+
- **Nullable Types** : The new API supports nullable types (for example, `data
|
|
128
|
+
class Search(val query: String?)`) and provides default values automatically
|
|
129
|
+
- **Testing** : Use `navController.currentBackStackEntry?.hasRoute<T>()` to check the current destination in a type-safe manner during UI tests
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-navigation-event
|
|
3
|
+
description: Intercept back gestures and run Predictive Back animations using the
|
|
4
|
+
NavigationEvent (androidx.navigationevent) library in Compose Android. Handles Activity
|
|
5
|
+
setup, parent-child dispatcher scoping in `ViewPagers` or tabs, Compose `NavigationBackHandler`,
|
|
6
|
+
and migration from legacy `BackHandler` on SDK 36+.
|
|
7
|
+
license: Apache-2.0
|
|
8
|
+
source: https://github.com/android/skills
|
|
9
|
+
routing: manual
|
|
10
|
+
stacks: [android]
|
|
11
|
+
metadata:
|
|
12
|
+
author: Google LLC
|
|
13
|
+
last-updated: '2026-09-01'
|
|
14
|
+
keywords:
|
|
15
|
+
- Android
|
|
16
|
+
- Navigation Event
|
|
17
|
+
- Jetpack Compose
|
|
18
|
+
- Back Navigation
|
|
19
|
+
- Dispatcher
|
|
20
|
+
- Guidelines
|
|
21
|
+
- Troubleshooting
|
|
22
|
+
- ComponentActivity
|
|
23
|
+
- Dialog
|
|
24
|
+
- ViewPager
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Common guidelines
|
|
28
|
+
|
|
29
|
+
- **For architecture concepts** : To understand the foundational architecture, continuous gesture event lifecycles, or class definitions of the Navigation Event library, read [Navigation Event overview](references/android/guide/navigation/navigation-event/index.md).
|
|
30
|
+
- **For Android target** : If compile SDK is lower than 36, set it to `36` or higher in `build.gradle.kts`.
|
|
31
|
+
- **For Compose Android target**: The project must use Jetpack Compose for Compose-specific APIs. This skill is scoped exclusively to Compose Android (Android Views and non-Compose implementations are excluded).
|
|
32
|
+
- **For activity dispatchers** : `ComponentActivity` automatically implements `NavigationEventDispatcherOwner` out-of-the-box. You must use the built-in `navigationEventDispatcher` without creating anonymous delegate owners or overriding member properties.
|
|
33
|
+
- **For dialog scoping** : Floating windows (Compose `Dialog`, `ModalBottomSheet`, `ComponentDialog`) automatically provide a `NavigationEventDispatcherOwner`. You don't need manual `CompositionLocalProvider` propagation for dialogs.
|
|
34
|
+
- **For parent-child dispatcher hierarchies** : When scoping navigation handling to `ViewPagers`, tabbed interfaces, or nested navigation containers in Compose, use `rememberNavigationEventDispatcherOwner()` to create a child owner linked to the parent. Disabling the owner (`enabled = false`) automatically cascades to disable all child handlers.
|
|
35
|
+
- **For Compose handlers** : A one-to-one relationship between `NavigationEventState` and handlers is strictly enforced. Never bind the same `NavigationEventState` to multiple active `NavigationBackHandler` instances (`IllegalArgumentException`).
|
|
36
|
+
|
|
37
|
+
## Step 1: Plan
|
|
38
|
+
|
|
39
|
+
To complete this step, you **MUST** ensure the following:
|
|
40
|
+
|
|
41
|
+
1. **Identify the target platform** : Verify the app is targeting Compose Android. If `compileSdk` is lower than 36, set it to `36` or higher in `build.gradle.kts`.
|
|
42
|
+
2. **Navigation check**: Check if Navigation 3 is in use. If it is in use, use Navigation 3's built-in back navigation support rather than manually implementing low-level dispatchers from this skill.
|
|
43
|
+
3. **Hierarchy check** : Identify host Activities, `ViewPagers`, tabbed interfaces, or nested navigation hosts that require back gesture interception or parent-child dispatcher linking.
|
|
44
|
+
4. **Migration check** : Check if the project is migrating from back handling (`OnBackPressedCallback`, `BackHandler`, `onBackPresser`) to `NavigationEvent` and `NavigationBackHandler`.
|
|
45
|
+
5. **Input interception** : Detect where the app is intercepting navigation events from gestures or hardware button presses requiring translation to `NavigationEvent`.
|
|
46
|
+
|
|
47
|
+
## Step 2: Set up dependencies
|
|
48
|
+
|
|
49
|
+
To complete this step, you **MUST** ensure the following:
|
|
50
|
+
|
|
51
|
+
- For setting up compile SDKs, declaring catalog versions, and adding dependencies, follow [setup guide](references/android/guide/navigation/navigation-event/setup.md).
|
|
52
|
+
|
|
53
|
+
## Step 3: Configure dispatcher and inputs
|
|
54
|
+
|
|
55
|
+
To complete this step, you **MUST** ensure the following:
|
|
56
|
+
|
|
57
|
+
- To configure your dispatcher, leverage automatic `ComponentActivity` or `ComponentDialog` owner resolution.
|
|
58
|
+
- Link parent-child dispatchers in Compose following [dispatcher guide](references/android/guide/navigation/navigation-event/dispatcher.md).
|
|
59
|
+
|
|
60
|
+
## Step 4: Handle back navigation and UI transitions
|
|
61
|
+
|
|
62
|
+
To complete this step, you **MUST** ensure the following:
|
|
63
|
+
|
|
64
|
+
- To create navigation event handlers, integrate back gesture interception in Compose, animate UI components during swipes, and migrate from legacy back handlers, follow [handle back guide](references/android/guide/navigation/navigation-event/handle-back.md).
|
|
65
|
+
|
|
66
|
+
## Step 5: Clean up resources
|
|
67
|
+
|
|
68
|
+
> [!WARNING]
|
|
69
|
+
> **Warning:** Compose APIs perform teardown automatically. When using Compose APIs such as `NavigationBackHandler` and `rememberNavigationEventDispatcherOwner()`, handler removal and dispatcher disposal occur automatically when the composable leaves the composition.
|
|
70
|
+
|
|
71
|
+
You **MUST** perform explicit manual cleanup only when managing custom
|
|
72
|
+
dispatchers or non-Compose handlers:
|
|
73
|
+
|
|
74
|
+
- Call `remove()` on active handlers during teardown.
|
|
75
|
+
- Call `isEnabled = false` to temporarily disable navigation subtrees.
|
|
76
|
+
- Call `dispose()` on dispatcher instances when hosting components are destroyed. Disposing a parent dispatcher automatically cascades to all child dispatchers.
|
|
77
|
+
|
|
78
|
+
## Core troubleshooting guidelines
|
|
79
|
+
|
|
80
|
+
### 1. Activity dispatcher setup (StackOverflowError recursion)
|
|
81
|
+
|
|
82
|
+
`ComponentActivity` implements `NavigationEventDispatcherOwner` automatically
|
|
83
|
+
out-of-the-box. Don't override `navigationEventDispatcher` or wrap it in an
|
|
84
|
+
anonymous delegate owner.
|
|
85
|
+
|
|
86
|
+
#### RIGHT
|
|
87
|
+
|
|
88
|
+
**Why this is RIGHT** : Compose apps use `ComponentActivity` as the host.
|
|
89
|
+
`LocalNavigationEventDispatcherOwner.current` automatically resolves the
|
|
90
|
+
Activity's built-in dispatcher.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
```kotlin
|
|
94
|
+
// RIGHT
|
|
95
|
+
class MainActivity : ComponentActivity() {
|
|
96
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
97
|
+
super.onCreate(savedInstanceState)
|
|
98
|
+
setContent {
|
|
99
|
+
MyApplicationContent()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
<br />
|
|
106
|
+
|
|
107
|
+
#### WRONG
|
|
108
|
+
|
|
109
|
+
**Why this is WRONG** : Implementing `NavigationEventDispatcherOwner` directly on
|
|
110
|
+
`MainActivity` and overriding `navigationEventDispatcher` with a new instance
|
|
111
|
+
shadows the library's extension property, causing a recursive infinite loop
|
|
112
|
+
crash on launch (`StackOverflowError`). Creating redundant anonymous delegate
|
|
113
|
+
owners (`object : NavigationEventDispatcherOwner`) is unnecessary.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
```kotlin
|
|
117
|
+
// WRONG
|
|
118
|
+
class MainActivity : ComponentActivity(), NavigationEventDispatcherOwner {
|
|
119
|
+
override val navigationEventDispatcher = NavigationEventDispatcher() // Shadow loop crash
|
|
120
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
121
|
+
super.onCreate(savedInstanceState)
|
|
122
|
+
setContent {
|
|
123
|
+
MyApplicationContent()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
<br />
|
|
130
|
+
|
|
131
|
+
### 2. Floating window and dialog scoping (automatic ComponentDialog owner)
|
|
132
|
+
|
|
133
|
+
Floating windows (Compose `Dialog`, `ModalBottomSheet`, and any window backed by
|
|
134
|
+
`ComponentDialog`) automatically provide a `NavigationEventDispatcherOwner`.
|
|
135
|
+
Don't manually re-provide `LocalNavigationEventDispatcherOwner` using
|
|
136
|
+
`CompositionLocalProvider` inside dialogs.
|
|
137
|
+
|
|
138
|
+
#### RIGHT
|
|
139
|
+
|
|
140
|
+
**Why this is RIGHT** : `ComponentDialog` handles navigation dispatchers
|
|
141
|
+
automatically. Compose `Dialog` components resolve their dispatcher owner
|
|
142
|
+
out-of-the-box without manual propagation.
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
```kotlin
|
|
146
|
+
// RIGHT
|
|
147
|
+
@Composable
|
|
148
|
+
fun MyDialog(onDismiss: () -> Unit) {
|
|
149
|
+
Dialog(onDismissRequest = onDismiss) {
|
|
150
|
+
val navigationState = rememberNavigationEventState(currentInfo = NavigationEventInfo.None)
|
|
151
|
+
NavigationBackHandler(
|
|
152
|
+
state = navigationState,
|
|
153
|
+
onBackCompleted = onDismiss
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
<br />
|
|
160
|
+
|
|
161
|
+
#### WRONG
|
|
162
|
+
|
|
163
|
+
**Why this is WRONG** : Wrapping dialog content in a manual
|
|
164
|
+
`CompositionLocalProvider` creates redundant boilerplate and obscures the
|
|
165
|
+
automatic dispatcher resolution provided by `ComponentDialog`.
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
```kotlin
|
|
169
|
+
// WRONG
|
|
170
|
+
@Composable
|
|
171
|
+
fun MyDialog(onDismiss: () -> Unit) {
|
|
172
|
+
val dispatcherOwner = LocalNavigationEventDispatcherOwner.current!!
|
|
173
|
+
Dialog(onDismissRequest = onDismiss) {
|
|
174
|
+
// Redundant: ComponentDialog provides NavigationEventDispatcherOwner automatically
|
|
175
|
+
CompositionLocalProvider( LocalNavigationEventDispatcherOwner provides dispatcherOwner) {
|
|
176
|
+
val navigationState = rememberNavigationEventState(currentInfo = NavigationEventInfo.None)
|
|
177
|
+
NavigationBackHandler(
|
|
178
|
+
state = navigationState,
|
|
179
|
+
onBackCompleted = onDismiss
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
<br />
|
|
187
|
+
|
|
188
|
+
### 3. Parent-child dispatcher hierarchy (`ViewPagers` and nested navigation)
|
|
189
|
+
|
|
190
|
+
When managing nested UI hierarchies such as `ViewPagers`, tabbed
|
|
191
|
+
interfaces, or custom navigation containers in Compose, use
|
|
192
|
+
`rememberNavigationEventDispatcherOwner()` to create a child owner linked to the
|
|
193
|
+
composition hierarchy. Setting `enabled = false` on the child owner
|
|
194
|
+
automatically disables its dispatcher and all registered child handlers.
|
|
195
|
+
|
|
196
|
+
#### RIGHT
|
|
197
|
+
|
|
198
|
+
**Why this is RIGHT** : Using `rememberNavigationEventDispatcherOwner(enabled =
|
|
199
|
+
isSelected)` creates a scoped child dispatcher linked to the parent from
|
|
200
|
+
`LocalNavigationEventDispatcherOwner.current`. Providing it using
|
|
201
|
+
`CompositionLocalProvider` ensures non-visible tabs or pages automatically stop
|
|
202
|
+
intercepting back gestures without leaking handlers.
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
```kotlin
|
|
206
|
+
// RIGHT: Scoping child navigation in a ViewPager or Tab interface
|
|
207
|
+
@Composable
|
|
208
|
+
fun TabPage(isSelected: Boolean) {
|
|
209
|
+
val childOwner = rememberNavigationEventDispatcherOwner(enabled = isSelected)
|
|
210
|
+
CompositionLocalProvider(LocalNavigationEventDispatcherOwner provides childOwner) {
|
|
211
|
+
val navigationState = rememberNavigationEventState(currentInfo = NavigationEventInfo.None)
|
|
212
|
+
NavigationBackHandler(
|
|
213
|
+
state = navigationState,
|
|
214
|
+
onBackCompleted = { /* Handle page back navigation */ }
|
|
215
|
+
)
|
|
216
|
+
// Page content
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
<br />
|
|
222
|
+
|
|
223
|
+
#### WRONG
|
|
224
|
+
|
|
225
|
+
**Why this is WRONG** : Creating unlinked standalone dispatchers, instantiating
|
|
226
|
+
raw dispatchers without remembering them across recompositions, or attempting to
|
|
227
|
+
use non-existent methods like `.addChild()` breaks hierarchy routing and leaves
|
|
228
|
+
child handlers active even when the page is inactive.
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
```kotlin
|
|
232
|
+
// WRONG
|
|
233
|
+
@Composable
|
|
234
|
+
fun TabPage(isSelected: Boolean) {
|
|
235
|
+
val parentDispatcher = LocalNavigationEventDispatcherOwner.current?.navigationEventDispatcher
|
|
236
|
+
val childDispatcher = NavigationEventDispatcher() // Unlinked and not remembered across recompositions
|
|
237
|
+
// WRONG: Method does not exist
|
|
238
|
+
parentDispatcher?.addChild(childDispatcher)
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
<br />
|
|
243
|
+
|
|
244
|
+
### 4. Compose multi-handler registration (IllegalArgumentException)
|
|
245
|
+
|
|
246
|
+
You must not bind the same `NavigationEventState` to multiple active
|
|
247
|
+
`NavigationBackHandler` instances, as this throws an `IllegalArgumentException`
|
|
248
|
+
at runtime. To handle conditional workflows (such as checking for unsaved
|
|
249
|
+
changes versus navigating back immediately), you must register a single unified
|
|
250
|
+
handler and branch logic inside `onBackCompleted`.
|
|
251
|
+
|
|
252
|
+
#### RIGHT
|
|
253
|
+
|
|
254
|
+
**Why this is RIGHT** : Using a single `NavigationBackHandler` with internal
|
|
255
|
+
branching logic inside `onBackCompleted` maintains a strict 1:1 mapping between
|
|
256
|
+
`NavigationEventState` and the handler, preventing state collisions.
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
```kotlin
|
|
260
|
+
// RIGHT
|
|
261
|
+
val navigationState = rememberNavigationEventState(currentInfo = NavigationEventInfo.None)
|
|
262
|
+
NavigationBackHandler(
|
|
263
|
+
state = navigationState,
|
|
264
|
+
isBackEnabled = true,
|
|
265
|
+
onBackCompleted = {
|
|
266
|
+
if (hasUnsavedChanges) {
|
|
267
|
+
showDiscardDialog()
|
|
268
|
+
} else {
|
|
269
|
+
onNavigateUp()
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
<br />
|
|
276
|
+
|
|
277
|
+
#### WRONG
|
|
278
|
+
|
|
279
|
+
**Why this is WRONG** : Attaching multiple `NavigationBackHandler` composables to
|
|
280
|
+
the same `navigationState` instance attempts to bind duplicate handlers to a
|
|
281
|
+
single state object, which throws an `IllegalArgumentException` at runtime.
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
```kotlin
|
|
285
|
+
// WRONG
|
|
286
|
+
val navigationState = rememberNavigationEventState(currentInfo = NavigationEventInfo.None)
|
|
287
|
+
NavigationBackHandler(
|
|
288
|
+
state = navigationState,
|
|
289
|
+
isBackEnabled = hasUnsavedChanges,
|
|
290
|
+
onBackCompleted = { /* Discard changes */ }
|
|
291
|
+
)
|
|
292
|
+
NavigationBackHandler(
|
|
293
|
+
state = navigationState,
|
|
294
|
+
isBackEnabled = !hasUnsavedChanges,
|
|
295
|
+
onBackCompleted = { /* Navigate up */ }
|
|
296
|
+
)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
<br />
|
|
300
|
+
|
|
301
|
+
## Checklist
|
|
302
|
+
|
|
303
|
+
**For Compose Android targets:**
|
|
304
|
+
|
|
305
|
+
- \[ \] Is compile SDK set to `36` or higher? (If compile SDK is lower than 36, set it to `36` or higher in `build.gradle.kts`).
|
|
306
|
+
- \[ \] Is `android:enableOnBackInvokedCallback` NOT explicitly set to `"false"` in `AndroidManifest.xml`? (On API 36+, it defaults to `"true"`; on API 33--35, ensure it is set to `"true"`).
|
|
307
|
+
- \[ \] Does the Activity rely on the built-in `ComponentActivity` dispatcher owner without redundant anonymous delegate wrapping?
|
|
308
|
+
- \[ \] Do dialogs or sheets rely on automatic `ComponentDialog` dispatcher resolution without redundant `CompositionLocalProvider` wrapping?
|
|
309
|
+
- \[ \] Are parent-child dispatcher relationships in Compose scoped using `rememberNavigationEventDispatcherOwner()` when managing nested hierarchies?
|
|
310
|
+
- \[ \] Is conditional back logic handled within a single unified `NavigationBackHandler` to avoid duplicate registration (`IllegalArgumentException`)?
|
|
311
|
+
- \[ \] Are legacy `BackHandler` usages migrated to `NavigationBackHandler` with predictive progress support?
|
|
312
|
+
- \[ \] Does the project build and pass tests successfully?
|