desktop: fix RTL text rendering under the send button (#4137)

The chat composer's text field reserved 50dp on the wrong horizontal side
when an RTL message was typed under an LTR system locale: BiDi auto-detection
right-aligned the text onto the BottomEnd edge where the send button sits,
hiding the first characters as they were typed.

The padding was originally written inside the CompositionLocalProvider(
LocalLayoutDirection provides Rtl) scope (#4675), where start resolved to
the right edge for RTL paragraphs. The "edge to edge design" refactor
(#5051) lifted the modifier out of that scope onto the outer BasicTextField,
so start began resolving against the global LTR direction and the
reservation drifted to the left.

Always reserve on the global end - the same side Alignment.BottomEnd in
SendMsgView resolves to - so the reservation tracks the send button
regardless of locale or typed-text direction. Behavior is byte-identical
for LTR text and for any RTL-locale combination; only the buggy
"RTL text + LTR system locale" pair changes.
This commit is contained in:
Narasimha-sc
2026-04-28 13:47:02 +00:00
parent ab4b056c60
commit bfc111cc61
@@ -83,12 +83,11 @@ actual fun PlatformTextField(
lastTimeWasRtlByCharacters.value = isRtlByCharacters
}
val isLtrGlobally = LocalLayoutDirection.current == LayoutDirection.Ltr
// Different padding here is for a text that is considered RTL with non-RTL locale set globally.
// In this case padding from right side should be bigger
val startEndPadding = if (cs.message.text.isEmpty() && showVoiceButton && isRtlByCharacters && isLtrGlobally) 95.dp else 50.dp
val startPadding = if (isRtlByCharacters && isLtrGlobally) startEndPadding else 0.dp
val endPadding = if (isRtlByCharacters && isLtrGlobally) 0.dp else startEndPadding
val padding = PaddingValues(startPadding, 12.dp, endPadding, 0.dp)
// Reserve space on the same side as the send button (Alignment.BottomEnd in SendMsgView),
// i.e. the global layout-direction's end. RTL text in an LTR locale right-aligns onto that
// edge and would otherwise render under the send button.
val endPadding = if (cs.message.text.isEmpty() && showVoiceButton && isRtlByCharacters && isLtrGlobally) 95.dp else 50.dp
val padding = PaddingValues(0.dp, 12.dp, endPadding, 0.dp)
var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = cs.message.text, selection = cs.message.selection)) }
val textFieldValue = textFieldValueState.copy(text = cs.message.text, selection = cs.message.selection)
val clipboard = LocalClipboardManager.current
@@ -116,7 +115,7 @@ actual fun PlatformTextField(
autoCorrectEnabled = true
),
modifier = Modifier
.padding(start = startPadding, end = endPadding)
.padding(end = endPadding)
.offset(y = (-5).dp)
.fillMaxWidth()
.focusRequester(focusReq)