Loading src/com/android/customization/picker/mode/ui/binder/DarkModeBinder.kt +19 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.customization.picker.mode.ui.viewmodel.DarkModeViewModel import com.android.wallpaper.customization.ui.binder.SwitchColorBinder import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel import com.google.android.material.materialswitch.MaterialSwitch import kotlinx.coroutines.launch Loading @@ -28,12 +30,28 @@ object DarkModeBinder { fun bind( darkModeToggle: MaterialSwitch, viewModel: DarkModeViewModel, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { viewModel.isEnabled.collect { darkModeToggle.isEnabled = it } } launch { viewModel.previewingIsDarkMode.collect { darkModeToggle.isChecked = it } } launch { var binding: SwitchColorBinder.Binding? = null viewModel.previewingIsDarkMode.collect { darkModeToggle.isChecked = it binding?.destroy() binding = SwitchColorBinder.bind( switch = darkModeToggle, isChecked = it, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } } launch { viewModel.toggleDarkMode.collect { darkModeToggle.setOnCheckedChangeListener { _, _ -> it.invoke() } Loading src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt +27 −3 Original line number Diff line number Diff line Loading @@ -325,11 +325,25 @@ object ClockFloatingSheetBinder { } launch { var binding: SwitchColorBinder.Binding? = null viewModel.previewingClockSize.collect { size -> when (size) { ClockSize.DYNAMIC -> clockSizeSwitch.isChecked = true ClockSize.SMALL -> clockSizeSwitch.isChecked = false } binding?.destroy() binding = SwitchColorBinder.bind( switch = clockSizeSwitch, isChecked = when (size) { ClockSize.DYNAMIC -> true ClockSize.SMALL -> false }, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) } } Loading @@ -346,6 +360,8 @@ object ClockFloatingSheetBinder { bindClockFontContent( clockFontContent = clockFontContent, viewModel = viewModel, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) } Loading @@ -353,6 +369,8 @@ object ClockFloatingSheetBinder { private fun bindClockFontContent( clockFontContent: View, viewModel: ClockPickerViewModel, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ) { val sliderViewList = Loading Loading @@ -409,9 +427,15 @@ object ClockFloatingSheetBinder { viewHolder.setIsVisible(booleanAxis != null) booleanAxis?.let { switchViewMap[it.key] = viewHolder viewHolder.initView(booleanAxis) { value -> viewHolder.initView( clockFontAxis = booleanAxis, onFontAxisValueUpdated = { value -> viewModel.updatePreviewFontAxis(booleanAxis.key, value) } }, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } } } Loading src/com/android/wallpaper/customization/ui/binder/ColorsFloatingSheetBinder.kt +2 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,8 @@ object ColorsFloatingSheetBinder { DarkModeBinder.bind( darkModeToggle = view.findViewById(R.id.dark_mode_toggle), viewModel = optionsViewModel.darkModeViewModel, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) Loading src/com/android/wallpaper/customization/ui/binder/SwitchColorBinder.kt 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wallpaper.customization.ui.binder import android.content.res.ColorStateList import androidx.lifecycle.LifecycleOwner import com.android.wallpaper.picker.customization.ui.binder.ColorUpdateBinder import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel import com.google.android.material.materialswitch.MaterialSwitch object SwitchColorBinder { private const val COLOR_TRANSPARENT = 0 interface Binding { /** Destroys the binding in spite of lifecycle state. */ fun destroy() } /** * Binds the color of a [MaterialSwitch] using [ColorUpdateBinder] according to Material 3 * specs. */ fun bind( switch: MaterialSwitch, isChecked: Boolean, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ): Binding { val bindingThumb: ColorUpdateBinder.Binding val bindingTrack: ColorUpdateBinder.Binding if (isChecked) { switch.trackDecorationTintList = ColorStateList.valueOf(COLOR_TRANSPARENT) bindingThumb = ColorUpdateBinder.bind( setColor = { color -> switch.thumbTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorOnPrimary, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) bindingTrack = ColorUpdateBinder.bind( setColor = { color -> switch.trackTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorPrimary, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } else { bindingThumb = ColorUpdateBinder.bind( setColor = { color -> switch.thumbTintList = ColorStateList.valueOf(color) switch.trackDecorationTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorOutline, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) bindingTrack = ColorUpdateBinder.bind( setColor = { color -> switch.trackTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorSurfaceContainerHighest, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } return object : Binding { override fun destroy() { bindingThumb.destroy() bindingTrack.destroy() } } } } src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt +25 −17 Original line number Diff line number Diff line Loading @@ -198,10 +198,10 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO val optionThemedIcons = homeScreenCustomizationOptionEntries .find { it.first == ThemePickerHomeCustomizationOption.THEMED_ICONS } ?.second .first { it.first == ThemePickerHomeCustomizationOption.THEMED_ICONS } .second val optionThemedIconsSwitch = optionThemedIcons?.findViewById<MaterialSwitch>(R.id.option_entry_switch) optionThemedIcons.requireViewById<MaterialSwitch>(R.id.option_entry_switch) ColorUpdateBinder.bind( setColor = { color -> Loading Loading @@ -318,7 +318,6 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } } if (optionThemedIconsSwitch != null) { launch { optionsViewModel.themedIconViewModel.isAvailable.collect { isAvailable -> optionThemedIconsSwitch.isEnabled = isAvailable Loading @@ -326,8 +325,18 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } launch { var binding: SwitchColorBinder.Binding? = null optionsViewModel.themedIconViewModel.isActivated.collect { optionThemedIconsSwitch.isChecked = it binding?.destroy() binding = SwitchColorBinder.bind( switch = optionThemedIconsSwitch, isChecked = it, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isOnMainScreen, lifecycleOwner = lifecycleOwner, ) } } Loading @@ -340,7 +349,6 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } } } } customizationOptionFloatingSheetViewMap ?.get(ThemePickerLockCustomizationOption.CLOCK) Loading Loading
src/com/android/customization/picker/mode/ui/binder/DarkModeBinder.kt +19 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.customization.picker.mode.ui.viewmodel.DarkModeViewModel import com.android.wallpaper.customization.ui.binder.SwitchColorBinder import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel import com.google.android.material.materialswitch.MaterialSwitch import kotlinx.coroutines.launch Loading @@ -28,12 +30,28 @@ object DarkModeBinder { fun bind( darkModeToggle: MaterialSwitch, viewModel: DarkModeViewModel, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { viewModel.isEnabled.collect { darkModeToggle.isEnabled = it } } launch { viewModel.previewingIsDarkMode.collect { darkModeToggle.isChecked = it } } launch { var binding: SwitchColorBinder.Binding? = null viewModel.previewingIsDarkMode.collect { darkModeToggle.isChecked = it binding?.destroy() binding = SwitchColorBinder.bind( switch = darkModeToggle, isChecked = it, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } } launch { viewModel.toggleDarkMode.collect { darkModeToggle.setOnCheckedChangeListener { _, _ -> it.invoke() } Loading
src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt +27 −3 Original line number Diff line number Diff line Loading @@ -325,11 +325,25 @@ object ClockFloatingSheetBinder { } launch { var binding: SwitchColorBinder.Binding? = null viewModel.previewingClockSize.collect { size -> when (size) { ClockSize.DYNAMIC -> clockSizeSwitch.isChecked = true ClockSize.SMALL -> clockSizeSwitch.isChecked = false } binding?.destroy() binding = SwitchColorBinder.bind( switch = clockSizeSwitch, isChecked = when (size) { ClockSize.DYNAMIC -> true ClockSize.SMALL -> false }, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) } } Loading @@ -346,6 +360,8 @@ object ClockFloatingSheetBinder { bindClockFontContent( clockFontContent = clockFontContent, viewModel = viewModel, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) } Loading @@ -353,6 +369,8 @@ object ClockFloatingSheetBinder { private fun bindClockFontContent( clockFontContent: View, viewModel: ClockPickerViewModel, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ) { val sliderViewList = Loading Loading @@ -409,9 +427,15 @@ object ClockFloatingSheetBinder { viewHolder.setIsVisible(booleanAxis != null) booleanAxis?.let { switchViewMap[it.key] = viewHolder viewHolder.initView(booleanAxis) { value -> viewHolder.initView( clockFontAxis = booleanAxis, onFontAxisValueUpdated = { value -> viewModel.updatePreviewFontAxis(booleanAxis.key, value) } }, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } } } Loading
src/com/android/wallpaper/customization/ui/binder/ColorsFloatingSheetBinder.kt +2 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,8 @@ object ColorsFloatingSheetBinder { DarkModeBinder.bind( darkModeToggle = view.findViewById(R.id.dark_mode_toggle), viewModel = optionsViewModel.darkModeViewModel, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isFloatingSheetActive, lifecycleOwner = lifecycleOwner, ) Loading
src/com/android/wallpaper/customization/ui/binder/SwitchColorBinder.kt 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wallpaper.customization.ui.binder import android.content.res.ColorStateList import androidx.lifecycle.LifecycleOwner import com.android.wallpaper.picker.customization.ui.binder.ColorUpdateBinder import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel import com.google.android.material.materialswitch.MaterialSwitch object SwitchColorBinder { private const val COLOR_TRANSPARENT = 0 interface Binding { /** Destroys the binding in spite of lifecycle state. */ fun destroy() } /** * Binds the color of a [MaterialSwitch] using [ColorUpdateBinder] according to Material 3 * specs. */ fun bind( switch: MaterialSwitch, isChecked: Boolean, colorUpdateViewModel: ColorUpdateViewModel, shouldAnimateColor: () -> Boolean, lifecycleOwner: LifecycleOwner, ): Binding { val bindingThumb: ColorUpdateBinder.Binding val bindingTrack: ColorUpdateBinder.Binding if (isChecked) { switch.trackDecorationTintList = ColorStateList.valueOf(COLOR_TRANSPARENT) bindingThumb = ColorUpdateBinder.bind( setColor = { color -> switch.thumbTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorOnPrimary, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) bindingTrack = ColorUpdateBinder.bind( setColor = { color -> switch.trackTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorPrimary, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } else { bindingThumb = ColorUpdateBinder.bind( setColor = { color -> switch.thumbTintList = ColorStateList.valueOf(color) switch.trackDecorationTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorOutline, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) bindingTrack = ColorUpdateBinder.bind( setColor = { color -> switch.trackTintList = ColorStateList.valueOf(color) }, color = colorUpdateViewModel.colorSurfaceContainerHighest, shouldAnimate = shouldAnimateColor, lifecycleOwner = lifecycleOwner, ) } return object : Binding { override fun destroy() { bindingThumb.destroy() bindingTrack.destroy() } } } }
src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt +25 −17 Original line number Diff line number Diff line Loading @@ -198,10 +198,10 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO val optionThemedIcons = homeScreenCustomizationOptionEntries .find { it.first == ThemePickerHomeCustomizationOption.THEMED_ICONS } ?.second .first { it.first == ThemePickerHomeCustomizationOption.THEMED_ICONS } .second val optionThemedIconsSwitch = optionThemedIcons?.findViewById<MaterialSwitch>(R.id.option_entry_switch) optionThemedIcons.requireViewById<MaterialSwitch>(R.id.option_entry_switch) ColorUpdateBinder.bind( setColor = { color -> Loading Loading @@ -318,7 +318,6 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } } if (optionThemedIconsSwitch != null) { launch { optionsViewModel.themedIconViewModel.isAvailable.collect { isAvailable -> optionThemedIconsSwitch.isEnabled = isAvailable Loading @@ -326,8 +325,18 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } launch { var binding: SwitchColorBinder.Binding? = null optionsViewModel.themedIconViewModel.isActivated.collect { optionThemedIconsSwitch.isChecked = it binding?.destroy() binding = SwitchColorBinder.bind( switch = optionThemedIconsSwitch, isChecked = it, colorUpdateViewModel = colorUpdateViewModel, shouldAnimateColor = isOnMainScreen, lifecycleOwner = lifecycleOwner, ) } } Loading @@ -340,7 +349,6 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO } } } } customizationOptionFloatingSheetViewMap ?.get(ThemePickerLockCustomizationOption.CLOCK) Loading