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