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

Fix for Update Global Offline Indicator #10140

Merged
merged 21 commits into from
Aug 3, 2022

Conversation

jasperhuangg
Copy link
Contributor

@jasperhuangg jasperhuangg commented Jul 27, 2022

NOTE TO REVIEWER: Recommend viewing diff without whitespace changes for more succinct review

We previously had this PR which was merged, but was later reverted due to a number of layout issues associated with the new KeyboardAvoidingView usage in the ScreenWrapper. This PR adds back everything that was reverted, and fixes the behavior of the ScreenWrapper in a number of places on Android. See linked issues in the old PR and the issue below for more context.

There were two main issues that we were running into that were causing bizarre gaps to form between the keyboard and the actual content. At times these gaps would push up the content so high that it would get cut off:

  1. On Android, we were using KeyboardAvoidingView components that had 'padding' passed into the behavior prop instead of 'height'. It's known that KeyboardAvoidingViews can have unexpected behavior if you don't use 'height'.
    https://user-images.githubusercontent.com/93399543/180846058-039d8bd0-d5e5-4d94-8ae1-9cb8e6c818bd.mp4
  2. On iOS, some components had KeyboardSpacer nested inside KeyboardAvoidingView, which would reapply the padding for the KeyboardAvoidingView twice, causing the gap to occur.

I've addressed both of these issues in this PR, primarily by refactoring the ScreenWrapper component (which houses the KeyboardAvoidingView).

Details

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/218715

Tests

  • Verify that no errors appear in the JS console
    See QA steps

PR Review Checklist

Contributor (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 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 included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • 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 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 was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team 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
  • 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 */
    • Any functional components have the displayName property
    • 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 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 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.
  • I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.

PR Reviewer Checklist

The Contributor+ will copy/paste it into a new comment and complete it after the author checklist is completed

  • 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 verified tests pass on all platforms & I tested again on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • 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 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 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 was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team 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 */
    • Any functional components have the displayName property
    • 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 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 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.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

QA Steps

  1. Sign into an account on NewDot.
  2. Turn off your wifi.
  3. Verify that the OfflineIndicator appears correctly (see screen captures).
  4. Turn on your wifi.
  5. Verify that the OfflineIndicator goes away.
  6. Repeat on all platforms.
  • Verify that no errors appear in the JS console

Screenshots

Web

Screen Shot 2022-08-01 at 7 33 26 PM

Mobile Web

ios safari
android chrome

Desktop

Screen Shot 2022-08-01 at 7 36 08 PM

iOS

Screen Shot 2022-08-01 at 7 28 56 PM

Android

Screen Shot 2022-08-01 at 7 30 31 PM

@jasperhuangg jasperhuangg self-assigned this Jul 27, 2022
@jasperhuangg jasperhuangg changed the title Fix for Update Global Offline Dndicator Fix for Update Global Offline Indicator Jul 27, 2022
@jasperhuangg jasperhuangg marked this pull request as ready for review July 28, 2022 18:31
@jasperhuangg jasperhuangg requested a review from a team as a code owner July 28, 2022 18:31
@melvin-bot melvin-bot bot requested review from arosiclair and removed request for a team July 28, 2022 18:31
@arosiclair
Copy link
Contributor

Code seems good, but I'm having trouble following all of the issues that came up with our first go at this. Can you summarize those issues and how to test them so we can make sure we've got it right this go around?

@jasperhuangg
Copy link
Contributor Author

@arosiclair got it! Will update the OP

@jasperhuangg
Copy link
Contributor Author

@arosiclair There seems to be a bug on Android that I found on main that you'll probably experience in this PR:

https://expensify.slack.com/archives/C03TQ48KC/p1659115536665949

@neil-marcellini neil-marcellini self-requested a review August 1, 2022 15:43
@neil-marcellini
Copy link
Contributor

This is a big PR and it's blocking a lot so I thought I would jump in and help review. Please fix those merge conflicts first.

@jasperhuangg
Copy link
Contributor Author

@neil-marcellini merge conflicts resolved!

Copy link
Contributor

@neil-marcellini neil-marcellini left a comment

Choose a reason for hiding this comment

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

I reviewed all the files and left 2 comments. Now I'm going to test all the pages that were changed, on all platforms. I'll also test out the offline indicator. Please add test and QA steps to the issue.

ios/Podfile.lock Outdated Show resolved Hide resolved
src/components/ScreenWrapper.js Show resolved Hide resolved
Copy link
Contributor

@neil-marcellini neil-marcellini left a comment

Choose a reason for hiding this comment

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

I'm not seeing the offline indicator on Android for some reason. (Edit: turn off mobile data)
image

@neil-marcellini
Copy link
Contributor

Hmm, it works fine on iOS.

src/pages/home/ReportScreen.js Outdated Show resolved Hide resolved
Copy link
Contributor

@neil-marcellini neil-marcellini left a comment

Choose a reason for hiding this comment

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

Here's what I get when offline on iOS, the spacing isn't fixed. It looks like the min height is getting set correctly, so something else must be causing it.

Aha, so if we show the recipient local time then we also apply this style that has minHeight: 90. That condition is probably why you didn't see the problem.

<View style={[shouldShowReportRecipientLocalTime && styles.chatItemComposeWithFirstRow, this.props.isComposerFullSize && styles.chatItemFullComposeRow]}>

App/src/styles/styles.js

Lines 1341 to 1343 in 2518e21

chatItemComposeWithFirstRow: {
minHeight: 90,
},

With a red border on `chatItemComposeWithFirstRow:

@neil-marcellini
Copy link
Contributor

Sorry to bring up another headache, but the full screen composer no longer works properly on iOS after these changes.

On your branch:

jaspers.mp4

On main:

main.mp4

@shawnborton
Copy link
Contributor

Also just wanted to confirm that we don't get any screen bouncing when the offline indicator shows up and disappears? Ideally this takes up the exact same space/spot as the "User is typing" indicator.

@jasperhuangg
Copy link
Contributor Author

Also just wanted to confirm that we don't get any screen bouncing when the offline indicator shows up and disappears? Ideally this takes up the exact same space/spot as the "User is typing" indicator.

Ah there is a very slight amount of jumping, I'll make sure to get rid of it.

@jasperhuangg
Copy link
Contributor Author

jasperhuangg commented Aug 2, 2022

@neil-marcellini fixed the issues you mentioned! thanks for being so thorough with this review I really appreciate it

Screen Shot 2022-08-02 at 4 01 03 PM

Screen Shot 2022-08-02 at 4 49 43 PM

Screen Shot 2022-08-02 at 4 45 53 PM

also @shawnborton made sure that there isn't any jumping happening:

Untitled.mp4

@shawnborton
Copy link
Contributor

Awesome, thank you!

@shawnborton shawnborton self-requested a review August 2, 2022 23:55
Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

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

Tested this nad looks good to me, the only problem I had was testing on iOS where it took a long while before the offline indicator showed up and then it kinda randomly dissappeared twice, probably not sure if the device is offline or not.

Not sure what is the best way to set the ios simulator offline. Styling wise it looks good to me!

Copy link
Contributor

@neil-marcellini neil-marcellini left a comment

Choose a reason for hiding this comment

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

Thanks for the changes, it's working really well now! I think it's good to go.

NAB:
It would be nice to move the mobile ReportTypingIndicator to the right side so that it doesn't stack on top of the offline indicator. It would also match the web / desktop behavior. Doing that might be kind of tricky, and I doubt many people hit the max comment length, so I think we can do it later.

Mobile:

Web:
image

@neil-marcellini neil-marcellini merged commit 1d06ec9 into main Aug 3, 2022
@neil-marcellini neil-marcellini deleted the jasper-fixUpdateGlobalOfflineIndicator branch August 3, 2022 15:52
@OSBotify
Copy link
Contributor

OSBotify commented Aug 3, 2022

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

@jasperhuangg
Copy link
Contributor Author

jasperhuangg commented Aug 3, 2022

It would be nice to move the mobile ReportTypingIndicator to the right side so that it doesn't stack on top of the offline indicator.

We can always make an issue for later? @neil-marcellini It's definitely going to be kinda tricky because the OfflineIndicator for mobile is going to be in the ScreenWrapper which is higher up in the component hierarchy than the ReportTypingIndicator so we'd have to figure out some way to apply flex styling to them both.

@OSBotify
Copy link
Contributor

OSBotify commented Aug 4, 2022

🚀 Deployed to staging by @neil-marcellini in version: 1.1.88-0 🚀

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

paddingStyle,
]}
>
<KeyboardAvoidingView style={[styles.w100, styles.h100]} behavior={this.props.keyboardAvoidingViewBehavior}>
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI, this caused the regression in #10905 because the FAB (floating action button) also has a keyboardAvoidingView in it, so this caused the code to have nested keyboardAvoidingViews.

@mananjadhav
Copy link
Collaborator

I am tagging this PR to highlight an issue fixed here. All conditions in ternary expressions or left-hand operands on conditional renders, should be boolean. This PR is one of the PRs that uses conditional render with string operands, hence I am tagging it here for the contributors to check.

We've also updated the item in the checklist with this PR to avoid this issue in the future.

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.

10 participants