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 package com.android.credentialmanager.ui.components
17
18 import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme
19 import androidx.compose.foundation.layout.Row
20 import androidx.compose.material3.Icon
21 import android.graphics.drawable.Drawable
22 import androidx.compose.foundation.layout.fillMaxWidth
23 import androidx.compose.foundation.layout.Arrangement
24 import androidx.compose.foundation.layout.BoxScope
25 import androidx.compose.foundation.layout.RowScope
26 import androidx.compose.foundation.layout.size
27 import androidx.compose.material.icons.Icons
28 import androidx.compose.material.icons.outlined.Lock
29 import androidx.compose.material.icons.outlined.LockOpen
30 import androidx.compose.runtime.Composable
31 import androidx.compose.ui.Alignment
32 import androidx.compose.ui.Modifier
33 import androidx.compose.ui.res.stringResource
34 import androidx.compose.ui.tooling.preview.Preview
35 import androidx.compose.ui.unit.dp
36 import androidx.wear.compose.material.Chip
37 import androidx.core.graphics.drawable.toBitmap
38 import androidx.wear.compose.material.ChipColors
39 import androidx.compose.ui.graphics.asImageBitmap
40 import androidx.compose.ui.graphics.Color
41 import androidx.compose.ui.text.style.TextAlign
42 import androidx.wear.compose.material.ChipDefaults
43 import com.android.credentialmanager.R
44 import com.android.credentialmanager.common.ui.components.WearButtonText
45 import com.android.credentialmanager.common.ui.components.WearSecondaryLabel
46 import com.android.credentialmanager.model.get.AuthenticationEntryInfo
47
48 /* Used as credential suggestion or user action chip. */
49 @Composable
CredentialsScreenChipnull50 fun CredentialsScreenChip(
51 primaryText: @Composable () -> Unit,
52 secondaryText: (@Composable () -> Unit)? = null,
53 onClick: () -> Unit,
54 icon: Drawable? = null,
55 isAuthenticationEntryLocked: Boolean? = null,
56 modifier: Modifier = Modifier,
57 colors: ChipColors = ChipDefaults.secondaryChipColors()
58 ) {
59 val labelParam: (@Composable RowScope.() -> Unit) =
60 {
61 var horizontalArrangement = Arrangement.Start
62 if (icon == null) {
63 horizontalArrangement = Arrangement.Center
64 }
65 Row(horizontalArrangement = horizontalArrangement, modifier = modifier.fillMaxWidth()) {
66 primaryText()
67 }
68 }
69
70 val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
71 secondaryText?.let {
72 {
73 Row {
74 secondaryText()
75 if (isAuthenticationEntryLocked != null) {
76 if (isAuthenticationEntryLocked) {
77 Icon(
78 Icons.Outlined.Lock,
79 contentDescription = null,
80 modifier = Modifier.size(12.dp).align(Alignment.CenterVertically),
81 tint = WearMaterialTheme.colors.onSurfaceVariant
82 )
83 } else {
84 Icon(
85 Icons.Outlined.LockOpen,
86 contentDescription = null,
87 modifier = Modifier.size(12.dp).align(Alignment.CenterVertically),
88 tint = WearMaterialTheme.colors.onSurfaceVariant
89 )
90 }
91 }
92 }
93 }
94 }
95
96 val iconParam: (@Composable BoxScope.() -> Unit)? =
97 icon?.toBitmap()?.asImageBitmap()?.let {
98 {
99 Icon(
100 bitmap = it,
101 // Decorative purpose only.
102 contentDescription = null,
103 modifier = Modifier.size(24.dp),
104 tint = Color.Unspecified
105 )
106 }
107 }
108
109 Chip(
110 label = labelParam,
111 onClick = onClick,
112 modifier = modifier.fillMaxWidth(),
113 secondaryLabel = secondaryLabelParam,
114 icon = iconParam,
115 colors = colors,
116 enabled = true,
117 )
118 }
119
120 @Preview
121 @Composable
CredentialsScreenChipPreviewnull122 fun CredentialsScreenChipPreview() {
123 CredentialsScreenChip(
124 primaryText = {
125 WearButtonText(
126 text = "Elisa Beckett",
127 textAlign = TextAlign.Start,
128 )
129 },
130 onClick = { },
131 secondaryText = {
132 WearSecondaryLabel(
133 text = "[email protected]",
134 color = WearMaterialTheme.colors.onSurfaceVariant
135 )
136 },
137 icon = null,
138 )
139 }
140
141 @Composable
SignInOptionsChipnull142 fun SignInOptionsChip(onClick: () -> Unit) {
143 CredentialsScreenChip(
144 primaryText = {
145 WearButtonText(
146 text = stringResource(R.string.dialog_sign_in_options_button),
147 textAlign = TextAlign.Center,
148 maxLines = 2
149 )
150 },
151 onClick = onClick,
152 )
153 }
154
155 @Preview
156 @Composable
SignInOptionsChipPreviewnull157 fun SignInOptionsChipPreview() {
158 SignInOptionsChip({})
159 }
160
161 @Composable
ContinueChipnull162 fun ContinueChip(onClick: () -> Unit) {
163 CredentialsScreenChip(
164 onClick = onClick,
165 primaryText = {
166 WearButtonText(
167 text = stringResource(R.string.dialog_continue_button),
168 textAlign = TextAlign.Center,
169 color = WearMaterialTheme.colors.surface,
170 )
171 },
172 colors = ChipDefaults.primaryChipColors(),
173 )
174 }
175
176 @Preview
177 @Composable
ContinueChipPreviewnull178 fun ContinueChipPreview() {
179 ContinueChip({})
180 }
181
182 @Composable
DismissChipnull183 fun DismissChip(onClick: () -> Unit) {
184 CredentialsScreenChip(
185 primaryText = {
186 WearButtonText(
187 text = stringResource(R.string.dialog_dismiss_button),
188 textAlign = TextAlign.Center,
189 maxLines = 2
190 )
191 },
192 onClick = onClick,
193 )
194 }
195 @Composable
LockedProviderChipnull196 fun LockedProviderChip(
197 authenticationEntryInfo: AuthenticationEntryInfo,
198 secondaryMaxLines: Int = 1,
199 onClick: () -> Unit,
200 ) {
201 val secondaryLabel = stringResource(
202 if (authenticationEntryInfo.isUnlockedAndEmpty)
203 R.string.locked_credential_entry_label_subtext_no_sign_in
204 else R.string.locked_credential_entry_label_subtext_tap_to_unlock
205 )
206
207 CredentialsScreenChip(
208 primaryText = {
209 WearButtonText(
210 text = authenticationEntryInfo.title,
211 textAlign = TextAlign.Start,
212 maxLines = 2,
213 )
214 },
215 icon = authenticationEntryInfo.icon,
216 secondaryText = {
217 WearSecondaryLabel(
218 text = secondaryLabel,
219 color = WearMaterialTheme.colors.onSurfaceVariant,
220 maxLines = secondaryMaxLines
221 )
222 },
223 isAuthenticationEntryLocked = !authenticationEntryInfo.isUnlockedAndEmpty,
224 onClick = onClick,
225 )
226 }
227
228 @Preview
229 @Composable
DismissChipPreviewnull230 fun DismissChipPreview() {
231 DismissChip({})
232 }
233
234