Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • Briar Desktop Briar Desktop
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 175
    • Issues 175
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 16
    • Merge requests 16
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • briar
  • Briar DesktopBriar Desktop
  • Issues
  • #99

Closed
Open
Created Oct 28, 2021 by Mikolai Gütschow@ialokimMaintainer

Avoid passing individual view models around

For now, all view models are injected by Dagger at the start of the application in the top composable and then passed to the individual composable functions that actually need it. This has several disadvantages:

  • the composables further up the tree have a lot of view models as parameters that are just passed down to other composables that actually need it. Also, adding a new view model adds a new function parameter to all composables up to the root resulting in a lot of unnecessary changes.
  • all view models are initialized when the application starts and also start to listen for events, even if the respective screen is not shown (yet)
  • there can always only be a single instance of a certain view model (unless we initialize two or more of them in the top composable). That would forbid us to support displaying several chats at the same time in separate windows (the Pidgin (?) way of doing things). That one might not be a big deal, though.

I would propose the following:

  • implement a ViewModelProvider similar to the one available in Android that could either hold all view models from the application start on (not resolving the third point) or instantiating them on demand
  • have a base ViewModel class/interface that provides the methods onInit() and onCleared() where such things as adding/removing the view model from the eventBus can be done
  • adopt the convention of only instantiating view models within composables called Screen (e.g. MainScreen for the view model handling the global state, PrivateMessageScreen for the contact list view model) and always provide a second composable with the same name that takes the view model as a parameter (allowing for easier testability). The view model should always be instantiated as down in the UI tree as possible and as up in the tree as necessary. Screens could be seen as analog to Fragment or Activity in the Android world.
  • implement a helper composable function called Screen that takes a view model class name and does the repetitive process of obtaining the view model from the provider, call onInit() and onCleared() when appropiate (the compose DisposableEffect will come to handy here). Additionally, Screen would take a composable function where the view model is available (similar to the ApplicationScope that exposes exitApplication and is available after runApplication).

As a rough sketch, the usage might then look like the following:

@Composable
fun PrivateMessageScreen() = Screen(ContactListViewModel::class) {
    PrivateMessageScreen(viewModel)
}
@Composable
fun PrivateMessageScreen(viewModel: ContactListViewModel) {
    // actual content using the viewModel
}
Assignee
Assign to
Time tracking