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

prevent from publishing dimensions change event when app changes state #11

Merged
merged 6 commits into from
Jun 9, 2022

Conversation

lbaldy
Copy link

@lbaldy lbaldy commented May 24, 2022

Summary

An issue raised in Expensify/App#2727 has to be fixed in react native core. This impacts IOS only.

React Native issue: facebook#29290

Changelog

a) The body of the _interfaceOrientationDidChange:

Here we make sure we run this function when the app is in active and also it was switching to fullscreeen or is not running in fullscreen.

- (void)_interfaceOrientationDidChange
{
  UIInterfaceOrientation nextOrientation = [RCTSharedApplication() statusBarOrientation];
  UIApplicationState appState = [RCTSharedApplication() applicationState];
  BOOL isRunningInFullScreen = CGRectEqualToRect([UIApplication sharedApplication].delegate.window.frame, [UIApplication sharedApplication].delegate.window.screen.bounds);

  // Update when we go from portrait to landscape, or landscape to portrait
  if ((((UIInterfaceOrientationIsPortrait(_currentInterfaceOrientation) &&
       !UIInterfaceOrientationIsPortrait(nextOrientation)) ||
      (UIInterfaceOrientationIsLandscape(_currentInterfaceOrientation) &&
       !UIInterfaceOrientationIsLandscape(nextOrientation)) || (isRunningInFullScreen != _isFullscreen || !isRunningInFullScreen)))
      && appState == UIApplicationStateActive) {
      #pragma clang diagnostic push
      #pragma clang diagnostic ignored "-Wdeprecated-declarations"
          [[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"didUpdateDimensions"
                                                                                body:RCTExportedDimensions(_moduleRegistry)];
            _currentInterfaceOrientation = nextOrientation;
            _isFullscreen = isRunningInFullScreen;
      #pragma clang diagnostic pop
  }


}

b) _interfaceFrameDidChange

Here we make sure we run it when the app is in active state.

- (void)_interfaceFrameDidChange
{
  NSDictionary *nextInterfaceDimensions = RCTExportedDimensions(_moduleRegistry);
    UIApplicationState appState = [RCTSharedApplication() applicationState];

  if (!([nextInterfaceDimensions isEqual:_currentInterfaceDimensions]) && appState == UIApplicationStateActive) {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"didUpdateDimensions"
                                                                              body:nextInterfaceDimensions];
          _currentInterfaceDimensions = nextInterfaceDimensions;
    #pragma clang diagnostic pop
  }
}

c) Add the _isFullscreen variable to hold the previous state for multitasking view.

@implementation RCTDeviceInfo {
  UIInterfaceOrientation _currentInterfaceOrientation;
  NSDictionary *_currentInterfaceDimensions;
  BOOL _isFullscreen;
}

d) We need to make sure to run the interfaceOrientationDidChange instead of interfaceFrameDidChange when the UIApplicationDidBecomeActiveNotification occurs.

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(interfaceOrientationDidChange)
                                               name:UIApplicationDidBecomeActiveNotification
                                             object:nil];

Test Plan

Test Preparation

  1. Make sure you have a working version of E/App.
  2. Open App/src/components/withWindowDimensions.js and update the constructor by changing this line:

this.onDimensionChange = _.debounce(this.onDimensionChange.bind(this), 100);

to

this.onDimensionChange = this.onDimensionChange.bind(this);

  1. Open the NewExpensify.xcodeproj in xCode.
  2. Open the RCTDeviceInfo.mm file and replace it's contents with the file from this PR.
  3. Select your device of choice (I suggest starting with iPad mini) and run the app though xCode.
  4. From this point you can move to the test scenarios described below.

iPad Mini tests:

Reproduction + Fix test video (Test 1): https://youtu.be/jyzoNHLYHPo
Reproduction + Fix test video (Test 2): https://youtu.be/CLimE-Fba-g

Test 1:

  1. Launch app in portrait, open chat - no sidebar visible.
  2. Switch to landscape - sidebar shows.
  3. Put app to background.
  4. Put app back to foreground - make sure the side menu doesn't flicker.

Test 2:

  1. Launch app in portrait, open chat - no sidebar visible.
  2. Switch to landscape - sidebar shows.
  3. Put app to background. Switch orientation back to portrait.
  4. Put app back to foreground - make sure the side menu hides again as it should be in portrait.

iPad Pro tests:

Reproduction + Fix test video (Test 3, Test 4): https://youtu.be/EJkUUQCiLRg

iPad mini test 1 applies.

Scenario 2 does not as the screen is too wide in both orientations and iPad pro shows sidebar always.

Test 3:

  1. launch the app.
  2. Make sure you're in landscape mode.
  3. See split screen with some other app. Make sure the side bar is visible.
  4. Play with the size of the view, resize it a bit. When the view shrinks it should hide the sidebar, when it grows it should show it.
  5. Move the app to background and back to foreground, please observe there are no flickers.

Test 4:

  1. Launch the app.
  2. Make sure you're in landscape mode.
  3. Make the multitasking view and make Expensify app a slide over app.
  4. Move back to fullscreen/split screen. Make sure the menu is shown accordingly
  5. Move the app to background and back to foreground, please observe there are no flickers.

iPhone:

Non reg with and without the fix video: https://youtu.be/kuv9in8vtbk

Please perform standard smoke tests on transformation changes.

@parasharrajat
Copy link
Member

I see that PR can be improved in the following ways.

  • Formatting of OP.
  • It would be good to link existing RN issues to the PR.
  • Videos and reproduction.

@lbaldy
Copy link
Author

lbaldy commented May 25, 2022

@parasharrajat I added the videos of me reproducing the issue and testing this with the fix applied. Had to upload to youtube due to size constrains here on Github.

  • Formatting of OP.
    I updated the formatting to make the PR description a little bit more legible. If you see anything else that should be improved please let me know.
  • It would be good to link existing RN issues to the PR.
    I am not sure which issues you are referring to? I linked the original issue from the Expensify/App repo already.
  • Videos and reproduction.
    Added.

Please let me know if you believe anything else has to be imoproved/corrected.

Thanks.

@parasharrajat
Copy link
Member

I will test this today.

@lbaldy
Copy link
Author

lbaldy commented Jun 2, 2022

Hi @parasharrajat any news on this one?

@parasharrajat
Copy link
Member

parasharrajat commented Jun 2, 2022

On my list. Sorry for the delay. I broke my Mac past week so things got piled up.

@parasharrajat
Copy link
Member

It would be good to link existing RN issues to the PR.

Existing issues about this bug we are trying to solve. Please search RN codebase and link any whatever looks the same. In case there are none, create a new one which we can refer to while submitting the PR to RN.

@lbaldy
Copy link
Author

lbaldy commented Jun 5, 2022

@parasharrajat I updated the original post.

I added the facebook#29290 which was mentioned in the original Expensify/App#2727.

@parasharrajat
Copy link
Member

parasharrajat commented Jun 6, 2022

I will start reviewing this in few minutes. Code looks fine to me.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

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

I see your test cases. But you didn't mention test process. How can a person test these code changes on E/App? Please add this detail.

Also, add steps to test your changes in standard testing example app of RN.

Comment on lines 182 to 185
if ((((UIInterfaceOrientationIsPortrait(_currentInterfaceOrientation) &&
!UIInterfaceOrientationIsPortrait(nextOrientation)) ||
(UIInterfaceOrientationIsLandscape(_currentInterfaceOrientation) &&
!UIInterfaceOrientationIsLandscape(nextOrientation))) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"]
sendDeviceEventWithName:@"didUpdateDimensions"
body:RCTExportedDimensions(_moduleRegistry, _bridge)];
#pragma clang diagnostic pop
!UIInterfaceOrientationIsLandscape(nextOrientation)) || (isRunningInFullScreen != _isFullscreen || !isRunningInFullScreen)))
Copy link
Member

Choose a reason for hiding this comment

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

Let's break this if condition in more readable form. Also, improve the comment to indicate every case.

Copy link
Author

Choose a reason for hiding this comment

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

done, in b0c3bc7

Comment on lines -213 to -214

_currentInterfaceDimensions = nextInterfaceDimensions;
Copy link
Member

@parasharrajat parasharrajat Jun 6, 2022

Choose a reason for hiding this comment

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

Why are we moving these inside the if blocks?

Copy link
Author

Choose a reason for hiding this comment

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

I added a comment in code, but that's moved inside so that we make sure that the state between JS and Obj-C is synced. Meaning we only update the 'Native' state when it's published to JS.

@parasharrajat
Copy link
Member

We need to make sure to run the interfaceOrientationDidChange instead of interfaceFrameDidChange when the UIApplicationDidBecomeActiveNotification occurs.

Why?

@lbaldy
Copy link
Author

lbaldy commented Jun 6, 2022

We need to make sure to run the interfaceOrientationDidChange instead of interfaceFrameDidChange when the UIApplicationDidBecomeActiveNotification occurs.

Why?

So that in case of this event we also have the extended handler, which considers the fullscreen as well as active state.

@lbaldy
Copy link
Author

lbaldy commented Jun 6, 2022

Updated

@parasharrajat
Copy link
Member

parasharrajat commented Jun 6, 2022

Interesting, I am trying to test the iOS build in landscape mode. I commented the code that was used to prevent the landscape but still app is not going to landscape. This is giving me nuts.

Sorry, ignore this. I was doing totally different thing. 🗣️

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

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

I am running final tests. Looking good.

React/CoreModules/RCTDeviceInfo.mm Outdated Show resolved Hide resolved
React/CoreModules/RCTDeviceInfo.mm Outdated Show resolved Hide resolved
React/CoreModules/RCTDeviceInfo.mm Outdated Show resolved Hide resolved
Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

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

LGTM.

cc: @iwiznia Please review this PR.

@iwiznia iwiznia self-requested a review June 6, 2022 22:25
lbaldy and others added 3 commits June 7, 2022 09:15
Co-authored-by: Rajat Parashar <parasharrajat@users.noreply.github.com>
Co-authored-by: Rajat Parashar <parasharrajat@users.noreply.github.com>


BOOL isActive = appState == UIApplicationStateActive;
BOOL isChangingFullscreen = (isRunningInFullScreen != _isFullscreen || !isRunningInFullScreen);
Copy link

@sketchydroide sketchydroide Jun 7, 2022

Choose a reason for hiding this comment

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

this is a weird condition, and the name does not seem to match the condition
If we are keeping the condition logic, I think we need a comment to explain why this is not simply
BOOL isChangingFullscreen = isRunningInFullScreen != _isFullscreen;
Also the condition logic could be simplified to
BOOL isChangingFullscreen = !isRunningInFullScreen || !_isFullscreen;
And again I'm not entirely sure that condition makes sense

Copy link
Author

Choose a reason for hiding this comment

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

This condition indeed can be shortened to what you suggested, good catch. Thanks.

The condition is needed and called this way because it catches two scenarios:

a) Simple resize when the app isn't in the fullscreen mode right now - the !isRunningInFullScreen
b) Resize when the app gets from slide over mode to fullscreen - isRunningInFullScreen != _isFullscreen

Anyway, I commented this line with the above.

Copy link

@sketchydroide sketchydroide left a comment

Choose a reason for hiding this comment

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

I have a question about one of the conditions about isChangingFullscreen

The rest seems good

@sketchydroide sketchydroide self-requested a review June 7, 2022 10:34
@lbaldy
Copy link
Author

lbaldy commented Jun 7, 2022

Updated

Copy link

@sketchydroide sketchydroide left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

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

LGTM

🎀 👀 🎀 C+ reviewed

@lbaldy
Copy link
Author

lbaldy commented Jun 9, 2022

@parasharrajat is there any action pending on me to get this one merged? Or shall we simply wait for inputs from @iwiznia.

Copy link

@Justicea83 Justicea83 left a comment

Choose a reason for hiding this comment

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

LGTM!

@sketchydroide
Copy link

@lbaldy I think @iwiznia is still reviwieng this PR, he asked me to take a look as I'm more confortable with ObjC, but I think his input is still important

@parasharrajat
Copy link
Member

shall we simply wait for inputs from @iwiznia.

This one.

@iwiznia iwiznia merged commit f690dc1 into Expensify:master Jun 9, 2022
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