Is my solution correct? What solutions do you recommend?
I use compose type safe navigation. I've created helper viewModel for navHost to store isValidated flag and for passing complex models from list to items ex. inside annoucementDetails (no deeplink variant) details = viewModel.getDataAndConsume(DETAILS_KEY):
Every things works fine but I'm looking for a simpler solution.
@HiltViewModel
class NavHostViewModel @Inject constructor(
val sessionManager: SessionManager
) : ViewModel() {
private val dataStore = mutableMapOf<String, Any>()
fun <T : Any> setData(key: String, value: T) {
dataStore[key] = value
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> getData(key: String): T? {
return dataStore[key] as? T
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> getDataAndConsume(key: String): T? {
val result = dataStore[key] as? T
removeData(key)
return result
}
fun removeData(key: String) {
dataStore.remove(key)
}
}
my NavHost:
composable<Route.AnnouncementDetails>(
deepLinks = listOf(
navDeepLink {
uriPattern = "myApp://announcements?id={id}"
}
)
) { backStackEntry ->
val args = backStackEntry.toRoute<Route.AnnouncementDetails>()
if (args.id != null) { // deeplink entry
var isDeepLinkValidated by remember { mutableStateOf<Boolean?>(null) }
LaunchedEffect(Unit) {
val validated = viewModel.getData<Boolean>(IS_VALIDATED)
if (validated == true) {
viewModel.removeData(IS_VALIDATED) // consume flag
isDeepLinkValidated = true
} else {
// mark that we're redirecting to validation
viewModel.setData(IS_VALIDATED, false)
navController.navigate(Route.ValidatePin)
}
}
if (isDeepLinkValidated == true) {
AnnouncementDetailsScreen(
id = args.id,
onBack = {
navController.navigateUp()
}
)
}
} else { // announcements list entry
var details by remember { mutableStateOf<AnnouncementDetails?>(null) }
LaunchedEffect(Unit) {
details = viewModel.getDataAndConsume(DETAILS_KEY)
}
AnnouncementDetailsScreen(
announcementDetails = details,
onBack = {
navController.navigateUp()
},
)
}
}
composable<Route.ValidatePin> {
PinBiometricValidationScreen(goNext = {
val isDeeplinkRedirect = viewModel.getData<Boolean>(IS_VALIDATED) == false
if (isDeeplinkRedirect) {
// Mark validation done and go back to previous destination
viewModel.setData(IS_VALIDATED, true)
val previousEntry = navController.previousBackStackEntry
val originalDestination = previousEntry?.toRoute<Route.AnnouncementDetails>() //
if (originalDestination?.id != null) {
navController.navigate(Route.Home) {
// This clears any previous history,
popUpTo(navController.graph.id) {
inclusive = true
}
}
navController.navigate(originalDestination)
} else {
navActions.navigateReplacingCurrent(route = Route.Home)
}
} else {
// Normal flow
navActions.navigateReplacingCurrent(route = Route.Home)
}
}, onForgotPin = {
navController.navigate(route = Route.ResetApp)
})
}