BIT-1402 adding Password checker to Add Edit Screen (#769)

This commit is contained in:
Oleg Semenenko
2024-01-24 21:48:28 -06:00
committed by Álison Fernandes
parent 27a9719532
commit 54802db0b3
4 changed files with 142 additions and 48 deletions

View File

@@ -19,7 +19,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
@@ -82,10 +81,12 @@ fun VaultAddEditScreen(
is VaultAddEditEvent.NavigateToMoveToOrganization -> {
onNavigateToMoveToOrganization(event.cipherId)
}
is VaultAddEditEvent.NavigateToCollections -> {
// TODO implement Collections in BIT-1575
Toast.makeText(context, "Not yet implemented.", Toast.LENGTH_SHORT).show()
}
VaultAddEditEvent.NavigateBack -> onNavigateBack.invoke()
}
}
@@ -227,13 +228,15 @@ private fun VaultAddEditItemDialogs(
)
}
is VaultAddEditState.DialogState.Error -> BitwardenBasicDialog(
visibilityState = BasicDialogState.Shown(
title = R.string.an_error_has_occurred.asText(),
message = dialogState.message,
),
onDismissRequest = onDismissRequest,
)
is VaultAddEditState.DialogState.Generic -> {
BitwardenBasicDialog(
visibilityState = BasicDialogState.Shown(
title = dialogState.title,
message = dialogState.message,
),
onDismissRequest = onDismissRequest,
)
}
null -> Unit
}

View File

@@ -5,6 +5,8 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.bitwarden.core.CipherView
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
import com.x8bit.bitwarden.data.platform.repository.model.DataState
import com.x8bit.bitwarden.data.platform.repository.util.takeUntilLoaded
@@ -56,6 +58,7 @@ private const val KEY_STATE = "state"
@Suppress("TooManyFunctions", "LargeClass")
class VaultAddEditViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val authRepository: AuthRepository,
private val clipboardManager: BitwardenClipboardManager,
private val vaultRepository: VaultRepository,
private val generatorRepository: GeneratorRepository,
@@ -220,8 +223,9 @@ class VaultAddEditViewModel @Inject constructor(
if (content.common.name.isBlank()) {
mutableStateFlow.update {
it.copy(
dialog = VaultAddEditState.DialogState.Error(
R.string.validation_field_required
dialog = VaultAddEditState.DialogState.Generic(
title = R.string.an_error_has_occurred.asText(),
message = R.string.validation_field_required
.asText(R.string.name.asText()),
),
)
@@ -519,12 +523,15 @@ class VaultAddEditViewModel @Inject constructor(
}
private fun handleLoginPasswordCheckerClick() {
viewModelScope.launch {
sendEvent(
event = VaultAddEditEvent.ShowToast(
message = "Password Checker".asText(),
),
)
onLoginType { loginType ->
mutableStateFlow.update {
it.copy(dialog = VaultAddEditState.DialogState.Loading(R.string.loading.asText()))
}
viewModelScope.launch {
val result = authRepository.getPasswordBreachCount(password = loginType.password)
sendAction(VaultAddEditAction.Internal.PasswordBreachReceive(result))
}
}
}
@@ -847,6 +854,9 @@ class VaultAddEditViewModel @Inject constructor(
is VaultAddEditAction.Internal.GeneratorResultReceive -> {
handleGeneratorResultReceive(action)
}
is VaultAddEditAction.Internal.PasswordBreachReceive ->
handlePasswordBreachReceive(action)
}
}
@@ -883,7 +893,8 @@ class VaultAddEditViewModel @Inject constructor(
is UpdateCipherResult.Error -> {
mutableStateFlow.update {
it.copy(
dialog = VaultAddEditState.DialogState.Error(
dialog = VaultAddEditState.DialogState.Generic(
title = R.string.an_error_has_occurred.asText(),
message = result
.errorMessage
?.asText()
@@ -981,8 +992,9 @@ class VaultAddEditViewModel @Inject constructor(
TotpCodeResult.CodeScanningError -> {
mutableStateFlow.update {
it.copy(
dialog = VaultAddEditState.DialogState.Error(
R.string.authenticator_key_read_error.asText(),
dialog = VaultAddEditState.DialogState.Generic(
title = R.string.an_error_has_occurred.asText(),
message = R.string.authenticator_key_read_error.asText(),
),
)
}
@@ -1012,6 +1024,24 @@ class VaultAddEditViewModel @Inject constructor(
}
}
private fun handlePasswordBreachReceive(
action: VaultAddEditAction.Internal.PasswordBreachReceive,
) {
val message = when (val result = action.result) {
is BreachCountResult.Error -> R.string.generic_error_message.asText()
is BreachCountResult.Success -> {
if (result.breachCount > 0) {
R.string.password_exposed.asText(result.breachCount)
} else {
R.string.password_safe.asText()
}
}
}
mutableStateFlow.update {
it.copy(dialog = VaultAddEditState.DialogState.Generic(message = message))
}
}
//endregion Internal Type Handlers
//region Utility Functions
@@ -1049,6 +1079,12 @@ class VaultAddEditViewModel @Inject constructor(
}
}
private inline fun onLoginType(
crossinline block: (VaultAddEditState.ViewState.Content.ItemType.Login) -> Unit,
) {
onContent { (it.type as? VaultAddEditState.ViewState.Content.ItemType.Login)?.let(block) }
}
private inline fun updateLoginContent(
crossinline block: (VaultAddEditState.ViewState.Content.ItemType.Login) ->
VaultAddEditState.ViewState.Content.ItemType.Login,
@@ -1427,17 +1463,20 @@ data class VaultAddEditState(
@Parcelize
sealed class DialogState : Parcelable {
/**
* Displays a generic dialog to the user.
*/
@Parcelize
data class Generic(
val title: Text? = null,
val message: Text,
) : DialogState()
/**
* Displays a loading dialog to the user.
*/
@Parcelize
data class Loading(val label: Text) : DialogState()
/**
* Displays an error dialog to the user.
*/
@Parcelize
data class Error(val message: Text) : DialogState()
}
}
@@ -1884,6 +1923,11 @@ sealed class VaultAddEditAction {
*/
sealed class Internal : VaultAddEditAction() {
/**
* Indicates that the password breach results have been received.
*/
data class PasswordBreachReceive(val result: BreachCountResult) : Internal()
/**
* Indicates that the vault totp code result has been received.
*/