Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import com.bitwarden.ui.platform.base.util.withLineBreaksAtWidth
import com.bitwarden.ui.platform.base.util.withVisualTransformation
import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.util.compoundVisualTransformation
import com.bitwarden.ui.platform.components.util.forceLtrVisualTransformation
import com.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
Expand Down Expand Up @@ -61,7 +63,10 @@ fun PasswordHistoryListItem(
)
Text(
text = formattedText.withVisualTransformation(
visualTransformation = nonLetterColorVisualTransformation(),
visualTransformation = compoundVisualTransformation(
forceLtrVisualTransformation(),
nonLetterColorVisualTransformation(),
),
),
style = textStyle,
color = BitwardenTheme.colorScheme.text.primary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.bitwarden.ui.platform.base.util.toListItemCardStyle
Expand All @@ -27,6 +28,7 @@ import com.bitwarden.ui.platform.components.header.BitwardenListHeaderText
import com.bitwarden.ui.platform.components.icon.model.IconData
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.text.BitwardenHyperTextLink
import com.bitwarden.ui.platform.components.util.forceLtrVisualTransformation
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
Expand Down Expand Up @@ -149,6 +151,7 @@ fun VaultItemIdentityContent(
index = identityState.propertyList.indexOf(element = ssn),
dividerPadding = 0.dp,
),
forceLtr = true,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
Expand All @@ -171,6 +174,7 @@ fun VaultItemIdentityContent(
index = identityState.propertyList.indexOf(element = passportNumber),
dividerPadding = 0.dp,
),
forceLtr = true,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
Expand All @@ -193,6 +197,7 @@ fun VaultItemIdentityContent(
index = identityState.propertyList.indexOf(element = licenseNumber),
dividerPadding = 0.dp,
),
forceLtr = true,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
Expand All @@ -215,6 +220,7 @@ fun VaultItemIdentityContent(
index = identityState.propertyList.indexOf(element = email),
dividerPadding = 0.dp,
),
forceLtr = true,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
Expand All @@ -237,6 +243,7 @@ fun VaultItemIdentityContent(
index = identityState.propertyList.indexOf(element = phone),
dividerPadding = 0.dp,
),
forceLtr = true,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin()
Expand Down Expand Up @@ -422,6 +429,7 @@ private fun IdentityCopyField(
onCopyClick: () -> Unit,
cardStyle: CardStyle,
modifier: Modifier = Modifier,
forceLtr: Boolean = false,
) {
BitwardenTextField(
label = label,
Expand All @@ -439,6 +447,11 @@ private fun IdentityCopyField(
},
textFieldTestTag = textFieldTestTag,
cardStyle = cardStyle,
visualTransformation = if (forceLtr) {
forceLtrVisualTransformation()
} else {
VisualTransformation.None
},
modifier = modifier,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.model.TooltipData
import com.bitwarden.ui.platform.components.text.BitwardenClickableText
import com.bitwarden.ui.platform.components.text.BitwardenHyperTextLink
import com.bitwarden.ui.platform.components.util.forceLtrVisualTransformation
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
Expand Down Expand Up @@ -473,6 +474,7 @@ private fun TotpField(
},
textFieldTestTag = "LoginTotpEntry",
cardStyle = CardStyle.Full,
visualTransformation = forceLtrVisualTransformation(),
modifier = modifier,
)
} else {
Expand Down Expand Up @@ -528,6 +530,7 @@ private fun UriField(
},
textFieldTestTag = "LoginUriEntry",
cardStyle = cardStyle,
visualTransformation = forceLtrVisualTransformation(),
modifier = modifier,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import com.bitwarden.ui.platform.base.util.nullableTestTag
import com.bitwarden.ui.platform.components.field.color.bitwardenTextFieldColors
import com.bitwarden.ui.platform.components.field.toolbar.BitwardenEmptyTextToolbar
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.util.compoundVisualTransformation
import com.bitwarden.ui.platform.components.util.forceLtrVisualTransformation
import com.bitwarden.ui.platform.theme.BitwardenTheme

/**
Expand Down Expand Up @@ -44,7 +46,10 @@ fun BitwardenHiddenPasswordField(
label = label?.let { { Text(text = it) } },
value = value,
onValueChange = { },
visualTransformation = PasswordVisualTransformation(),
visualTransformation = compoundVisualTransformation(
PasswordVisualTransformation(),
forceLtrVisualTransformation(),
),
singleLine = true,
enabled = false,
readOnly = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.base.util.cardStyle
Expand All @@ -56,6 +55,8 @@ import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.model.TooltipData
import com.bitwarden.ui.platform.components.row.BitwardenRowOfActions
import com.bitwarden.ui.platform.components.support.BitwardenSupportingContent
import com.bitwarden.ui.platform.components.util.compoundVisualTransformation
import com.bitwarden.ui.platform.components.util.forceLtrVisualTransformation
import com.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
Expand Down Expand Up @@ -140,6 +141,21 @@ fun BitwardenPasswordField(
TextToolbarType.NONE -> BitwardenEmptyTextToolbar
}
var lastTextValue by remember(value) { mutableStateOf(value = value) }

val visualTransformation = when {
!showPassword -> compoundVisualTransformation(
PasswordVisualTransformation(),
forceLtrVisualTransformation(),
Comment thread
SaintPatrck marked this conversation as resolved.
Outdated
)

readOnly -> compoundVisualTransformation(
nonLetterColorVisualTransformation(),
forceLtrVisualTransformation(),
)

else -> forceLtrVisualTransformation()
}

CompositionLocalProvider(value = LocalTextToolbar provides textToolbar) {
Column(
modifier = modifier
Expand Down Expand Up @@ -191,11 +207,7 @@ fun BitwardenPasswordField(
onValueChange(it.text)
}
},
visualTransformation = when {
!showPassword -> PasswordVisualTransformation()
readOnly -> nonLetterColorVisualTransformation()
else -> VisualTransformation.None
},
visualTransformation = visualTransformation,
singleLine = singleLine,
readOnly = readOnly,
keyboardOptions = KeyboardOptions(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.bitwarden.ui.platform.components.util

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation

/**
* A [VisualTransformation] that chains multiple other [VisualTransformation]s.
*
* This is useful for applying multiple transformations to a text field. The transformations
* are applied in the order they are provided.
*/
private class CompoundVisualTransformation(
vararg val transformations: VisualTransformation,
) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
return transformations.fold(
TransformedText(
text,
OffsetMapping.Identity,
),
) { acc, transformation ->
val result = transformation.filter(acc.text)

val composedMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
val originalTransformed = acc.offsetMapping.originalToTransformed(offset)
return result.offsetMapping.originalToTransformed(originalTransformed)
}

override fun transformedToOriginal(offset: Int): Int {
val resultOriginal = result.offsetMapping.transformedToOriginal(offset)
return acc.offsetMapping.transformedToOriginal(resultOriginal)
}
}
TransformedText(result.text, composedMapping)
}
}
}

/**
* Remembers a [CompoundVisualTransformation] for the given [transformations].
*
* This is an optimization to avoid creating a new [CompoundVisualTransformation] on every
* recomposition.
*/
@Composable
fun compoundVisualTransformation(
vararg transformations: VisualTransformation,
): VisualTransformation =
remember(*transformations) {
CompoundVisualTransformation(*transformations)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.bitwarden.ui.platform.components.util

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation

// Unicode characters for forcing LTR direction
private const val LRO = "\u202A"
private const val PDF = "\u202C"

/**
* A [VisualTransformation] that forces the output to have an LTR text direction.
*
* This is useful for password fields where the input should always be LTR, even when the rest of
* the UI is RTL.
*/
private object ForceLtrVisualTransformation : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val forcedLtrText = buildAnnotatedString {
append(LRO)
append(text)
append(PDF)
}

val offsetMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int = offset + 1

override fun transformedToOriginal(offset: Int): Int =
(offset - 1).coerceIn(0, text.length)
}

return TransformedText(forcedLtrText, offsetMapping)
}
}

/**
* Remembers a [ForceLtrVisualTransformation] for the given [transformations].
*
* This is an optimization to avoid creating a new [ForceLtrVisualTransformation] on every
* recomposition.
*/
@Composable
fun forceLtrVisualTransformation(): VisualTransformation = remember {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the Remember do anything here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only to expose ForceLtrTransformation since it's internal and follow the existing pattern(s).

ForceLtrVisualTransformation
}
Loading