fix: smart navigation waits for DataStore before routing
Use flow.first() instead of collectAsState(initial = null) to determine start destination. The previous approach fired immediately with the initial null value before DataStore loaded from disk, always routing to Setup. Now the loading screen suspends until preferences are actually read. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
54a5b38fc6
commit
ebdf72e2c1
2 changed files with 8 additions and 29 deletions
|
|
@ -8,7 +8,6 @@ import androidx.activity.enableEdgeToEdge
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import no.naiv.implausibly.data.AppPreferences
|
import no.naiv.implausibly.data.AppPreferences
|
||||||
import no.naiv.implausibly.data.repository.InstanceRepository
|
import no.naiv.implausibly.data.repository.InstanceRepository
|
||||||
import no.naiv.implausibly.data.repository.SiteRepository
|
|
||||||
import no.naiv.implausibly.ui.navigation.AppNavHost
|
import no.naiv.implausibly.ui.navigation.AppNavHost
|
||||||
import no.naiv.implausibly.ui.theme.ImplausiblyTheme
|
import no.naiv.implausibly.ui.theme.ImplausiblyTheme
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -18,7 +17,6 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
@Inject lateinit var appPreferences: AppPreferences
|
@Inject lateinit var appPreferences: AppPreferences
|
||||||
@Inject lateinit var instanceRepository: InstanceRepository
|
@Inject lateinit var instanceRepository: InstanceRepository
|
||||||
@Inject lateinit var siteRepository: SiteRepository
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -27,8 +25,7 @@ class MainActivity : ComponentActivity() {
|
||||||
ImplausiblyTheme {
|
ImplausiblyTheme {
|
||||||
AppNavHost(
|
AppNavHost(
|
||||||
appPreferences = appPreferences,
|
appPreferences = appPreferences,
|
||||||
instanceRepository = instanceRepository,
|
instanceRepository = instanceRepository
|
||||||
siteRepository = siteRepository
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,14 @@ package no.naiv.implausibly.ui.navigation
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import no.naiv.implausibly.data.AppPreferences
|
import no.naiv.implausibly.data.AppPreferences
|
||||||
import no.naiv.implausibly.data.repository.InstanceRepository
|
import no.naiv.implausibly.data.repository.InstanceRepository
|
||||||
import no.naiv.implausibly.data.repository.SiteRepository
|
|
||||||
import no.naiv.implausibly.ui.common.LoadingIndicator
|
import no.naiv.implausibly.ui.common.LoadingIndicator
|
||||||
import no.naiv.implausibly.ui.dashboard.DashboardScreen
|
import no.naiv.implausibly.ui.dashboard.DashboardScreen
|
||||||
import no.naiv.implausibly.ui.setup.SetupScreen
|
import no.naiv.implausibly.ui.setup.SetupScreen
|
||||||
|
|
@ -25,42 +20,29 @@ import no.naiv.implausibly.ui.sites.SiteListScreen
|
||||||
* App-level navigation host.
|
* App-level navigation host.
|
||||||
*
|
*
|
||||||
* On launch, checks DataStore for a previously selected instance/site.
|
* On launch, checks DataStore for a previously selected instance/site.
|
||||||
* If found, navigates directly to the dashboard (or site list if no site
|
* If found, navigates directly to the dashboard. Otherwise, shows setup.
|
||||||
* is selected). Otherwise, shows the setup screen.
|
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavHost(
|
fun AppNavHost(
|
||||||
appPreferences: AppPreferences,
|
appPreferences: AppPreferences,
|
||||||
instanceRepository: InstanceRepository,
|
instanceRepository: InstanceRepository
|
||||||
siteRepository: SiteRepository
|
|
||||||
) {
|
) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
// Collect saved preferences to determine start destination
|
|
||||||
val savedInstanceId by appPreferences.selectedInstanceId.collectAsState(initial = null)
|
|
||||||
val savedSiteId by appPreferences.selectedSiteId.collectAsState(initial = null)
|
|
||||||
var hasNavigated by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = Routes.LOADING
|
startDestination = Routes.LOADING
|
||||||
) {
|
) {
|
||||||
// Loading screen — resolves start destination from preferences
|
|
||||||
composable(Routes.LOADING) {
|
composable(Routes.LOADING) {
|
||||||
LoadingIndicator()
|
LoadingIndicator()
|
||||||
|
|
||||||
LaunchedEffect(savedInstanceId, savedSiteId) {
|
// Use flow.first() to suspend until DataStore actually loads
|
||||||
// Wait for preferences to load (initial null vs actual null)
|
LaunchedEffect(Unit) {
|
||||||
// Once we have a value (even if null), navigate
|
val instanceId = appPreferences.selectedInstanceId.first()
|
||||||
if (hasNavigated) return@LaunchedEffect
|
val siteId = appPreferences.selectedSiteId.first()
|
||||||
hasNavigated = true
|
|
||||||
|
|
||||||
val instanceId = savedInstanceId
|
|
||||||
val siteId = savedSiteId
|
|
||||||
|
|
||||||
val destination = when {
|
val destination = when {
|
||||||
instanceId != null && siteId != null -> {
|
instanceId != null && siteId != null -> {
|
||||||
// Verify the instance still exists
|
|
||||||
val instance = instanceRepository.getById(instanceId)
|
val instance = instanceRepository.getById(instanceId)
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
Routes.dashboard(instanceId, siteId)
|
Routes.dashboard(instanceId, siteId)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue