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) <noreply@anthropic.com>
This commit is contained in:
parent
1434f2f842
commit
3e0ad6c350
2 changed files with 20 additions and 31 deletions
|
|
@ -16,12 +16,6 @@ import no.naiv.implausibly.ui.dashboard.DashboardScreen
|
||||||
import no.naiv.implausibly.ui.setup.SetupScreen
|
import no.naiv.implausibly.ui.setup.SetupScreen
|
||||||
import no.naiv.implausibly.ui.sites.SiteListScreen
|
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
|
@Composable
|
||||||
fun AppNavHost(
|
fun AppNavHost(
|
||||||
appPreferences: AppPreferences,
|
appPreferences: AppPreferences,
|
||||||
|
|
@ -36,7 +30,6 @@ fun AppNavHost(
|
||||||
composable(Routes.LOADING) {
|
composable(Routes.LOADING) {
|
||||||
LoadingIndicator()
|
LoadingIndicator()
|
||||||
|
|
||||||
// Use flow.first() to suspend until DataStore actually loads
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val instanceId = appPreferences.selectedInstanceId.first()
|
val instanceId = appPreferences.selectedInstanceId.first()
|
||||||
val siteId = appPreferences.selectedSiteId.first()
|
val siteId = appPreferences.selectedSiteId.first()
|
||||||
|
|
@ -47,11 +40,11 @@ fun AppNavHost(
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
Routes.dashboard(instanceId, siteId)
|
Routes.dashboard(instanceId, siteId)
|
||||||
} else {
|
} else {
|
||||||
Routes.SETUP
|
Routes.setup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instanceId != null -> Routes.siteList(instanceId)
|
instanceId != null -> Routes.siteList(instanceId)
|
||||||
else -> Routes.SETUP
|
else -> Routes.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
navController.navigate(destination) {
|
navController.navigate(destination) {
|
||||||
|
|
@ -60,27 +53,26 @@ fun AppNavHost(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
composable(Routes.SETUP) {
|
// Single setup route with optional clone params
|
||||||
SetupScreen(
|
|
||||||
onInstanceAdded = { instanceId ->
|
|
||||||
navController.navigate(Routes.siteList(instanceId)) {
|
|
||||||
popUpTo(Routes.SETUP) { inclusive = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
composable(
|
composable(
|
||||||
route = Routes.SETUP_CLONE,
|
route = Routes.SETUP,
|
||||||
arguments = listOf(
|
arguments = listOf(
|
||||||
navArgument("cloneInstanceId") { type = NavType.StringType },
|
navArgument("cloneInstanceId") {
|
||||||
navArgument("cloneSiteId") { type = NavType.StringType }
|
type = NavType.StringType
|
||||||
|
nullable = true
|
||||||
|
defaultValue = null
|
||||||
|
},
|
||||||
|
navArgument("cloneSiteId") {
|
||||||
|
type = NavType.StringType
|
||||||
|
nullable = true
|
||||||
|
defaultValue = null
|
||||||
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
SetupScreen(
|
SetupScreen(
|
||||||
onInstanceAdded = { instanceId ->
|
onInstanceAdded = { instanceId ->
|
||||||
navController.navigate(Routes.siteList(instanceId)) {
|
navController.navigate(Routes.siteList(instanceId)) {
|
||||||
popUpTo(0) { inclusive = true }
|
popUpTo(Routes.SETUP) { inclusive = true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -113,7 +105,7 @@ fun AppNavHost(
|
||||||
DashboardScreen(
|
DashboardScreen(
|
||||||
onBack = { navController.popBackStack() },
|
onBack = { navController.popBackStack() },
|
||||||
onNavigateToSetup = {
|
onNavigateToSetup = {
|
||||||
navController.navigate(Routes.SETUP) {
|
navController.navigate(Routes.setup()) {
|
||||||
popUpTo(0) { inclusive = true }
|
popUpTo(0) { inclusive = true }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
package no.naiv.implausibly.ui.navigation
|
package no.naiv.implausibly.ui.navigation
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigation route constants.
|
|
||||||
* Arguments are passed as path parameters (strings only — no complex objects).
|
|
||||||
*/
|
|
||||||
object Routes {
|
object Routes {
|
||||||
const val LOADING = "loading"
|
const val LOADING = "loading"
|
||||||
const val SETUP = "setup"
|
const val SETUP = "setup?cloneInstanceId={cloneInstanceId}&cloneSiteId={cloneSiteId}"
|
||||||
const val SETUP_CLONE = "setup?cloneInstanceId={cloneInstanceId}&cloneSiteId={cloneSiteId}"
|
|
||||||
const val SITE_LIST = "site_list/{instanceId}"
|
const val SITE_LIST = "site_list/{instanceId}"
|
||||||
const val DASHBOARD = "dashboard/{instanceId}/{siteId}"
|
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 siteList(instanceId: String) = "site_list/$instanceId"
|
||||||
fun dashboard(instanceId: String, siteId: String) = "dashboard/$instanceId/$siteId"
|
fun dashboard(instanceId: String, siteId: String) = "dashboard/$instanceId/$siteId"
|
||||||
fun setupClone(instanceId: String, siteId: String) = "setup?cloneInstanceId=$instanceId&cloneSiteId=$siteId"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue