-
-
Notifications
You must be signed in to change notification settings - Fork 593
feat: android orientation management #679
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
Conversation
There was a problem hiding this 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) { |
There was a problem hiding this comment.
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)) { |
There was a problem hiding this comment.
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(){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public int getScreenOrientation(){ | |
| public int getScreenOrientation() { |
70c1380 to
4043353
Compare
| public void onStackUpdate() { | ||
| @Override | ||
| public void onContainerUpdate() { | ||
| View child = mScreenView.getChildAt(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call super?
e8578cc to
beb5f06
Compare
android/src/main/java/com/swmansion/rnscreens/ScreenContainer.java
Outdated
Show resolved
Hide resolved
android/src/main/java/com/swmansion/rnscreens/ScreenFragment.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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() { |
There was a problem hiding this comment.
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
android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java
Outdated
Show resolved
Hide resolved
| 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
android/src/main/java/com/swmansion/rnscreens/ScreenContainer.java
Outdated
Show resolved
Hide resolved
| mFragmentManager.executePendingTransactions(); | ||
|
|
||
| performUpdate(); | ||
| notifyContainerUpdate(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
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.
Description
SCwill stand forScreenContainer. Added orientation management on Android. On every update ofnative-stackor navigators with usingSCwe check if there is orientation change needed. We do it by checking the topScreenand, if there is no childHeaderConfig(which has the priority) and there is aHeaderConfigabove theScreen, changing the orientation according to it. If there are no childSCs in theScreeninonContainerUpdateeven though theScreenhas a childSC, it means that the child has not firedonAttachedToWindow, where the registration of childSChappens. It is not a problem, because then the correct update of orientation will be fired inonAttachedToWindowof the childScreenHeaderConfig, if it exists.Changes
getHeaderConfigfor unified checking for ifScreenhas a headerupdateChildFragmentsmethod for updatingSC/ScreenStackchildren on updatehasChildScreenWithConfigthat parses childSCsand checks if any of theirScreenshaveHeaderConfigTest code and steps to reproduce
Test42.jsinTestsExampleproject.Checklist