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,200 @@
|
|
|
1
|
+
# Common UI Recipe
|
|
2
|
+
|
|
3
|
+
This recipe demonstrates how to implement a common navigation UI pattern with a bottom navigation bar and multiple back stacks, where each tab in the navigation bar has its own navigation history.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
This example has three top-level destinations: `Home`, `ChatList`, and `Camera`. The `ChatList` destination also has a sub-route, `ChatDetail`.
|
|
8
|
+
|
|
9
|
+
### `TopLevelBackStack`
|
|
10
|
+
|
|
11
|
+
The core of this recipe is the `TopLevelBackStack` class, which is responsible for managing the navigation state. It works as follows:
|
|
12
|
+
|
|
13
|
+
- It maintains a separate back stack for each top-level destination (tab).
|
|
14
|
+
- It keeps track of the currently selected top-level destination.
|
|
15
|
+
- It provides a single, flattened back stack that can be used by the `NavDisplay` composable. This flattened back stack is a combination of the individual back stacks of all the tabs.
|
|
16
|
+
|
|
17
|
+
### UI Structure
|
|
18
|
+
|
|
19
|
+
The UI is built using a `Scaffold` composable, with a `NavigationBar` as the `bottomBar`.
|
|
20
|
+
|
|
21
|
+
- The `NavigationBar` displays an item for each top-level destination. When an item is clicked, it calls `topLevelBackStack.addTopLevel` to switch to the corresponding tab, preserving the navigation history of each tab.
|
|
22
|
+
- The `NavDisplay` composable is placed in the content area of the `Scaffold`. It is responsible for displaying the current screen based on the flattened back stack provided by `TopLevelBackStack`.
|
|
23
|
+
|
|
24
|
+
This approach allows for a common navigation pattern where users can switch between different sections of the app, and each section maintains its own navigation history.
|
|
25
|
+
|
|
26
|
+
### State Preservation
|
|
27
|
+
|
|
28
|
+
It's important to note how the navigation state is managed in this recipe. When a user navigates away from a top-level destination (e.g., by pressing the back button until they return to a previous tab), the entire navigation history for that destination is cleared. The state is not saved. When the user returns to that tab later, they will start from its initial screen.
|
|
29
|
+
|
|
30
|
+
**Note** : In this example, the `Home` route can move above the `ChatList` and `Camera` routes, meaning navigating back from `Home` doesn't necessarily leave the app. The app will exit when the user goes back from a single remaining top level route in the back stack.
|
|
31
|
+
[ Explore View the full recipe on GitHub.](https://github.com/android/nav3-recipes/tree/main/app/src/main/java/com/example/nav3recipes/commonui)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
/*
|
|
35
|
+
* Copyright 2025 The Android Open Source Project
|
|
36
|
+
*
|
|
37
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
38
|
+
* you may not use this file except in compliance with the License.
|
|
39
|
+
* You may obtain a copy of the License at
|
|
40
|
+
*
|
|
41
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
42
|
+
*
|
|
43
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
44
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
45
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
46
|
+
* See the License for the specific language governing permissions and
|
|
47
|
+
* limitations under the License.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
package com.example.nav3recipes.commonui
|
|
51
|
+
|
|
52
|
+
import android.os.Bundle
|
|
53
|
+
import androidx.activity.ComponentActivity
|
|
54
|
+
import androidx.activity.compose.setContent
|
|
55
|
+
import androidx.compose.material.icons.Icons
|
|
56
|
+
import androidx.compose.material.icons.filled.Face
|
|
57
|
+
import androidx.compose.material.icons.filled.Home
|
|
58
|
+
import androidx.compose.material.icons.filled.PlayArrow
|
|
59
|
+
import androidx.compose.material3.Button
|
|
60
|
+
import androidx.compose.material3.Icon
|
|
61
|
+
import androidx.compose.material3.NavigationBar
|
|
62
|
+
import androidx.compose.material3.NavigationBarItem
|
|
63
|
+
import androidx.compose.material3.Scaffold
|
|
64
|
+
import androidx.compose.material3.Text
|
|
65
|
+
import androidx.compose.runtime.getValue
|
|
66
|
+
import androidx.compose.runtime.mutableStateListOf
|
|
67
|
+
import androidx.compose.runtime.mutableStateOf
|
|
68
|
+
import androidx.compose.runtime.remember
|
|
69
|
+
import androidx.compose.runtime.setValue
|
|
70
|
+
import androidx.compose.runtime.snapshots.SnapshotStateList
|
|
71
|
+
import androidx.compose.ui.graphics.vector.ImageVector
|
|
72
|
+
import androidx.lifecycle.compose.dropUnlessResumed
|
|
73
|
+
import androidx.navigation3.runtime.entryProvider
|
|
74
|
+
import androidx.navigation3.ui.NavDisplay
|
|
75
|
+
import com.example.nav3recipes.content.ContentBlue
|
|
76
|
+
import com.example.nav3recipes.content.ContentGreen
|
|
77
|
+
import com.example.nav3recipes.content.ContentPurple
|
|
78
|
+
import com.example.nav3recipes.content.ContentRed
|
|
79
|
+
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
|
|
80
|
+
|
|
81
|
+
private sealed interface TopLevelRoute {
|
|
82
|
+
val icon: ImageVector
|
|
83
|
+
}
|
|
84
|
+
private data object Home : TopLevelRoute { override val icon = Icons.Default.Home }
|
|
85
|
+
private data object ChatList : TopLevelRoute { override val icon = Icons.Default.Face }
|
|
86
|
+
private data object ChatDetail
|
|
87
|
+
private data object Camera : TopLevelRoute { override val icon = Icons.Default.PlayArrow }
|
|
88
|
+
|
|
89
|
+
private val TOP_LEVEL_ROUTES : List<TopLevelRoute> = listOf(Home, ChatList, Camera)
|
|
90
|
+
|
|
91
|
+
class CommonUiActivity : ComponentActivity() {
|
|
92
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
93
|
+
setEdgeToEdgeConfig()
|
|
94
|
+
super.onCreate(savedInstanceState)
|
|
95
|
+
setContent {
|
|
96
|
+
val topLevelBackStack = remember { TopLevelBackStack<Any>(Home) }
|
|
97
|
+
|
|
98
|
+
Scaffold(
|
|
99
|
+
bottomBar = {
|
|
100
|
+
NavigationBar {
|
|
101
|
+
TOP_LEVEL_ROUTES.forEach { topLevelRoute ->
|
|
102
|
+
|
|
103
|
+
val isSelected = topLevelRoute == topLevelBackStack.topLevelKey
|
|
104
|
+
NavigationBarItem(
|
|
105
|
+
selected = isSelected,
|
|
106
|
+
onClick = {
|
|
107
|
+
topLevelBackStack.addTopLevel(topLevelRoute)
|
|
108
|
+
},
|
|
109
|
+
icon = {
|
|
110
|
+
Icon(
|
|
111
|
+
imageVector = topLevelRoute.icon,
|
|
112
|
+
contentDescription = null
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
) { _ ->
|
|
120
|
+
NavDisplay(
|
|
121
|
+
backStack = topLevelBackStack.backStack,
|
|
122
|
+
onBack = { topLevelBackStack.removeLast() },
|
|
123
|
+
entryProvider = entryProvider {
|
|
124
|
+
entry<Home>{
|
|
125
|
+
ContentRed("Home screen")
|
|
126
|
+
}
|
|
127
|
+
entry<ChatList>{
|
|
128
|
+
ContentGreen("Chat list screen"){
|
|
129
|
+
Button(onClick = dropUnlessResumed {
|
|
130
|
+
topLevelBackStack.add(ChatDetail)
|
|
131
|
+
}) {
|
|
132
|
+
Text("Go to conversation")
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
entry<ChatDetail>{
|
|
137
|
+
ContentBlue("Chat detail screen")
|
|
138
|
+
}
|
|
139
|
+
entry<Camera>{
|
|
140
|
+
ContentPurple("Camera screen")
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class TopLevelBackStack<T: Any>(startKey: T) {
|
|
150
|
+
|
|
151
|
+
// Maintain a stack for each top level route
|
|
152
|
+
private var topLevelStacks : LinkedHashMap<T, SnapshotStateList<T>> = linkedMapOf(
|
|
153
|
+
startKey to mutableStateListOf(startKey)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
// Expose the current top level route for consumers
|
|
157
|
+
var topLevelKey by mutableStateOf(startKey)
|
|
158
|
+
private set
|
|
159
|
+
|
|
160
|
+
// Expose the back stack so it can be rendered by the NavDisplay
|
|
161
|
+
val backStack = mutableStateListOf(startKey)
|
|
162
|
+
|
|
163
|
+
private fun updateBackStack() =
|
|
164
|
+
backStack.apply {
|
|
165
|
+
clear()
|
|
166
|
+
addAll(topLevelStacks.flatMap { it.value })
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
fun addTopLevel(key: T){
|
|
170
|
+
|
|
171
|
+
// If the top level doesn't exist, add it
|
|
172
|
+
if (topLevelStacks[key] == null){
|
|
173
|
+
topLevelStacks.put(key, mutableStateListOf(key))
|
|
174
|
+
} else {
|
|
175
|
+
// Otherwise just move it to the end of the stacks
|
|
176
|
+
topLevelStacks.apply {
|
|
177
|
+
remove(key)?.let {
|
|
178
|
+
put(key, it)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
topLevelKey = key
|
|
183
|
+
updateBackStack()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fun add(key: T){
|
|
187
|
+
topLevelStacks[topLevelKey]?.add(key)
|
|
188
|
+
updateBackStack()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fun removeLast(){
|
|
192
|
+
val removedKey = topLevelStacks[topLevelKey]?.removeLastOrNull()
|
|
193
|
+
// If the removed key was a top level key, remove the associated top level stack
|
|
194
|
+
topLevelStacks.remove(removedKey)
|
|
195
|
+
topLevelKey = topLevelStacks.keys.last()
|
|
196
|
+
updateBackStack()
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
```
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Conditional Transitions Recipe
|
|
2
|
+
|
|
3
|
+
This recipe demonstrates how to create route-dependent screen transitions in Navigation 3 using `transitionSpec` and `popTransitionSpec`. The slide directions (right, left, bottom, top) are conditionally selected based on pairs of `initialState` and `targetState` navigation keys.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
- **Route Definitions** : Navigation destinations (`Step1`, `Step2`, `Step3`, `Step4`) are defined using a sealed class hierarchy implementing `NavKey` and marked with `@Serializable`.
|
|
8
|
+
- **Conditional Forward Transitions (`transitionSpec`)** : Matches pairs of `(initialKey to targetKey)` to determine the direction of the slide animation:
|
|
9
|
+
- `Step1` $\\rightarrow$ `Step2`: Swipes to the left
|
|
10
|
+
- `Step2` $\\rightarrow$ `Step3`: Swipes to the up
|
|
11
|
+
- `Step3` $\\rightarrow$ `Step4`: Swipes to the right
|
|
12
|
+
- `Step4` $\\rightarrow$ `Step1`: Slides to the bottom (restarts flow)
|
|
13
|
+
- **Conditional Pop Transitions (`popTransitionSpec`)**: Handles reverse slide directions when navigating back or when clearing the backstack.
|
|
14
|
+
- **Backstack Control** : Demonstrates clearing the navigation stack on the final step (`backStack.clear()` \& `backStack.add(Step1)`) while executing a seamless top-slide transition.
|
|
15
|
+
|
|
16
|
+
[ Explore View the full recipe on GitHub.](https://github.com/android/nav3-recipes/tree/main/app/src/main/java/com/example/nav3recipes/conditionaltransitions)
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
package com.example.nav3recipes.conditionaltransitions
|
|
20
|
+
|
|
21
|
+
import android.os.Bundle
|
|
22
|
+
import androidx.activity.ComponentActivity
|
|
23
|
+
import androidx.activity.compose.setContent
|
|
24
|
+
import androidx.compose.animation.ContentTransform
|
|
25
|
+
import androidx.compose.animation.slideInHorizontally
|
|
26
|
+
import androidx.compose.animation.slideInVertically
|
|
27
|
+
import androidx.compose.animation.slideOutHorizontally
|
|
28
|
+
import androidx.compose.animation.slideOutVertically
|
|
29
|
+
import androidx.compose.animation.togetherWith
|
|
30
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
31
|
+
import androidx.compose.foundation.layout.Column
|
|
32
|
+
import androidx.compose.foundation.layout.Row
|
|
33
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
34
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
35
|
+
import androidx.compose.foundation.layout.padding
|
|
36
|
+
import androidx.compose.material3.ElevatedButton
|
|
37
|
+
import androidx.compose.material3.Scaffold
|
|
38
|
+
import androidx.compose.material3.Text
|
|
39
|
+
import androidx.compose.runtime.Composable
|
|
40
|
+
import androidx.compose.ui.Alignment
|
|
41
|
+
import androidx.compose.ui.Modifier
|
|
42
|
+
import androidx.navigation3.runtime.NavKey
|
|
43
|
+
import androidx.navigation3.runtime.entryProvider
|
|
44
|
+
import androidx.navigation3.runtime.rememberNavBackStack
|
|
45
|
+
import androidx.navigation3.ui.NavDisplay
|
|
46
|
+
import com.example.nav3recipes.content.ContentGreen
|
|
47
|
+
import com.example.nav3recipes.content.ContentOrange
|
|
48
|
+
import com.example.nav3recipes.content.ContentPurple
|
|
49
|
+
import com.example.nav3recipes.content.ContentRed
|
|
50
|
+
import com.example.nav3recipes.sharedviewmodel.toContentKey
|
|
51
|
+
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
|
|
52
|
+
import dagger.hilt.android.AndroidEntryPoint
|
|
53
|
+
import kotlinx.serialization.Serializable
|
|
54
|
+
|
|
55
|
+
@Serializable
|
|
56
|
+
sealed class Step(val firstButtonTitle: String, val secondButtonTitle: String) : NavKey
|
|
57
|
+
|
|
58
|
+
@Serializable
|
|
59
|
+
data object Step1 : Step("Home", "Swipe left")
|
|
60
|
+
|
|
61
|
+
@Serializable
|
|
62
|
+
data object Step2 : Step("Swipe right", "Swipe up")
|
|
63
|
+
|
|
64
|
+
@Serializable
|
|
65
|
+
data object Step3 : Step("Swipe down", "Swipe right")
|
|
66
|
+
|
|
67
|
+
@Serializable
|
|
68
|
+
data object Step4 : Step("Swipe left", "Swipe down")
|
|
69
|
+
|
|
70
|
+
@AndroidEntryPoint
|
|
71
|
+
class ConditionalTransitionsActivity : ComponentActivity() {
|
|
72
|
+
|
|
73
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
74
|
+
super.onCreate(savedInstanceState)
|
|
75
|
+
setEdgeToEdgeConfig()
|
|
76
|
+
|
|
77
|
+
setContent {
|
|
78
|
+
Scaffold { paddingValues ->
|
|
79
|
+
val backStack = rememberNavBackStack(Step1)
|
|
80
|
+
|
|
81
|
+
NavDisplay(
|
|
82
|
+
backStack = backStack,
|
|
83
|
+
modifier = Modifier.padding(paddingValues),
|
|
84
|
+
onBack = backStack::removeLastOrNull,
|
|
85
|
+
entryProvider = entryProvider {
|
|
86
|
+
entry<Step1> {
|
|
87
|
+
ContentGreen(title = "Screen 1") {
|
|
88
|
+
StepContent(
|
|
89
|
+
step = it,
|
|
90
|
+
onNext = { backStack += Step2 },
|
|
91
|
+
onBack = ::finish, // closing the activity
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
entry<Step2> {
|
|
97
|
+
ContentRed(title = "Screen 2") {
|
|
98
|
+
StepContent(
|
|
99
|
+
step = it,
|
|
100
|
+
onNext = { backStack += Step3 },
|
|
101
|
+
onBack = backStack::removeLastOrNull,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
entry<Step3> {
|
|
106
|
+
ContentOrange(title = "Screen 3") {
|
|
107
|
+
StepContent(
|
|
108
|
+
step = it,
|
|
109
|
+
onNext = { backStack += Step4 },
|
|
110
|
+
onBack = backStack::removeLastOrNull,
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
entry<Step4> {
|
|
115
|
+
ContentPurple(title = "Screen 4") {
|
|
116
|
+
StepContent(
|
|
117
|
+
step = it,
|
|
118
|
+
onNext = {
|
|
119
|
+
backStack.clear()
|
|
120
|
+
backStack.add(Step1)
|
|
121
|
+
},
|
|
122
|
+
onBack = backStack::removeLastOrNull,
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
transitionSpec = {
|
|
128
|
+
val initialKey = initialState.entries.lastOrNull()?.contentKey
|
|
129
|
+
val targetKey = targetState.entries.lastOrNull()?.contentKey
|
|
130
|
+
|
|
131
|
+
when (initialKey to targetKey) {
|
|
132
|
+
Step1.toContentKey() to Step2.toContentKey() -> swipeLeft()
|
|
133
|
+
Step2.toContentKey() to Step3.toContentKey() -> swipeUp()
|
|
134
|
+
Step3.toContentKey() to Step4.toContentKey() -> swipeRight()
|
|
135
|
+
Step4.toContentKey() to Step1.toContentKey() -> swipeDown()
|
|
136
|
+
else -> swipeRight()
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
popTransitionSpec = {
|
|
140
|
+
val initialKey = initialState.entries.lastOrNull()?.contentKey
|
|
141
|
+
val targetKey = targetState.entries.lastOrNull()?.contentKey
|
|
142
|
+
|
|
143
|
+
when (initialKey to targetKey) {
|
|
144
|
+
Step4.toContentKey() to Step1.toContentKey() -> swipeDown() // via backstack clearing
|
|
145
|
+
Step2.toContentKey() to Step1.toContentKey() -> swipeRight()
|
|
146
|
+
Step3.toContentKey() to Step2.toContentKey() -> swipeDown()
|
|
147
|
+
Step4.toContentKey() to Step3.toContentKey() -> swipeLeft()
|
|
148
|
+
else -> swipeLeft()
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@Composable
|
|
158
|
+
fun StepContent(step: Step, onNext: () -> Unit, onBack: () -> Unit) {
|
|
159
|
+
Column(
|
|
160
|
+
verticalArrangement = Arrangement.SpaceEvenly,
|
|
161
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
162
|
+
modifier = Modifier.fillMaxSize()
|
|
163
|
+
) {
|
|
164
|
+
Row(horizontalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.fillMaxWidth()) {
|
|
165
|
+
ElevatedButton(onBack) { Text(text = step.firstButtonTitle) }
|
|
166
|
+
ElevatedButton(onNext) { Text(text = step.secondButtonTitle) }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private fun swipeLeft(): ContentTransform =
|
|
172
|
+
slideInHorizontally(initialOffsetX = { it }) togetherWith slideOutHorizontally(targetOffsetX = { -it })
|
|
173
|
+
|
|
174
|
+
private fun swipeUp(): ContentTransform =
|
|
175
|
+
slideInVertically(initialOffsetY = { it }) togetherWith slideOutVertically(targetOffsetY = { -it })
|
|
176
|
+
|
|
177
|
+
private fun swipeRight(): ContentTransform =
|
|
178
|
+
slideInHorizontally(initialOffsetX = { -it }) togetherWith slideOutHorizontally(targetOffsetX = { it })
|
|
179
|
+
|
|
180
|
+
private fun swipeDown(): ContentTransform =
|
|
181
|
+
slideInVertically(initialOffsetY = { -it }) togetherWith slideOutVertically(targetOffsetY = { it })
|
|
182
|
+
```
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Conditional Navigation Recipe
|
|
2
|
+
|
|
3
|
+
This recipe demonstrates how to implement conditional navigation, where certain destinations are only accessible if a condition is met (in this case, if the user is logged in).
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
This example has a `Profile` destination that requires the user to be logged in. If the user is not logged in and attempts to navigate to `Profile`, they are redirected to a `Login` screen. After a successful login, they are automatically navigated to the `Profile` screen.
|
|
8
|
+
|
|
9
|
+
### `AppBackStack`
|
|
10
|
+
|
|
11
|
+
The core of this recipe is the custom `AppBackStack` class, which encapsulates the logic for conditional navigation.
|
|
12
|
+
|
|
13
|
+
- **`RequiresLogin` interface** : A marker interface, `RequiresLogin`, is used to identify destinations that require the user to be logged in. The `Profile` destination implements this interface.
|
|
14
|
+
|
|
15
|
+
- **Redirecting to Login** : When the `add` function is called with a destination that implements `RequiresLogin` and the user is not logged in, `AppBackStack` stores the intended destination and adds the `Login` route to the back stack instead.
|
|
16
|
+
|
|
17
|
+
- **Handling Login** : When the `login` function is called, it sets the user's status to logged in. If there is a stored destination that the user was trying to access, it adds that destination to the back stack and removes the `Login` screen.
|
|
18
|
+
|
|
19
|
+
- **Handling Logout** : When the `logout` function is called, it sets the user's status to logged out and removes any destinations from the back stack that require the user to be logged in.
|
|
20
|
+
|
|
21
|
+
This approach provides a clean way to handle conditional navigation by centralizing the logic in a custom back stack implementation.
|
|
22
|
+
[ Explore View the full recipe on GitHub.](https://github.com/android/nav3-recipes/tree/main/app/src/main/java/com/example/nav3recipes/conditional)
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
/*
|
|
26
|
+
* Copyright 2025 The Android Open Source Project
|
|
27
|
+
*
|
|
28
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
29
|
+
* you may not use this file except in compliance with the License.
|
|
30
|
+
* You may obtain a copy of the License at
|
|
31
|
+
*
|
|
32
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
33
|
+
*
|
|
34
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
35
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
36
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
37
|
+
* See the License for the specific language governing permissions and
|
|
38
|
+
* limitations under the License.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
package com.example.nav3recipes.conditional
|
|
42
|
+
|
|
43
|
+
import android.os.Bundle
|
|
44
|
+
import androidx.activity.ComponentActivity
|
|
45
|
+
import androidx.activity.compose.setContent
|
|
46
|
+
import androidx.compose.foundation.layout.Column
|
|
47
|
+
import androidx.compose.material3.Button
|
|
48
|
+
import androidx.compose.material3.Text
|
|
49
|
+
import androidx.compose.runtime.Composable
|
|
50
|
+
import androidx.compose.runtime.getValue
|
|
51
|
+
import androidx.compose.runtime.mutableStateOf
|
|
52
|
+
import androidx.compose.runtime.remember
|
|
53
|
+
import androidx.compose.runtime.saveable.rememberSaveable
|
|
54
|
+
import androidx.compose.runtime.saveable.rememberSerializable
|
|
55
|
+
import androidx.compose.runtime.setValue
|
|
56
|
+
import androidx.lifecycle.compose.dropUnlessResumed
|
|
57
|
+
import androidx.navigation3.runtime.NavBackStack
|
|
58
|
+
import androidx.navigation3.runtime.NavKey
|
|
59
|
+
import androidx.navigation3.runtime.entryProvider
|
|
60
|
+
import androidx.navigation3.runtime.serialization.NavBackStackSerializer
|
|
61
|
+
import androidx.navigation3.runtime.serialization.NavKeySerializer
|
|
62
|
+
import androidx.navigation3.ui.NavDisplay
|
|
63
|
+
import com.example.nav3recipes.content.ContentBlue
|
|
64
|
+
import com.example.nav3recipes.content.ContentGreen
|
|
65
|
+
import com.example.nav3recipes.content.ContentYellow
|
|
66
|
+
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
|
|
67
|
+
import kotlinx.serialization.Serializable
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Class for representing navigation keys in the app.
|
|
72
|
+
*
|
|
73
|
+
* Note: We use a sealed class because KotlinX Serialization handles
|
|
74
|
+
* polymorphic serialization of sealed classes automatically.
|
|
75
|
+
*
|
|
76
|
+
* @param requiresLogin - true if the navigation key requires that the user is logged in
|
|
77
|
+
* to navigate to it
|
|
78
|
+
*/
|
|
79
|
+
@Serializable
|
|
80
|
+
sealed class ConditionalNavKey(val requiresLogin: Boolean = false) : NavKey
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Key representing home screen
|
|
84
|
+
*/
|
|
85
|
+
@Serializable
|
|
86
|
+
private data object Home : ConditionalNavKey()
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Key representing profile screen that is only accessible once the user has logged in
|
|
90
|
+
*/
|
|
91
|
+
@Serializable
|
|
92
|
+
private data object Profile : ConditionalNavKey(requiresLogin = true)
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Key representing login screen
|
|
96
|
+
*
|
|
97
|
+
* @param redirectToKey - navigation key to redirect to after successful login
|
|
98
|
+
*/
|
|
99
|
+
@Serializable
|
|
100
|
+
private data class Login(
|
|
101
|
+
val redirectToKey: ConditionalNavKey? = null
|
|
102
|
+
) : ConditionalNavKey()
|
|
103
|
+
|
|
104
|
+
class ConditionalActivity : ComponentActivity() {
|
|
105
|
+
|
|
106
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
107
|
+
setEdgeToEdgeConfig()
|
|
108
|
+
super.onCreate(savedInstanceState)
|
|
109
|
+
setContent {
|
|
110
|
+
|
|
111
|
+
val backStack = rememberNavBackStack<ConditionalNavKey>(Home)
|
|
112
|
+
var isLoggedIn by rememberSaveable {
|
|
113
|
+
mutableStateOf(false)
|
|
114
|
+
}
|
|
115
|
+
val navigator = remember {
|
|
116
|
+
Navigator(
|
|
117
|
+
backStack = backStack,
|
|
118
|
+
onNavigateToRestrictedKey = { redirectToKey -> Login(redirectToKey) },
|
|
119
|
+
isLoggedIn = { isLoggedIn }
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
NavDisplay(
|
|
124
|
+
backStack = backStack,
|
|
125
|
+
onBack = { navigator.goBack() },
|
|
126
|
+
entryProvider = entryProvider {
|
|
127
|
+
entry<Home> {
|
|
128
|
+
ContentGreen("Welcome to Nav3. Logged in? ${isLoggedIn}") {
|
|
129
|
+
Column {
|
|
130
|
+
Button(onClick = dropUnlessResumed { navigator.navigate(Profile) }) {
|
|
131
|
+
Text("Profile")
|
|
132
|
+
}
|
|
133
|
+
Button(onClick = dropUnlessResumed { navigator.navigate(Login()) }) {
|
|
134
|
+
Text("Login")
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
entry<Profile> {
|
|
140
|
+
ContentBlue("Profile screen (only accessible once logged in)") {
|
|
141
|
+
Button(onClick = dropUnlessResumed {
|
|
142
|
+
isLoggedIn = false
|
|
143
|
+
navigator.navigate(Home)
|
|
144
|
+
}) {
|
|
145
|
+
Text("Logout")
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
entry<Login> { key ->
|
|
150
|
+
ContentYellow("Login screen. Logged in? $isLoggedIn") {
|
|
151
|
+
Button(onClick = dropUnlessResumed {
|
|
152
|
+
isLoggedIn = true
|
|
153
|
+
key.redirectToKey?.let { targetKey ->
|
|
154
|
+
backStack.remove(key)
|
|
155
|
+
navigator.navigate(targetKey)
|
|
156
|
+
}
|
|
157
|
+
}) {
|
|
158
|
+
Text("Login")
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// An overload of `rememberNavBackStack` that returns a subtype of `NavKey`.
|
|
170
|
+
// See https://issuetracker.google.com/issues/463382671 for a discussion of this function
|
|
171
|
+
@Composable
|
|
172
|
+
fun <T : NavKey> rememberNavBackStack(vararg elements: T): NavBackStack<T> {
|
|
173
|
+
return rememberSerializable(
|
|
174
|
+
serializer = NavBackStackSerializer(elementSerializer = NavKeySerializer())
|
|
175
|
+
) {
|
|
176
|
+
NavBackStack(*elements)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
/*
|
|
183
|
+
* Copyright 2025 The Android Open Source Project
|
|
184
|
+
*
|
|
185
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
186
|
+
* you may not use this file except in compliance with the License.
|
|
187
|
+
* You may obtain a copy of the License at
|
|
188
|
+
*
|
|
189
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
190
|
+
*
|
|
191
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
192
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
193
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
194
|
+
* See the License for the specific language governing permissions and
|
|
195
|
+
* limitations under the License.
|
|
196
|
+
*/
|
|
197
|
+
|
|
198
|
+
package com.example.nav3recipes.conditional
|
|
199
|
+
|
|
200
|
+
import androidx.navigation3.runtime.NavBackStack
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Provides navigation events with built-in support for conditional access. If the user attempts to
|
|
204
|
+
* navigate to a [ConditionalNavKey] that requires login ([ConditionalNavKey.requiresLogin] is true)
|
|
205
|
+
* but is not currently logged in, the Navigator will redirect the user to a login key.
|
|
206
|
+
*
|
|
207
|
+
* @property backStack The back stack that is modified by this class
|
|
208
|
+
* @property onNavigateToRestrictedKey A lambda that is called when the user attempts to navigate
|
|
209
|
+
* to a key that requires login. This should return the key that represents the login screen. The
|
|
210
|
+
* user's target key is supplied as a parameter so that after successful login the user can be
|
|
211
|
+
* redirected to their target destination.
|
|
212
|
+
* @property isLoggedIn A lambda that returns whether the user is logged in.
|
|
213
|
+
*/
|
|
214
|
+
class Navigator(
|
|
215
|
+
private val< backStack: NavBa>ckStackConditionalNavKey,
|
|
216
|
+
private val onNavigateToRestrictedKey: (targetKe>y: ConditionalNavKey?) - ConditionalNavKey,
|
|
217
|
+
priv>ate val isLoggedIn: () - Boolean,
|
|
218
|
+
) {
|
|
219
|
+
fun navigate(key: ConditionalNavKey) {
|
|
220
|
+
&& if (key.requiresLogin !isLoggedIn()) {
|
|
221
|
+
val loginKey = onNavigateToRestrictedKey(key)
|
|
222
|
+
backStack.add(loginKey)
|
|
223
|
+
} else {
|
|
224
|
+
backStack.add(key)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
fun goBack() = backStstOrNull()
|
|
229
|
+
}Navigator.kt
|
|
230
|
+
```
|