BIT-2101 BIT-2103: Update export flow for JSON (password protected) (#1188)

This commit is contained in:
Caleb Derosier
2024-03-29 13:51:17 -06:00
committed by Álison Fernandes
parent 3565054a4c
commit 90ff2897f5
5 changed files with 170 additions and 23 deletions

View File

@@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.auth.feature.createaccount.PasswordStrengthIndicator
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.appbar.BitwardenTopAppBar
@@ -164,9 +165,15 @@ fun ExportVaultScreen(
) { innerPadding ->
ExportVaultScreenContent(
state = state,
onConfirmFilePasswordInputChanged = remember(viewModel) {
{ viewModel.trySendAction(ExportVaultAction.ConfirmFilePasswordInputChange(it)) }
},
onExportFormatOptionSelected = remember(viewModel) {
{ viewModel.trySendAction(ExportVaultAction.ExportFormatOptionSelect(it)) }
},
onFilePasswordInputChanged = remember(viewModel) {
{ viewModel.trySendAction(ExportVaultAction.FilePasswordInputChange(it)) }
},
onPasswordInputChanged = remember(viewModel) {
{ viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(it)) }
},
@@ -182,7 +189,9 @@ fun ExportVaultScreen(
@Suppress("LongMethod")
private fun ExportVaultScreenContent(
state: ExportVaultState,
onConfirmFilePasswordInputChanged: (String) -> Unit,
onExportFormatOptionSelected: (ExportVaultFormat) -> Unit,
onFilePasswordInputChanged: (String) -> Unit,
onPasswordInputChanged: (String) -> Unit,
onExportVaultClick: () -> Unit,
modifier: Modifier = Modifier,
@@ -226,6 +235,37 @@ private fun ExportVaultScreenContent(
Spacer(modifier = Modifier.height(8.dp))
if (state.exportFormat == ExportVaultFormat.JSON_ENCRYPTED) {
BitwardenPasswordField(
label = stringResource(id = R.string.file_password),
value = state.filePasswordInput,
onValueChange = onFilePasswordInputChanged,
hint = stringResource(id = R.string.password_used_to_export),
modifier = Modifier
.semantics { testTag = "FilePasswordEntry" }
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(8.dp))
PasswordStrengthIndicator(
modifier = Modifier.padding(horizontal = 16.dp),
state = state.passwordStrengthState,
)
Spacer(modifier = Modifier.height(4.dp))
BitwardenPasswordField(
label = stringResource(id = R.string.confirm_file_password),
value = state.confirmFilePasswordInput,
onValueChange = onConfirmFilePasswordInputChanged,
modifier = Modifier
.semantics { testTag = "ConfirmFilePasswordEntry" }
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(16.dp))
}
BitwardenPasswordField(
label = stringResource(id = R.string.master_password),
value = state.passwordInput,

View File

@@ -12,6 +12,7 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
import com.x8bit.bitwarden.data.vault.manager.FileManager
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.data.vault.repository.model.ExportVaultDataResult
import com.x8bit.bitwarden.ui.auth.feature.createaccount.PasswordStrengthState
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
@@ -46,10 +47,13 @@ class ExportVaultViewModel @Inject constructor(
) : BaseViewModel<ExportVaultState, ExportVaultEvent, ExportVaultAction>(
initialState = savedStateHandle[KEY_STATE]
?: ExportVaultState(
confirmFilePasswordInput = "",
dialogState = null,
exportData = null,
exportFormat = ExportVaultFormat.JSON,
filePasswordInput = "",
passwordInput = "",
passwordStrengthState = PasswordStrengthState.NONE,
policyPreventsExport = policyManager
.getActivePolicies(type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT)
.any(),
@@ -66,7 +70,12 @@ class ExportVaultViewModel @Inject constructor(
when (action) {
ExportVaultAction.CloseButtonClick -> handleCloseButtonClicked()
ExportVaultAction.ConfirmExportVaultClicked -> handleConfirmExportVaultClicked()
is ExportVaultAction.ConfirmFilePasswordInputChange -> {
handleConfirmFilePasswordInputChanged(action)
}
ExportVaultAction.DialogDismiss -> handleDialogDismiss()
is ExportVaultAction.FilePasswordInputChange -> handleFilePasswordInputChanged(action)
is ExportVaultAction.ExportFormatOptionSelect -> handleExportFormatOptionSelect(action)
is ExportVaultAction.PasswordInputChanged -> handlePasswordInputChanged(action)
is ExportVaultAction.ExportLocationReceive -> handleExportLocationReceive(action)
@@ -118,6 +127,17 @@ class ExportVaultViewModel @Inject constructor(
}
}
/**
* Update the state with the new confirm file password input.
*/
private fun handleConfirmFilePasswordInputChanged(
action: ExportVaultAction.ConfirmFilePasswordInputChange,
) {
mutableStateFlow.update {
it.copy(confirmFilePasswordInput = action.input)
}
}
/**
* Dismiss the dialog.
*/
@@ -155,6 +175,15 @@ class ExportVaultViewModel @Inject constructor(
}
}
/**
* Update the state with the new file password input.
*/
private fun handleFilePasswordInputChanged(action: ExportVaultAction.FilePasswordInputChange) {
mutableStateFlow.update {
it.copy(filePasswordInput = action.input)
}
}
/**
* Update the state with the new password input.
*/
@@ -267,9 +296,12 @@ class ExportVaultViewModel @Inject constructor(
data class ExportVaultState(
@IgnoredOnParcel
val exportData: String? = null,
val confirmFilePasswordInput: String,
val dialogState: DialogState?,
val exportFormat: ExportVaultFormat,
val filePasswordInput: String,
val passwordInput: String,
val passwordStrengthState: PasswordStrengthState,
val policyPreventsExport: Boolean,
) : Parcelable {
/**
@@ -330,6 +362,11 @@ sealed class ExportVaultAction {
*/
data object ConfirmExportVaultClicked : ExportVaultAction()
/**
* Indicates that the confirm file password input has changed.
*/
data class ConfirmFilePasswordInputChange(val input: String) : ExportVaultAction()
/**
* Indicates that the dialog has been dismissed.
*/
@@ -347,6 +384,11 @@ sealed class ExportVaultAction {
val fileUri: Uri,
) : ExportVaultAction()
/**
* Indicates that the file password input has changed.
*/
data class FilePasswordInputChange(val input: String) : ExportVaultAction()
/**
* Indicates that the password input has changed.
*/