1 /*
<lambda>null2  * Copyright (C) 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 
17 package com.android.wallpaper.customization.ui.binder
18 
19 import android.content.Context
20 import android.content.res.Configuration.UI_MODE_NIGHT_MASK
21 import android.content.res.Configuration.UI_MODE_NIGHT_YES
22 import android.view.View
23 import android.widget.TextView
24 import androidx.lifecycle.Lifecycle
25 import androidx.lifecycle.LifecycleOwner
26 import androidx.lifecycle.lifecycleScope
27 import androidx.lifecycle.repeatOnLifecycle
28 import androidx.recyclerview.widget.LinearLayoutManager
29 import androidx.recyclerview.widget.RecyclerView
30 import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder2
31 import com.android.customization.picker.color.ui.view.ColorOptionIconView2
32 import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
33 import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
34 import com.android.customization.picker.mode.ui.binder.DarkModeBinder
35 import com.android.themepicker.R
36 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.COLORS
37 import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
38 import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
39 import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
40 import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
41 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
42 import java.lang.ref.WeakReference
43 import kotlinx.coroutines.launch
44 
45 object ColorsFloatingSheetBinder {
46 
47     fun bind(
48         view: View,
49         optionsViewModel: ThemePickerCustomizationOptionsViewModel,
50         colorUpdateViewModel: ColorUpdateViewModel,
51         lifecycleOwner: LifecycleOwner,
52     ) {
53         val viewModel = optionsViewModel.colorPickerViewModel2
54 
55         val subhead = view.requireViewById<TextView>(R.id.color_type_tab_subhead)
56 
57         val colorsAdapter =
58             createOptionItemAdapter(view.resources.configuration.uiMode, lifecycleOwner)
59         val colorsList =
60             view.requireViewById<RecyclerView>(R.id.colors_horizontal_list).also {
61                 it.initColorsList(view.context.applicationContext, colorsAdapter)
62             }
63 
64         val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
65         val tabAdapter =
66             FloatingToolbarTabAdapter(
67                     colorUpdateViewModel = WeakReference(colorUpdateViewModel),
68                     shouldAnimateColor = { optionsViewModel.selectedOption.value == COLORS },
69                 )
70                 .also { tabs.setAdapter(it) }
71 
72         DarkModeBinder.bind(
73             darkModeToggle = view.findViewById(R.id.dark_mode_toggle),
74             viewModel = optionsViewModel.darkModeViewModel,
75             lifecycleOwner = lifecycleOwner,
76         )
77 
78         lifecycleOwner.lifecycleScope.launch {
79             lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
80                 launch { viewModel.colorTypeTabs.collect { tabAdapter.submitList(it) } }
81 
82                 launch { viewModel.colorTypeTabSubheader.collect { subhead.text = it } }
83 
84                 launch {
85                     viewModel.colorOptions.collect { colorOptions ->
86                         colorsAdapter.setItems(colorOptions) {
87                             var indexToFocus = colorOptions.indexOfFirst { it.isSelected.value }
88                             indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
89                             (colorsList.layoutManager as LinearLayoutManager)
90                                 .scrollToPositionWithOffset(indexToFocus, 0)
91                         }
92                     }
93                 }
94 
95                 launch {
96                     viewModel.previewingColorOption.collect { colorModel ->
97                         if (colorModel != null) {
98                             colorUpdateViewModel.previewColors(
99                                 colorModel.colorOption.seedColor,
100                                 colorModel.colorOption.style,
101                             )
102                         } else colorUpdateViewModel.resetPreview()
103                     }
104                 }
105             }
106         }
107     }
108 
109     private fun createOptionItemAdapter(
110         uiMode: Int,
111         lifecycleOwner: LifecycleOwner,
112     ): OptionItemAdapter2<ColorOptionIconViewModel> =
113         OptionItemAdapter2(
114             layoutResourceId = R.layout.color_option2,
115             lifecycleOwner = lifecycleOwner,
116             bindPayload = { itemView: View, colorIcon: ColorOptionIconViewModel ->
117                 val colorOptionIconView =
118                     itemView.requireViewById<ColorOptionIconView2>(
119                         com.android.wallpaper.R.id.background
120                     )
121                 val night = uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
122                 ColorOptionIconBinder2.bind(colorOptionIconView, colorIcon, night)
123                 // Return null since it does not need the lifecycleOwner to launch any job for later
124                 // disposal when rebind.
125                 return@OptionItemAdapter2 null
126             },
127         )
128 
129     private fun RecyclerView.initColorsList(
130         context: Context,
131         adapter: OptionItemAdapter2<ColorOptionIconViewModel>,
132     ) {
133         apply {
134             this.adapter = adapter
135             layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
136             addItemDecoration(
137                 SingleRowListItemSpacing(
138                     context.resources.getDimensionPixelSize(
139                         R.dimen.floating_sheet_content_horizontal_padding
140                     ),
141                     0,
142                 )
143             )
144         }
145     }
146 }
147