Search code examples
androidkotlinandroid-jetpack-compose

Navigate from compose to fragment when compose is hosted by fragment


I am moving my app to jetpack compose from view. The default navigation is using the nav_graph. The app has been built following the principle of one activity, multiple fragments. In order to move the app slowly, I am trying to just load the compose in the fragment. so the fragment can be seen as a nest for compose. I am doing it for to keep the navigation in place prior to moving the navigation. I am trying to make compose to navigate to the fragment using the nav_graph.

Currently, my fragment looks like this:

SignInFragment:

class SignInFragment : BaseFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val composeView = ComposeView(requireContext())
        composeView.apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                activity?.let {
                    SignInScreen()
                }
            }
        }
        return composeView
    }
}

and I am trying to navigate to the HomeFragment. Currently, I was using the navigation as below:

findNavController().navigate(SignInFragmentDirections.actionSignInFragmentToHomeFragment())

Now my composable is as below:

@Composable
fun SignInScreen(authViewModel: AuthViewModel = viewModel())
{

    val authState by authViewModel.authState.collectAsState()

    val lifecycleEventObserver = remember {
        LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_RESUME) {
                authViewModel.checkAuthorized()
            }
        }
    }
    ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleEventObserver)

    if(authState is AuthUIState.LoginSuccess) {
        navigateToDashboard()
    }

    Button(
        onClick = { authViewModel.signIn() },
    ) {
        Text("SignIn")
    }

}

fun navigateToDashboard() {
// Try to navigate to home fragment
}

Basically when I am loading SignInScreen, I am checking the state of the authorization. If authorized, I am redirecting to the HomePage otherwise, I display the button for the user to signIn.

I cannot figure out a way to do the navigateToDashboard()

I am really trying to keep the fragment just for the nav_graph, so I can do the transition when all screens are in Compose.

any idea?


Solution

  • Let your fragments do the navigation as before.
    Pass a callback function as parameter from fragment to compose.
    So base on your code, change SignInFragment like this:

    class SignInFragment : BaseFragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            val composeView = ComposeView(requireContext())
            composeView.apply {
                setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
                setContent {
                    activity?.let {
                        SignInScreen(
                            navigateToDashboard = ::navigateToDashboard
                        )
                    }
                }
            }
            return composeView
        }
        
        fun navigateToDashboard(){
            findNavController().navigate(SignInFragmentDirections.actionSignInFragmentToDashboardFragment())
        }
    }
    

    And SignInScreen:

    @Composable
    fun SignInScreen(
            authViewModel: AuthViewModel = viewModel(),
            navigateToDashboard:()->Unit,
    ){
    
        val authState by authViewModel.authState.collectAsState()
    
        val lifecycleEventObserver = remember {
            LifecycleEventObserver { _, event ->
                if (event == Lifecycle.Event.ON_RESUME) {
                    authViewModel.checkAuthorized()
                }
            }
        }
        ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleEventObserver)
    
        if(authState is AuthUIState.LoginSuccess) {
            navigateToDashboard()
        }
    
        Button(
            onClick = { authViewModel.signIn() },
        ) {
            Text("SignIn")
        }
    
    }
    

    Hope it helps.