Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Android - Chat - Message gets displayed from right to left #32297

Merged

Conversation

samilabud
Copy link
Contributor

@samilabud samilabud commented Nov 30, 2023

Details

The root cause is that Android only converts RTL text to LTR text using Unicode controls and by default, when you start writing in a language that is written in RTL mode it converts the input text to RTL.

Fixed Issues

$ #30584
PROPOSAL: #30584 (comment)

Tests

  1. Launch App
  2. Open any chat and paste an RTL text in the compose box, for example " مثال "
  3. Continue typing some content
  • Verify that no errors appear in the JS console

Offline tests

N/A

QA Steps

  1. Launch App
  2. Open any chat and paste an RTL text in the compose box, for example " مثال "
  3. Continue typing some content
  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG))
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android.Native.mov
Android: mWeb Chrome
Android.Chrome.mov
iOS: Native
Iphone.Native.mp4
iOS: mWeb Safari
Iphone.Safari.mov
MacOS: Chrome / Safari
Web.Chrome.mp4
MacOS: Desktop
MAC.Desktop.mov

@samilabud samilabud requested a review from a team as a code owner November 30, 2023 19:33
@melvin-bot melvin-bot bot requested review from allroundexperts and removed request for a team November 30, 2023 19:33
Copy link

melvin-bot bot commented Nov 30, 2023

@allroundexperts Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@allroundexperts
Copy link
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: Native
Screen.Recording.2023-12-04.at.12.35.43.AM.mov
Android: mWeb Chrome
Screen.Recording.2023-12-04.at.12.34.17.AM.mov
iOS: Native
Screen.Recording.2023-12-04.at.12.32.33.AM.mov
iOS: mWeb Safari
Screen.Recording.2023-12-04.at.12.32.00.AM.mov
MacOS: Chrome / Safari Screenshot 2023-12-04 at 12 27 38 AM
MacOS: Desktop
Screen.Recording.2023-12-04.at.12.30.32.AM.mov

Copy link
Contributor

@allroundexperts allroundexperts left a comment

Choose a reason for hiding this comment

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

Looks good!

@melvin-bot melvin-bot bot requested a review from tgolen December 3, 2023 19:45
@samilabud samilabud force-pushed the android_chat_displayed_right_to_left_30584 branch from c81a9fe to 7c11e93 Compare December 4, 2023 23:13
@HardikChoudhary24
Copy link
Contributor

HardikChoudhary24 commented Dec 5, 2023

@samilabud @allroundexperts As I had worked on this for other platforms previously, I was getting some issues, and similar issues are visible in this change also:

  • Mention Suggestions
  • Draft comments
  • Sending an empty message
  • No placeholder for the composer
23-12-05-16-38-32.mp4

@allroundexperts
Copy link
Contributor

Thanks for testing this out @HardikChoudhary24. In the screenshots I attached, I can see that the placeholder was appearing at-least 🤔. @samilabud Can you please check the issues that @HardikChoudhary24 pointed out?

@samilabud
Copy link
Contributor Author

Good catch @HardikChoudhary24 thank you!.

@allroundexperts currently this works better, please check it out:

Testing.messages.gets.displayed.from.right.to.left.mp4

Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

I feel like the diff changed by an order of magnitude since the last time I looked at it and now I don't really follow the scope of the solution.

Are the problems mentioned by @HardikChoudhary24 caused by your PR, or are they existing bugs that are being fixed in this PR?

I think if they are regressions caused by your PR, they should be fixed in this PR. If they are existing bugs, then we should open up a new GH to track and fix them independently.

@samilabud
Copy link
Contributor Author

samilabud commented Dec 6, 2023

I feel like the diff changed by an order of magnitude since the last time I looked at it and now I don't really follow the scope of the solution.

Are the problems mentioned by @HardikChoudhary24 caused by your PR, or are they existing bugs that are being fixed in this PR?

I think if they are regressions caused by your PR, they should be fixed in this PR. If they are existing bugs, then we should open up a new GH to track and fix them independently.

Hi, issues mentioned by @HardikChoudhary24 are caused by my PR but it looks like they tried this before and didn't works or something.

I have fixed every scenario inside the corresponding files to make this change affect only android mobiles, also I have added comments that explain the why of this changes, please check them out 🙏🏼

Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

I know this is a lot of comments, but the changes in this PR really went down an interesting path!

src/libs/convertToLTR/index.android.ts Outdated Show resolved Hide resolved
src/libs/convertToLTR/index.android.ts Outdated Show resolved Hide resolved
src/libs/convertToLTR/index.android.ts Outdated Show resolved Hide resolved
src/libs/convertToLTR/index.ts Outdated Show resolved Hide resolved
src/libs/convertToLTRForComposer/index.android.ts Outdated Show resolved Hide resolved
src/libs/convertToLTR/index.android.ts Outdated Show resolved Hide resolved
src/libs/convertToLTR/index.ts Outdated Show resolved Hide resolved
@samilabud
Copy link
Contributor Author

I know this is a lot of comments, but the changes in this PR really went down an interesting path!

Thanks for the suggestions, I think I've addressed everything, please check back when you get a chance 🙏🏼

…naming variable from newCommentConverted to newCommentConvertedToLTR
@samilabud
Copy link
Contributor Author

Hi @tgolen, I think I finished with the changes please double-check because I marked the conversations as resolved and currently I see just 2 comments from you, could you please mark them as unsolved when you add a new comment? or maybe it is better to never mark comments as resolved 🤔.

BTW when I was testing I found a new bug (this is not related to this PR, the test was in https://staging.new.expensify.com):

Staging.Bug.in.Web.Chrome.mp4

Do you know where we can report this? I think we can fix it too.

@tgolen
Copy link
Contributor

tgolen commented Dec 8, 2023

For bugs not related to your PR, you can post them in the slack channel #expensify-bugs.

For the comments, I would usually never manually mark things as resolved. I know there were some issues with my previous review and having multiple comments, so I will go through it this morning and clean it up and give another review.

@samilabud
Copy link
Contributor Author

For bugs not related to your PR, you can post them in the slack channel #expensify-bugs.

For the comments, I would usually never manually mark things as resolved. I know there were some issues with my previous review and having multiple comments, so I will go through it this morning and clean it up and give another review.

Got it, thank you!

tgolen
tgolen previously approved these changes Dec 8, 2023
@tgolen
Copy link
Contributor

tgolen commented Dec 8, 2023

@allroundexperts do you want to give another testing pass on this to ensure it's still in working order before it's merged? There were quite a few changes since your initial testing I think.

@allroundexperts
Copy link
Contributor

Sure thing @tgolen. I'll retest this tonight/tomorrow.

@samilabud
Copy link
Contributor Author

I did some tests after the last change and everything seems to be ok:

Testing.regex.variable.names.mp4

Copy link
Contributor

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

It's looking better! I think we just need to clean up some of the grammar and comment formatting and then this is good.

* Sending an empty message;
* Mention suggestions not works if @ or \s (at or space) is the first character;
* Placeholder is not displayed if the unicode character is the only character remaining;
* force: always remove the LTR unicode, going to be used when composer is consider as empty */
Copy link
Contributor

Choose a reason for hiding this comment

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

The */ needs to go on the next line by itself.

* Sending an empty message;
* Mention suggestions not works if @ or \s (at or space) is the first character;
* Placeholder is not displayed if the unicode character is the only character remaining;
* force: always remove the LTR unicode, going to be used when composer is consider as empty */
Copy link
Contributor

Choose a reason for hiding this comment

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

If the force: comment is for the force param, please format it as a legit @param doc.

import ConvertToLTRForComposer from './types';

/**
* Android only - The composer can be converted to LTR if its content is the LTR character followed by an @ or space
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment should also explain why it's OK to convert it in these cases and why it shouldn't be converted. Consider adding "because..." and then fill out the rest.

* Android only - The composer can be converted to LTR if its content is the LTR character followed by an @ or space
*/
function canComposerBeConvertedToLTR(text: string): boolean {
// this handle cases when user type only spaces
Copy link
Contributor

Choose a reason for hiding this comment

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

Please start comments with a capital letter

Copy link
Contributor

Choose a reason for hiding this comment

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

"this handle cases" is not good grammar and should be more like "This regex handles the case when a user only types spaces into the composer.

function canComposerBeConvertedToLTR(text: string): boolean {
// this handle cases when user type only spaces
const containOnlySpaces = /^\s*$/;
// this handle the case where someone has RTL enabled and they began typing an @mention for someone.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do comments end with a period or not? Let's be consistent

const containOnlySpaces = /^\s*$/;
// this handle the case where someone has RTL enabled and they began typing an @mention for someone.
const startsWithLTRAndAt = new RegExp(`^${CONST.UNICODE.LTR}@$`);
// this handle cases could send empty messages when composer is multiline
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not quite sure what this means and the grammar is a bit confusing. Are you trying to say this?

This regex handles the case where the composer can contain multiple lines of whitespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right, sorry 😣!

@samilabud
Copy link
Contributor Author

Hi @tgolen, please verify again when you get a chance.

Comment on lines 26 to 27
* @newComment: the comment written by the user
* @force: always remove the LTR unicode, going to be used when composer is consider as empty */
Copy link
Contributor

Choose a reason for hiding this comment

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

These need to follow the JSDocs format: https://jsdoc.app/tags-param.

Copy link
Contributor

Choose a reason for hiding this comment

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

The */ is still on the wrong line.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, thanks for the link, I appreciate it (TIL).
Done.

@tgolen
Copy link
Contributor

tgolen commented Dec 17, 2023

All yours @allroundexperts

@allroundexperts
Copy link
Contributor

@samilabud Now I am getting the following issue:

Screen.Recording.2023-12-19.at.7.13.21.PM.mov

@samilabud
Copy link
Contributor Author

@samilabud Now I am getting the following issue:

Screen.Recording.2023-12-19.at.7.13.21.PM.mov

Hi, do you mean the delay where text takes to be from left to right? If so, this seems to be the expect behavior due android has not transitions when we convert the input to LTR from RTL

@allroundexperts
Copy link
Contributor

@samilabud I'm talking about the text suddenly moving from right to left. This did not happen in your previous versions. You can also confirm this by watching your / mine screen recordings for Android.

@samilabud
Copy link
Contributor Author

@samilabud I'm talking about the text suddenly moving from right to left. This did not happen in your previous versions. You can also confirm this by watching your / mine screen recordings for Android.

Got it, I have noticed this behavior from beginning but it seems related to emulator/device available resources, this happen even in web version with a bug I reported previously in this thread.

@samilabud
Copy link
Contributor Author

@allroundexperts I'm thinking maybe you mean the way it was it the beginning that we never allow the input to be converted to RTL but this causes mentions to not work, or blank messages to be sent, and so on. If this is a big issue please let me know so I can try to find another way to convert the input.

@tgolen
Copy link
Contributor

tgolen commented Dec 21, 2023

What's the status with this?

@allroundexperts I think you are suggesting that earlier commits in this PR didn't have the delay. Is that right?

@samilabud
Copy link
Contributor Author

Yes, this has been happening since the first commits (see the video at sec 3 to this comment) but maybe you don't notice because this depends on the resources available:

image

The reason is that we previously converted (in the proposal) the input before the user started typing (adding the Unicode), and now we have to wait for the user to type (to add the Unicode if has the conditions - to avoid sending an empty message, or mentions and placeholder works correctly).

In summary, as we have to wait for the user to write it is noticeable when Android converts the input from RTL to LTR.

@tgolen
Copy link
Contributor

tgolen commented Dec 21, 2023

I think that is OK to live with for now. Thank you for explaining! @allroundexperts are you OK for me to merge this then?

@allroundexperts
Copy link
Contributor

@tgolen If that's fine, then I think we can merge this.

@tgolen tgolen merged commit 91adf38 into Expensify:main Dec 26, 2023
16 checks passed
@tgolen
Copy link
Contributor

tgolen commented Dec 26, 2023

Late Christmas present :D I wish I could have merged this yesterday 🎄 🎅

@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@samilabud
Copy link
Contributor Author

Late Christmas present :D I wish I could have merged this yesterday 🎄 🎅

Thank you all, merry late Christmas! 🎄🎁 😊

@OSBotify
Copy link
Contributor

🚀 Deployed to production by https://github.com/mountiny in version: 1.4.18-8 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 failure ❌
🕸 web 🕸 success ✅

@samilabud samilabud deleted the android_chat_displayed_right_to_left_30584 branch April 29, 2024 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants