1 /*
2  * 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.picker.customization.ui.view.animator
18 
19 import android.animation.ValueAnimator
20 import androidx.core.animation.addListener
21 import androidx.core.animation.doOnEnd
22 import androidx.recyclerview.widget.DefaultItemAnimator
23 import androidx.recyclerview.widget.RecyclerView.State
24 import androidx.recyclerview.widget.RecyclerView.ViewHolder
25 import com.android.wallpaper.R
26 import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter.TabViewHolder
27 
28 class TabItemAnimator : DefaultItemAnimator() {
29 
canReuseUpdatedViewHoldernull30     override fun canReuseUpdatedViewHolder(viewHolder: ViewHolder, payloads: MutableList<Any>) =
31         true
32 
33     override fun recordPreLayoutInformation(
34         state: State,
35         viewHolder: ViewHolder,
36         changeFlags: Int,
37         payloads: MutableList<Any>,
38     ): ItemHolderInfo {
39         if (changeFlags == FLAG_CHANGED && payloads.isNotEmpty()) {
40             return when (payloads[0] as? Int) {
41                 SELECT_ITEM -> TabItemHolderInfo(true)
42                 UNSELECT_ITEM -> TabItemHolderInfo(false)
43                 else -> super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads)
44             }
45         }
46         return super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads)
47     }
48 
animateChangenull49     override fun animateChange(
50         oldHolder: ViewHolder,
51         newHolder: ViewHolder,
52         preLayoutInfo: ItemHolderInfo,
53         postLayoutInfo: ItemHolderInfo,
54     ): Boolean {
55         if (preLayoutInfo is TabItemHolderInfo) {
56             val viewHolder = newHolder as TabViewHolder
57             val iconSize =
58                 viewHolder.itemView.resources.getDimensionPixelSize(
59                     R.dimen.floating_tab_toolbar_tab_icon_size
60                 )
61             ValueAnimator.ofFloat(
62                     if (preLayoutInfo.selectItem) 0f else 1f,
63                     if (preLayoutInfo.selectItem) 1f else 0f,
64                 )
65                 .apply {
66                     addUpdateListener {
67                         val value = it.animatedValue as Float
68                         viewHolder.icon.layoutParams =
69                             viewHolder.icon.layoutParams.apply {
70                                 width = (value * iconSize).toInt()
71                             }
72                         viewHolder.container.background.alpha =
73                             (value * BACKGROUND_ALPHA_MAX).toInt()
74                     }
75                     addListener { doOnEnd { dispatchAnimationFinished(viewHolder) } }
76                     duration = ANIMATION_DURATION_MILLIS
77                 }
78                 .start()
79             return true
80         }
81 
82         return super.animateChange(oldHolder, newHolder, preLayoutInfo, postLayoutInfo)
83     }
84 
85     class TabItemHolderInfo(val selectItem: Boolean) : ItemHolderInfo()
86 
87     companion object {
88         const val SELECT_ITEM = 3024
89         const val UNSELECT_ITEM = 1114
90         const val BACKGROUND_ALPHA_MAX = 255
91         const val ANIMATION_DURATION_MILLIS = 200L
92     }
93 }
94