Merge "UX impovements: removed navigation & smoothen dialog transition."

This commit is contained in:
Helen Qin
2022-09-23 17:45:40 +00:00
committed by Android (Google) Code Review
10 changed files with 220 additions and 357 deletions

View File

@@ -26,7 +26,6 @@ android_app {
"androidx.lifecycle_lifecycle-livedata",
"androidx.lifecycle_lifecycle-runtime-ktx",
"androidx.lifecycle_lifecycle-viewmodel-compose",
"androidx.navigation_navigation-compose",
"androidx.recyclerview_recyclerview",
],

View File

@@ -2,28 +2,86 @@ package com.android.credentialmanager
import android.content.Context
import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.createflow.CreatePasskeyUiState
import com.android.credentialmanager.createflow.CreateScreenState
import com.android.credentialmanager.createflow.ProviderInfo
import com.android.credentialmanager.createflow.ProviderList
import com.android.credentialmanager.getflow.CredentialOptionInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
// Consider repo per screen, similar to view model?
class CredentialManagerRepo(
private val context: Context
) {
fun getCredentialProviderList(): List<com.android.credentialmanager.getflow.ProviderInfo> {
private fun getCredentialProviderList():
List<com.android.credentialmanager.getflow.ProviderInfo> {
return listOf(
com.android.credentialmanager.getflow.ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Google Password Manager",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@gmail.com",
id = "id-1",
),
CredentialOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett Work",
subtitle = "elisa.beckett.work@google.com",
id = "id-2",
),
)
),
com.android.credentialmanager.getflow.ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Lastpass",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@lastpass.com",
id = "id-1",
),
)
),
com.android.credentialmanager.getflow.ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Dashlane",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@dashlane.com",
id = "id-1",
),
)
),
)
}
private fun createCredentialProviderList(): List<ProviderInfo> {
return listOf(
com.android.credentialmanager.getflow.ProviderInfo(
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Google Password Manager",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@gmail.com",
id = "id-1",
),
CredentialOptionInfo(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett Work",
subtitle = "elisa.beckett.work@google.com",
@@ -31,13 +89,13 @@ class CredentialManagerRepo(
),
)
),
com.android.credentialmanager.getflow.ProviderInfo(
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Lastpass",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@lastpass.com",
@@ -45,13 +103,13 @@ class CredentialManagerRepo(
),
)
),
com.android.credentialmanager.getflow.ProviderInfo(
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Dashlane",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = listOf(
CredentialOptionInfo(
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@dashlane.com",
@@ -62,58 +120,20 @@ class CredentialManagerRepo(
)
}
fun createCredentialProviderList(): ProviderList {
return ProviderList(
listOf(
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Google Password Manager",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@gmail.com",
id = "id-1",
),
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett Work",
subtitle = "elisa.beckett.work@google.com",
id = "id-2",
),
)
),
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Lastpass",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@lastpass.com",
id = "id-1",
),
)
),
ProviderInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = "Dashlane",
appDomainName = "tribank.us",
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
createOptions = listOf(
CreateOptionInfo(
icon = context.getDrawable(R.drawable.ic_passkey)!!,
title = "Elisa Backett",
subtitle = "elisa.beckett@dashlane.com",
id = "id-1",
),
)
),
)
fun getCredentialInitialUiState(): GetCredentialUiState {
val providerList = getCredentialProviderList()
return GetCredentialUiState(
providerList,
GetScreenState.CREDENTIAL_SELECTION,
providerList.first()
)
}
fun createPasskeyInitialUiState(): CreatePasskeyUiState {
val providerList = createCredentialProviderList()
return CreatePasskeyUiState(
providers = providerList,
currentScreenState = CreateScreenState.PASSKEY_INTRO,
)
}

View File

@@ -1,18 +1,14 @@
package com.android.credentialmanager
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import com.android.credentialmanager.createflow.CreatePasskeyViewModel
import com.android.credentialmanager.createflow.createPasskeyGraph
import com.android.credentialmanager.getflow.GetCredentialViewModel
import com.android.credentialmanager.getflow.getCredentialsGraph
import com.android.credentialmanager.common.DialogType
import com.android.credentialmanager.createflow.CreatePasskeyScreen
import com.android.credentialmanager.getflow.GetCredentialScreen
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
@ExperimentalMaterialApi
@@ -22,42 +18,35 @@ class CredentialSelectorActivity : ComponentActivity() {
CredentialManagerRepo.setup(this)
val startDestination = intent.extras?.getString(
"start_destination",
"getCredentials"
) ?: "getCredentials"
"CREATE_PASSKEY"
) ?: "CREATE_PASSKEY"
setContent {
CredentialSelectorTheme {
AppNavHost(
startDestination = startDestination,
onCancel = {this.finish()}
)
CredentialManagerBottomSheet(startDestination)
}
}
}
@ExperimentalMaterialApi
@Composable
fun AppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String,
onCancel: () -> Unit,
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
createPasskeyGraph(
navController = navController,
viewModel = CreatePasskeyViewModel(CredentialManagerRepo.repo),
onCancel = onCancel
)
getCredentialsGraph(
navController = navController,
viewModel = GetCredentialViewModel(CredentialManagerRepo.repo),
onCancel = onCancel
)
fun CredentialManagerBottomSheet(operationType: String) {
val dialogType = DialogType.toDialogType(operationType)
when (dialogType) {
DialogType.CREATE_PASSKEY -> {
CreatePasskeyScreen(cancelActivity = onCancel)
}
DialogType.GET_CREDENTIALS -> {
GetCredentialScreen(cancelActivity = onCancel)
}
else -> {
Log.w("AccountSelector", "Unknown type, not rendering any UI")
this.finish()
}
}
}
private val onCancel = {
this@CredentialSelectorActivity.finish()
}
}

View File

@@ -0,0 +1,18 @@
package com.android.credentialmanager.common
enum class DialogType {
CREATE_PASSKEY,
GET_CREDENTIALS,
CREATE_PASSWORD,
UNKNOWN;
companion object {
fun toDialogType(value: String): DialogType {
return try {
valueOf(value)
} catch (e: IllegalArgumentException) {
UNKNOWN
}
}
}
}

View File

@@ -10,13 +10,16 @@ data class ProviderInfo(
val createOptions: List<CreateOptionInfo>,
)
data class ProviderList(
val providers: List<ProviderInfo>,
)
data class CreateOptionInfo(
val icon: Drawable,
val title: String,
val subtitle: String,
val id: String,
)
/** The name of the current screen. */
enum class CreateScreenState {
PASSKEY_INTRO,
PROVIDER_SELECTION,
CREATION_OPTION_SELECTION,
}

View File

@@ -25,22 +25,15 @@ import androidx.compose.material.Text
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavType
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import androidx.navigation.navigation
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.credentialmanager.R
import com.android.credentialmanager.ui.theme.Grey100
import com.android.credentialmanager.ui.theme.Shapes
@@ -49,54 +42,11 @@ import com.android.credentialmanager.ui.theme.lightBackgroundColor
import com.android.credentialmanager.ui.theme.lightColorAccentSecondary
import com.android.credentialmanager.ui.theme.lightSurface1
@ExperimentalMaterialApi
fun NavGraphBuilder.createPasskeyGraph(
navController: NavController,
viewModel: CreatePasskeyViewModel,
onCancel: () -> Unit,
startDestination: String = "intro", // TODO: get this from view model
) {
navigation(startDestination = startDestination, route = "createPasskey") {
composable("intro") {
CreatePasskeyIntroDialog(
onCancel = onCancel,
onConfirm = {viewModel.onConfirm(navController)}
)
}
composable("providerSelection") {
ProviderSelectionDialog(
providerList = viewModel.uiState.collectAsState().value.providerList,
onProviderSelected = {viewModel.onProviderSelected(it, navController)},
onCancel = onCancel
)
}
composable(
"createCredentialSelection/{providerName}",
arguments = listOf(navArgument("providerName") {type = NavType.StringType})
) {
val arguments = it.arguments
if (arguments == null) {
throw java.lang.IllegalStateException("createCredentialSelection without a provider name")
}
CreationSelectionDialog(
providerInfo = viewModel.getProviderInfoByName(arguments.getString("providerName")!!),
onOptionSelected = {viewModel.onCreateOptionSelected(it)},
onCancel = onCancel,
multiProvider = viewModel.uiState.collectAsState().value.providerList.providers.size > 1,
onMoreOptionSelected = {viewModel.onMoreOptionSelected(navController)},
)
}
}
}
/**
* BEGIN INTRO CONTENT
*/
@ExperimentalMaterialApi
@Composable
fun CreatePasskeyIntroDialog(
onCancel: () -> Unit = {},
onConfirm: () -> Unit = {},
fun CreatePasskeyScreen(
viewModel: CreatePasskeyViewModel = viewModel(),
cancelActivity: () -> Unit,
) {
val state = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
@@ -105,9 +55,25 @@ fun CreatePasskeyIntroDialog(
ModalBottomSheetLayout(
sheetState = state,
sheetContent = {
ConfirmationCard(
onCancel = onCancel, onConfirm = onConfirm
)
val uiState = viewModel.uiState
when (uiState.currentScreenState) {
CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
onConfirm = {viewModel.onConfirmIntro()},
onCancel = cancelActivity,
)
CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
providerList = uiState.providers,
onCancel = cancelActivity,
onProviderSelected = {viewModel.onProviderSelected(it)}
)
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
providerInfo = uiState.selectedProvider!!,
onOptionSelected = {viewModel.onCreateOptionSelected(it)},
onCancel = cancelActivity,
multiProvider = uiState.providers.size > 1,
onMoreOptionSelected = {viewModel.onMoreOptionSelected()}
)
}
},
scrimColor = Color.Transparent,
sheetShape = Shapes.medium,
@@ -115,7 +81,7 @@ fun CreatePasskeyIntroDialog(
LaunchedEffect(state.currentValue) {
when (state.currentValue) {
ModalBottomSheetValue.Hidden -> {
onCancel()
cancelActivity()
}
}
}
@@ -178,49 +144,10 @@ fun ConfirmationCard(
}
}
/**
* END INTRO CONTENT
*/
/**
* BEGIN PROVIDER SELECTION CONTENT
*/
@ExperimentalMaterialApi
@Composable
fun ProviderSelectionDialog(
providerList: ProviderList,
onProviderSelected: (String) -> Unit,
onCancel: () -> Unit,
) {
val state = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
skipHalfExpanded = true
)
ModalBottomSheetLayout(
sheetState = state,
sheetContent = {
ProviderSelectionCard(
providerList = providerList,
onCancel = onCancel,
onProviderSelected = onProviderSelected
)
},
scrimColor = Color.Transparent,
sheetShape = Shapes.medium,
) {}
LaunchedEffect(state.currentValue) {
when (state.currentValue) {
ModalBottomSheetValue.Hidden -> {
onCancel()
}
}
}
}
@ExperimentalMaterialApi
@Composable
fun ProviderSelectionCard(
providerList: ProviderList,
providerList: List<ProviderInfo>,
onProviderSelected: (String) -> Unit,
onCancel: () -> Unit
) {
@@ -251,7 +178,7 @@ fun ProviderSelectionCard(
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
providerList.providers.forEach {
providerList.forEach {
item {
ProviderRow(providerInfo = it, onProviderSelected = onProviderSelected)
}
@@ -304,14 +231,6 @@ fun ProviderRow(providerInfo: ProviderInfo, onProviderSelected: (String) -> Unit
}
}
/**
* END PROVIDER SELECTION CONTENT
*/
/**
* BEGIN COMMON COMPONENTS
*/
@Composable
fun CancelButton(text: String, onclick: () -> Unit) {
val colors = ButtonDefaults.buttonColors(
@@ -352,45 +271,6 @@ fun NavigationButton(
}
}
/**
* BEGIN CREATE OPTION SELECTION CONTENT
*/
@ExperimentalMaterialApi
@Composable
fun CreationSelectionDialog(
providerInfo: ProviderInfo,
onOptionSelected: (String) -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionSelected: () -> Unit,
) {
val state = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
skipHalfExpanded = true
)
ModalBottomSheetLayout(
sheetState = state,
sheetContent = {
CreationSelectionCard(
providerInfo = providerInfo,
onCancel = onCancel,
onOptionSelected = onOptionSelected,
multiProvider = multiProvider,
onMoreOptionSelected = onMoreOptionSelected,
)
},
scrimColor = Color.Transparent,
sheetShape = Shapes.medium,
) {}
LaunchedEffect(state.currentValue) {
when (state.currentValue) {
ModalBottomSheetValue.Hidden -> {
onCancel()
}
}
}
}
@ExperimentalMaterialApi
@Composable
fun CreationSelectionCard(
@@ -516,26 +396,3 @@ fun MoreOptionRow(onSelect: () -> Unit) {
)
}
}
/**
* END CREATE OPTION SELECTION CONTENT
*/
/**
* END COMMON COMPONENTS
*/
@ExperimentalMaterialApi
@Preview(showBackground = true)
@Composable
fun CreatePasskeyEntryScreenPreview() {
// val providers = ProviderList(
// listOf(
// ProviderInfo(null),
// ProviderInfo(null, "Dashlane"),
// ProviderInfo(null, "LastPass")
// )
// )
// TatiAccountSelectorTheme {
// ConfirmationCard({}, {})
// }
}

View File

@@ -1,38 +1,45 @@
package com.android.credentialmanager.createflow
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.navigation.NavController
import com.android.credentialmanager.CredentialManagerRepo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
data class CreatePasskeyUiState(
val providerList: ProviderList,
val providers: List<ProviderInfo>,
val currentScreenState: CreateScreenState,
val selectedProvider: ProviderInfo? = null,
)
class CreatePasskeyViewModel(
credManRepo: CredentialManagerRepo
credManRepo: CredentialManagerRepo = CredentialManagerRepo.getInstance()
) : ViewModel() {
private val _uiState = MutableStateFlow(
CreatePasskeyUiState(credManRepo.createCredentialProviderList())
)
val uiState: StateFlow<CreatePasskeyUiState> = _uiState.asStateFlow()
var uiState by mutableStateOf(credManRepo.createPasskeyInitialUiState())
private set
fun onConfirm(navController: NavController) {
if (uiState.value.providerList.providers.size > 1) {
navController.navigate("providerSelection")
} else if (uiState.value.providerList.providers.size == 1) {
onProviderSelected(uiState.value.providerList.providers[0].name, navController)
fun onConfirmIntro() {
if (uiState.providers.size > 1) {
uiState = uiState.copy(
currentScreenState = CreateScreenState.PROVIDER_SELECTION
)
} else if (uiState.providers.size == 1){
uiState = uiState.copy(
currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
selectedProvider = uiState.providers.first()
)
} else {
throw java.lang.IllegalStateException("Empty provider list.")
}
}
fun onProviderSelected(providerName: String, navController: NavController) {
return navController.navigate("createCredentialSelection/$providerName")
fun onProviderSelected(providerName: String) {
uiState = uiState.copy(
currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
selectedProvider = getProviderInfoByName(providerName)
)
}
fun onCreateOptionSelected(createOptionId: String) {
@@ -40,12 +47,12 @@ class CreatePasskeyViewModel(
}
fun getProviderInfoByName(providerName: String): ProviderInfo {
return uiState.value.providerList.providers.single {
return uiState.providers.single {
it.name.equals(providerName)
}
}
fun onMoreOptionSelected(navController: NavController) {
navController.navigate("moreOption")
fun onMoreOptionSelected() {
Log.d("Account Selector", "On more option selected")
}
}

View File

@@ -21,7 +21,6 @@ import androidx.compose.material.Text
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -29,10 +28,7 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import androidx.navigation.navigation
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.credentialmanager.R
import com.android.credentialmanager.createflow.CancelButton
import com.android.credentialmanager.ui.theme.Grey100
@@ -40,37 +36,11 @@ import com.android.credentialmanager.ui.theme.Shapes
import com.android.credentialmanager.ui.theme.Typography
import com.android.credentialmanager.ui.theme.lightBackgroundColor
@ExperimentalMaterialApi
fun NavGraphBuilder.getCredentialsGraph(
navController: NavController,
viewModel: GetCredentialViewModel,
onCancel: () -> Unit,
startDestination: String = "credentialSelection", // TODO: get this from view model
) {
navigation(startDestination = startDestination, route = "getCredentials") {
composable("credentialSelection") {
CredentialSelectionDialog(
providerInfo = viewModel.getDefaultProviderInfo(),
onOptionSelected = {viewModel.onCredentailSelected(it, navController)},
onCancel = onCancel,
multiProvider = viewModel.uiState.collectAsState().value.providers.size > 1,
onMoreOptionSelected = {viewModel.onMoreOptionSelected(navController)}
)
}
}
}
/**
* BEGIN CREATE OPTION SELECTION CONTENT
*/
@ExperimentalMaterialApi
@Composable
fun CredentialSelectionDialog(
providerInfo: ProviderInfo,
onOptionSelected: (String) -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionSelected: () -> Unit,
fun GetCredentialScreen(
viewModel: GetCredentialViewModel = viewModel(),
cancelActivity: () -> Unit,
) {
val state = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
@@ -79,13 +49,16 @@ fun CredentialSelectionDialog(
ModalBottomSheetLayout(
sheetState = state,
sheetContent = {
CredentialSelectionCard(
providerInfo = providerInfo,
onCancel = onCancel,
onOptionSelected = onOptionSelected,
multiProvider = multiProvider,
onMoreOptionSelected = onMoreOptionSelected,
)
val uiState = viewModel.uiState
when (uiState.currentScreenState) {
GetScreenState.CREDENTIAL_SELECTION -> CredentialSelectionCard(
providerInfo = uiState.selectedProvider!!,
onCancel = cancelActivity,
onOptionSelected = {viewModel.onCredentailSelected(it)},
multiProvider = uiState.providers.size > 1,
onMoreOptionSelected = {viewModel.onMoreOptionSelected()},
)
}
},
scrimColor = Color.Transparent,
sheetShape = Shapes.medium,
@@ -93,7 +66,7 @@ fun CredentialSelectionDialog(
LaunchedEffect(state.currentValue) {
when (state.currentValue) {
ModalBottomSheetValue.Hidden -> {
onCancel()
cancelActivity()
}
}
}
@@ -121,7 +94,9 @@ fun CredentialSelectionCard(
Text(
text = stringResource(R.string.choose_sign_in_title),
style = Typography.subtitle1,
modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
modifier = Modifier
.padding(all = 24.dp)
.align(alignment = Alignment.CenterHorizontally)
)
Text(
text = providerInfo.appDomainName,
@@ -184,7 +159,6 @@ fun CredentialOptionRow(
leadingIcon = {
Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp),
bitmap = credentialOptionInfo.icon.toBitmap().asImageBitmap(),
// painter = painterResource(R.drawable.ic_passkey),
// TODO: add description.
contentDescription = "")
},
@@ -227,6 +201,3 @@ fun MoreOptionRow(onSelect: () -> Unit) {
)
}
}
/**
* END CREATE OPTION SELECTION CONTENT
*/

View File

@@ -1,36 +1,30 @@
package com.android.credentialmanager.getflow
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.navigation.NavController
import com.android.credentialmanager.CredentialManagerRepo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
data class GetCredentialUiState(
val providers: List<ProviderInfo>
val providers: List<ProviderInfo>,
val currentScreenState: GetScreenState,
val selectedProvider: ProviderInfo? = null,
)
class GetCredentialViewModel(
credManRepo: CredentialManagerRepo
credManRepo: CredentialManagerRepo = CredentialManagerRepo.getInstance()
) : ViewModel() {
private val _uiState = MutableStateFlow(
GetCredentialUiState(credManRepo.getCredentialProviderList())
)
val uiState: StateFlow<GetCredentialUiState> = _uiState.asStateFlow()
var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
private set
fun getDefaultProviderInfo(): ProviderInfo {
// TODO: correctly get the default provider.
return uiState.value.providers.first()
}
fun onCredentailSelected(credentialId: String, navController: NavController) {
fun onCredentailSelected(credentialId: String) {
Log.d("Account Selector", "credential selected: $credentialId")
}
fun onMoreOptionSelected(navController: NavController) {
fun onMoreOptionSelected() {
Log.d("Account Selector", "More Option selected")
}
}

View File

@@ -16,3 +16,8 @@ data class CredentialOptionInfo(
val subtitle: String,
val id: String,
)
/** The name of the current screen. */
enum class GetScreenState {
CREDENTIAL_SELECTION,
}