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