Browse Source

Detach root by default when modal is displayed

Guy Carmeli 6 years ago
parent
commit
66b5c4600a

+ 1
- 12
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java View File

172
     }
172
     }
173
 
173
 
174
     public void showModal(final ViewController viewController, CommandListener listener) {
174
     public void showModal(final ViewController viewController, CommandListener listener) {
175
-        modalStack.showModal(viewController, new CommandListenerAdapter() {
176
-            @Override
177
-            public void onSuccess(String childId) {
178
-                contentLayout.removeView(root.getView());
179
-                listener.onSuccess(childId);
180
-            }
181
-
182
-            @Override
183
-            public void onError(String message) {
184
-                listener.onError(message);
185
-            }
186
-        });
175
+        modalStack.showModal(viewController, root, listener);
187
     }
176
     }
188
 
177
 
189
     public void dismissModal(final String componentId, CommandListener listener) {
178
     public void dismissModal(final String componentId, CommandListener listener) {

+ 6
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java View File

3
 import android.animation.Animator;
3
 import android.animation.Animator;
4
 import android.animation.AnimatorListenerAdapter;
4
 import android.animation.AnimatorListenerAdapter;
5
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
6
+import android.view.ViewManager;
6
 
7
 
7
 import com.reactnativenavigation.anim.ModalAnimator;
8
 import com.reactnativenavigation.anim.ModalAnimator;
8
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
9
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
23
         this.content = contentLayout;
24
         this.content = contentLayout;
24
     }
25
     }
25
 
26
 
26
-    public void showModal(ViewController toAdd, @Nullable ViewController toRemove, CommandListener listener) {
27
+    public void showModal(ViewController toAdd, ViewController toRemove, CommandListener listener) {
27
         content.addView(toAdd.getView());
28
         content.addView(toAdd.getView());
28
         if (toAdd.options.animations.showModal.enable.isTrueOrUndefined()) {
29
         if (toAdd.options.animations.showModal.enable.isTrueOrUndefined()) {
29
             animator.show(toAdd.getView(), toAdd.options.animations.showModal, new AnimatorListenerAdapter() {
30
             animator.show(toAdd.getView(), toAdd.options.animations.showModal, new AnimatorListenerAdapter() {
30
                 @Override
31
                 @Override
31
                 public void onAnimationEnd(Animator animation) {
32
                 public void onAnimationEnd(Animator animation) {
32
-                    onShowModalEnd(toRemove, listener, toAdd);
33
+                    onShowModalEnd(toAdd, toRemove, listener);
33
                 }
34
                 }
34
             });
35
             });
35
         } else {
36
         } else {
36
-            onShowModalEnd(toRemove, listener, toAdd);
37
+            onShowModalEnd(toAdd, toRemove, listener);
37
         }
38
         }
38
     }
39
     }
39
 
40
 
40
-    private void onShowModalEnd(@Nullable ViewController toRemove, CommandListener listener, ViewController toAdd) {
41
-        if (toRemove != null) content.removeView(toRemove.getView());
41
+    private void onShowModalEnd(ViewController toAdd, ViewController toRemove, CommandListener listener) {
42
+        ((ViewManager) toRemove.getView().getParent()).removeView(toRemove.getView());
42
         listener.onSuccess(toAdd.getId());
43
         listener.onSuccess(toAdd.getId());
43
     }
44
     }
44
 
45
 

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalStack.java View File

23
         presenter.setContentLayout(contentLayout);
23
         presenter.setContentLayout(contentLayout);
24
     }
24
     }
25
 
25
 
26
-    public void showModal(ViewController viewController, CommandListener listener) {
27
-        ViewController toRemove = isEmpty() ? null : peek();
26
+    public void showModal(ViewController viewController, ViewController root, CommandListener listener) {
27
+        ViewController toRemove = isEmpty() ? root : peek();
28
         modals.add(viewController);
28
         modals.add(viewController);
29
         presenter.showModal(viewController, toRemove, listener);
29
         presenter.showModal(viewController, toRemove, listener);
30
     }
30
     }

+ 1
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java View File

426
 
426
 
427
         uut.dismissModal(child1.getId(), new CommandListenerAdapter());
427
         uut.dismissModal(child1.getId(), new CommandListenerAdapter());
428
         assertThat(parentController.getView().getParent()).isNotNull();
428
         assertThat(parentController.getView().getParent()).isNotNull();
429
+        verify(parentController, times(2)).onViewAppeared();
429
     }
430
     }
430
 
431
 
431
     @Test
432
     @Test

+ 19
- 8
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java View File

1
 package com.reactnativenavigation.viewcontrollers.modal;
1
 package com.reactnativenavigation.viewcontrollers.modal;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
+import android.view.ViewGroup;
4
 import android.widget.FrameLayout;
5
 import android.widget.FrameLayout;
5
 
6
 
6
 import com.reactnativenavigation.BaseTest;
7
 import com.reactnativenavigation.BaseTest;
9
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.utils.CommandListenerAdapter;
11
 import com.reactnativenavigation.utils.CommandListenerAdapter;
11
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
12
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
13
+import com.reactnativenavigation.viewcontrollers.ParentController;
12
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
 
15
 
14
 import org.junit.Test;
16
 import org.junit.Test;
17
+import org.mockito.Mockito;
15
 
18
 
16
 import static org.assertj.core.api.Java6Assertions.assertThat;
19
 import static org.assertj.core.api.Java6Assertions.assertThat;
17
 import static org.mockito.ArgumentMatchers.any;
20
 import static org.mockito.ArgumentMatchers.any;
19
 import static org.mockito.Mockito.spy;
22
 import static org.mockito.Mockito.spy;
20
 import static org.mockito.Mockito.times;
23
 import static org.mockito.Mockito.times;
21
 import static org.mockito.Mockito.verify;
24
 import static org.mockito.Mockito.verify;
25
+import static org.mockito.Mockito.when;
22
 
26
 
23
 public class ModalPresenterTest extends BaseTest {
27
 public class ModalPresenterTest extends BaseTest {
24
     private static final String MODAL_ID_1 = "modalId1";
28
     private static final String MODAL_ID_1 = "modalId1";
29
     private ModalPresenter uut;
33
     private ModalPresenter uut;
30
     private FrameLayout contentLayout;
34
     private FrameLayout contentLayout;
31
     private ModalAnimator animator;
35
     private ModalAnimator animator;
36
+    private ViewController rootController;
32
 
37
 
33
     @Override
38
     @Override
34
     public void beforeEach() {
39
     public void beforeEach() {
35
         Activity activity = newActivity();
40
         Activity activity = newActivity();
36
-        animator = spy(new ModalAnimator(activity));
37
-        uut = new ModalPresenter(animator);
41
+
42
+        ViewGroup root = new FrameLayout(activity);
43
+        rootController = Mockito.mock(ParentController.class);
44
+        when(this.rootController.getView()).then(invocation -> root);
38
         contentLayout = new FrameLayout(activity);
45
         contentLayout = new FrameLayout(activity);
46
+        contentLayout.addView(root);
39
         activity.setContentView(contentLayout);
47
         activity.setContentView(contentLayout);
48
+
49
+        animator = spy(new ModalAnimator(activity));
50
+        uut = new ModalPresenter(animator);
40
         uut.setContentLayout(contentLayout);
51
         uut.setContentLayout(contentLayout);
41
         modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
52
         modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
42
         modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
53
         modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
52
                 verify(modal1, times(1)).onViewAppeared();
63
                 verify(modal1, times(1)).onViewAppeared();
53
             }
64
             }
54
         });
65
         });
55
-        uut.showModal(modal1, null, listener);
66
+        uut.showModal(modal1, rootController, listener);
56
         verify(animator, times(0)).show(
67
         verify(animator, times(0)).show(
57
                 eq(modal1.getView()),
68
                 eq(modal1.getView()),
58
                 eq(modal1.options.animations.showModal),
69
                 eq(modal1.options.animations.showModal),
97
     public void dismissModal_animatesByDefault() {
108
     public void dismissModal_animatesByDefault() {
98
         disableShowModalAnimation(modal1);
109
         disableShowModalAnimation(modal1);
99
 
110
 
100
-        uut.showModal(modal1, null, new CommandListenerAdapter());
101
-        uut.dismissModal(modal1, null, new CommandListenerAdapter() {
111
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
112
+        uut.dismissModal(modal1, rootController, new CommandListenerAdapter() {
102
             @Override
113
             @Override
103
             public void onSuccess(String childId) {
114
             public void onSuccess(String childId) {
104
                 verify(modal1, times(1)).onViewDisappear();
115
                 verify(modal1, times(1)).onViewDisappear();
122
         disableShowModalAnimation(modal1);
133
         disableShowModalAnimation(modal1);
123
         disableDismissModalAnimation(modal1);
134
         disableDismissModalAnimation(modal1);
124
 
135
 
125
-        uut.showModal(modal1, null, new CommandListenerAdapter());
126
-        uut.dismissModal(modal1, null, new CommandListenerAdapter());
136
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
137
+        uut.dismissModal(modal1, rootController, new CommandListenerAdapter());
127
         verify(modal1, times(1)).onViewDisappear();
138
         verify(modal1, times(1)).onViewDisappear();
128
         verify(modal1, times(1)).destroy();
139
         verify(modal1, times(1)).destroy();
129
         verify(animator, times(0)).dismiss(any(), any());
140
         verify(animator, times(0)).dismiss(any(), any());
133
     public void dismissModal_previousModalIsAddedBackToHierarchy() {
144
     public void dismissModal_previousModalIsAddedBackToHierarchy() {
134
         disableShowModalAnimation(modal1, modal2);
145
         disableShowModalAnimation(modal1, modal2);
135
 
146
 
136
-        uut.showModal(modal1, null, new CommandListenerAdapter());
147
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
137
         uut.showModal(modal2, modal1, new CommandListenerAdapter());
148
         uut.showModal(modal2, modal1, new CommandListenerAdapter());
138
         assertThat(modal1.getView().getParent()).isNull();
149
         assertThat(modal1.getView().getParent()).isNull();
139
         uut.dismissModal(modal2, modal1, new CommandListenerAdapter());
150
         uut.dismissModal(modal2, modal1, new CommandListenerAdapter());

+ 34
- 21
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java View File

10
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Options;
11
 import com.reactnativenavigation.utils.CommandListenerAdapter;
11
 import com.reactnativenavigation.utils.CommandListenerAdapter;
12
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
12
 import com.reactnativenavigation.viewcontrollers.Navigator.CommandListener;
13
+import com.reactnativenavigation.viewcontrollers.ParentController;
13
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 
15
 
15
 import org.junit.Test;
16
 import org.junit.Test;
17
+import org.mockito.Mockito;
16
 
18
 
17
 import java.util.EmptyStackException;
19
 import java.util.EmptyStackException;
18
 
20
 
25
 import static org.mockito.Mockito.times;
27
 import static org.mockito.Mockito.times;
26
 import static org.mockito.Mockito.verify;
28
 import static org.mockito.Mockito.verify;
27
 import static org.mockito.Mockito.verifyZeroInteractions;
29
 import static org.mockito.Mockito.verifyZeroInteractions;
30
+import static org.mockito.Mockito.when;
28
 
31
 
29
 public class ModalStackTest extends BaseTest {
32
 public class ModalStackTest extends BaseTest {
30
     private static final String MODAL_ID_1 = "modalId1";
33
     private static final String MODAL_ID_1 = "modalId1";
38
     private Activity activity;
41
     private Activity activity;
39
     private ModalPresenter presenter;
42
     private ModalPresenter presenter;
40
     private ModalAnimator animator;
43
     private ModalAnimator animator;
44
+    private ViewController rootController;
41
 
45
 
42
     @Override
46
     @Override
43
     public void beforeEach() {
47
     public void beforeEach() {
44
         activity = newActivity();
48
         activity = newActivity();
49
+
45
         ViewGroup root = new FrameLayout(activity);
50
         ViewGroup root = new FrameLayout(activity);
46
-        activity.setContentView(root);
51
+        rootController = Mockito.mock(ParentController.class);
52
+        when(this.rootController.getView()).then(invocation -> root);
53
+        FrameLayout activityContentView = new FrameLayout(activity);
54
+        activityContentView.addView(root);
55
+        activity.setContentView(activityContentView);
56
+
47
         animator = spy(new ModalAnimatorMock(activity));
57
         animator = spy(new ModalAnimatorMock(activity));
48
         presenter = spy(new ModalPresenter(animator));
58
         presenter = spy(new ModalPresenter(animator));
49
         uut = new ModalStack(presenter);
59
         uut = new ModalStack(presenter);
50
-        uut.setContentLayout(root);
60
+        uut.setContentLayout(activityContentView);
51
         modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
61
         modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
52
         modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
62
         modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
53
         modal3 = spy(new SimpleViewController(activity, MODAL_ID_3, new Options()));
63
         modal3 = spy(new SimpleViewController(activity, MODAL_ID_3, new Options()));
57
     public void modalRefIsSaved() {
67
     public void modalRefIsSaved() {
58
         disableShowModalAnimation(modal1);
68
         disableShowModalAnimation(modal1);
59
         CommandListener listener = spy(new CommandListenerAdapter());
69
         CommandListener listener = spy(new CommandListenerAdapter());
60
-        uut.showModal(modal1, listener);
70
+        uut.showModal(modal1, rootController, listener);
61
         verify(listener, times(1)).onSuccess(modal1.getId());
71
         verify(listener, times(1)).onSuccess(modal1.getId());
62
         assertThat(findModal(MODAL_ID_1)).isNotNull();
72
         assertThat(findModal(MODAL_ID_1)).isNotNull();
63
     }
73
     }
65
     @Test
75
     @Test
66
     public void showModal() {
76
     public void showModal() {
67
         CommandListener listener = spy(new CommandListenerAdapter());
77
         CommandListener listener = spy(new CommandListenerAdapter());
68
-        uut.showModal(modal1, listener);
78
+        uut.showModal(modal1, rootController, listener);
69
         verify(listener, times(1)).onSuccess(modal1.getId());
79
         verify(listener, times(1)).onSuccess(modal1.getId());
70
         assertThat(uut.size()).isOne();
80
         assertThat(uut.size()).isOne();
71
-        verify(presenter, times(1)).showModal(modal1, null, listener);
81
+        verify(presenter, times(1)).showModal(modal1, rootController, listener);
72
         assertThat(findModal(MODAL_ID_1)).isNotNull();
82
         assertThat(findModal(MODAL_ID_1)).isNotNull();
73
     }
83
     }
74
 
84
 
75
     @SuppressWarnings("Convert2Lambda")
85
     @SuppressWarnings("Convert2Lambda")
76
     @Test
86
     @Test
77
     public void dismissModal() {
87
     public void dismissModal() {
78
-        uut.showModal(modal1, new CommandListenerAdapter());
88
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
79
         CommandListener listener = new CommandListenerAdapter();
89
         CommandListener listener = new CommandListenerAdapter();
80
         Runnable onModalWillDismiss = spy(new Runnable() {
90
         Runnable onModalWillDismiss = spy(new Runnable() {
81
             @Override
91
             @Override
107
 
117
 
108
     @Test
118
     @Test
109
     public void dismissAllModals() {
119
     public void dismissAllModals() {
110
-        uut.showModal(modal1, new CommandListenerAdapter());
111
-        uut.showModal(modal2, new CommandListenerAdapter());
120
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
121
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
112
         CommandListener listener = spy(new CommandListenerAdapter() {
122
         CommandListener listener = spy(new CommandListenerAdapter() {
113
             @Override
123
             @Override
114
             public void onSuccess(String childId) {
124
             public void onSuccess(String childId) {
132
     @SuppressWarnings("Convert2Lambda")
142
     @SuppressWarnings("Convert2Lambda")
133
     @Test
143
     @Test
134
     public void dismissAllModals_onlyTopModalIsAnimated() {
144
     public void dismissAllModals_onlyTopModalIsAnimated() {
135
-        uut.showModal(modal1, new CommandListenerAdapter());
136
-        uut.showModal(modal2, new CommandListenerAdapter());
145
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
146
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
137
 
147
 
138
         ViewGroup view1 = modal1.getView();
148
         ViewGroup view1 = modal1.getView();
139
         ViewGroup view2 = modal2.getView();
149
         ViewGroup view2 = modal2.getView();
154
 
164
 
155
     @Test
165
     @Test
156
     public void dismissAllModals_bottomModalsAreDestroyed() {
166
     public void dismissAllModals_bottomModalsAreDestroyed() {
157
-        uut.showModal(modal1, new CommandListenerAdapter());
158
-        uut.showModal(modal2, new CommandListenerAdapter());
167
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
168
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
159
 
169
 
160
         uut.dismissAllModals(new CommandListenerAdapter(), () -> {});
170
         uut.dismissAllModals(new CommandListenerAdapter(), () -> {});
161
 
171
 
167
     @Test
177
     @Test
168
     public void isEmpty() {
178
     public void isEmpty() {
169
         assertThat(uut.isEmpty()).isTrue();
179
         assertThat(uut.isEmpty()).isTrue();
170
-        uut.showModal(modal1, new CommandListenerAdapter());
180
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
171
         assertThat(uut.isEmpty()).isFalse();
181
         assertThat(uut.isEmpty()).isFalse();
172
         uut.dismissAllModals(new CommandListenerAdapter(), () -> {});
182
         uut.dismissAllModals(new CommandListenerAdapter(), () -> {});
173
         assertThat(uut.isEmpty()).isTrue();
183
         assertThat(uut.isEmpty()).isTrue();
177
     public void peek() {
187
     public void peek() {
178
         assertThat(uut.isEmpty()).isTrue();
188
         assertThat(uut.isEmpty()).isTrue();
179
         assertThatThrownBy(() -> uut.peek()).isInstanceOf(EmptyStackException.class);
189
         assertThatThrownBy(() -> uut.peek()).isInstanceOf(EmptyStackException.class);
180
-        uut.showModal(modal1, new CommandListenerAdapter() {
190
+        uut.showModal(modal1, rootController, new CommandListenerAdapter() {
181
             @Override
191
             @Override
182
             public void onSuccess(String childId) {
192
             public void onSuccess(String childId) {
183
                 assertThat(uut.peek()).isEqualTo(modal1);
193
                 assertThat(uut.peek()).isEqualTo(modal1);
189
     public void onDismiss_onViewAppearedInvokedOnPreviousModal() {
199
     public void onDismiss_onViewAppearedInvokedOnPreviousModal() {
190
         disableShowModalAnimation(modal1, modal2);
200
         disableShowModalAnimation(modal1, modal2);
191
 
201
 
192
-        uut.showModal(modal1, new CommandListenerAdapter());
193
-        uut.showModal(modal2, new CommandListenerAdapter());
202
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
203
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
194
         uut.dismissModal(modal2.getId(), () -> {}, new CommandListenerAdapter());
204
         uut.dismissModal(modal2.getId(), () -> {}, new CommandListenerAdapter());
195
         verify(modal1, times(2)).onViewAppeared();
205
         verify(modal1, times(2)).onViewAppeared();
196
     }
206
     }
200
         disableShowModalAnimation(modal1, modal2, modal3);
210
         disableShowModalAnimation(modal1, modal2, modal3);
201
         disableDismissModalAnimation(modal1, modal2, modal3);
211
         disableDismissModalAnimation(modal1, modal2, modal3);
202
 
212
 
203
-        uut.showModal(modal1, new CommandListenerAdapter());
204
-        uut.showModal(modal2, new CommandListenerAdapter());
205
-        uut.showModal(modal3, new CommandListenerAdapter());
213
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
214
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
215
+        uut.showModal(modal3, rootController, new CommandListenerAdapter());
206
 
216
 
207
         uut.dismissModal(modal2.getId(), () -> {}, new CommandListenerAdapter());
217
         uut.dismissModal(modal2.getId(), () -> {}, new CommandListenerAdapter());
208
         assertThat(uut.size()).isEqualTo(2);
218
         assertThat(uut.size()).isEqualTo(2);
220
     @Test
230
     @Test
221
     public void handleBack_dismissModal() {
231
     public void handleBack_dismissModal() {
222
         disableDismissModalAnimation(modal1);
232
         disableDismissModalAnimation(modal1);
223
-        uut.showModal(modal1, new CommandListenerAdapter());
233
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
224
         assertThat(uut.handleBack(new CommandListenerAdapter(), () -> {})).isTrue();
234
         assertThat(uut.handleBack(new CommandListenerAdapter(), () -> {})).isTrue();
225
         verify(modal1, times(1)).onViewDisappear();
235
         verify(modal1, times(1)).onViewDisappear();
226
 
236
 
234
                 return true;
244
                 return true;
235
             }
245
             }
236
         });
246
         });
237
-        uut.showModal(backHandlingModal, new CommandListenerAdapter());
247
+        uut.showModal(backHandlingModal, rootController, new CommandListenerAdapter());
248
+
249
+        rootController.getView().getViewTreeObserver().dispatchOnGlobalLayout();
250
+
238
         assertThat(uut.handleBack(new CommandListenerAdapter(), any())).isTrue();
251
         assertThat(uut.handleBack(new CommandListenerAdapter(), any())).isTrue();
239
         verify(backHandlingModal, times(1)).handleBack(any());
252
         verify(backHandlingModal, times(1)).handleBack(any());
240
         verify(backHandlingModal, times(0)).onViewDisappear();
253
         verify(backHandlingModal, times(0)).onViewDisappear();