1 /*
2 * Copyright (C) 2023 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.permissioncontroller.wear.permission.components.material2
18
19 import android.graphics.drawable.Drawable
20 import androidx.annotation.StringRes
21 import androidx.compose.foundation.layout.BoxScope
22 import androidx.compose.foundation.layout.PaddingValues
23 import androidx.compose.foundation.layout.Row
24 import androidx.compose.foundation.layout.RowScope
25 import androidx.compose.foundation.layout.fillMaxWidth
26 import androidx.compose.foundation.layout.size
27 import androidx.compose.foundation.shape.CircleShape
28 import androidx.compose.foundation.shape.RoundedCornerShape
29 import androidx.compose.runtime.Composable
30 import androidx.compose.ui.Modifier
31 import androidx.compose.ui.draw.clip
32 import androidx.compose.ui.graphics.Color
33 import androidx.compose.ui.graphics.vector.ImageVector
34 import androidx.compose.ui.res.painterResource
35 import androidx.compose.ui.res.stringResource
36 import androidx.compose.ui.text.style.Hyphens
37 import androidx.compose.ui.text.style.TextAlign
38 import androidx.compose.ui.text.style.TextOverflow
39 import androidx.compose.ui.unit.dp
40 import androidx.wear.compose.material.Chip
41 import androidx.wear.compose.material.ChipColors
42 import androidx.wear.compose.material.ChipDefaults
43 import androidx.wear.compose.material.ContentAlpha
44 import androidx.wear.compose.material.Icon
45 import androidx.wear.compose.material.MaterialTheme
46 import androidx.wear.compose.material.Text
47 import androidx.wear.compose.material.contentColorFor
48 import com.android.permissioncontroller.wear.permission.components.rememberDrawablePainter
49
50 /**
51 * This component is an alternative to [Chip], providing the following:
52 * - a convenient way of providing a label and a secondary label;
53 * - a convenient way of providing an icon, and choosing their size based on the sizes recommended
54 * by the Wear guidelines;
55 */
56 @Composable
Chipnull57 fun Chip(
58 label: String,
59 labelMaxLines: Int? = null,
60 onClick: () -> Unit,
61 modifier: Modifier = Modifier,
62 secondaryLabel: String? = null,
63 secondaryLabelMaxLines: Int? = null,
64 icon: Any? = null,
65 iconContentDescription: String? = null,
66 largeIcon: Boolean = false,
67 textColor: Color = MaterialTheme.colors.onSurface,
68 iconColor: Color = Color.Unspecified,
69 colors: ChipColors = chipDefaultColors(),
70 enabled: Boolean = true,
71 ) {
72 val iconParam: (@Composable BoxScope.() -> Unit)? =
73 icon?.let {
74 {
75 val iconSize =
76 if (largeIcon) {
77 ChipDefaults.LargeIconSize
78 } else {
79 ChipDefaults.IconSize
80 }
81
82 Row {
83 val iconModifier = Modifier.size(iconSize).clip(CircleShape)
84 when (icon) {
85 is ImageVector ->
86 Icon(
87 imageVector = icon,
88 tint = iconColor,
89 contentDescription = iconContentDescription,
90 modifier = iconModifier,
91 )
92 is Int ->
93 Icon(
94 painter = painterResource(id = icon),
95 tint = iconColor,
96 contentDescription = iconContentDescription,
97 modifier = iconModifier,
98 )
99 is Drawable ->
100 Icon(
101 painter = rememberDrawablePainter(icon),
102 tint = iconColor,
103 contentDescription = iconContentDescription,
104 modifier = iconModifier,
105 )
106 else -> {}
107 }
108 }
109 }
110 }
111
112 Chip(
113 label = label,
114 labelMaxLines = labelMaxLines,
115 onClick = onClick,
116 modifier = modifier,
117 secondaryLabel = secondaryLabel,
118 secondaryLabelMaxLines = secondaryLabelMaxLines,
119 icon = iconParam,
120 largeIcon = largeIcon,
121 textColor = textColor,
122 colors = colors,
123 enabled = enabled,
124 )
125 }
126
127 /**
128 * This component is an alternative to [Chip], providing the following:
129 * - a convenient way of providing a label and a secondary label;
130 * - a convenient way of providing an icon, and choosing their size based on the sizes recommended
131 * by the Wear guidelines;
132 */
133 @Composable
Chipnull134 fun Chip(
135 @StringRes labelId: Int,
136 labelMaxLines: Int? = null,
137 onClick: () -> Unit,
138 modifier: Modifier = Modifier,
139 @StringRes secondaryLabel: Int? = null,
140 secondaryLabelMaxLines: Int? = null,
141 icon: Any? = null,
142 largeIcon: Boolean = false,
143 textColor: Color = MaterialTheme.colors.onSurface,
144 iconColor: Color = Color.Unspecified,
145 colors: ChipColors = chipDefaultColors(),
146 enabled: Boolean = true,
147 ) {
148 Chip(
149 label = stringResource(id = labelId),
150 labelMaxLines = labelMaxLines,
151 onClick = onClick,
152 modifier = modifier,
153 secondaryLabel = secondaryLabel?.let { stringResource(id = it) },
154 secondaryLabelMaxLines = secondaryLabelMaxLines,
155 icon = icon,
156 largeIcon = largeIcon,
157 textColor = textColor,
158 iconColor = iconColor,
159 colors = colors,
160 enabled = enabled,
161 )
162 }
163
164 /**
165 * This component is an alternative to [Chip], providing the following:
166 * - a convenient way of providing a label and a secondary label;
167 */
168 // Setting the color as per
169 // https://source.corp.google.com/piper///depot/google3/java/com/google/android/clockwork/common/wearable/wearmaterial/button/res/color/wear_button_secondary_text_stateful.xml?q=wear_button_secondary_text_stateful
170 @Composable
Chipnull171 fun Chip(
172 label: String,
173 labelMaxLines: Int? = null,
174 onClick: () -> Unit,
175 modifier: Modifier = Modifier,
176 secondaryLabel: String? = null,
177 secondaryLabelMaxLines: Int? = null,
178 icon: (@Composable BoxScope.() -> Unit)? = null,
179 largeIcon: Boolean = false,
180 textColor: Color = MaterialTheme.colors.onSurface,
181 secondaryTextColor: Color = MaterialTheme.colors.primary,
182 colors: ChipColors = chipDefaultColors(),
183 enabled: Boolean = true,
184 ) {
185 val hasSecondaryLabel = secondaryLabel != null
186 val hasIcon = icon != null
187
188 val labelParam: (@Composable RowScope.() -> Unit) = {
189 Text(
190 text = label,
191 color = textColor,
192 modifier = Modifier.fillMaxWidth(),
193 textAlign = if (hasSecondaryLabel || hasIcon) TextAlign.Start else TextAlign.Center,
194 overflow = TextOverflow.Ellipsis,
195 maxLines = labelMaxLines ?: if (hasSecondaryLabel) 1 else 2,
196 style = MaterialTheme.typography.button.copy(hyphens = Hyphens.Auto),
197 )
198 }
199
200 val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
201 secondaryLabel?.let {
202 {
203 Text(
204 text = secondaryLabel,
205 color = secondaryTextColor,
206 overflow = TextOverflow.Ellipsis,
207 maxLines = secondaryLabelMaxLines ?: 1,
208 style = MaterialTheme.typography.caption2.copy(hyphens = Hyphens.Auto),
209 )
210 }
211 }
212
213 val contentPadding =
214 if (largeIcon) {
215 val verticalPadding = ChipDefaults.ChipVerticalPadding
216 PaddingValues(
217 start = 10.dp,
218 top = verticalPadding,
219 end = ChipDefaults.ChipHorizontalPadding,
220 bottom = verticalPadding,
221 )
222 } else {
223 ChipDefaults.ContentPadding
224 }
225
226 Chip(
227 label = labelParam,
228 onClick = onClick,
229 modifier = modifier.fillMaxWidth(),
230 secondaryLabel = secondaryLabelParam,
231 icon = icon,
232 colors = colors,
233 enabled = enabled,
234 contentPadding = contentPadding,
235 shape = RoundedCornerShape(26.dp),
236 )
237 }
238
239 /** Default colors of a Chip. */
chipDefaultColorsnull240 @Composable fun chipDefaultColors(): ChipColors = ChipDefaults.secondaryChipColors()
241
242 /**
243 * ChipColors that disabled alpha is applied based on [ChipDefaults.secondaryChipColors()]. It is
244 * used for a Chip which would like to respond to click events, meanwhile it seems disabled.
245 */
246 @Composable
247 fun chipDisabledColors(): ChipColors {
248 val backgroundColor = MaterialTheme.colors.surface
249 val contentColor = contentColorFor(backgroundColor)
250 val secondaryContentColor = contentColor
251 val iconColor = contentColor
252
253 return ChipDefaults.chipColors(
254 backgroundColor = backgroundColor.copy(alpha = ContentAlpha.disabled),
255 contentColor = contentColor.copy(alpha = ContentAlpha.disabled),
256 secondaryContentColor = secondaryContentColor.copy(alpha = ContentAlpha.disabled),
257 iconColor = iconColor.copy(alpha = ContentAlpha.disabled),
258 )
259 }
260