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