Merge "[CredManUI] Make all bottom sheet pages scrollable." into udc-dev am: cc21455e00
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21655427 Change-Id: I2fdee8a7f029c3960e42ef2b24b0474cca4cafe1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user