voyager icon indicating copy to clipboard operation
voyager copied to clipboard

Support of `defaultArgs` in the `Screen.getViewModel()` method

Open nvkleban opened this issue 1 year ago • 0 comments

Problem: I want my ViewModels to be able to receive through Hilt:

  1. SavedStateHandle
  2. Dependencies like Usecases, Repositories etc.
  3. Screen arguments

Solution: Default args for a savedStateHandle is one of the currently recommended ways to pass navigation arguments to the ViewModel.

I've looked into code and it seems like it would be pretty easy to add defaultArgs support into Voyager.

So it will look something like:

@Composable
public inline fun <reified T : ViewModel> Screen.getViewModel(
    viewModelProviderFactory: ViewModelProvider.Factory? = null,
    defaultArgs: Bundle? = null
): T {
   ...

   val defaultCreationExtras = if (defaultArgs != null) {
       val mutableCreationExtras = MutableCreationExtras(hasDefaultViewModelProviderFactory.defaultViewModelCreationExtras)
       val currentDefaultArgs = mutableCreationExtras[DEFAULT_ARGS_KEY]
       if (currentDefaultArgs != null) defaultArgs.putAll(currentDefaultArgs)
       mutableCreationExtras[DEFAULT_ARGS_KEY] = defaultArgs
       mutableCreationExtras
   } else {
       hasDefaultViewModelProviderFactory.defaultViewModelCreationExtras
   }
        
   val provider = ViewModelProvider(
       store = viewModelStore,
       factory = factory,
       defaultCreationExtras = defaultCreationExtras
   )

   ...
}
Screen(index: Int): AndroidScreen() {
    ...
    val viewModel: HiltDetailsViewModel = getViewModel(defaultArgs = bundleOf("index", index))
    ...
}
@HiltViewModel
class HiltDetailsViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: SomeRepository,
    private val index: Int = requireNotNull(savedStateHandle["index"])
) : ViewModel() {
   ...
}

I can make PR if this solution looks ok.

And by the way looks like Dagger team finally made a solution for a @AssistedInject issue, I found it in the Dagger documentation but some APIs not released yet.

nvkleban avatar Nov 09 '23 18:11 nvkleban