• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.photopicker.core.embedded
17 
18 import androidx.lifecycle.ViewModel
19 import androidx.lifecycle.ViewModelProvider
20 import com.android.photopicker.core.Background
21 import com.android.photopicker.core.banners.BannerManager
22 import com.android.photopicker.core.configuration.ConfigurationManager
23 import com.android.photopicker.core.events.Events
24 import com.android.photopicker.core.features.FeatureManager
25 import com.android.photopicker.core.selection.Selection
26 import com.android.photopicker.core.user.UserMonitor
27 import com.android.photopicker.data.DataService
28 import com.android.photopicker.data.model.Media
29 import com.android.photopicker.features.albumgrid.AlbumGridViewModel
30 import com.android.photopicker.features.categorygrid.CategoryGridViewModel
31 import com.android.photopicker.features.categorygrid.data.CategoryDataService
32 import com.android.photopicker.features.photogrid.PhotoGridViewModel
33 import com.android.photopicker.features.preparemedia.MediaPreparerViewModel
34 import com.android.photopicker.features.preview.PreviewViewModel
35 import com.android.photopicker.features.profileselector.ProfileSelectorViewModel
36 import com.android.photopicker.features.search.SearchViewModel
37 import com.android.photopicker.features.search.data.SearchDataService
38 import dagger.Lazy
39 import kotlinx.coroutines.CoroutineDispatcher
40 
41 /**
42  * A [ViewModelProvider.Factory] to construct view models for the Embedded Photopicker.
43  *
44  * The activity based Photopicker depends on an Activity implementation underneath of Hilt to create
45  * / inject view model classes. Since embedded runs as a standalone remote-rendered [ComposeView]
46  * this factory emulates the dependency injection of hilt for view models by calling the @Inject
47  * constructors manually, and providing the dependencies from the Hilt injection container.
48  *
49  * Any new View models that need to be able to be used during an Embedded session will need to
50  * provide a construction implementation in this factory, or code that attempts to obtain that view
51  * model at run time will cause a crash.
52  *
53  * Additionally, this factory must receive references to the injectable Photopicker dependencies
54  * from the [EmbeddedSessionModule] inside of the [EmbeddedServiceComponent]
55  *
56  * This has the side-effect of having to manually wire up some dependencies for view models in the
57  * embedded picker, but allows the Compose based UI to be unaware of how view models get resolved.
58  *
59  * @property backgroundDispatcher
60  * @property configurationManager
61  * @property dataService
62  * @property events
63  * @property featureManager
64  * @property selection
65  * @property userMonitor
66  */
67 @Suppress("UNCHECKED_CAST")
68 class EmbeddedViewModelFactory(
69     @Background val backgroundDispatcher: CoroutineDispatcher,
70     val configurationManager: Lazy<ConfigurationManager>,
71     val bannerManager: Lazy<BannerManager>,
72     val dataService: Lazy<DataService>,
73     val searchDataService: Lazy<SearchDataService>,
74     val categoryDataService: Lazy<CategoryDataService>,
75     val events: Lazy<Events>,
76     val featureManager: Lazy<FeatureManager>,
77     val selection: Lazy<Selection<Media>>,
78     val userMonitor: Lazy<UserMonitor>,
79 ) : ViewModelProvider.Factory {
createnull80     override fun <T : ViewModel> create(modelClass: Class<T>): T {
81         with(modelClass) {
82             return when {
83                 isAssignableFrom(AlbumGridViewModel::class.java) ->
84                     AlbumGridViewModel(null, selection.get(), dataService.get(), events.get()) as T
85                 isAssignableFrom(MediaPreparerViewModel::class.java) ->
86                     MediaPreparerViewModel(
87                         null,
88                         backgroundDispatcher,
89                         selection.get(),
90                         userMonitor.get(),
91                         configurationManager.get(),
92                         events.get(),
93                     )
94                         as T
95                 isAssignableFrom(PhotoGridViewModel::class.java) ->
96                     PhotoGridViewModel(
97                         null,
98                         selection.get(),
99                         dataService.get(),
100                         events.get(),
101                         bannerManager.get(),
102                     )
103                         as T
104                 isAssignableFrom(PreviewViewModel::class.java) ->
105                     PreviewViewModel(
106                         null,
107                         selection.get(),
108                         userMonitor.get(),
109                         dataService.get(),
110                         events.get(),
111                         configurationManager.get(),
112                     )
113                         as T
114                 isAssignableFrom(ProfileSelectorViewModel::class.java) ->
115                     ProfileSelectorViewModel(
116                         null,
117                         selection.get(),
118                         userMonitor.get(),
119                         events.get(),
120                         configurationManager.get(),
121                     )
122                         as T
123                 isAssignableFrom(SearchViewModel::class.java) ->
124                     SearchViewModel(
125                         null,
126                         backgroundDispatcher,
127                         searchDataService.get(),
128                         dataService.get(),
129                         selection.get(),
130                         events.get(),
131                         configurationManager.get(),
132                     )
133                         as T
134                 isAssignableFrom(CategoryGridViewModel::class.java) ->
135                     CategoryGridViewModel(
136                         null,
137                         selection.get(),
138                         categoryDataService.get(),
139                         dataService.get(),
140                         events.get(),
141                     )
142                         as T
143                 else ->
144                     throw IllegalArgumentException(
145                         "Unknown ViewModel class: ${modelClass.simpleName}"
146                     )
147             }
148         }
149     }
150 }
151