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.settingslib.widget
18 
19 import android.content.Context
20 import android.content.res.ColorStateList
21 import android.graphics.drawable.Drawable
22 import android.util.AttributeSet
23 import android.view.View
24 import android.widget.ImageView
25 import androidx.annotation.StringRes
26 import androidx.core.content.ContextCompat
27 import androidx.preference.Preference
28 import androidx.preference.PreferenceViewHolder
29 import com.android.settingslib.widget.preference.statusbanner.R
30 import com.google.android.material.button.MaterialButton
31 
32 class StatusBannerPreference @JvmOverloads constructor(
33     context: Context,
34     attrs: AttributeSet? = null,
35     defStyleAttr: Int = 0,
36     defStyleRes: Int = 0
37 ) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
38 
39     enum class BannerStatus {
40         GENERIC,
41         LOW,
42         MEDIUM,
43         HIGH
44     }
45     var iconLevel: BannerStatus = BannerStatus.GENERIC
46         set(value) {
47             field = value
48             notifyChanged()
49         }
50     var buttonLevel: BannerStatus = BannerStatus.GENERIC
51         set(value) {
52             field = value
53             notifyChanged()
54         }
55     private var buttonText: String = ""
56         set(value) {
57             field = value
58             notifyChanged()
59         }
60     private var listener: View.OnClickListener? = null
61 
62     init {
63         layoutResource = R.layout.settingslib_expressive_preference_statusbanner
64         isSelectable = false
65 
66         initAttributes(context, attrs, defStyleAttr)
67     }
68 
initAttributesnull69     private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
70         context.obtainStyledAttributes(
71             attrs,
72             R.styleable.StatusBanner, defStyleAttr, 0
73         ).apply {
74             iconLevel = getInteger(R.styleable.StatusBanner_iconLevel, 0).toBannerStatus()
75             if (icon == null) {
76                 icon = getIconDrawable(iconLevel)
77             } else {
78                 icon!!.setTintList(ColorStateList.valueOf(getBackgroundColor(iconLevel)))
79             }
80             buttonLevel = getInteger(R.styleable.StatusBanner_buttonLevel, 0).toBannerStatus()
81             buttonText = getString(R.styleable.StatusBanner_buttonText) ?: ""
82             recycle()
83         }
84     }
85 
toBannerStatusnull86     private fun Int.toBannerStatus(): BannerStatus = when (this) {
87         1 -> BannerStatus.LOW
88         2 -> BannerStatus.MEDIUM
89         3 -> BannerStatus.HIGH
90         else -> BannerStatus.GENERIC
91     }
92 
onBindViewHoldernull93     override fun onBindViewHolder(holder: PreferenceViewHolder) {
94         super.onBindViewHolder(holder)
95         holder.isDividerAllowedBelow = false
96         holder.isDividerAllowedAbove = false
97 
98         (holder.findViewById(R.id.icon_background) as? ImageView)?.apply {
99             setImageDrawable(getBackgroundDrawable(iconLevel))
100         }
101 
102         holder.findViewById(android.R.id.icon_frame)?.apply {
103             visibility = if (icon != null) View.VISIBLE else View.GONE
104         }
105 
106         (holder.findViewById(R.id.status_banner_button) as? MaterialButton)?.apply {
107             setBackgroundColor(getBackgroundColor(buttonLevel))
108             text = buttonText
109             setOnClickListener(listener)
110             visibility = if (listener != null) View.VISIBLE else View.GONE
111         }
112     }
113 
114     /**
115      * Sets the text to be displayed in button.
116      */
setButtonTextnull117     fun setButtonText(@StringRes textResId: Int) {
118         buttonText = context.getString(textResId)
119     }
120 
121     /**
122      * Register a callback to be invoked when positive button is clicked.
123      */
setButtonOnClickListenernull124     fun setButtonOnClickListener(listener: View.OnClickListener) {
125         this.listener = listener
126         notifyChanged()
127     }
128 
getBackgroundColornull129     private fun getBackgroundColor(level: BannerStatus): Int {
130         return when (level) {
131             BannerStatus.LOW -> ContextCompat.getColor(
132                 context,
133                 R.color.settingslib_expressive_color_status_level_low
134             )
135 
136             BannerStatus.MEDIUM -> ContextCompat.getColor(
137                 context,
138                 R.color.settingslib_expressive_color_status_level_medium
139             )
140 
141             BannerStatus.HIGH -> ContextCompat.getColor(
142                 context,
143                 R.color.settingslib_expressive_color_status_level_high
144             )
145 
146             else -> ContextCompat.getColor(
147                 context,
148                 com.android.settingslib.widget.theme.R.color.settingslib_materialColorPrimary
149             )
150         }
151     }
152 
getIconDrawablenull153     private fun getIconDrawable(level: BannerStatus): Drawable? {
154         return when (level) {
155             BannerStatus.LOW -> ContextCompat.getDrawable(
156                 context,
157                 R.drawable.settingslib_expressive_icon_status_level_low
158             )
159 
160             BannerStatus.MEDIUM -> ContextCompat.getDrawable(
161                 context,
162                 R.drawable.settingslib_expressive_icon_status_level_medium
163             )
164 
165             BannerStatus.HIGH -> ContextCompat.getDrawable(
166                 context,
167                 R.drawable.settingslib_expressive_icon_status_level_high
168             )
169 
170             else -> null
171         }
172     }
173 
getBackgroundDrawablenull174     private fun getBackgroundDrawable(level: BannerStatus): Drawable? {
175         return when (level) {
176             BannerStatus.LOW -> ContextCompat.getDrawable(
177                 context,
178                 R.drawable.settingslib_expressive_background_level_low
179             )
180 
181             BannerStatus.MEDIUM -> ContextCompat.getDrawable(
182                 context,
183                 R.drawable.settingslib_expressive_background_level_medium
184             )
185 
186             BannerStatus.HIGH -> ContextCompat.getDrawable(
187                 context,
188                 R.drawable.settingslib_expressive_background_level_high
189             )
190 
191             else -> ContextCompat.getDrawable(
192                 context,
193                 R.drawable.settingslib_expressive_background_generic
194             )
195         }
196     }
197 }