olshevski / compose-navigation-reimagined

🌈 Type-safe navigation library for Jetpack Compose
https://olshevski.github.io/compose-navigation-reimagined/
MIT License
534 stars 18 forks source link

Share ViewModel between screen and dialog #26

Closed zunjae closed 11 months ago

zunjae commented 11 months ago

Hello

I have 1 viewmodel that is used a lot in a screen and a dialog. I am trying to figure out how to share this viewmodel between the two composables

Normally I could just

@Composable
internal fun NavHostScope<DoggoDestination>.DoggoDialog(
  onDismiss: () -> Unit
) {
  val a = koinViewModel<A>(
    viewModelStoreOwner = hostEntries.find {
      it.destination is DoggoDestination.ActiveScreen
    }!!
  )

but since the viewmodel uses a different navcontroller and sealed class for destinations I don't think this will work. Do you have any other idea?

olshevski commented 11 months ago

@zunjae I've added a new API for this to the upcoming version 1.5.0 (there is 1.5.0-beta01 available now).

The new API is a bit trickier, but allows to access ViewModels outside of NavHost.

First, you need to create and manually set NavHostState:

val navHostState = rememberNavHostState(navController.backstack)
NavHost(state = navHostState) { destination ->
    // ...
}

Then, you can get a NavHostEntry for any entry in the backstack:

val activeScreenHostEntry = navHostState.backstack.entries.find { it.destination is DoggoDestination.ActiveScreen }?.let {
    navHostState.getHostEntry(it.id)
} ?: error("There is no ActiveScreen in the backstack")

Then you may pass activeScreenHostEntry as the viewModelStoreOwner argument into the koinViewModel method in a dialog.

olshevski commented 11 months ago

@zunjae Or maybe I misinterpreted your question. Do you have a separate NavController just for dialogs?

zunjae commented 11 months ago

Hi. I do have a separate navcontroller for dialogs. I am simply following this https://olshevski.github.io/compose-navigation-reimagined/dialogs/

olshevski commented 11 months ago

@zunjae Ok, then I got it right, try the code I mentioned previously.

zunjae commented 11 months ago

Thank you. I managed to make it work. In the end I decided to make an extension function so I can simply do

      val parent = navHostState.getParent(MyScreen)
      val viewModel = koinViewModel<MyViewModel>(viewModelStoreOwner = parent)
olshevski commented 11 months ago

@zunjae Cool! I also gave it a second thought and decided to make small changes to this API. In the final release it will be similar to NavHostScope interface, so you can do something like this:

havHostState.hostEntries.find {
  it.destination is DoggoDestination.ActiveScreen
}!!