Closed kbecciv closed 3 months ago
Triggered auto assignment to @kadiealexander (Bug
), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.
We think that this bug might be related to #vip-vsb
@kadiealexander FYI I haven't added the External label as I wasn't 100% sure about this issue. Please take a look and add the label if you agree it's a bug and can be handled by external contributors.
Job added to Upwork: https://www.upwork.com/jobs/~011bc1604b6420e233
Triggered auto assignment to Contributor-plus team member for initial proposal review - @eh2077 (External
)
The cursor selection moves to the left by one character when adding a character after inserting an emoji.
When we add a text to the composer, it will save the new selection position to a ref if the commentValue
is not equal to newComment
https://github.com/Expensify/App/blob/2514f2988eb26858d30fa501c0040b1f8fc2e239/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx#L439-L444
commentValue
is the text that we type while the newComment
is the commentValue
that has emoji code replaced to emoji character (for example :smile:
to π).
If they are different, we want to manually correct the selection, however, on iOS, the selection prop is buggy so we use the ref sync solution that imperatively updates the selection that is introduced in https://github.com/Expensify/App/pull/30835.
It will update/sync the selection in onChangeText
.
However, there are a few things to notice here.
First, when we add an emoji from the emoji picker, commentValue
is not equal to newComment
even though there is no emoji code converted to an emoji character. The reason behind this is that we add a whitespace to the text
So, commentValue
doesn't have the whitespace while the newComment
has the whitespace. Previously, commentValue
already contained the whitespace every time we added an emoji from the emoji picker, but this PR changes it so the whitespace is also added when we add the emoji from the device keyboard emoji picker.
This will then set the selection to the ref (syncSelectionWithOnChangeTextRef).
Next, if we add an emoji from the emoji picker, onChangeText
won't be triggered. onChangeText
will only be triggered if we input the text manually from keyboard.
So, when we add a character, it will run the selection sync logic which contains the old selection.
We need to compare newComment
with the commentValue
with whitespace appended because the manual selection correction is only used when we add emoji through emoji code.
const commentWithSpaceInserted = isEmojiInserted ? ComposerUtils.insertWhiteSpaceAtIndex(commentValue, endIndex) : commentValue;
...
if (commentWithSpaceInserted !== newComment) {
...
Clear the ref every time we call updateComment
. This is to invalidate any old selection sync ref.
https://github.com/Expensify/App/blob/2514f2988eb26858d30fa501c0040b1f8fc2e239/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx#L408-L411
const updateComment = useCallback(
(commentValue: string, shouldDebounceSaveComment?: boolean) => {
if (isIOSNative) {
syncSelectionWithOnChangeTextRef.current = null;
}
iOS - Chat - The cursor moves one space backward when inserting text after an emoji
When inputting text into the composer, the system saves the new selection position to a reference (ref) if the commentValue doesn't match the newComment. This disparity occurs due to the presence of an extra whitespace added to newComment during emoji insertion, which is absent in commentValue.
Instead of comparing commentValue and newComment, directly track the insertion point to determine cursor positioning. Calculate the newCursorPosition dynamically based on the difference in length between the old and new comments.
// Calculate the new cursor position based on the difference in text length
const currentLength = commentRef.current.length;
const newLength = newCommentConverted.length;
let newCursorPosition = cursorPosition ?? 0;
// Determine if an emoji was inserted and adjust cursor position accordingly
if (isEmojiInserted && newLength > currentLength) {
newCursorPosition = endIndex + 1; // Move the cursor after the inserted emoji
} else if (currentLength > newLength) {
newCursorPosition = Math.max(selection.end - (currentLength - newLength), 0); // Adjust cursor for deleted characters
} else {
newCursorPosition = selection.end + (newLength - currentLength); // Adjust cursor for added characters
}
// Update the selection position and clear the ref if necessary
setSelection({ start: newCursorPosition, end: newCursorPosition });
if (isIOSNative) {
syncSelectionWithOnChangeTextRef.current = { position: newCursorPosition, value: newComment };
}
This approach ensures accurate cursor positioning by directly tracking insertion points and dynamically adjusting cursor positions, thereby resolving the cursor issue caused by indirect comparisons and ensuring correct placement after inserting emojis or additional text.
video:-https://drive.google.com/file/d/19PDhzOkps6aXYRAWwyeWr3qyrc_xXzAP/view?usp=sharing
@bernhardoj 's proposal looks good to me. Nice write up to unwrap the root cause! I also agree with the idea of fixing it by narrowing the scope of the manual-selection-correction-specific code.
πππ C+ reviewed
Triggered auto assignment to @MonilBhavsar, see https://stackoverflow.com/c/expensify/questions/7972 for more details.
@MonilBhavsar Friendly bump, wdyt https://github.com/Expensify/App/issues/42664#issuecomment-2137553685
Yes, looking at this...
@bernhardoj proposal's looks good and simple.
Is there any specific reason to clear syncSelectionWithOnChangeTextRef
?
π£ @eh2077 π An offer has been automatically sent to your Upwork account for the Reviewer role π Thanks for contributing to the Expensify app!
π£ @bernhardoj π An offer has been automatically sent to your Upwork account for the Contributor role π Thanks for contributing to the Expensify app!
Offer link Upwork job Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review π§βπ» Keep in mind: Code of Conduct | Contributing π
Is there any specific reason to clear syncSelectionWithOnChangeTextRef?
Do you mean the alternative solution? syncSelectionWithOnChangeTextRef
is supposed to be consumed (in onChangeText
) every time we type something (updateComment
). But as explained in my proposal, onChangeText
will only be called when we type from the keyboard, not from adding an emoji from the emoji picker. So, I suggest an alternative solution to always clear it before creating a new syncSelectionWithOnChangeTextRef
so each syncSelectionWithOnChangeTextRef
corresponds to each updateComment
.
Btw, after retesting my main solution, it causes a regression, the cursor is before the emoji when adding an emoji
https://github.com/Expensify/App/assets/50919443/110ec416-3e5c-4739-8b18-5eb769c352ed
so I use the alternative instead.
PR is ready.
cc: @eh2077
Makes sense, thanks!
Reviewing
label has been removed, please complete the "BugZero Checklist".
The solution for this issue has been :rocket: deployed to production :rocket: in version 1.4.82-4 and is now subject to a 7-day regression period :calendar:. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2024-06-20. :confetti_ball:
For reference, here are some details about the assignees on this issue:
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
Do we agree π or π
Payouts due:
If you havenβt already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Version Number: v1.4.76-1 Reproducible in staging?: y Reproducible in production?: y If this was caught during regression testing, add the test name, ID and link from TestRail: https://expensify.testrail.io/index.php?/tests/view/4577924 Issue reported by: Applause - Internal Team
Action Performed:
Pre-requisite: the user must be logged in.
Expected Result:
The cursor should remain at the end of the compose box content.
Actual Result:
The cursor moves one space backward when inserting text after an emoji.
Workaround:
n/a
Platforms:
Which of our officially supported platforms is this issue occurring on?
Screenshots/Videos
Add any screenshot/video evidence
https://github.com/Expensify/App/assets/93399543/b44491bc-2ce6-45cb-91f4-07e68ab4d95c
View all open jobs on GitHub
Upwork Automation - Do Not Edit
Issue Owner
Current Issue Owner: @kadiealexander