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.compose.foundation.layout.Row
19 import androidx.compose.material3.Icon
20 import android.graphics.drawable.Drawable
21 import androidx.compose.foundation.layout.BoxScope
22 import androidx.compose.foundation.layout.RowScope
23 import androidx.compose.foundation.layout.size
24 import androidx.compose.foundation.layout.fillMaxWidth
25 import androidx.compose.runtime.Composable
26 import androidx.compose.ui.Modifier
27 import androidx.compose.ui.res.stringResource
28 import androidx.compose.ui.tooling.preview.Preview
29 import androidx.compose.ui.unit.dp
30 import androidx.wear.compose.material.Chip
31 import androidx.core.graphics.drawable.toBitmap
32 import androidx.wear.compose.material.ChipColors
33 import androidx.compose.ui.graphics.asImageBitmap
34 import androidx.compose.ui.graphics.Color
35 import androidx.compose.ui.text.style.TextAlign
36 import androidx.wear.compose.material.ChipDefaults
37 import com.android.credentialmanager.R
38 import com.android.credentialmanager.common.ui.components.WearButtonText
39 import com.android.credentialmanager.common.ui.components.WearSecondaryLabel
40 import com.android.credentialmanager.model.get.AuthenticationEntryInfo
41
42 /* Used as credential suggestion or user action chip. */
43 @Composable
CredentialsScreenChipnull44 fun CredentialsScreenChip(
45 label: String,
46 onClick: () -> Unit,
47 secondaryLabel: String? = null,
48 icon: Drawable? = null,
49 isAuthenticationEntryLocked: Boolean = false,
50 textAlign: TextAlign = TextAlign.Center,
51 modifier: Modifier = Modifier,
52 colors: ChipColors = ChipDefaults.secondaryChipColors()
53 ) {
54 return CredentialsScreenChip(
55 onClick,
56 text = {
57 WearButtonText(
58 text = label,
59 textAlign = textAlign,
60 maxLines = if (secondaryLabel != null) 1 else 2
61 )
62 },
63 secondaryLabel,
64 icon,
65 isAuthenticationEntryLocked,
66 modifier,
67 colors
68 )
69 }
70
71
72
73 /* Used as credential suggestion or user action chip. */
74 @Composable
CredentialsScreenChipnull75 fun CredentialsScreenChip(
76 onClick: () -> Unit,
77 text: @Composable () -> Unit,
78 secondaryLabel: String? = null,
79 icon: Drawable? = null,
80 isAuthenticationEntryLocked: Boolean = false,
81 modifier: Modifier = Modifier,
82 colors: ChipColors = ChipDefaults.primaryChipColors(),
83 ) {
84 val labelParam: (@Composable RowScope.() -> Unit) =
85 {
86 text()
87 }
88
89 val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
90 secondaryLabel?.let {
91 {
92 Row {
93 WearSecondaryLabel(
94 text = secondaryLabel,
95 )
96
97 if (isAuthenticationEntryLocked)
98 // TODO(b/324465527) change this to lock icon and correct size once figma mocks are
99 // updated
100 Icon(
101 bitmap = checkNotNull(icon?.toBitmap()?.asImageBitmap()),
102 // Decorative purpose only.
103 contentDescription = null,
104 modifier = Modifier.size(10.dp),
105 tint = Color.Unspecified
106 )
107 }
108 }
109 }
110
111 val iconParam: (@Composable BoxScope.() -> Unit)? =
112 icon?.toBitmap()?.asImageBitmap()?.let {
113 {
114 Icon(
115 bitmap = it,
116 // Decorative purpose only.
117 contentDescription = null,
118 modifier = Modifier.size(24.dp),
119 tint = Color.Unspecified
120 )
121 }
122 }
123
124 Chip(
125 label = labelParam,
126 onClick = onClick,
127 modifier = modifier.fillMaxWidth(),
128 secondaryLabel = secondaryLabelParam,
129 icon = iconParam,
130 colors = colors,
131 enabled = true,
132 )
133 }
134
135 @Preview
136 @Composable
CredentialsScreenChipPreviewnull137 fun CredentialsScreenChipPreview() {
138 CredentialsScreenChip(
139 label = "Elisa Beckett",
140 onClick = { },
141 secondaryLabel = "beckett_bakery@gmail.com",
142 icon = null,
143 )
144 }
145
146 @Composable
SignInOptionsChipnull147 fun SignInOptionsChip(onClick: () -> Unit) {
148 CredentialsScreenChip(
149 label = stringResource(R.string.dialog_sign_in_options_button),
150 textAlign = TextAlign.Start,
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 text = {
166 WearButtonText(
167 text = stringResource(R.string.dialog_continue_button),
168 textAlign = TextAlign.Center,
169 )
170 },
171 colors = ChipDefaults.primaryChipColors(),
172 )
173 }
174
175 @Preview
176 @Composable
ContinueChipPreviewnull177 fun ContinueChipPreview() {
178 ContinueChip({})
179 }
180
181 @Composable
DismissChipnull182 fun DismissChip(onClick: () -> Unit) {
183 CredentialsScreenChip(
184 label = stringResource(R.string.dialog_dismiss_button),
185 onClick = onClick,
186 )
187 }
188 @Composable
LockedProviderChipnull189 fun LockedProviderChip(
190 authenticationEntryInfo: AuthenticationEntryInfo,
191 onClick: () -> Unit
192 ) {
193 val secondaryLabel = stringResource(
194 if (authenticationEntryInfo.isUnlockedAndEmpty)
195 R.string.locked_credential_entry_label_subtext_no_sign_in
196 else R.string.locked_credential_entry_label_subtext_tap_to_unlock
197 )
198
199 CredentialsScreenChip(
200 label = authenticationEntryInfo.title,
201 icon = authenticationEntryInfo.icon,
202 secondaryLabel = secondaryLabel,
203 textAlign = TextAlign.Start,
204 isAuthenticationEntryLocked = !authenticationEntryInfo.isUnlockedAndEmpty,
205 onClick = onClick,
206 )
207 }
208
209 @Preview
210 @Composable
DismissChipPreviewnull211 fun DismissChipPreview() {
212 DismissChip({})
213 }
214
215