0

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)
    })
}

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.