Remove BitwardenReadOnlyTextFieldWithActions (#597)

This commit is contained in:
David Perez 2024-01-13 08:51:29 -06:00 committed by Álison Fernandes
parent 8f22231c4a
commit 96a9a41836
5 changed files with 64 additions and 133 deletions

View file

@ -1,99 +0,0 @@
package com.x8bit.bitwarden.ui.platform.components
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.text
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.R
/**
* Represents a Bitwarden-styled text field accompanied by a series of actions.
* This component allows for a more versatile design by accepting
* icons or actions next to the text field. This composable is read-only and because it uses
* the BitwardenTextField we clear the semantics here to prevent talk back from clarifying the
* component is "editable" or "disabled".
*
* @param label Label for the text field.
* @param value Current text in the text field.
* @param modifier [Modifier] applied to this layout composable.
* @param singleLine when `true`, this text field becomes a single line that horizontally scrolls
* instead of wrapping onto multiple lines.
* @param textStyle An optional style that may be used to override the default used.
* @param shouldAddCustomLineBreaks If `true`, line breaks will be inserted to allow for filling
* an entire line before breaking. `false` by default.
* @param visualTransformation Transforms the visual representation of the input [value].
* @param actions A lambda containing the set of actions (usually icons or similar) to display
* next to the text field. This lambda extends [RowScope],
* providing flexibility in the layout definition.
*/
@Composable
fun BitwardenReadOnlyTextFieldWithActions(
label: String,
value: String,
modifier: Modifier = Modifier,
singleLine: Boolean = true,
textStyle: TextStyle? = null,
shouldAddCustomLineBreaks: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
actions: @Composable RowScope.() -> Unit = {},
) {
Row(
modifier = modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) {},
verticalAlignment = Alignment.CenterVertically,
) {
BitwardenTextField(
modifier = Modifier
.weight(1f)
.clearAndSetSemantics {
contentDescription = "$label, $value"
text = AnnotatedString(label)
},
readOnly = true,
singleLine = singleLine,
label = label,
value = value,
onValueChange = {},
textStyle = textStyle,
shouldAddCustomLineBreaks = shouldAddCustomLineBreaks,
visualTransformation = visualTransformation,
)
BitwardenRowOfActions(actions)
}
}
@Preview(showBackground = true)
@Composable
private fun BitwardenReadOnlyTextFieldWithActions_preview() {
BitwardenReadOnlyTextFieldWithActions(
label = "Username",
value = "john.doe",
actions = {
Icon(
painter = painterResource(id = R.drawable.ic_tooltip),
contentDescription = "",
modifier = Modifier.size(24.dp),
)
Icon(
painter = painterResource(id = R.drawable.ic_tooltip),
contentDescription = "",
modifier = Modifier.size(24.dp),
)
},
)
}

View file

@ -33,7 +33,7 @@ fun BitwardenStepper(
if (clampedValue != value && clampedValue != null) {
onValueChange(clampedValue)
}
BitwardenReadOnlyTextFieldWithActions(
BitwardenTextFieldWithActions(
label = label,
// we use a space instead of empty string to make sure label is shown small and above
// the input
@ -68,6 +68,8 @@ fun BitwardenStepper(
isEnabled = isIncrementEnabled,
)
},
readOnly = true,
onValueChange = {},
modifier = modifier,
)
}

View file

@ -8,7 +8,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
@ -36,6 +39,9 @@ fun BitwardenTextFieldWithActions(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
textStyle: TextStyle? = null,
shouldAddCustomLineBreaks: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
readOnly: Boolean = false,
singleLine: Boolean = true,
keyboardType: KeyboardType = KeyboardType.Text,
@ -43,7 +49,9 @@ fun BitwardenTextFieldWithActions(
actions: @Composable RowScope.() -> Unit = {},
) {
Row(
modifier = modifier.fillMaxWidth(),
modifier = modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) { },
verticalAlignment = Alignment.CenterVertically,
) {
BitwardenTextField(
@ -56,6 +64,9 @@ fun BitwardenTextFieldWithActions(
onValueChange = onValueChange,
keyboardType = keyboardType,
trailingIconContent = trailingIconContent,
textStyle = textStyle,
shouldAddCustomLineBreaks = shouldAddCustomLineBreaks,
visualTransformation = visualTransformation,
)
BitwardenRowOfActions(actions)
}
@ -65,9 +76,10 @@ fun BitwardenTextFieldWithActions(
@Composable
private fun BitwardenTextFieldWithActions_preview() {
BitwardenTheme {
BitwardenReadOnlyTextFieldWithActions(
BitwardenTextFieldWithActions(
label = "Username",
value = "user@example.com",
onValueChange = {},
actions = {
Icon(
painter = painterResource(id = R.drawable.ic_tooltip),

View file

@ -53,10 +53,10 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenMediumTopAppBar
import com.x8bit.bitwarden.ui.platform.components.BitwardenMultiSelectButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField
import com.x8bit.bitwarden.ui.platform.components.BitwardenReadOnlyTextFieldWithActions
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.BitwardenStepper
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextFieldWithActions
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
@ -290,7 +290,7 @@ private fun GeneratedStringItem(
onCopyClick: () -> Unit,
onRegenerateClick: () -> Unit,
) {
BitwardenReadOnlyTextFieldWithActions(
BitwardenTextFieldWithActions(
label = "",
value = generatedText,
singleLine = false,
@ -310,6 +310,8 @@ private fun GeneratedStringItem(
onClick = onRegenerateClick,
)
},
onValueChange = {},
readOnly = true,
textStyle = LocalNonMaterialTypography.current.sensitiveInfoSmall,
shouldAddCustomLineBreaks = true,
visualTransformation = nonLetterColorVisualTransformation(),

View file

@ -7,13 +7,13 @@ import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.filterToOne
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasContentDescription
import androidx.compose.ui.test.hasProgressBarRangeInfo
import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onLast
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
@ -230,15 +230,17 @@ class GeneratorScreenTest : BaseComposeTest() {
.assertIsOff()
composeTestRule
.onNodeWithContentDescription("Minimum numbers, 1")
.onChildren()
.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "1")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription("Minimum numbers, 1")
.onChildren()
.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "1")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.assertIsDisplayed()
@ -367,8 +369,9 @@ class GeneratorScreenTest : BaseComposeTest() {
fun `in Passcode_Password state, decrementing the minimum numbers counter should send MinNumbersCounterChange action`() {
val initialMinNumbers = 1
composeTestRule.onNodeWithContentDescription("Minimum numbers, 1")
.onChildren()
composeTestRule.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "1")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -387,8 +390,9 @@ class GeneratorScreenTest : BaseComposeTest() {
fun `in Passcode_Password state, incrementing the minimum numbers counter should send MinNumbersCounterChange action`() {
val initialMinNumbers = 1
composeTestRule.onNodeWithContentDescription("Minimum numbers, 1")
.onChildren()
composeTestRule.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "1")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()
@ -420,8 +424,9 @@ class GeneratorScreenTest : BaseComposeTest() {
),
)
composeTestRule.onNodeWithContentDescription("Minimum numbers, $initialMinNumbers")
.onChildren()
composeTestRule.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "$initialMinNumbers")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -447,8 +452,9 @@ class GeneratorScreenTest : BaseComposeTest() {
),
)
composeTestRule.onNodeWithContentDescription("Minimum numbers, $initialMinNumbers")
.onChildren()
composeTestRule.onNodeWithText("Minimum numbers")
.assertTextEquals("Minimum numbers", "$initialMinNumbers")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()
@ -461,8 +467,9 @@ class GeneratorScreenTest : BaseComposeTest() {
fun `in Passcode_Password state, decrementing the minimum special characters counter should send MinSpecialCharactersChange action`() {
val initialSpecialChars = 1
composeTestRule.onNodeWithContentDescription("Minimum special, 1")
.onChildren()
composeTestRule.onNodeWithText("Minimum special")
.assertTextEquals("Minimum special", "1")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -481,8 +488,9 @@ class GeneratorScreenTest : BaseComposeTest() {
fun `in Passcode_Password state, incrementing the minimum special characters counter should send MinSpecialCharactersChange action`() {
val initialSpecialChars = 1
composeTestRule.onNodeWithContentDescription("Minimum special, 1")
.onChildren()
composeTestRule.onNodeWithText("Minimum special")
.assertTextEquals("Minimum special", "1")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()
@ -514,8 +522,9 @@ class GeneratorScreenTest : BaseComposeTest() {
),
)
composeTestRule.onNodeWithContentDescription("Minimum special, $initialSpecialChars")
.onChildren()
composeTestRule.onNodeWithText("Minimum special")
.assertTextEquals("Minimum special", "$initialSpecialChars")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -541,8 +550,9 @@ class GeneratorScreenTest : BaseComposeTest() {
),
)
composeTestRule.onNodeWithContentDescription("Minimum special, $initialSpecialChars")
.onChildren()
composeTestRule.onNodeWithText("Minimum special")
.assertTextEquals("Minimum special", "$initialSpecialChars")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()
@ -595,8 +605,9 @@ class GeneratorScreenTest : BaseComposeTest() {
// Unicode for "minus" used for content description
composeTestRule
.onNodeWithContentDescription("Number of words, $initialNumWords")
.onChildren()
.onNodeWithText("Number of words")
.assertTextEquals("Number of words", "$initialNumWords")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -629,8 +640,9 @@ class GeneratorScreenTest : BaseComposeTest() {
// Unicode for "minus" used for content description
composeTestRule
.onNodeWithContentDescription("Number of words, $initialNumWords")
.onChildren()
.onNodeWithText("Number of words")
.assertTextEquals("Number of words", "$initialNumWords")
.onSiblings()
.filterToOne(hasContentDescription("\u2212"))
.performScrollTo()
.performClick()
@ -656,8 +668,9 @@ class GeneratorScreenTest : BaseComposeTest() {
// Unicode for "minus" used for content description
composeTestRule
.onNodeWithContentDescription("Number of words, $initialNumWords")
.onChildren()
.onNodeWithText("Number of words")
.assertTextEquals("Number of words", "$initialNumWords")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()
@ -681,8 +694,9 @@ class GeneratorScreenTest : BaseComposeTest() {
)
composeTestRule
.onNodeWithContentDescription("Number of words, 3")
.onChildren()
.onNodeWithText("Number of words")
.assertTextEquals("Number of words", "3")
.onSiblings()
.filterToOne(hasContentDescription("+"))
.performScrollTo()
.performClick()