From 3e0ad6c350bcfa0b4209bff702587c3140a9e191 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Wed, 18 Mar 2026 17:23:56 +0100 Subject: [PATCH] fix: clone navigation uses single setup route with optional params Previous approach had two separate composable entries for setup and setup-with-clone-params, which Jetpack Navigation couldn't distinguish. Now uses one route with nullable query param arguments and defaultValue null, so navigating to "setup" opens fresh and "setup?cloneInstanceId= ...&cloneSiteId=..." opens pre-filled. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../implausibly/ui/navigation/AppNavHost.kt | 40 ++++++++----------- .../naiv/implausibly/ui/navigation/Routes.kt | 11 ++--- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/no/naiv/implausibly/ui/navigation/AppNavHost.kt b/app/src/main/java/no/naiv/implausibly/ui/navigation/AppNavHost.kt index e02838f..c609e35 100644 --- a/app/src/main/java/no/naiv/implausibly/ui/navigation/AppNavHost.kt +++ b/app/src/main/java/no/naiv/implausibly/ui/navigation/AppNavHost.kt @@ -16,12 +16,6 @@ import no.naiv.implausibly.ui.dashboard.DashboardScreen import no.naiv.implausibly.ui.setup.SetupScreen import no.naiv.implausibly.ui.sites.SiteListScreen -/** - * App-level navigation host. - * - * On launch, checks DataStore for a previously selected instance/site. - * If found, navigates directly to the dashboard. Otherwise, shows setup. - */ @Composable fun AppNavHost( appPreferences: AppPreferences, @@ -36,7 +30,6 @@ fun AppNavHost( composable(Routes.LOADING) { LoadingIndicator() - // Use flow.first() to suspend until DataStore actually loads LaunchedEffect(Unit) { val instanceId = appPreferences.selectedInstanceId.first() val siteId = appPreferences.selectedSiteId.first() @@ -47,11 +40,11 @@ fun AppNavHost( if (instance != null) { Routes.dashboard(instanceId, siteId) } else { - Routes.SETUP + Routes.setup() } } instanceId != null -> Routes.siteList(instanceId) - else -> Routes.SETUP + else -> Routes.setup() } navController.navigate(destination) { @@ -60,27 +53,26 @@ fun AppNavHost( } } - composable(Routes.SETUP) { - SetupScreen( - onInstanceAdded = { instanceId -> - navController.navigate(Routes.siteList(instanceId)) { - popUpTo(Routes.SETUP) { inclusive = true } - } - } - ) - } - + // Single setup route with optional clone params composable( - route = Routes.SETUP_CLONE, + route = Routes.SETUP, arguments = listOf( - navArgument("cloneInstanceId") { type = NavType.StringType }, - navArgument("cloneSiteId") { type = NavType.StringType } + navArgument("cloneInstanceId") { + type = NavType.StringType + nullable = true + defaultValue = null + }, + navArgument("cloneSiteId") { + type = NavType.StringType + nullable = true + defaultValue = null + } ) ) { SetupScreen( onInstanceAdded = { instanceId -> navController.navigate(Routes.siteList(instanceId)) { - popUpTo(0) { inclusive = true } + popUpTo(Routes.SETUP) { inclusive = true } } } ) @@ -113,7 +105,7 @@ fun AppNavHost( DashboardScreen( onBack = { navController.popBackStack() }, onNavigateToSetup = { - navController.navigate(Routes.SETUP) { + navController.navigate(Routes.setup()) { popUpTo(0) { inclusive = true } } }, diff --git a/app/src/main/java/no/naiv/implausibly/ui/navigation/Routes.kt b/app/src/main/java/no/naiv/implausibly/ui/navigation/Routes.kt index f50522f..87611fb 100644 --- a/app/src/main/java/no/naiv/implausibly/ui/navigation/Routes.kt +++ b/app/src/main/java/no/naiv/implausibly/ui/navigation/Routes.kt @@ -1,18 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-only package no.naiv.implausibly.ui.navigation -/** - * Navigation route constants. - * Arguments are passed as path parameters (strings only — no complex objects). - */ object Routes { const val LOADING = "loading" - const val SETUP = "setup" - const val SETUP_CLONE = "setup?cloneInstanceId={cloneInstanceId}&cloneSiteId={cloneSiteId}" + const val SETUP = "setup?cloneInstanceId={cloneInstanceId}&cloneSiteId={cloneSiteId}" const val SITE_LIST = "site_list/{instanceId}" const val DASHBOARD = "dashboard/{instanceId}/{siteId}" + fun setup() = "setup" + fun setupClone(instanceId: String, siteId: String) = + "setup?cloneInstanceId=$instanceId&cloneSiteId=$siteId" fun siteList(instanceId: String) = "site_list/$instanceId" fun dashboard(instanceId: String, siteId: String) = "dashboard/$instanceId/$siteId" - fun setupClone(instanceId: String, siteId: String) = "setup?cloneInstanceId=$instanceId&cloneSiteId=$siteId" }