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