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 package com.android.wallpaper.picker.preview.ui.binder
18 
19 import android.graphics.Point
20 import android.view.View
21 import android.widget.Button
22 import android.widget.FrameLayout
23 import androidx.core.view.isVisible
24 import androidx.lifecycle.Lifecycle
25 import androidx.lifecycle.LifecycleOwner
26 import androidx.lifecycle.lifecycleScope
27 import androidx.lifecycle.repeatOnLifecycle
28 import com.android.wallpaper.R
29 import com.android.wallpaper.model.Screen
30 import com.android.wallpaper.model.wallpaper.DeviceDisplayType
31 import com.android.wallpaper.picker.preview.ui.view.DualDisplayAspectRatioLayout
32 import com.android.wallpaper.picker.preview.ui.view.DualDisplayAspectRatioLayout.Companion.getViewId
33 import com.android.wallpaper.picker.preview.ui.viewmodel.WallpaperPreviewViewModel
34 import com.android.wallpaper.util.wallpaperconnection.WallpaperConnectionUtils
35 import kotlinx.coroutines.CompletableDeferred
36 import kotlinx.coroutines.CoroutineScope
37 import kotlinx.coroutines.launch
38 
39 /** Binds the dialog on small preview confirming and setting wallpaper with destination. */
40 object SetWallpaperDialogBinder {
41     private val PreviewScreenIds =
42         mapOf(
43             Screen.LOCK_SCREEN to R.id.lock_preview_selector,
44             Screen.HOME_SCREEN to R.id.home_preview_selector,
45         )
46 
47     fun bind(
48         dialogContent: View,
49         wallpaperPreviewViewModel: WallpaperPreviewViewModel,
50         isFoldable: Boolean,
51         handheldDisplaySize: Point,
52         lifecycleOwner: LifecycleOwner,
53         mainScope: CoroutineScope,
54         onFinishActivity: () -> Unit,
55         onDismissDialog: () -> Unit,
56         wallpaperConnectionUtils: WallpaperConnectionUtils,
57         isFirstBinding: Boolean,
58         navigate: ((View) -> Unit)?,
59     ) {
60         val previewLayout: View =
61             if (isFoldable) dialogContent.requireViewById(R.id.foldable_previews)
62             else dialogContent.requireViewById(R.id.handheld_previews)
63         if (isFoldable)
64             bindFoldablePreview(
65                 previewLayout,
66                 wallpaperPreviewViewModel,
67                 mainScope,
68                 lifecycleOwner,
69                 wallpaperConnectionUtils,
70                 isFirstBinding,
71                 navigate,
72             )
73         else
74             bindHandheldPreview(
75                 previewLayout,
76                 wallpaperPreviewViewModel,
77                 handheldDisplaySize,
78                 mainScope,
79                 lifecycleOwner,
80                 wallpaperConnectionUtils,
81                 isFirstBinding,
82                 navigate,
83             )
84 
85         val cancelButton = dialogContent.requireViewById<Button>(R.id.button_cancel)
86         cancelButton.setOnClickListener { onDismissDialog() }
87 
88         val confirmButton = dialogContent.requireViewById<Button>(R.id.button_set)
89         lifecycleOwner.lifecycleScope.launch {
90             lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
91                 launch {
92                     wallpaperPreviewViewModel.showSetWallpaperDialog.collect { show ->
93                         if (!show) {
94                             onDismissDialog()
95                         }
96                     }
97                 }
98 
99                 launch {
100                     wallpaperPreviewViewModel.setWallpaperDialogOnConfirmButtonClicked.collect {
101                         onClicked ->
102                         confirmButton.setOnClickListener {
103                             mainScope.launch {
104                                 onClicked()
105                                 onFinishActivity()
106                             }
107                         }
108                     }
109                 }
110 
111                 launch {
112                     wallpaperPreviewViewModel.setWallpaperDialogSelectedScreens.collect {
113                         selectedScreens ->
114                         confirmButton.isEnabled = selectedScreens.isNotEmpty()
115                         PreviewScreenIds.forEach { screenId ->
116                             bindPreviewSelector(
117                                 previewLayout.requireViewById(screenId.value),
118                                 screenId.key,
119                                 selectedScreens,
120                                 wallpaperPreviewViewModel,
121                             )
122                         }
123                     }
124                 }
125             }
126         }
127     }
128 
129     private fun bindFoldablePreview(
130         previewLayout: View,
131         wallpaperPreviewViewModel: WallpaperPreviewViewModel,
132         mainScope: CoroutineScope,
133         lifecycleOwner: LifecycleOwner,
134         wallpaperConnectionUtils: WallpaperConnectionUtils,
135         isFirstBinding: Boolean,
136         navigate: ((View) -> Unit)?,
137     ) {
138         previewLayout.isVisible = true
139         PreviewScreenIds.forEach { screenId ->
140             val dualDisplayAspectRatioLayout: DualDisplayAspectRatioLayout =
141                 previewLayout
142                     .requireViewById<FrameLayout>(screenId.value)
143                     .requireViewById(R.id.dual_preview)
144 
145             dualDisplayAspectRatioLayout.setDisplaySizes(
146                 mapOf(
147                     DeviceDisplayType.FOLDED to wallpaperPreviewViewModel.smallerDisplaySize,
148                     DeviceDisplayType.UNFOLDED to
149                         wallpaperPreviewViewModel.wallpaperDisplaySize.value,
150                 )
151             )
152             DeviceDisplayType.FOLDABLE_DISPLAY_TYPES.forEach { display ->
153                 val previewDisplaySize = dualDisplayAspectRatioLayout.getPreviewDisplaySize(display)
154                 val view: View = dualDisplayAspectRatioLayout.requireViewById(display.getViewId())
155                 previewDisplaySize?.let {
156                     SmallPreviewBinder.bind(
157                         applicationContext = previewLayout.context.applicationContext,
158                         view = view,
159                         viewModel = wallpaperPreviewViewModel,
160                         mainScope = mainScope,
161                         viewLifecycleOwner = lifecycleOwner,
162                         screen = screenId.key,
163                         displaySize = it,
164                         deviceDisplayType = display,
165                         currentNavDestId = R.id.setWallpaperDialog,
166                         wallpaperConnectionUtils = wallpaperConnectionUtils,
167                         isFirstBindingDeferred = CompletableDeferred(isFirstBinding),
168                         navigate = navigate,
169                     )
170                 }
171             }
172         }
173     }
174 
175     private fun bindHandheldPreview(
176         previewLayout: View,
177         wallpaperPreviewViewModel: WallpaperPreviewViewModel,
178         displaySize: Point,
179         mainScope: CoroutineScope,
180         lifecycleOwner: LifecycleOwner,
181         wallpaperConnectionUtils: WallpaperConnectionUtils,
182         isFirstBinding: Boolean,
183         navigate: ((View) -> Unit)?,
184     ) {
185         previewLayout.isVisible = true
186         PreviewScreenIds.forEach { screenId ->
187             val view: View =
188                 previewLayout
189                     .requireViewById<FrameLayout>(screenId.value)
190                     .requireViewById(R.id.preview)
191             SmallPreviewBinder.bind(
192                 applicationContext = previewLayout.context.applicationContext,
193                 view = view,
194                 viewModel = wallpaperPreviewViewModel,
195                 screen = screenId.key,
196                 displaySize = displaySize,
197                 deviceDisplayType = DeviceDisplayType.SINGLE,
198                 mainScope = mainScope,
199                 viewLifecycleOwner = lifecycleOwner,
200                 currentNavDestId = R.id.setWallpaperDialog,
201                 isFirstBindingDeferred = CompletableDeferred(isFirstBinding),
202                 wallpaperConnectionUtils = wallpaperConnectionUtils,
203                 navigate = navigate,
204             )
205         }
206     }
207 
208     private fun bindPreviewSelector(
209         selector: View,
210         screen: Screen,
211         selectedScreens: Set<Screen>,
212         dialogViewModel: WallpaperPreviewViewModel,
213     ) {
214         selector.isActivated = selectedScreens.contains(screen)
215         selector.isSelected = selector.isActivated
216         selector.setOnClickListener { dialogViewModel.onSetWallpaperDialogScreenSelected(screen) }
217     }
218 }
219