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

Basic implementation of RCTModalHostView #1996

Merged
merged 10 commits into from
Nov 6, 2018
Merged

Conversation

howlettt
Copy link
Contributor

@howlettt howlettt commented Oct 9, 2018

My first stab at creating a modal implementation #618

@msftclas
Copy link

msftclas commented Oct 9, 2018

CLA assistant check
All CLA requirements met.

@howlettt
Copy link
Contributor Author

I believe the AppVeyor build failed since I apparently didn't push the RNTester submodule, which I have since pushed

public ReactModalShadowNode()
: base(false, true)
{
ApplicationView.GetForCurrentView().VisibleBoundsChanged += ApplicationViewOnVisibleBoundsChanged;
Copy link
Contributor

Choose a reason for hiding this comment

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

ApplicationView.GetForCurrentView().VisibleBoundsChanged [](start = 12, length = 56)

This won't work, unfortunately. This code is executed by layout manager thread.. It is a "Dispatcher" thread but with no active window.
You may have fallen into the trap of the DEBUG build that uses same main UI thread as LM thread as a workaround for some OS/VS/Debugging issue (Release has the CREATE_LAYOUT_THREAD defined)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just tested this running the Visual Studio release configuration, which I can see is enabling the CREATE_LAYOUT_THREAD, but the VisibleBoundsChanged event is still firing and resizing the dialog, am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After some more testing on a phone I noticed a few sizing issues. While fixing these issues I found a way to remove the VisibleBoundsChanged event.

Copy link
Contributor

@reseul reseul Oct 15, 2018

Choose a reason for hiding this comment

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

@howlettt I tested your branch since you made me curious about your findings. Even though you removed the bounds change, you still have the "ApplicationView.GetForCurrentView().VisibleBounds" when adding the child.
It's true that he visible bounds of the LM view seem to mimic the main view, looks like a code hazard to me.
The problem becomes more visible when you open new views. For ex, in RNTester:

  • Go to last item in list and choose "Multi Window", and then "New top level window". That creates a clone like RNTester window.
  • Size the 2 windows differently.
  • You'll see that LMView.VisibleBounds returns the values for main view even if you actually present the modal from the second.

This is not correct conceptually, though to be honest I played with various knobs and things look nice on screen in all cases (you may know better than me when those dimensions returned by the view really matter).

For RootViews RN cheats since the sizes come from JS side and UIImplementation just shoves them into the shadow nodes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm that could explain a oddity I saw (and had to work around) with the VisibleBounds returning slight incorrect sizing. The VisibleBounds call in the shadow node is currently only required for phone, desktop works fine without it. I haven't been able to find any other way to get phone to play nice. This solution is based off the Android code ModalHostShadowNode.java where they do a similar sizing call. I'll play with it some more to see if I get an idea of how to remove this VisibleBounds call, but currently I don't have any theories.

@LuisMiguelFilipe
Copy link

I tried using this implementation with ReactNative 0.52.0

The modal gets displayed with its RN content. But the RN is not reacting - for example click events are not performed. It seems that the modal node is not being orchestrated by React Native.

Shouldn't the modal be positioned under the ReactNativeHost node instead of being a top node?

Am i missing anything or is the PR still missing that part?

@howlettt
Copy link
Contributor Author

howlettt commented Nov 1, 2018

@LuisMiguelFilipe I've tested the modal using RN 0.55.0 and click events work. I specifically had to implement a TouchHandler to get the events firing. Would you be able to update to 55 and see if that fixes the events?
As for the node positioning, not entirely sure if I understand what you're referring to. Internally the modal is using a UWP ContentDialog, if that helps answer your question.

@howlettt
Copy link
Contributor Author

howlettt commented Nov 4, 2018

@reseul I've pushed the best workaround that I've come up with where the shadow node no longer requires the visible bounds

/// Instantiates the <see cref="ReactModalShadowNode"/>.
/// </summary>
public ReactModalShadowNode()
: base(false, true)
Copy link
Contributor

Choose a reason for hiding this comment

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

true [](start = 25, length = 5)

Did you use "delegated layout" on purpose? It would make me happy, that would mean there's more than one usage scenario for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had originally used it on purpose, but I don't recall exactly why, so I did some testing and it seems it's not required anymore. Sorry for getting your hopes up hah

}

/// <summary>
/// Shows the dialog if not visible otherwise updates it's properties
Copy link
Contributor

Choose a reason for hiding this comment

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

it's [](start = 62, length = 4)

small typo

contentSize.Height -= inputPane.OccludedRect.Height;

uiManagerModule.ActionQueue.Dispatch(() =>
{
Copy link
Contributor

Choose a reason for hiding this comment

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

This is good solution

// If multiple events have been dispatched, ignore all but the newest
if (currentCount == _resizeCount)
{
uiManagerModule.UIImplementation.UpdateRootNodeSize(tag, contentSize.Width, contentSize.Height);
Copy link
Contributor

Choose a reason for hiding this comment

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

uiManagerModule.UIImplementation.UpdateRootNodeSize(tag, contentSize.Width, contentSize.Height); [](start = 20, length = 96)

You should add a small comment pointing to the fact the tag is not really a root view, but it kind of works like one in some regards.

@reseul
Copy link
Contributor

reseul commented Nov 6, 2018

@howlettt This looks good, thanks for addressing the comments.
I just added some nits, I'm ready to approve but I know any change you make would dismiss that.

@reseul reseul merged commit 9614b68 into microsoft:master Nov 6, 2018
@howlettt
Copy link
Contributor Author

howlettt commented Nov 7, 2018

Awesome, thanks @reseul

@AhmedMustafa505
Copy link

Hello, how can I use this modal or how can I update the react-native-windows files to include your implemented modal ?

@howlettt
Copy link
Contributor Author

This modal implementation was done before the move to C++ so it's no longer supported.
See here for a recent update #2989 (comment)

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