Skip to content

Conversation

@WoLewicki
Copy link
Member

@WoLewicki WoLewicki commented Oct 22, 2020

Description

SC will stand for ScreenContainer. Added orientation management on Android. On every update of native-stack or navigators with using SC we check if there is orientation change needed. We do it by checking the top Screen and, if there is no child HeaderConfig (which has the priority) and there is a HeaderConfig above the Screen, changing the orientation according to it. If there are no child SCs in the Screen in onContainerUpdate even though the Screen has a child SC, it means that the child has not fired onAttachedToWindow, where the registration of child SC happens. It is not a problem, because then the correct update of orientation will be fired in onAttachedToWindow of the child Screen HeaderConfig, if it exists.

Changes

  • Added getHeaderConfig for unified checking for if Screen has a header
  • Abstracted updateChildFragments method for updating SC/ScreenStack children on update
  • Added hasChildScreenWithConfig that parses child SCs and checks if any of their Screens have HeaderConfig

Test code and steps to reproduce

Test42.js in TestsExample project.

Checklist

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

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

Accepting to unblock but I'm a bit hesitant of the code that does view hierarchy traversal. I don't understand why is it necessary – change events are fired at all levels when new screen appear, no?

Lets maybe discuss that last issue over call. Looks good otherwise.

return null;
}

protected static boolean checkIfChildWithConfig(View view) {
Copy link
Member

Choose a reason for hiding this comment

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

rename this to make it more descriptive. Do we really want to traverse all view hierarchy? Maybe it should be enought to only traverse fragments hierarchy?

}

// orientation
if (!ScreenFragment.checkIfChildWithConfig(getScreen() != null ? getScreen().getChildAt(1) : null)) {
Copy link
Member

Choose a reason for hiding this comment

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

This look weird. What's the point of calling checkIfChildWithConfig(null)? Does it have side effect? I also commented that the name of this method isn't really very informative. Also its role isn't very clear by looking at that name neither by looking at the way we use it in different places.

return null;
}

public int getScreenOrientation(){
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public int getScreenOrientation(){
public int getScreenOrientation() {

@WoLewicki WoLewicki force-pushed the @wolewicki/android-orientation branch from 70c1380 to 4043353 Compare December 16, 2020 14:07
public void onStackUpdate() {
@Override
public void onContainerUpdate() {
View child = mScreenView.getChildAt(0);
Copy link
Member

Choose a reason for hiding this comment

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

call super?

@WoLewicki WoLewicki force-pushed the @wolewicki/android-orientation branch from e8578cc to beb5f06 Compare December 22, 2020 11:02
Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

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

Left a few more comments inline. sorry for delaying this but I think we are really close.

tryCommitTransaction();
}

protected void updateChildFragments() {
Copy link
Member

Choose a reason for hiding this comment

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

There is nothing that we update in this method. maybe rename to notifyOnUpdate or notifyContainerUpdate or sth else along these lines

ScreenStackHeaderConfig config = findHeaderConfig();
boolean configInChild = hasChildScreenWithConfig(getScreen());
if (!configInChild && config != null && config.getScreenFragment().getActivity() != null) {
// if there is no child with config, we look for a parent with config to set the orientation
Copy link
Member

Choose a reason for hiding this comment

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

I'm still a bit confused by this. Why we check if children have config while findHeaderConfig searches for the config in current container or in its parents? If it isn't trivial to explain maybe we can discuss over call and figure out best way to describe it here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's have a structure of ScreenStack -> ScreenContainer -> ScreenStack. We do this check in case the update of the container was triggered after setting the orientation in the child stack, which would result in setting the orientation of the parent ScreenStack even though the child ScreenStack should have priority. At the same time, we want to have an option to change the orientation on every update of container, because the middle ScreenContainer can have children that are not ScreenStacks, so after navigating from a child that is a ScreenStack to a child that is not, we want the orientation to be taken and applied from the parent ScreenStack.

Is this explanation clear enough?

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, it is probably good to change the code to only look for the parent Screen with config if there is no child with config to avoid traversing the hierarchy when not needed.

for (ScreenContainer sc : screen.getFragment().getChildScreenContainers()) {
if (sc instanceof ScreenStack) {
// we check only the top screen of stack for header config
Screen topScreen = ((ScreenStack) sc).getTopScreen();
Copy link
Member

Choose a reason for hiding this comment

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

We may already be doing this in othre places but it struct me that we refer to subclasses (stack) from places that operate on a lower level of abstraction (screen) . Maybe we can add some interface method to screen container such that we can avoid testing against the type here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we don't do it in other places. I can add getTopScreen method to ScreenContainer that will return the Screen with ActivityState.ON_TOP.

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

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

Accepting this to ublock. Code looks mostly fine, I left a few more comments.

mFragmentManager.executePendingTransactions();

performUpdate();
notifyContainerUpdate();
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this be called directly from perfomUpdate? Are there any other ways performUpdate method is called when we don't want notify to be triggered? If not why?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think not. I added this here since we call it both in ScreenContainer and ScreenStack this way and if it is in perfomUpdate, then we need to use this method in both classes. I don't have a strong opinion on this.

return null;
}

protected boolean hasChildScreenWithConfig(Screen screen) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it'd be worth keeping track of whether there are children with config upon container updates. It seem like this parameter can change when we add new children or when the "top screen changes". Maybe we could add some bottom-up notification mechanism that'd be triggered when such an even occur that'd allow to keep the up-to-date information whether there are children with config instead of doing this traversal which potentially runs on every level in screen container hierarchy and runs the same code for the same container instances multiple times.

ViewParent parent = getScreen().getContainer();
while (parent != null) {
if (parent instanceof Screen) {
((Screen) parent).getFragment().mHasChildWithConfig = hasChildWithConfig;
Copy link
Member

Choose a reason for hiding this comment

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

If this does not result in mHasChildWithConfig change there is no point in updating other parents up the view hierarchy (there will be no updates as well) – we can break the loop if this occurs

return false;
}

protected void markParentFragments(boolean hasChildWithConfig) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is correct. If there is one childrent with config and one without, then when the second one updates, it will send information to the parent that there is no config (but the first childrent still has config).

I think that instead this method should actually check flags with all its children (not recursively) and then if the new value for the flag is different than the previous one also notify its parent

@WoLewicki WoLewicki merged commit bcd5e4d into master Jan 25, 2021
@WoLewicki WoLewicki deleted the @wolewicki/android-orientation branch January 25, 2021 14:52
WoLewicki added a commit that referenced this pull request Jan 28, 2021
SC will stand for ScreenContainer. Added orientation management on Android. On every update of native-stack or navigators with using SC we check if there is orientation change needed. We do it by checking the top Screen and, if there is no child HeaderConfig (which has the priority) and there is a HeaderConfig above the Screen, changing the orientation according to it. If there are no child SCs in the Screen in onContainerUpdate even though the Screen has a child SC, it means that the child has not fired onAttachedToWindow, where the registration of child SC happens. It is not a problem, because then the correct update of orientation will be fired in onAttachedToWindow of the child Screen HeaderConfig, if it exists.
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.

4 participants