diff options
| author | 2022-09-23 17:45:40 +0000 | |
|---|---|---|
| committer | 2022-09-23 17:45:40 +0000 | |
| commit | 6b5cf8a1b691081611aae4e82fb6269ea1f82ffd (patch) | |
| tree | 44e07fda325c7ff0f1a80cf93c9ae74e7efb8ddc | |
| parent | 94444a89d29358ce0fd220851522aca568d7b1cf (diff) | |
| parent | b802ce00d56ac8ceca1688afbba50c5b1e7968aa (diff) | |
Merge "UX impovements: removed navigation & smoothen dialog transition."
10 files changed, 221 insertions, 358 deletions
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp index ed92af997a68..51943fffb36d 100644 --- a/packages/CredentialManager/Android.bp +++ b/packages/CredentialManager/Android.bp @@ -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", ], diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index f20104a19af2..59186336056e 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -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, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt index dd4ba11e9202..5cd6a13a377a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt @@ -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() + } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt new file mode 100644 index 000000000000..8bb80a1b02fd --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt @@ -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 + } + } + } +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 62c244cfb121..5aa1e9ba6183 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -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, +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt index fb6db2172123..60a8e4b24d57 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt @@ -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 @@ -50,53 +43,10 @@ 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({}, {}) - // } -} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt index 355428555735..e42016d59b0b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt @@ -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() - - 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) + var uiState by mutableStateOf(credManRepo.createPasskeyInitialUiState()) + private set + + 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") } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 6ad14db00024..4b957e84fc2b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -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 @@ -41,36 +37,10 @@ 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 - */ diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt index 20057de8fec2..06bcd7fedc6f 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt @@ -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") } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 8710eceeb723..867e9c2acc63 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -16,3 +16,8 @@ data class CredentialOptionInfo( val subtitle: String, val id: String, ) + +/** The name of the current screen. */ +enum class GetScreenState { + CREDENTIAL_SELECTION, +} |