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.healthconnect.controller.permissions.request.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.Hyphens
38 import androidx.compose.ui.text.style.TextAlign
39 import androidx.compose.ui.text.style.TextOverflow
40 import androidx.compose.ui.unit.dp
41 import androidx.wear.compose.material.Chip
42 import androidx.wear.compose.material.ChipColors
43 import androidx.wear.compose.material.ChipDefaults
44 import androidx.wear.compose.material.ContentAlpha
45 import androidx.wear.compose.material.Icon
46 import androidx.wear.compose.material.MaterialTheme
47 import androidx.wear.compose.material.Text
48 import androidx.wear.compose.material.contentColorFor
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 =
197 MaterialTheme.typography.button.copy(
198 fontWeight = FontWeight.W600,
199 hyphens = Hyphens.Auto
200 )
201 )
202 }
203
204 val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
205 secondaryLabel?.let {
206 {
207 Text(
208 text = secondaryLabel,
209 color = secondaryTextColor,
210 overflow = TextOverflow.Ellipsis,
211 maxLines = secondaryLabelMaxLines ?: 1,
212 style = MaterialTheme.typography.caption2
213 )
214 }
215 }
216
217 val contentPadding =
218 if (largeIcon) {
219 val verticalPadding = ChipDefaults.ChipVerticalPadding
220 PaddingValues(
221 start = 10.dp,
222 top = verticalPadding,
223 end = ChipDefaults.ChipHorizontalPadding,
224 bottom = verticalPadding
225 )
226 } else {
227 ChipDefaults.ContentPadding
228 }
229
230 Chip(
231 label = labelParam,
232 onClick = onClick,
233 modifier = modifier.fillMaxWidth(),
234 secondaryLabel = secondaryLabelParam,
235 icon = icon,
236 colors = colors,
237 enabled = enabled,
238 contentPadding = contentPadding,
239 shape = RoundedCornerShape(26.dp)
240 )
241 }
242
243 /** Default colors of a Chip. */
chipDefaultColorsnull244 @Composable fun chipDefaultColors(): ChipColors = ChipDefaults.secondaryChipColors()
245
246 /**
247 * ChipColors that disabled alpha is applied based on [ChipDefaults.secondaryChipColors()]. It is
248 * used for a Chip which would like to respond to click events, meanwhile it seems disabled.
249 */
250 @Composable
251 fun chipDisabledColors(): ChipColors {
252 val backgroundColor = MaterialTheme.colors.surface
253 val contentColor = contentColorFor(backgroundColor)
254 val secondaryContentColor = contentColor
255 val iconColor = contentColor
256
257 return ChipDefaults.chipColors(
258 backgroundColor = backgroundColor.copy(alpha = ContentAlpha.disabled),
259 contentColor = contentColor.copy(alpha = ContentAlpha.disabled),
260 secondaryContentColor = secondaryContentColor.copy(alpha = ContentAlpha.disabled),
261 iconColor = iconColor.copy(alpha = ContentAlpha.disabled)
262 )
263 }
264