Browse Source

Don't crash if Modal related commands are called before root is set

We should also support showingModals on Android regardless of root
Guy Carmeli 6 years ago
parent
commit
aa8135dcbf

+ 14
- 1
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.support.annotation.NonNull;
5
 import android.support.annotation.NonNull;
6
+import android.support.annotation.Nullable;
6
 import android.view.ViewGroup;
7
 import android.view.ViewGroup;
7
 
8
 
8
 import com.reactnativenavigation.anim.ModalAnimator;
9
 import com.reactnativenavigation.anim.ModalAnimator;
14
 
15
 
15
 public class ModalPresenter {
16
 public class ModalPresenter {
16
 
17
 
17
-    private ViewGroup content;
18
+    @Nullable private ViewGroup content;
18
     private ModalAnimator animator;
19
     private ModalAnimator animator;
19
     private Options defaultOptions = new Options();
20
     private Options defaultOptions = new Options();
20
     private EventEmitter eventEmitter;
21
     private EventEmitter eventEmitter;
32
     }
33
     }
33
 
34
 
34
     public void showModal(ViewController toAdd, ViewController toRemove, CommandListener listener) {
35
     public void showModal(ViewController toAdd, ViewController toRemove, CommandListener listener) {
36
+        if (content == null) {
37
+            listener.onError("Could not show modal before setRoot is called");
38
+            return;
39
+        }
35
         Options options = toAdd.resolveCurrentOptions(defaultOptions);
40
         Options options = toAdd.resolveCurrentOptions(defaultOptions);
36
         toAdd.setWaitForRender(options.animations.showModal.waitForRender);
41
         toAdd.setWaitForRender(options.animations.showModal.waitForRender);
37
         content.addView(toAdd.getView());
42
         content.addView(toAdd.getView());
67
     }
72
     }
68
 
73
 
69
     public void dismissTopModal(ViewController toDismiss, @NonNull ViewController toAdd, CommandListener listener) {
74
     public void dismissTopModal(ViewController toDismiss, @NonNull ViewController toAdd, CommandListener listener) {
75
+        if (content == null) {
76
+            listener.onError("Could not dismiss modal before setRoot is called");
77
+            return;
78
+        }
70
         toAdd.attachView(content, 0);
79
         toAdd.attachView(content, 0);
71
         dismissModal(toDismiss, listener);
80
         dismissModal(toDismiss, listener);
72
     }
81
     }
73
 
82
 
74
     public void dismissModal(ViewController toDismiss, CommandListener listener) {
83
     public void dismissModal(ViewController toDismiss, CommandListener listener) {
84
+        if (content == null) {
85
+            listener.onError("Could not dismiss modal before setRoot is called");
86
+            return;
87
+        }
75
         if (toDismiss.options.animations.dismissModal.enable.isTrueOrUndefined()) {
88
         if (toDismiss.options.animations.dismissModal.enable.isTrueOrUndefined()) {
76
             animator.dismiss(toDismiss.getView(), toDismiss.options.animations.dismissModal, new AnimatorListenerAdapter() {
89
             animator.dismiss(toDismiss.getView(), toDismiss.options.animations.dismissModal, new AnimatorListenerAdapter() {
77
                 @Override
90
                 @Override

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

19
 import org.json.JSONException;
19
 import org.json.JSONException;
20
 import org.json.JSONObject;
20
 import org.json.JSONObject;
21
 import org.junit.Test;
21
 import org.junit.Test;
22
+import org.mockito.Mockito;
22
 
23
 
23
 import static org.assertj.core.api.Java6Assertions.assertThat;
24
 import static org.assertj.core.api.Java6Assertions.assertThat;
24
 import static org.mockito.ArgumentMatchers.any;
25
 import static org.mockito.ArgumentMatchers.any;
136
         verifyZeroInteractions(animator);
137
         verifyZeroInteractions(animator);
137
     }
138
     }
138
 
139
 
140
+    @Test
141
+    public void showModal_rejectIfContentIsNull() {
142
+        uut.setContentLayout(null);
143
+        CommandListenerAdapter listener = Mockito.mock(CommandListenerAdapter.class);
144
+        uut.showModal(modal1, modal2, listener);
145
+        verify(listener).onError(any());
146
+    }
147
+
139
     @Test
148
     @Test
140
     public void dismissModal_animatesByDefault() {
149
     public void dismissModal_animatesByDefault() {
141
         disableShowModalAnimation(modal1);
150
         disableShowModalAnimation(modal1);
210
         assertThat(root.getView().getParent()).isNotNull();
219
         assertThat(root.getView().getParent()).isNotNull();
211
         verify(root, times(0)).onViewDisappear();
220
         verify(root, times(0)).onViewDisappear();
212
     }
221
     }
222
+
223
+    @Test
224
+    public void dismissTopModal_rejectIfContentIsNull() {
225
+        uut.setContentLayout(null);
226
+        CommandListenerAdapter listener = Mockito.mock(CommandListenerAdapter.class);
227
+        uut.dismissTopModal(modal1, modal2, listener);
228
+        verify(listener).onError(any());
229
+    }
230
+
231
+    @Test
232
+    public void dismissModal_rejectIfContentIsNull() {
233
+        uut.setContentLayout(null);
234
+        CommandListenerAdapter listener = Mockito.mock(CommandListenerAdapter.class);
235
+        uut.dismissModal(modal1, listener);
236
+        verify(listener).onError(any());
237
+    }
213
 }
238
 }