Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6777f3f7 authored by Catherine Liang's avatar Catherine Liang
Browse files

Update color option icon colors based on theme (2/2)

Color option icons do not update based on light/dark theme color because
they do not use material dynamic colors. Update them with animation
based on theme changes in the system and based on what is being
previewed in the color picker.

Flag: com.android.systemui.shared.new_customization_picker_ui
Test: manually verified by toggling dark theme
Bug: 350718581
Change-Id: I8fd6754ad52a873f979abddf9809c4ffb5b970be
parent 247d15b2
Loading
Loading
Loading
Loading
+47 −16
Original line number Diff line number Diff line
@@ -17,11 +17,17 @@

package com.android.customization.picker.color.ui.binder

import android.animation.Animator
import android.animation.ValueAnimator
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.customization.picker.color.ui.view.ColorOptionIconView2
import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
import com.android.wallpaper.picker.customization.ui.binder.ColorUpdateBinder
import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
import kotlinx.coroutines.launch

object ColorOptionIconBinder2 {

@@ -33,7 +39,6 @@ object ColorOptionIconBinder2 {
    fun bind(
        view: ColorOptionIconView2,
        viewModel: ColorOptionIconViewModel,
        darkTheme: Boolean,
        colorUpdateViewModel: ColorUpdateViewModel,
        shouldAnimateColor: () -> Boolean,
        lifecycleOwner: LifecycleOwner,
@@ -45,24 +50,50 @@ object ColorOptionIconBinder2 {
                shouldAnimate = shouldAnimateColor,
                lifecycleOwner = lifecycleOwner,
            )
        if (darkTheme) {
        view.bindColor(
            viewModel.lightThemeColor0,
            viewModel.lightThemeColor1,
            viewModel.lightThemeColor2,
            viewModel.lightThemeColor3,
            viewModel.darkThemeColor0,
            viewModel.darkThemeColor1,
            viewModel.darkThemeColor2,
            viewModel.darkThemeColor3,
        )
        } else {
            view.bindColor(
                viewModel.lightThemeColor0,
                viewModel.lightThemeColor1,
                viewModel.lightThemeColor2,
                viewModel.lightThemeColor3,
        var animator: Animator? = null
        val job =
            lifecycleOwner.lifecycleScope.launch {
                lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                    var currentDarkMode: Boolean? = null
                    colorUpdateViewModel.isDarkMode.collect { isDarkMode ->
                        animator?.end()
                        val previousDarkMode = currentDarkMode
                        if (previousDarkMode != null) {
                            animator =
                                ValueAnimator.ofFloat(
                                        if (previousDarkMode) 1f else 0f,
                                        if (isDarkMode) 1f else 0f,
                                    )
                                    .apply {
                                        duration = ColorUpdateBinder.COLOR_ANIMATION_DURATION_MILLIS
                                        addUpdateListener {
                                            val progress = it.animatedValue as Float
                                            view.setDarkThemeProgress(progress)
                                        }
                                    }
                                    .also { it.start() }
                        } else {
                            view.setDarkThemeProgress(if (isDarkMode) 1f else 0f)
                        }
                        currentDarkMode = isDarkMode
                    }
                }
            }
        return object : Binding {
            override fun destroy() {
                binding.destroy()
                job.cancel()
                animator?.cancel()
            }
        }
    }
+44 −16
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.customization.picker.color.ui.view

import android.animation.ArgbEvaluator
import android.annotation.ColorInt
import android.content.Context
import android.graphics.Canvas
@@ -35,10 +36,20 @@ class ColorOptionIconView2(context: Context, attrs: AttributeSet) :

    private val path = Path()

    private var color0 = DEFAULT_PLACEHOLDER_COLOR
    private var color1 = DEFAULT_PLACEHOLDER_COLOR
    private var color2 = DEFAULT_PLACEHOLDER_COLOR
    private var color3 = DEFAULT_PLACEHOLDER_COLOR
    // progress 0 is light theme and 1 is dark theme
    var darkThemeProgress = 0f
        private set

    private val argbEvaluator = ArgbEvaluator()

    private var lightThemeColor0 = DEFAULT_PLACEHOLDER_COLOR
    private var lightThemeColor1 = DEFAULT_PLACEHOLDER_COLOR
    private var lightThemeColor2 = DEFAULT_PLACEHOLDER_COLOR
    private var lightThemeColor3 = DEFAULT_PLACEHOLDER_COLOR
    private var darkThemeColor0 = DEFAULT_PLACEHOLDER_COLOR
    private var darkThemeColor1 = DEFAULT_PLACEHOLDER_COLOR
    private var darkThemeColor2 = DEFAULT_PLACEHOLDER_COLOR
    private var darkThemeColor3 = DEFAULT_PLACEHOLDER_COLOR
    private var strokeColor = DEFAULT_PLACEHOLDER_COLOR
    private val strokeWidth =
        context.resources
@@ -55,15 +66,28 @@ class ColorOptionIconView2(context: Context, attrs: AttributeSet) :
     * @param color3 the color in the bottom right quadrant
     */
    fun bindColor(
        @ColorInt color0: Int,
        @ColorInt color1: Int,
        @ColorInt color2: Int,
        @ColorInt color3: Int,
        @ColorInt lightThemeColor0: Int,
        @ColorInt lightThemeColor1: Int,
        @ColorInt lightThemeColor2: Int,
        @ColorInt lightThemeColor3: Int,
        @ColorInt darkThemeColor0: Int,
        @ColorInt darkThemeColor1: Int,
        @ColorInt darkThemeColor2: Int,
        @ColorInt darkThemeColor3: Int,
    ) {
        this.color0 = color0
        this.color1 = color1
        this.color2 = color2
        this.color3 = color3
        this.lightThemeColor0 = lightThemeColor0
        this.lightThemeColor1 = lightThemeColor1
        this.lightThemeColor2 = lightThemeColor2
        this.lightThemeColor3 = lightThemeColor3
        this.darkThemeColor0 = darkThemeColor0
        this.darkThemeColor1 = darkThemeColor1
        this.darkThemeColor2 = darkThemeColor2
        this.darkThemeColor3 = darkThemeColor3
        invalidate()
    }

    fun setDarkThemeProgress(progress: Float) {
        this.darkThemeProgress = progress
        invalidate()
    }

@@ -100,16 +124,20 @@ class ColorOptionIconView2(context: Context, attrs: AttributeSet) :
        canvas.apply {
            paint.style = Paint.Style.FILL
            // top left
            paint.color = color0
            paint.color =
                argbEvaluator.evaluate(darkThemeProgress, lightThemeColor0, darkThemeColor0) as Int
            drawRect(0f, 0f, width / 2, height / 2, paint)
            // top right
            paint.color = color1
            paint.color =
                argbEvaluator.evaluate(darkThemeProgress, lightThemeColor1, darkThemeColor1) as Int
            drawRect(width / 2, 0f, width, height / 2, paint)
            // bottom left
            paint.color = color2
            paint.color =
                argbEvaluator.evaluate(darkThemeProgress, lightThemeColor2, darkThemeColor2) as Int
            drawRect(0f, height / 2, width / 2, height, paint)
            // bottom right
            paint.color = color3
            paint.color =
                argbEvaluator.evaluate(darkThemeProgress, lightThemeColor3, darkThemeColor3) as Int
            drawRect(width / 2, height / 2, width, height, paint)
        }

+0 −4
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@ import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver.OnGlobalLayoutListener
@@ -492,12 +490,10 @@ object ClockFloatingSheetBinder {
            bindPayload = { itemView: View, colorIcon: ColorOptionIconViewModel ->
                val colorOptionIconView: ColorOptionIconView2 =
                    itemView.requireViewById(com.android.wallpaper.R.id.background)
                val night = uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
                val binding =
                    ColorOptionIconBinder2.bind(
                        view = colorOptionIconView,
                        viewModel = colorIcon,
                        darkTheme = night,
                        colorUpdateViewModel = colorUpdateViewModel,
                        shouldAnimateColor = shouldAnimateColor,
                        lifecycleOwner = lifecycleOwner,
+0 −6
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.wallpaper.customization.ui.binder

import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
@@ -103,7 +101,6 @@ object ColorsFloatingSheetBinder {

        val colorsAdapter =
            createOptionItemAdapter(
                uiMode = view.resources.configuration.uiMode,
                colorUpdateViewModel = colorUpdateViewModel,
                shouldAnimateColor = isFloatingSheetActive,
                lifecycleOwner = lifecycleOwner,
@@ -172,7 +169,6 @@ object ColorsFloatingSheetBinder {
    }

    private fun createOptionItemAdapter(
        uiMode: Int,
        colorUpdateViewModel: ColorUpdateViewModel,
        shouldAnimateColor: () -> Boolean,
        lifecycleOwner: LifecycleOwner,
@@ -185,12 +181,10 @@ object ColorsFloatingSheetBinder {
                    itemView.requireViewById<ColorOptionIconView2>(
                        com.android.wallpaper.R.id.background
                    )
                val night = uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
                val binding =
                    ColorOptionIconBinder2.bind(
                        view = colorOptionIconView,
                        viewModel = colorIcon,
                        darkTheme = night,
                        colorUpdateViewModel = colorUpdateViewModel,
                        shouldAnimateColor = shouldAnimateColor,
                        lifecycleOwner = lifecycleOwner,
+0 −1
Original line number Diff line number Diff line
@@ -377,7 +377,6 @@ constructor(private val defaultCustomizationOptionsBinder: DefaultCustomizationO
                                    view = optionColorsIcon,
                                    viewModel =
                                        ColorOptionIconViewModel.fromColorOption(colorOption),
                                    darkTheme = view.resources.configuration.isNightModeActive,
                                    colorUpdateViewModel = colorUpdateViewModel,
                                    shouldAnimateColor = isOnMainScreen,
                                    lifecycleOwner = lifecycleOwner,