mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
BIT-515, BIT-512 Adding the ability to view and edit secure note items. (#462)
This commit is contained in:
parent
fd9ca8f544
commit
1c8501b69b
5 changed files with 181 additions and 2 deletions
|
@ -217,7 +217,11 @@ private fun VaultItemContent(
|
|||
}
|
||||
|
||||
is VaultItemState.ViewState.Content.ItemType.SecureNote -> {
|
||||
// TODO UI for viewing SecureNote BIT-515
|
||||
VaultItemSecureNoteContent(
|
||||
commonState = viewState.common,
|
||||
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.item
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultCommonItemTypeHandlers
|
||||
|
||||
/**
|
||||
* The top level content UI state for the [VaultItemScreen] when viewing a secure note cipher.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun VaultItemSecureNoteContent(
|
||||
commonState: VaultItemState.ViewState.Content.Common,
|
||||
vaultCommonItemTypeHandlers: VaultCommonItemTypeHandlers,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(modifier = modifier) {
|
||||
item {
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.item_information),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = commonState.name,
|
||||
onValueChange = { },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
commonState.notes?.let { notes ->
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.notes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.notes),
|
||||
value = notes,
|
||||
onValueChange = { },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
commonState.customFields.takeUnless { it.isEmpty() }?.let { customFields ->
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.custom_fields),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
items(customFields) { customField ->
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
CustomField(
|
||||
customField = customField,
|
||||
onCopyCustomHiddenField = vaultCommonItemTypeHandlers.onCopyCustomHiddenField,
|
||||
onCopyCustomTextField = vaultCommonItemTypeHandlers.onCopyCustomTextField,
|
||||
onShowHiddenFieldClick = vaultCommonItemTypeHandlers.onShowHiddenFieldClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.semantics(mergeDescendants = true) { },
|
||||
) {
|
||||
Text(
|
||||
text = "${stringResource(id = R.string.date_updated)}: ",
|
||||
style = LocalNonMaterialTypography.current.labelMediumProminent,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Text(
|
||||
text = commonState.lastUpdated,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(88.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -768,7 +768,7 @@ sealed class VaultItemAction {
|
|||
) : Common()
|
||||
|
||||
/**
|
||||
* The user has clicked to display the a hidden field.
|
||||
* The user has clicked to display the hidden field.
|
||||
*/
|
||||
data class HiddenFieldVisibilityClicked(
|
||||
val field: VaultItemState.ViewState.Content.Common.Custom.HiddenField,
|
||||
|
|
|
@ -1164,6 +1164,12 @@ private val EMPTY_IDENTITY_VIEW_STATE: VaultItemState.ViewState.Content =
|
|||
type = EMPTY_IDENTITY_TYPE,
|
||||
)
|
||||
|
||||
private val EMPTY_SECURE_NOTE_VIEW_STATE =
|
||||
VaultItemState.ViewState.Content(
|
||||
common = EMPTY_COMMON,
|
||||
type = VaultItemState.ViewState.Content.ItemType.SecureNote,
|
||||
)
|
||||
|
||||
private val DEFAULT_LOGIN_VIEW_STATE: VaultItemState.ViewState.Content =
|
||||
VaultItemState.ViewState.Content(
|
||||
type = DEFAULT_LOGIN,
|
||||
|
@ -1176,12 +1182,20 @@ private val DEFAULT_IDENTITY_VIEW_STATE: VaultItemState.ViewState.Content =
|
|||
common = DEFAULT_COMMON,
|
||||
)
|
||||
|
||||
private val DEFAULT_SECURE_NOTE_VIEW_STATE: VaultItemState.ViewState.Content =
|
||||
VaultItemState.ViewState.Content(
|
||||
common = DEFAULT_COMMON,
|
||||
type = VaultItemState.ViewState.Content.ItemType.SecureNote,
|
||||
)
|
||||
|
||||
private val EMPTY_VIEW_STATES = listOf(
|
||||
EMPTY_LOGIN_VIEW_STATE,
|
||||
EMPTY_IDENTITY_VIEW_STATE,
|
||||
EMPTY_SECURE_NOTE_VIEW_STATE,
|
||||
)
|
||||
|
||||
private val DEFAULT_VIEW_STATES = listOf(
|
||||
DEFAULT_LOGIN_VIEW_STATE,
|
||||
DEFAULT_IDENTITY_VIEW_STATE,
|
||||
DEFAULT_SECURE_NOTE_VIEW_STATE,
|
||||
)
|
||||
|
|
|
@ -170,4 +170,33 @@ class CipherViewExtensionsTest {
|
|||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toViewState should transform full CipherView into ViewState Secure Note Content with premium`() {
|
||||
val viewState = createCipherView(type = CipherType.SECURE_NOTE, isEmpty = false)
|
||||
.toViewState(isPremiumUser = true)
|
||||
|
||||
assertEquals(
|
||||
VaultItemState.ViewState.Content(
|
||||
common = createCommonContent(isEmpty = false),
|
||||
type = VaultItemState.ViewState.Content.ItemType.SecureNote,
|
||||
),
|
||||
viewState,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toViewState should transform empty Secure Note CipherView into ViewState Secure Note Content`() {
|
||||
val viewState = createCipherView(type = CipherType.SECURE_NOTE, isEmpty = true)
|
||||
.toViewState(isPremiumUser = true)
|
||||
|
||||
val expectedState = VaultItemState.ViewState.Content(
|
||||
common = createCommonContent(isEmpty = true).copy(isPremiumUser = true),
|
||||
type = VaultItemState.ViewState.Content.ItemType.SecureNote,
|
||||
)
|
||||
|
||||
assertEquals(expectedState, viewState)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue