[CredManUI] Make all bottom sheet pages scrollable.

Test: manual
Bug: 271163212
Change-Id: I4d234fb60f99a4b041509e9bf3570b65424a7e3f
This commit is contained in:
Helen Qin
2023-02-28 22:47:19 +00:00
parent e56fc10af8
commit cd54c345df
4 changed files with 372 additions and 373 deletions

View File

@@ -16,11 +16,13 @@
package com.android.credentialmanager.common.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
@@ -40,7 +42,8 @@ import androidx.compose.ui.unit.dp
fun SheetContainerCard(
topAppBar: (@Composable () -> Unit)? = null,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit,
contentVerticalArrangement: Arrangement.Vertical = Arrangement.Top,
content: LazyListScope.() -> Unit,
) {
Card(
modifier = modifier.fillMaxWidth().wrapContentHeight(),
@@ -54,7 +57,7 @@ fun SheetContainerCard(
if (topAppBar != null) {
topAppBar()
}
Column(
LazyColumn(
modifier = Modifier.padding(
start = 24.dp,
end = 24.dp,
@@ -63,6 +66,7 @@ fun SheetContainerCard(
).fillMaxWidth().wrapContentHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
content = content,
verticalArrangement = contentVerticalArrangement,
)
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.credentialmanager.common.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
@Composable
fun EntryListColumn(content: LazyListScope.() -> Unit) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp),
content = content,
)
}

View File

@@ -8,11 +8,12 @@ import androidx.activity.result.IntentSenderRequest
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
@@ -23,7 +24,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
@@ -43,7 +43,6 @@ import com.android.credentialmanager.common.ui.ConfirmButton
import com.android.credentialmanager.common.ui.CredentialContainerCard
import com.android.credentialmanager.common.ui.CtaButtonRow
import com.android.credentialmanager.common.ui.Entry
import com.android.credentialmanager.common.ui.EntryListColumn
import com.android.credentialmanager.common.ui.HeadlineIcon
import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.ModalBottomSheet
@@ -157,53 +156,67 @@ fun PasskeyIntroCard(
onLearnMore: () -> Unit,
) {
SheetContainerCard {
val onboardingImageResource = remember {
mutableStateOf(R.drawable.ic_passkeys_onboarding)
item {
val onboardingImageResource = remember {
mutableStateOf(R.drawable.ic_passkeys_onboarding)
}
if (isSystemInDarkTheme()) {
onboardingImageResource.value = R.drawable.ic_passkeys_onboarding_dark
} else {
onboardingImageResource.value = R.drawable.ic_passkeys_onboarding
}
Row(
modifier = Modifier.wrapContentHeight().fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
) {
Image(
painter = painterResource(onboardingImageResource.value),
contentDescription = null,
modifier = Modifier.size(316.dp, 168.dp)
)
}
}
if (isSystemInDarkTheme()) {
onboardingImageResource.value = R.drawable.ic_passkeys_onboarding_dark
} else {
onboardingImageResource.value = R.drawable.ic_passkeys_onboarding
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item { HeadlineText(text = stringResource(R.string.passkey_creation_intro_title)) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_password),
text = stringResource(R.string.passkey_creation_intro_body_password),
)
}
Image(
painter = painterResource(onboardingImageResource.value),
contentDescription = null,
modifier = Modifier
.align(alignment = Alignment.CenterHorizontally).size(316.dp, 168.dp)
)
Divider(thickness = 16.dp, color = Color.Transparent)
HeadlineText(text = stringResource(R.string.passkey_creation_intro_title))
Divider(thickness = 16.dp, color = Color.Transparent)
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_password),
text = stringResource(R.string.passkey_creation_intro_body_password),
)
Divider(thickness = 16.dp, color = Color.Transparent)
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_fingerprint),
text = stringResource(R.string.passkey_creation_intro_body_fingerprint),
)
Divider(thickness = 16.dp, color = Color.Transparent)
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_device),
text = stringResource(R.string.passkey_creation_intro_body_device),
)
Divider(thickness = 24.dp, color = Color.Transparent)
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_fingerprint),
text = stringResource(R.string.passkey_creation_intro_body_fingerprint),
)
}
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
PasskeyBenefitRow(
leadingIconPainter = painterResource(R.drawable.ic_passkeys_onboarding_device),
text = stringResource(R.string.passkey_creation_intro_body_device),
)
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.string_learn_more),
onClick = onLearnMore
)
},
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
},
)
item {
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.string_learn_more),
onClick = onLearnMore
)
},
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
},
)
}
}
}
@@ -218,30 +231,32 @@ fun ProviderSelectionCard(
onMoreOptionsSelected: () -> Unit,
) {
SheetContainerCard {
HeadlineIcon(bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap())
Divider(thickness = 16.dp, color = Color.Transparent)
HeadlineText(
text = stringResource(
R.string.choose_provider_title,
when (requestDisplayInfo.type) {
CredentialType.PASSKEY ->
stringResource(R.string.passkeys)
CredentialType.PASSWORD ->
stringResource(R.string.passwords)
CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
}
item { HeadlineIcon(bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
HeadlineText(
text = stringResource(
R.string.choose_provider_title,
when (requestDisplayInfo.type) {
CredentialType.PASSKEY ->
stringResource(R.string.passkeys)
CredentialType.PASSWORD ->
stringResource(R.string.passwords)
CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
}
)
)
)
Divider(thickness = 24.dp, color = Color.Transparent)
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
BodyMediumText(text = stringResource(R.string.choose_provider_body))
Divider(thickness = 16.dp, color = Color.Transparent)
CredentialContainerCard {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
sortedCreateOptionsPairs.forEach { entry ->
item {
item { BodyMediumText(text = stringResource(R.string.choose_provider_body)) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
Column(
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
sortedCreateOptionsPairs.forEach { entry ->
MoreOptionsInfoRow(
requestDisplayInfo = requestDisplayInfo,
providerInfo = entry.second,
@@ -256,8 +271,6 @@ fun ProviderSelectionCard(
}
)
}
}
item {
MoreOptionsDisabledProvidersRow(
disabledProviders = disabledProviderList,
onDisabledProvidersSelected = onDisabledProvidersSelected,
@@ -266,15 +279,17 @@ fun ProviderSelectionCard(
}
}
if (hasRemoteEntry) {
Divider(thickness = 24.dp, color = Color.Transparent)
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.string_more_options),
onMoreOptionsSelected
)
}
)
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.string_more_options),
onMoreOptionsSelected
)
}
)
}
}
}
}
@@ -310,14 +325,14 @@ fun MoreOptionsSelectionCard(
else onBackCreationSelectionButtonSelected,
)
}) {
Divider(thickness = 16.dp, color = Color.Transparent)
CredentialContainerCard {
EntryListColumn {
// Only in the flows with default provider(not first time use) we can show the
// createOptions here, or they will be shown on ProviderSelectionCard
if (hasDefaultProvider) {
sortedCreateOptionsPairs.forEach { entry ->
item {
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
// Only in the flows with default provider(not first time use) we can show the
// createOptions here, or they will be shown on ProviderSelectionCard
if (hasDefaultProvider) {
sortedCreateOptionsPairs.forEach { entry ->
MoreOptionsInfoRow(
requestDisplayInfo = requestDisplayInfo,
providerInfo = entry.second,
@@ -329,26 +344,23 @@ fun MoreOptionsSelectionCard(
entry.first
)
)
})
}
)
}
}
item {
MoreOptionsDisabledProvidersRow(
disabledProviders = disabledProviderList,
onDisabledProvidersSelected =
onDisabledProvidersSelected,
)
}
}
enabledProviderList.forEach {
if (it.remoteEntry != null) {
item {
enabledProviderList.forEach {
if (it.remoteEntry != null) {
RemoteEntryRow(
remoteInfo = it.remoteEntry!!,
onRemoteEntrySelected = onRemoteEntrySelected,
)
return@forEach
}
return@forEach
}
}
}
@@ -363,30 +375,34 @@ fun MoreOptionsRowIntroCard(
onUseOnceSelected: () -> Unit,
) {
SheetContainerCard {
HeadlineIcon(imageVector = Icons.Outlined.NewReleases)
Divider(thickness = 24.dp, color = Color.Transparent)
HeadlineText(
text = stringResource(
R.string.use_provider_for_all_title,
providerInfo.displayName
item { HeadlineIcon(imageVector = Icons.Outlined.NewReleases) }
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
HeadlineText(
text = stringResource(
R.string.use_provider_for_all_title,
providerInfo.displayName
)
)
)
Divider(thickness = 24.dp, color = Color.Transparent)
BodyMediumText(text = stringResource(R.string.use_provider_for_all_description))
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.use_once),
onClick = onUseOnceSelected
)
},
rightButton = {
ConfirmButton(
stringResource(R.string.set_as_default),
onClick = onChangeDefaultSelected
)
},
)
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item { BodyMediumText(text = stringResource(R.string.use_provider_for_all_description)) }
item {
CtaButtonRow(
leftButton = {
ActionButton(
stringResource(R.string.use_once),
onClick = onUseOnceSelected
)
},
rightButton = {
ConfirmButton(
stringResource(R.string.set_as_default),
onClick = onChangeDefaultSelected
)
},
)
}
}
}
@@ -402,38 +418,44 @@ fun CreationSelectionCard(
hasDefaultProvider: Boolean,
) {
SheetContainerCard {
HeadlineIcon(
bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
tint = Color.Unspecified,
)
Divider(thickness = 4.dp, color = Color.Transparent)
LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName)
Divider(thickness = 16.dp, color = Color.Transparent)
HeadlineText(
text = when (requestDisplayInfo.type) {
CredentialType.PASSKEY -> stringResource(
R.string.choose_create_option_passkey_title,
requestDisplayInfo.appName
)
CredentialType.PASSWORD -> stringResource(
R.string.choose_create_option_password_title,
requestDisplayInfo.appName
)
CredentialType.UNKNOWN -> stringResource(
R.string.choose_create_option_sign_in_title,
requestDisplayInfo.appName
)
}
)
Divider(thickness = 24.dp, color = Color.Transparent)
CredentialContainerCard {
PrimaryCreateOptionRow(
requestDisplayInfo = requestDisplayInfo,
entryInfo = createOptionInfo,
onOptionSelected = onOptionSelected
item {
HeadlineIcon(
bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
tint = Color.Unspecified,
)
}
Divider(thickness = 24.dp, color = Color.Transparent)
item { Divider(thickness = 4.dp, color = Color.Transparent) }
item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item {
HeadlineText(
text = when (requestDisplayInfo.type) {
CredentialType.PASSKEY -> stringResource(
R.string.choose_create_option_passkey_title,
requestDisplayInfo.appName
)
CredentialType.PASSWORD -> stringResource(
R.string.choose_create_option_password_title,
requestDisplayInfo.appName
)
CredentialType.UNKNOWN -> stringResource(
R.string.choose_create_option_sign_in_title,
requestDisplayInfo.appName
)
}
)
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
PrimaryCreateOptionRow(
requestDisplayInfo = requestDisplayInfo,
entryInfo = createOptionInfo,
onOptionSelected = onOptionSelected
)
}
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
var createOptionsSize = 0
var remoteEntry: RemoteInfo? = null
enabledProviderList.forEach { enabledProvider ->
@@ -450,29 +472,33 @@ fun CreationSelectionCard(
} else {
createOptionsSize > 1 || remoteEntry != null
}
CtaButtonRow(
leftButton = if (shouldShowMoreOptionsButton) {
{
ActionButton(
stringResource(R.string.string_more_options),
onMoreOptionsSelected
item {
CtaButtonRow(
leftButton = if (shouldShowMoreOptionsButton) {
{
ActionButton(
stringResource(R.string.string_more_options),
onMoreOptionsSelected
)
}
} else null,
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
}
} else null,
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
},
)
if (createOptionInfo.footerDescription != null) {
Divider(
thickness = 1.dp,
color = MaterialTheme.colorScheme.outlineVariant,
modifier = Modifier.padding(vertical = 16.dp)
},
)
BodySmallText(text = createOptionInfo.footerDescription)
}
if (createOptionInfo.footerDescription != null) {
item {
Divider(
thickness = 1.dp,
color = MaterialTheme.colorScheme.outlineVariant,
modifier = Modifier.padding(vertical = 16.dp)
)
}
item { BodySmallText(text = createOptionInfo.footerDescription) }
}
}
}
@@ -485,29 +511,30 @@ fun ExternalOnlySelectionCard(
onConfirm: () -> Unit,
) {
SheetContainerCard {
HeadlineIcon(painter = painterResource(R.drawable.ic_other_devices))
Divider(thickness = 16.dp, color = Color.Transparent)
HeadlineText(text = stringResource(R.string.create_passkey_in_other_device_title))
Divider(
thickness = 24.dp,
color = Color.Transparent
)
CredentialContainerCard {
PrimaryCreateOptionRow(
requestDisplayInfo = requestDisplayInfo,
entryInfo = activeRemoteEntry,
onOptionSelected = onOptionSelected
item { HeadlineIcon(painter = painterResource(R.drawable.ic_other_devices)) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
item { HeadlineText(text = stringResource(R.string.create_passkey_in_other_device_title)) }
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
PrimaryCreateOptionRow(
requestDisplayInfo = requestDisplayInfo,
entryInfo = activeRemoteEntry,
onOptionSelected = onOptionSelected
)
}
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CtaButtonRow(
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
},
)
}
Divider(thickness = 24.dp, color = Color.Transparent)
CtaButtonRow(
rightButton = {
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
},
)
}
}
@@ -515,40 +542,38 @@ fun ExternalOnlySelectionCard(
fun MoreAboutPasskeysIntroCard(
onBackPasskeyIntroButtonSelected: () -> Unit,
) {
SheetContainerCard(topAppBar = {
MoreOptionTopAppBar(
text = stringResource(R.string.more_about_passkeys_title),
onNavigationIconClicked = onBackPasskeyIntroButtonSelected,
)
}) {
LazyColumn(
modifier = Modifier.fillMaxWidth().wrapContentHeight(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.passwordless_technology_title)
)
BodyMediumText(text = stringResource(R.string.passwordless_technology_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.public_key_cryptography_title)
)
BodyMediumText(text = stringResource(R.string.public_key_cryptography_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.improved_account_security_title)
)
BodyMediumText(text = stringResource(R.string.improved_account_security_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.seamless_transition_title)
)
BodyMediumText(text = stringResource(R.string.seamless_transition_detail))
}
SheetContainerCard(
topAppBar = {
MoreOptionTopAppBar(
text = stringResource(R.string.more_about_passkeys_title),
onNavigationIconClicked = onBackPasskeyIntroButtonSelected,
)
},
contentVerticalArrangement = Arrangement.spacedBy(8.dp)
) {
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.passwordless_technology_title)
)
BodyMediumText(text = stringResource(R.string.passwordless_technology_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.public_key_cryptography_title)
)
BodyMediumText(text = stringResource(R.string.public_key_cryptography_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.improved_account_security_title)
)
BodyMediumText(text = stringResource(R.string.improved_account_security_detail))
}
item {
MoreAboutPasskeySectionHeader(
text = stringResource(R.string.seamless_transition_title)
)
BodyMediumText(text = stringResource(R.string.seamless_transition_detail))
}
}
}

View File

@@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Divider
import androidx.compose.material3.TextButton
@@ -141,70 +140,72 @@ fun PrimarySelectionCard(
providerDisplayInfo.sortedUserNameToCredentialEntryList
val authenticationEntryList = providerDisplayInfo.authenticationEntryList
SheetContainerCard {
HeadlineText(
text = stringResource(
if (sortedUserNameToCredentialEntryList
.size == 1 && authenticationEntryList.isEmpty()
) {
if (sortedUserNameToCredentialEntryList.first()
.sortedCredentialEntryList.first().credentialType
== CredentialType.PASSKEY
) R.string.get_dialog_title_use_passkey_for
else R.string.get_dialog_title_use_sign_in_for
} else if (
sortedUserNameToCredentialEntryList
.isEmpty() && authenticationEntryList.size == 1
) {
R.string.get_dialog_title_use_sign_in_for
} else R.string.get_dialog_title_choose_sign_in_for,
requestDisplayInfo.appName
),
)
Divider(thickness = 24.dp, color = Color.Transparent)
CredentialContainerCard {
val usernameForCredentialSize = sortedUserNameToCredentialEntryList.size
val authenticationEntrySize = authenticationEntryList.size
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
// Show max 4 entries in this primary page
if (usernameForCredentialSize + authenticationEntrySize <= 4) {
items(sortedUserNameToCredentialEntryList) {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
}
items(authenticationEntryList) {
AuthenticationEntryRow(
authenticationEntryInfo = it,
onEntrySelected = onEntrySelected,
)
}
} else if (usernameForCredentialSize < 4) {
items(sortedUserNameToCredentialEntryList) {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
}
items(authenticationEntryList.take(4 - usernameForCredentialSize)) {
AuthenticationEntryRow(
authenticationEntryInfo = it,
onEntrySelected = onEntrySelected,
)
}
} else {
items(sortedUserNameToCredentialEntryList.take(4)) {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
item {
HeadlineText(
text = stringResource(
if (sortedUserNameToCredentialEntryList
.size == 1 && authenticationEntryList.isEmpty()
) {
if (sortedUserNameToCredentialEntryList.first()
.sortedCredentialEntryList.first().credentialType
== CredentialType.PASSKEY
) R.string.get_dialog_title_use_passkey_for
else R.string.get_dialog_title_use_sign_in_for
} else if (
sortedUserNameToCredentialEntryList
.isEmpty() && authenticationEntryList.size == 1
) {
R.string.get_dialog_title_use_sign_in_for
} else R.string.get_dialog_title_choose_sign_in_for,
requestDisplayInfo.appName
),
)
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CredentialContainerCard {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
val usernameForCredentialSize = sortedUserNameToCredentialEntryList.size
val authenticationEntrySize = authenticationEntryList.size
// Show max 4 entries in this primary page
if (usernameForCredentialSize + authenticationEntrySize <= 4) {
sortedUserNameToCredentialEntryList.forEach {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
}
authenticationEntryList.forEach {
AuthenticationEntryRow(
authenticationEntryInfo = it,
onEntrySelected = onEntrySelected,
)
}
} else if (usernameForCredentialSize < 4) {
sortedUserNameToCredentialEntryList.forEach {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
}
authenticationEntryList.take(4 - usernameForCredentialSize).forEach {
AuthenticationEntryRow(
authenticationEntryInfo = it,
onEntrySelected = onEntrySelected,
)
}
} else {
sortedUserNameToCredentialEntryList.take(4).forEach {
CredentialEntryRow(
credentialEntryInfo = it.sortedCredentialEntryList.first(),
onEntrySelected = onEntrySelected,
)
}
}
}
}
}
Divider(thickness = 24.dp, color = Color.Transparent)
item { Divider(thickness = 24.dp, color = Color.Transparent) }
var totalEntriesCount = sortedUserNameToCredentialEntryList
.flatMap { it.sortedCredentialEntryList }.size + authenticationEntryList
.size + providerInfoList.flatMap { it.actionEntryList }.size
@@ -212,24 +213,26 @@ fun PrimarySelectionCard(
// Row horizontalArrangement differs on only one actionButton(should place on most
// left)/only one confirmButton(should place on most right)/two buttons exist the same
// time(should be one on the left, one on the right)
CtaButtonRow(
leftButton = if (totalEntriesCount > 1) {
{
ActionButton(
stringResource(R.string.get_dialog_use_saved_passkey_for),
onMoreOptionSelected
)
}
} else null,
rightButton = if (activeEntry != null) { // Only one sign-in options exist
{
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
}
} else null,
)
item {
CtaButtonRow(
leftButton = if (totalEntriesCount > 1) {
{
ActionButton(
stringResource(R.string.get_dialog_use_saved_passkey_for),
onMoreOptionSelected
)
}
} else null,
rightButton = if (activeEntry != null) { // Only one sign-in options exist
{
ConfirmButton(
stringResource(R.string.string_continue),
onClick = onConfirm
)
}
} else null,
)
}
}
}
@@ -252,48 +255,46 @@ fun AllSignInOptionCard(
onNavigationIconClicked = if (isNoAccount) onCancel else onBackButtonClicked,
)
}) {
LazyColumn {
// For username
items(sortedUserNameToCredentialEntryList) { item ->
PerUserNameCredentials(
perUserNameCredentialEntryList = item,
// For username
items(sortedUserNameToCredentialEntryList) { item ->
PerUserNameCredentials(
perUserNameCredentialEntryList = item,
onEntrySelected = onEntrySelected,
)
}
// Locked password manager
if (authenticationEntryList.isNotEmpty()) {
item {
LockedCredentials(
authenticationEntryList = authenticationEntryList,
onEntrySelected = onEntrySelected,
)
}
// Locked password manager
if (authenticationEntryList.isNotEmpty()) {
item {
LockedCredentials(
authenticationEntryList = authenticationEntryList,
onEntrySelected = onEntrySelected,
)
}
}
// From another device
val remoteEntry = providerDisplayInfo.remoteEntry
if (remoteEntry != null) {
item {
RemoteEntryCard(
remoteEntry = remoteEntry,
onEntrySelected = onEntrySelected,
)
}
}
}
// From another device
val remoteEntry = providerDisplayInfo.remoteEntry
if (remoteEntry != null) {
item {
Divider(
thickness = 1.dp,
color = Color.LightGray,
modifier = Modifier.padding(top = 16.dp)
)
}
// Manage sign-ins (action chips)
item {
ActionChips(
providerInfoList = providerInfoList,
onEntrySelected = onEntrySelected
RemoteEntryCard(
remoteEntry = remoteEntry,
onEntrySelected = onEntrySelected,
)
}
}
item {
Divider(
thickness = 1.dp,
color = Color.LightGray,
modifier = Modifier.padding(top = 16.dp)
)
}
// Manage sign-ins (action chips)
item {
ActionChips(
providerInfoList = providerInfoList,
onEntrySelected = onEntrySelected
)
}
}
}