1 /* <lambda>null2 * Copyright (C) 2023 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 */ 17 18 package com.android.customization.picker.grid.ui.fragment 19 20 import android.os.Bundle 21 import android.util.Log 22 import android.view.LayoutInflater 23 import android.view.View 24 import android.view.ViewGroup 25 import android.view.ViewGroup.MarginLayoutParams 26 import android.widget.Button 27 import android.widget.Toast 28 import androidx.core.content.ContextCompat 29 import androidx.core.view.ViewCompat 30 import androidx.core.view.WindowInsetsCompat 31 import androidx.core.view.isVisible 32 import androidx.core.view.updateLayoutParams 33 import androidx.lifecycle.ViewModelProvider 34 import androidx.transition.Transition 35 import androidx.transition.doOnStart 36 import com.android.customization.model.CustomizationManager.Callback 37 import com.android.customization.module.ThemePickerInjector 38 import com.android.customization.picker.grid.domain.interactor.GridInteractor 39 import com.android.customization.picker.grid.ui.binder.GridScreenBinder 40 import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel 41 import com.android.themepicker.R 42 import com.android.wallpaper.config.BaseFlags 43 import com.android.wallpaper.model.Screen 44 import com.android.wallpaper.module.CurrentWallpaperInfoFactory 45 import com.android.wallpaper.module.InjectorProvider 46 import com.android.wallpaper.picker.AppbarFragment 47 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor 48 import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder 49 import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel 50 import com.android.wallpaper.util.PreviewUtils 51 import kotlinx.coroutines.Dispatchers 52 import kotlinx.coroutines.ExperimentalCoroutinesApi 53 import kotlinx.coroutines.suspendCancellableCoroutine 54 55 private val TAG = GridFragment::class.java.simpleName 56 57 @OptIn(ExperimentalCoroutinesApi::class) 58 class GridFragment : AppbarFragment() { 59 60 private lateinit var gridInteractor: GridInteractor 61 62 override fun onCreateView( 63 inflater: LayoutInflater, 64 container: ViewGroup?, 65 savedInstanceState: Bundle? 66 ): View { 67 val view = 68 inflater.inflate( 69 R.layout.fragment_grid, 70 container, 71 false, 72 ) 73 ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets -> 74 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 75 v.updateLayoutParams<MarginLayoutParams> { 76 topMargin = insets.top 77 bottomMargin = insets.bottom 78 } 79 WindowInsetsCompat.CONSUMED 80 } 81 setUpToolbar(view) 82 83 val isGridApplyButtonEnabled = BaseFlags.get().isGridApplyButtonEnabled(requireContext()) 84 85 val injector = InjectorProvider.getInjector() as ThemePickerInjector 86 87 val wallpaperInfoFactory = injector.getCurrentWallpaperInfoFactory(requireContext()) 88 var screenPreviewBinding = 89 bindScreenPreview( 90 view, 91 wallpaperInfoFactory, 92 injector.getWallpaperInteractor(requireContext()), 93 injector.getGridInteractor(requireContext()) 94 ) 95 96 val viewModelFactory = injector.getGridScreenViewModelFactory(requireContext()) 97 gridInteractor = injector.getGridInteractor(requireContext()) 98 GridScreenBinder.bind( 99 view = view, 100 viewModel = 101 ViewModelProvider( 102 this, 103 viewModelFactory, 104 )[GridScreenViewModel::class.java], 105 lifecycleOwner = this, 106 backgroundDispatcher = Dispatchers.IO, 107 onOptionsChanged = { 108 screenPreviewBinding.destroy() 109 screenPreviewBinding = 110 bindScreenPreview( 111 view, 112 wallpaperInfoFactory, 113 injector.getWallpaperInteractor(requireContext()), 114 gridInteractor, 115 ) 116 if (isGridApplyButtonEnabled) { 117 val applyButton: Button = view.requireViewById(R.id.apply_button) 118 applyButton.isEnabled = !gridInteractor.isSelectedOptionApplied() 119 } 120 }, 121 isGridApplyButtonEnabled = isGridApplyButtonEnabled, 122 onOptionApplied = { 123 gridInteractor.applySelectedOption( 124 object : Callback { 125 override fun onSuccess() { 126 Toast.makeText( 127 context, 128 getString( 129 R.string.toast_of_changing_grid, 130 gridInteractor.getSelectOptionStateFlow().value?.title 131 ), 132 Toast.LENGTH_SHORT 133 ) 134 .show() 135 val applyButton: Button = view.requireViewById(R.id.apply_button) 136 applyButton.isEnabled = false 137 } 138 139 override fun onError(throwable: Throwable?) { 140 val errorMsg = 141 getString( 142 R.string.toast_of_failure_to_change_grid, 143 gridInteractor.getSelectOptionStateFlow().value?.title 144 ) 145 Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show() 146 Log.e(TAG, errorMsg, throwable) 147 } 148 } 149 ) 150 } 151 ) 152 153 (returnTransition as? Transition)?.doOnStart { 154 view.requireViewById<View>(R.id.preview).isVisible = false 155 } 156 157 return view 158 } 159 160 override fun getDefaultTitle(): CharSequence { 161 return getString(R.string.grid_title) 162 } 163 164 override fun getToolbarTextColor(): Int { 165 return ContextCompat.getColor( 166 requireContext(), 167 com.android.wallpaper.R.color.system_on_surface 168 ) 169 } 170 171 private fun bindScreenPreview( 172 view: View, 173 wallpaperInfoFactory: CurrentWallpaperInfoFactory, 174 wallpaperInteractor: WallpaperInteractor, 175 gridInteractor: GridInteractor 176 ): ScreenPreviewBinder.Binding { 177 return ScreenPreviewBinder.bind( 178 activity = requireActivity(), 179 previewView = view.requireViewById(R.id.preview), 180 viewModel = 181 ScreenPreviewViewModel( 182 previewUtils = 183 PreviewUtils( 184 context = requireContext(), 185 authorityMetadataKey = 186 requireContext() 187 .getString( 188 com.android.wallpaper.R.string.grid_control_metadata_name, 189 ), 190 ), 191 initialExtrasProvider = { 192 val bundle = Bundle() 193 bundle.putString( 194 "name", 195 gridInteractor.getSelectOptionStateFlow().value?.name 196 ) 197 bundle 198 }, 199 wallpaperInfoProvider = { 200 suspendCancellableCoroutine { continuation -> 201 wallpaperInfoFactory.createCurrentWallpaperInfos( 202 context, 203 /* forceRefresh= */ true, 204 ) { homeWallpaper, lockWallpaper, _ -> 205 continuation.resume(homeWallpaper ?: lockWallpaper, null) 206 } 207 } 208 }, 209 wallpaperInteractor = wallpaperInteractor, 210 screen = Screen.HOME_SCREEN, 211 ), 212 lifecycleOwner = viewLifecycleOwner, 213 offsetToStart = false, 214 onWallpaperPreviewDirty = { activity?.recreate() }, 215 ) 216 } 217 218 override fun onBackPressed(): Boolean { 219 if (BaseFlags.get().isGridApplyButtonEnabled(requireContext())) { 220 gridInteractor.clearSelectedOption() 221 } 222 return super.onBackPressed() 223 } 224 } 225