Browse Source

Merge options (#3930)

mergeOptions support for commands
Guy Carmeli 6 years ago
parent
commit
2c7dccc677
No account linked to committer's email address
26 changed files with 241 additions and 180 deletions
  1. 1
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java
  2. 22
    16
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  3. 1
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildController.java
  4. 1
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  5. 8
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  6. 2
    12
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  7. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalStack.java
  8. 9
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java
  9. 8
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  10. 2
    2
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java
  11. 13
    13
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  12. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  13. 7
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java
  14. 18
    5
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java
  15. 46
    19
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.java
  16. 10
    10
      lib/ios/RNNBridgeModule.m
  17. 14
    14
      lib/ios/RNNCommandsHandler.h
  18. 15
    11
      lib/ios/RNNCommandsHandler.m
  19. 1
    1
      lib/ios/RNNModalManager.h
  20. 2
    2
      lib/ios/RNNModalManager.m
  21. 3
    3
      lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
  22. 4
    4
      lib/ios/ReactNativeNavigationTests/RNNModalManagerTest.m
  23. 10
    10
      lib/src/Navigation.ts
  24. 8
    8
      lib/src/adapters/NativeCommandsSender.ts
  25. 17
    17
      lib/src/commands/Commands.test.ts
  26. 15
    15
      lib/src/commands/Commands.ts

+ 1
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java View File

@@ -10,6 +10,7 @@ import com.reactnativenavigation.utils.TypefaceLoader;
10 10
 import org.json.JSONObject;
11 11
 
12 12
 public class Options {
13
+    public static final Options EMPTY = new Options();
13 14
 
14 15
     @NonNull
15 16
     public static Options parse(TypefaceLoader typefaceManager, JSONObject json) {

+ 22
- 16
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.react;
2 2
 
3 3
 import android.support.annotation.NonNull;
4
+import android.support.annotation.Nullable;
4 5
 
5 6
 import com.facebook.react.ReactInstanceManager;
6 7
 import com.facebook.react.bridge.Arguments;
@@ -70,14 +71,12 @@ public class NavigationModule extends ReactContextBaseJavaModule {
70 71
 
71 72
 	@ReactMethod
72 73
 	public void setDefaultOptions(ReadableMap options) {
73
-        final Options defaultOptions = Options.parse(new TypefaceLoader(activity()), JSONParser.parse(options));
74
-        handle(() -> navigator().setDefaultOptions(defaultOptions));
74
+        handle(() -> navigator().setDefaultOptions(parse(options)));
75 75
     }
76 76
 
77 77
 	@ReactMethod
78
-	public void mergeOptions(String onComponentId, ReadableMap options) {
79
-		final Options navOptions = Options.parse(new TypefaceLoader(activity()), JSONParser.parse(options));
80
-		handle(() -> navigator().mergeOptions(onComponentId, navOptions));
78
+	public void mergeOptions(String onComponentId, @Nullable ReadableMap options) {
79
+		handle(() -> navigator().mergeOptions(onComponentId, parse(options)));
81 80
 	}
82 81
 
83 82
 	@ReactMethod
@@ -99,18 +98,18 @@ public class NavigationModule extends ReactContextBaseJavaModule {
99 98
     }
100 99
 
101 100
 	@ReactMethod
102
-	public void pop(String commandId, String componentId, ReadableMap options, Promise promise) {
103
-		handle(() -> navigator().pop(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
101
+	public void pop(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
102
+		handle(() -> navigator().pop(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
104 103
 	}
105 104
 
106 105
 	@ReactMethod
107
-	public void popTo(String commandId, String componentId, Promise promise) {
108
-		handle(() -> navigator().popTo(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
106
+	public void popTo(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
107
+		handle(() -> navigator().popTo(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
109 108
 	}
110 109
 
111 110
 	@ReactMethod
112
-	public void popToRoot(String commandId, String componentId, Promise promise) {
113
-		handle(() -> navigator().popToRoot(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
111
+	public void popToRoot(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
112
+		handle(() -> navigator().popToRoot(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
114 113
 	}
115 114
 
116 115
 	@ReactMethod
@@ -123,13 +122,16 @@ public class NavigationModule extends ReactContextBaseJavaModule {
123 122
 	}
124 123
 
125 124
 	@ReactMethod
126
-	public void dismissModal(String commandId, String componentId, Promise promise) {
127
-		handle(() -> navigator().dismissModal(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
125
+	public void dismissModal(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
126
+		handle(() -> {
127
+            navigator().mergeOptions(componentId, parse(mergeOptions));
128
+            navigator().dismissModal(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now));
129
+        });
128 130
 	}
129 131
 
130
-	@ReactMethod
131
-	public void dismissAllModals(String commandId, Promise promise) {
132
-		handle(() -> navigator().dismissAllModals(new NativeCommandListener(commandId, promise, eventEmitter, now)));
132
+    @ReactMethod
133
+	public void dismissAllModals(String commandId, @Nullable ReadableMap mergeOptions, Promise promise) {
134
+		handle(() -> navigator().dismissAllModals(parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
133 135
 	}
134 136
 
135 137
 	@ReactMethod
@@ -161,6 +163,10 @@ public class NavigationModule extends ReactContextBaseJavaModule {
161 163
         );
162 164
 	}
163 165
 
166
+    private  Options parse(@Nullable ReadableMap mergeOptions) {
167
+        return mergeOptions == null ? Options.EMPTY : Options.parse(new TypefaceLoader(activity()), JSONParser.parse(mergeOptions));
168
+    }
169
+
164 170
 	private Map<String, ExternalComponentCreator> externalComponentCreator() {
165 171
         return ((NavigationApplication) activity().getApplication()).getExternalComponents();
166 172
     }

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

@@ -55,6 +55,7 @@ public abstract class ChildController<T extends ViewGroup> extends ViewControlle
55 55
 
56 56
     @Override
57 57
     public void mergeOptions(Options options) {
58
+        if (options == Options.EMPTY) return;
58 59
         presenter.mergeOptions(getView(), options);
59 60
         super.mergeOptions(options);
60 61
     }

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

@@ -63,6 +63,7 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
63 63
 
64 64
     @Override
65 65
     public void mergeOptions(Options options) {
66
+        if (options == Options.EMPTY) return;
66 67
         performOnParentController(parentController -> parentController.mergeChildOptions(options, this, getView()));
67 68
         super.mergeOptions(options);
68 69
     }

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

@@ -156,18 +156,18 @@ public class Navigator extends ParentController {
156 156
         applyOnStack(id, listener, stack -> stack.setRoot(viewController, listener));
157 157
     }
158 158
 
159
-    public void pop(String id, CommandListener listener) {
160
-        applyOnStack(id, listener, stack -> stack.pop(listener));
159
+    public void pop(String id, Options mergeOptions, CommandListener listener) {
160
+        applyOnStack(id, listener, stack -> stack.pop(mergeOptions, listener));
161 161
     }
162 162
 
163
-    public void popToRoot(final String id, CommandListener listener) {
164
-        applyOnStack(id, listener, stack -> stack.popToRoot(listener));
163
+    public void popToRoot(final String id, Options mergeOptions, CommandListener listener) {
164
+        applyOnStack(id, listener, stack -> stack.popToRoot(mergeOptions, listener));
165 165
     }
166 166
 
167
-    public void popTo(final String id, CommandListener listener) {
167
+    public void popTo(final String id, Options mergeOptions, CommandListener listener) {
168 168
         ViewController target = findControllerById(id);
169 169
         if (target != null) {
170
-            target.performOnParentStack(stack -> ((StackController) stack).popTo(target, listener));
170
+            target.performOnParentStack(stack -> ((StackController) stack).popTo(target, mergeOptions, listener));
171 171
         } else {
172 172
             listener.onError("Failed to execute stack command. Stack by " + id + " not found.");
173 173
         }
@@ -185,8 +185,8 @@ public class Navigator extends ParentController {
185 185
         modalStack.dismissModal(componentId, root, listener);
186 186
     }
187 187
 
188
-    public void dismissAllModals(CommandListener listener) {
189
-        modalStack.dismissAllModals(listener, root);
188
+    public void dismissAllModals(Options mergeOptions, CommandListener listener) {
189
+        modalStack.dismissAllModals(root, mergeOptions, listener);
190 190
     }
191 191
 
192 192
     public void showOverlay(ViewController overlay, CommandListener listener) {

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

@@ -137,21 +137,11 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
137 137
         this.parentController = parentController;
138 138
     }
139 139
 
140
-    boolean performOnParentStack(Task<StackController> task) {
140
+    void performOnParentStack(Task<StackController> task) {
141 141
         if (parentController instanceof StackController) {
142 142
             task.run((StackController) parentController);
143
-            return true;
144
-        }
145
-        if (this instanceof StackController) {
143
+        } else if (this instanceof StackController) {
146 144
             task.run((StackController) this);
147
-            return true;
148
-        }
149
-        return false;
150
-    }
151
-
152
-    void performOnParentStack(Task accept, Runnable reject) {
153
-        if (!performOnParentStack(accept)) {
154
-            reject.run();
155 145
         }
156 146
     }
157 147
 

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

@@ -78,7 +78,7 @@ public class ModalStack {
78 78
         }
79 79
     }
80 80
 
81
-    public void dismissAllModals(CommandListener listener, ViewController root) {
81
+    public void dismissAllModals(ViewController root, Options mergeOptions, CommandListener listener) {
82 82
         if (modals.isEmpty()) {
83 83
             listener.onError("Nothing to dismiss");
84 84
             return;
@@ -87,6 +87,8 @@ public class ModalStack {
87 87
         String topModalId = peek().getId();
88 88
         int modalsDismissed = size();
89 89
 
90
+        peek().mergeOptions(mergeOptions);
91
+
90 92
         while (!modals.isEmpty()) {
91 93
             if (modals.size() == 1) {
92 94
                 dismissModal(modals.get(0).getId(), root, new CommandListenerAdapter(listener) {

+ 9
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java View File

@@ -189,7 +189,7 @@ public class StackController extends ParentController<StackLayout> {
189 189
         }
190 190
     }
191 191
 
192
-    public void pop(CommandListener listener) {
192
+    public void pop(Options mergeOptions, CommandListener listener) {
193 193
         if (!canPop()) {
194 194
             listener.onError("Nothing to pop");
195 195
             return;
@@ -197,6 +197,7 @@ public class StackController extends ParentController<StackLayout> {
197 197
 
198 198
         final ViewController disappearing = stack.pop();
199 199
         final ViewController appearing = stack.peek();
200
+        disappearing.mergeOptions(mergeOptions);
200 201
         disappearing.onViewWillDisappear();
201 202
         appearing.onViewWillAppear();
202 203
         Options resolvedOptions = resolveCurrentOptions();
@@ -221,8 +222,8 @@ public class StackController extends ParentController<StackLayout> {
221 222
         listener.onSuccess(disappearing.getId());
222 223
     }
223 224
 
224
-    public void popTo(final ViewController viewController, CommandListener listener) {
225
-        if (!stack.containsId(viewController.getId())) {
225
+    public void popTo(ViewController viewController, Options mergeOptions, CommandListener listener) {
226
+        if (!stack.containsId(viewController.getId()) || peek().equals(viewController)) {
226 227
             listener.onError("Nothing to pop");
227 228
             return;
228 229
         }
@@ -238,10 +239,10 @@ public class StackController extends ParentController<StackLayout> {
238 239
             currentControlId = iterator.next();
239 240
         }
240 241
 
241
-        pop(listener);
242
+        pop(mergeOptions, listener);
242 243
     }
243 244
 
244
-    public void popToRoot(CommandListener listener) {
245
+    public void popToRoot(Options mergeOptions, CommandListener listener) {
245 246
         if (!canPop()) {
246 247
             listener.onError("Nothing to pop");
247 248
             return;
@@ -255,7 +256,7 @@ public class StackController extends ParentController<StackLayout> {
255 256
             }
256 257
         }
257 258
 
258
-        pop(listener);
259
+        pop(mergeOptions, listener);
259 260
     }
260 261
 
261 262
     private void removeAndDestroyController(ViewController controller) {
@@ -278,7 +279,7 @@ public class StackController extends ParentController<StackLayout> {
278 279
     @Override
279 280
     public boolean handleBack(CommandListener listener) {
280 281
         if (canPop()) {
281
-            pop(listener);
282
+            pop(Options.EMPTY, listener);
282 283
             return true;
283 284
         }
284 285
         return false;
@@ -313,7 +314,7 @@ public class StackController extends ParentController<StackLayout> {
313 314
 
314 315
     private void onNavigationButtonPressed(String buttonId) {
315 316
         if (Constants.BACK_BUTTON_ID.equals(buttonId)) {
316
-            pop(new CommandListenerAdapter());
317
+            pop(Options.EMPTY, new CommandListenerAdapter());
317 318
         } else {
318 319
             sendOnNavigationButtonPressed(buttonId);
319 320
         }

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

@@ -13,6 +13,7 @@ import com.reactnativenavigation.views.StackLayout;
13 13
 import org.junit.Test;
14 14
 
15 15
 import static org.assertj.core.api.Java6Assertions.assertThat;
16
+import static org.mockito.ArgumentMatchers.any;
16 17
 import static org.mockito.Mockito.spy;
17 18
 import static org.mockito.Mockito.times;
18 19
 import static org.mockito.Mockito.verify;
@@ -77,4 +78,11 @@ public class ComponentViewControllerTest extends BaseTest {
77 78
         uut.sendOnNavigationButtonPressed("btn1");
78 79
         verify(view, times(1)).sendOnNavigationButtonPressed("btn1");
79 80
     }
81
+
82
+    @Test
83
+    public void mergeOptions_emptyOptionsAreIgnored() {
84
+        ComponentViewController spy = spy(uut);
85
+        spy.mergeOptions(Options.EMPTY);
86
+        verify(spy, times(0)).performOnParentController(any());
87
+    }
80 88
 }

+ 2
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java View File

@@ -103,7 +103,7 @@ public class FloatingActionButtonTest extends BaseTest {
103 103
         stackController.push(childFab, new CommandListenerAdapter());
104 104
         childFab.onViewAppeared();
105 105
         assertThat(hasFab()).isTrue();
106
-        stackController.pop(new CommandListenerAdapter());
106
+        stackController.pop(Options.EMPTY, new CommandListenerAdapter());
107 107
         childNoFab.onViewAppeared();
108 108
         assertThat(hasFab()).isFalse();
109 109
     }
@@ -115,7 +115,7 @@ public class FloatingActionButtonTest extends BaseTest {
115 115
         stackController.push(childNoFab, new CommandListenerAdapter());
116 116
         childNoFab.onViewAppeared();
117 117
         assertThat(hasFab()).isFalse();
118
-        stackController.pop(new CommandListenerAdapter());
118
+        stackController.pop(Options.EMPTY, new CommandListenerAdapter());
119 119
         childFab.onViewAppeared();
120 120
         assertThat(hasFab()).isTrue();
121 121
     }

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

@@ -188,9 +188,9 @@ public class NavigatorTest extends BaseTest {
188 188
 
189 189
     @Test
190 190
     public void pop_InvalidDoesNothing() {
191
-        uut.pop("123", new CommandListenerAdapter());
191
+        uut.pop("123", Options.EMPTY, new CommandListenerAdapter());
192 192
         uut.setRoot(child1, new CommandListenerAdapter());
193
-        uut.pop(child1.getId(), new CommandListenerAdapter());
193
+        uut.pop(child1.getId(), Options.EMPTY, new CommandListenerAdapter());
194 194
         assertThat(uut.getChildControllers()).hasSize(1);
195 195
     }
196 196
 
@@ -208,7 +208,7 @@ public class NavigatorTest extends BaseTest {
208 208
                 stack2.push(child4, new CommandListenerAdapter() {
209 209
                             @Override
210 210
                             public void onSuccess(String childId) {
211
-                                uut.pop("child4", new CommandListenerAdapter());
211
+                                uut.pop("child4", Options.EMPTY, new CommandListenerAdapter());
212 212
                                 assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
213 213
                             }
214 214
                         }
@@ -226,7 +226,7 @@ public class NavigatorTest extends BaseTest {
226 226
         stack.push(child1, new CommandListenerAdapter());
227 227
         stack.push(child2, new CommandListenerAdapter());
228 228
 
229
-        uut.pop(stack.getId(), new CommandListenerAdapter());
229
+        uut.pop(stack.getId(), Options.EMPTY, new CommandListenerAdapter());
230 230
         assertThat(stack.getChildControllers()).containsOnly(child1);
231 231
     }
232 232
 
@@ -244,7 +244,7 @@ public class NavigatorTest extends BaseTest {
244 244
         stack2.push(child5, new CommandListenerAdapter() {
245 245
             @Override
246 246
             public void onSuccess(String childId) {
247
-                uut.popTo(child2.getId(), new CommandListenerAdapter());
247
+                uut.popTo(child2.getId(), Options.EMPTY, new CommandListenerAdapter());
248 248
                 assertThat(stack2.getChildControllers()).containsOnly(child2);
249 249
             }
250 250
         });
@@ -264,7 +264,7 @@ public class NavigatorTest extends BaseTest {
264 264
         stack2.push(child5, new CommandListenerAdapter() {
265 265
             @Override
266 266
             public void onSuccess(String childId) {
267
-                uut.popToRoot(child3.getId(), new CommandListenerAdapter());
267
+                uut.popToRoot(child3.getId(), Options.EMPTY, new CommandListenerAdapter());
268 268
                 assertThat(stack2.getChildControllers()).containsOnly(child2);
269 269
             }
270 270
         });
@@ -370,9 +370,9 @@ public class NavigatorTest extends BaseTest {
370 370
 
371 371
     @Test
372 372
     public void pop_InvalidDoesNothing_Promise() {
373
-        uut.pop("123", new CommandListenerAdapter());
373
+        uut.pop("123", Options.EMPTY, new CommandListenerAdapter());
374 374
         uut.setRoot(child1, new CommandListenerAdapter());
375
-        uut.pop(child1.getId(), new CommandListenerAdapter() {
375
+        uut.pop(child1.getId(), Options.EMPTY, new CommandListenerAdapter() {
376 376
             @Override
377 377
             public void onError(String reason) {
378 378
                 assertThat(uut.getChildControllers()).hasSize(1);
@@ -393,7 +393,7 @@ public class NavigatorTest extends BaseTest {
393 393
         stack2.push(child4, new CommandListenerAdapter() {
394 394
             @Override
395 395
             public void onSuccess(String childId) {
396
-                uut.pop("child4", new CommandListenerAdapter());
396
+                uut.pop("child4", Options.EMPTY, new CommandListenerAdapter());
397 397
                 assertThat(stack2.getChildControllers()).containsOnly(child2, child3);
398 398
             }
399 399
         });
@@ -431,8 +431,8 @@ public class NavigatorTest extends BaseTest {
431 431
                 assertThat(spy.getChildControllers().size()).isEqualTo(1);
432 432
             }
433 433
         };
434
-        uut.pop("child2", listener);
435
-        verify(spy, times(1)).pop(listener);
434
+        uut.pop("child2", Options.EMPTY, listener);
435
+        verify(spy, times(1)).pop(Options.EMPTY, listener);
436 436
     }
437 437
 
438 438
     @Test
@@ -505,7 +505,7 @@ public class NavigatorTest extends BaseTest {
505 505
         disablePushAnimation(child2);
506 506
         disableShowModalAnimation(child1);
507 507
 
508
-        uut.dismissAllModals(new CommandListenerAdapter());
508
+        uut.dismissAllModals(Options.EMPTY, new CommandListenerAdapter());
509 509
         verify(parentVisibilityListener, times(0)).onViewAppeared(parentController.getView());
510 510
 
511 511
         uut.setRoot(parentController, new CommandListenerAdapter());
@@ -513,7 +513,7 @@ public class NavigatorTest extends BaseTest {
513 513
 
514 514
         verify(parentVisibilityListener, times(1)).onViewAppeared(parentController.getView());
515 515
         uut.showModal(child1, new CommandListenerAdapter());
516
-        uut.dismissAllModals(new CommandListenerAdapter());
516
+        uut.dismissAllModals(Options.EMPTY, new CommandListenerAdapter());
517 517
 
518 518
         verify(parentVisibilityListener, times(2)).onViewAppeared(parentController.getView());
519 519
     }

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

@@ -232,7 +232,7 @@ public class TopTabsViewControllerTest extends BaseTest {
232 232
         uut.onViewAppeared();
233 233
 
234 234
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
235
-        stackController.pop(new CommandListenerAdapter() {
235
+        stackController.pop(Options.EMPTY, new CommandListenerAdapter() {
236 236
             @Override
237 237
             public void onSuccess(String childId) {
238 238
                 assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();

+ 7
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java View File

@@ -11,6 +11,7 @@ import com.reactnativenavigation.viewcontrollers.ParentController;
11 11
 import org.junit.Test;
12 12
 import org.mockito.Mockito;
13 13
 
14
+import static org.mockito.ArgumentMatchers.any;
14 15
 import static org.mockito.Mockito.spy;
15 16
 import static org.mockito.Mockito.times;
16 17
 import static org.mockito.Mockito.verify;
@@ -64,4 +65,10 @@ public class ChildControllerTest extends BaseTest {
64 65
         uut.mergeOptions(options);
65 66
         verify(presenter).mergeOptions(uut.getView(), options);
66 67
     }
68
+
69
+    @Test
70
+    public void mergeOptions_emptyOptionsAreIgnored() {
71
+        uut.mergeOptions(Options.EMPTY);
72
+        verify(presenter, times(0)).mergeOptions(any(), any());
73
+    }
67 74
 }

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

@@ -141,7 +141,7 @@ public class ModalStackTest extends BaseTest {
141 141
                 assertThat(uut.isEmpty()).isTrue();
142 142
             }
143 143
         });
144
-        uut.dismissAllModals(listener, rootController);
144
+        uut.dismissAllModals(rootController, Options.EMPTY, listener);
145 145
         verify(listener, times(1)).onSuccess(anyString());
146 146
         verifyZeroInteractions(listener);
147 147
     }
@@ -149,10 +149,23 @@ public class ModalStackTest extends BaseTest {
149 149
     @Test
150 150
     public void dismissAllModals_rejectIfEmpty() {
151 151
         CommandListener spy = spy(new CommandListenerAdapter());
152
-        uut.dismissAllModals(spy, rootController);
152
+        uut.dismissAllModals(rootController, Options.EMPTY, spy);
153 153
         verify(spy, times(1)).onError(any());
154 154
     }
155 155
 
156
+    @Test
157
+    public void dismissAllModals_optionsAreMergedOnTopModal() {
158
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
159
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
160
+        uut.showModal(modal3, rootController, new CommandListenerAdapter());
161
+
162
+        Options mergeOptions = new Options();
163
+        uut.dismissAllModals(rootController, mergeOptions, new CommandListenerAdapter());
164
+        verify(modal3).mergeOptions(mergeOptions);
165
+        verify(modal1, times(0)).mergeOptions(mergeOptions);
166
+        verify(modal2, times(0)).mergeOptions(mergeOptions);
167
+    }
168
+
156 169
     @SuppressWarnings("Convert2Lambda")
157 170
     @Test
158 171
     public void dismissAllModals_onlyTopModalIsAnimated() {
@@ -162,7 +175,7 @@ public class ModalStackTest extends BaseTest {
162 175
         ViewGroup view1 = modal1.getView();
163 176
         ViewGroup view2 = modal2.getView();
164 177
         CommandListener listener = spy(new CommandListenerAdapter());
165
-        uut.dismissAllModals(listener, rootController);
178
+        uut.dismissAllModals(rootController, Options.EMPTY, listener);
166 179
         verify(presenter, times(1)).dismissTopModal(eq(modal2), eq(rootController), any());
167 180
         verify(listener).onSuccess(modal2.getId());
168 181
         verify(animator, times(0)).dismiss(eq(view1), eq(modal1.options.animations.dismissModal), any());
@@ -175,7 +188,7 @@ public class ModalStackTest extends BaseTest {
175 188
         uut.showModal(modal1, rootController, new CommandListenerAdapter());
176 189
         uut.showModal(modal2, rootController, new CommandListenerAdapter());
177 190
 
178
-        uut.dismissAllModals(new CommandListenerAdapter(), rootController);
191
+        uut.dismissAllModals(rootController, Options.EMPTY, new CommandListenerAdapter());
179 192
 
180 193
         verify(modal1, times(1)).destroy();
181 194
         verify(modal1, times(1)).onViewDisappear();
@@ -187,7 +200,7 @@ public class ModalStackTest extends BaseTest {
187 200
         assertThat(uut.isEmpty()).isTrue();
188 201
         uut.showModal(modal1, rootController, new CommandListenerAdapter());
189 202
         assertThat(uut.isEmpty()).isFalse();
190
-        uut.dismissAllModals(new CommandListenerAdapter(), rootController);
203
+        uut.dismissAllModals(rootController, Options.EMPTY, new CommandListenerAdapter());
191 204
         assertThat(uut.isEmpty()).isTrue();
192 205
     }
193 206
 

+ 46
- 19
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.java View File

@@ -227,7 +227,7 @@ public class StackControllerTest extends BaseTest {
227 227
             @Override
228 228
             public void onSuccess(String childId) {
229 229
                 assertContainsOnlyId(child2.getId(), child1.getId());
230
-                uut.pop(new CommandListenerAdapter());
230
+                uut.pop(Options.EMPTY, new CommandListenerAdapter());
231 231
                 assertContainsOnlyId(child1.getId());
232 232
             }
233 233
         });
@@ -239,7 +239,7 @@ public class StackControllerTest extends BaseTest {
239 239
         uut.push(child2, new CommandListenerAdapter() {
240 240
             @Override
241 241
             public void onSuccess(String childId) {
242
-                uut.pop(new CommandListenerAdapter());
242
+                uut.pop(Options.EMPTY, new CommandListenerAdapter());
243 243
                 verify(uut, times(1)).applyChildOptions(uut.options, eq((ReactComponent) child1.getView()));
244 244
             }
245 245
         });
@@ -260,7 +260,7 @@ public class StackControllerTest extends BaseTest {
260 260
         uut.push(child2, new CommandListenerAdapter() {
261 261
             @Override
262 262
             public void onSuccess(String childId) {
263
-                uut.pop(new CommandListenerAdapter() {
263
+                uut.pop(Options.EMPTY, new CommandListenerAdapter() {
264 264
                     @Override
265 265
                     public void onSuccess(String childId) {
266 266
                         verify(presenter, times(1)).onChildWillAppear(child1.options, child2.options);
@@ -312,11 +312,11 @@ public class StackControllerTest extends BaseTest {
312 312
     @Test
313 313
     public void popDoesNothingWhenZeroOrOneChild() {
314 314
         assertThat(uut.isEmpty()).isTrue();
315
-        uut.pop(new CommandListenerAdapter());
315
+        uut.pop(Options.EMPTY, new CommandListenerAdapter());
316 316
         assertThat(uut.isEmpty()).isTrue();
317 317
 
318 318
         uut.push(child1, new CommandListenerAdapter());
319
-        uut.pop(new CommandListenerAdapter());
319
+        uut.pop(Options.EMPTY, new CommandListenerAdapter());
320 320
         assertContainsOnlyId(child1.getId());
321 321
     }
322 322
 
@@ -417,7 +417,7 @@ public class StackControllerTest extends BaseTest {
417 417
             public void onSuccess(String childId) {
418 418
                 assertIsChild(uut.getView(), child2View);
419 419
                 assertNotChildOf(uut.getView(), child1View);
420
-                uut.pop(new CommandListenerAdapter());
420
+                uut.pop(Options.EMPTY, new CommandListenerAdapter());
421 421
                 assertNotChildOf(uut.getView(), child2View);
422 422
                 assertIsChild(uut.getView(), child1View);
423 423
             }
@@ -433,7 +433,7 @@ public class StackControllerTest extends BaseTest {
433 433
         uut.ensureViewIsCreated();
434 434
 
435 435
         assertThat(child2.getView().getParent()).isEqualTo(uut.getView());
436
-        uut.pop(new CommandListenerAdapter());
436
+        uut.pop(Options.EMPTY, new CommandListenerAdapter());
437 437
         assertThat(child1.getView().getParent()).isEqualTo(uut.getView());
438 438
 
439 439
         assertThat(child1.getView().getLayoutParams().width).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT);
@@ -453,7 +453,7 @@ public class StackControllerTest extends BaseTest {
453 453
                 assertThat(uut.size()).isEqualTo(3);
454 454
                 assertThat(uut.peek()).isEqualTo(child3);
455 455
 
456
-                uut.popTo(child1, new CommandListenerAdapter());
456
+                uut.popTo(child1, Options.EMPTY, new CommandListenerAdapter());
457 457
 
458 458
                 assertThat(uut.size()).isEqualTo(1);
459 459
                 assertThat(uut.peek()).isEqualTo(child1);
@@ -461,12 +461,27 @@ public class StackControllerTest extends BaseTest {
461 461
         });
462 462
     }
463 463
 
464
+    @Test
465
+    public void popTo_optionsAreMergedOnTopChild() {
466
+        disablePushAnimation(child1, child2);
467
+        uut.push(child1, new CommandListenerAdapter());
468
+
469
+        Options mergeOptions = new Options();
470
+        uut.popTo(child2, mergeOptions, new CommandListenerAdapter());
471
+        uut.popTo(child1, mergeOptions, new CommandListenerAdapter());
472
+        verify(child1, times(0)).mergeOptions(mergeOptions);
473
+
474
+        uut.push(child2, new CommandListenerAdapter());
475
+        uut.popTo(child1, mergeOptions, new CommandListenerAdapter());
476
+        verify(child2).mergeOptions(mergeOptions);
477
+    }
478
+
464 479
     @Test
465 480
     public void popTo_NotAChildOfThisStack_DoesNothing() {
466 481
         uut.push(child1, new CommandListenerAdapter());
467 482
         uut.push(child3, new CommandListenerAdapter());
468 483
         assertThat(uut.size()).isEqualTo(2);
469
-        uut.popTo(child2, new CommandListenerAdapter());
484
+        uut.popTo(child2, Options.EMPTY, new CommandListenerAdapter());
470 485
         assertThat(uut.size()).isEqualTo(2);
471 486
     }
472 487
 
@@ -478,7 +493,7 @@ public class StackControllerTest extends BaseTest {
478 493
         uut.push(child4, new CommandListenerAdapter() {
479 494
             @Override
480 495
             public void onSuccess(String childId) {
481
-                uut.popTo(child2, new CommandListenerAdapter() {
496
+                uut.popTo(child2, Options.EMPTY, new CommandListenerAdapter() {
482 497
                     @Override
483 498
                     public void onSuccess(String childId) {
484 499
                         verify(animator, times(0)).pop(eq(child1.getView()), any(), any());
@@ -503,7 +518,7 @@ public class StackControllerTest extends BaseTest {
503 518
                 assertThat(uut.size()).isEqualTo(3);
504 519
                 assertThat(uut.peek()).isEqualTo(child3);
505 520
 
506
-                uut.popToRoot(new CommandListenerAdapter() {
521
+                uut.popToRoot(Options.EMPTY, new CommandListenerAdapter() {
507 522
                     @Override
508 523
                     public void onSuccess(String childId) {
509 524
                         assertThat(uut.size()).isEqualTo(1);
@@ -524,7 +539,7 @@ public class StackControllerTest extends BaseTest {
524 539
         uut.push(child3, new CommandListenerAdapter() {
525 540
             @Override
526 541
             public void onSuccess(String childId) {
527
-                uut.popToRoot(new CommandListenerAdapter() {
542
+                uut.popToRoot(Options.EMPTY, new CommandListenerAdapter() {
528 543
                     @Override
529 544
                     public void onSuccess(String childId) {
530 545
                         verify(animator, times(1)).pop(eq(child3.getView()), eq(child3.options.animations.pop), any());
@@ -544,7 +559,7 @@ public class StackControllerTest extends BaseTest {
544 559
         uut.push(child2, new CommandListenerAdapter());
545 560
         uut.push(child3, new CommandListenerAdapter());
546 561
 
547
-        uut.popToRoot(new CommandListenerAdapter() {
562
+        uut.popToRoot(Options.EMPTY, new CommandListenerAdapter() {
548 563
             @Override
549 564
             public void onSuccess(String childId) {
550 565
                 verify(child1, times(0)).destroy();
@@ -558,11 +573,23 @@ public class StackControllerTest extends BaseTest {
558 573
     public void popToRoot_EmptyStackDoesNothing() {
559 574
         assertThat(uut.isEmpty()).isTrue();
560 575
         CommandListenerAdapter listener = spy(new CommandListenerAdapter());
561
-        uut.popToRoot(listener);
576
+        uut.popToRoot(Options.EMPTY, listener);
562 577
         assertThat(uut.isEmpty()).isTrue();
563 578
         verify(listener, times(1)).onError(any());
564 579
     }
565 580
 
581
+    @Test
582
+    public void popToRoot_optionsAreMergedOnTopChild() {
583
+        disablePushAnimation(child1, child2);
584
+        uut.push(child1, new CommandListenerAdapter());
585
+        uut.push(child2, new CommandListenerAdapter());
586
+
587
+        Options mergeOptions = new Options();
588
+        uut.popToRoot(mergeOptions, new CommandListenerAdapter());
589
+        verify(child2).mergeOptions(mergeOptions);
590
+        verify(child1, times(0)).mergeOptions(mergeOptions);
591
+    }
592
+
566 593
     @Test
567 594
     public void findControllerById_ReturnsSelfOrChildrenById() {
568 595
         assertThat(uut.findControllerById("123")).isNull();
@@ -591,7 +618,7 @@ public class StackControllerTest extends BaseTest {
591 618
             @Override
592 619
             public void onSuccess(String childId) {
593 620
                 verify(child3, times(0)).destroy();
594
-                uut.pop(new CommandListenerAdapter());
621
+                uut.pop(Options.EMPTY, new CommandListenerAdapter());
595 622
                 verify(child3, times(1)).destroy();
596 623
             }
597 624
         });
@@ -605,7 +632,7 @@ public class StackControllerTest extends BaseTest {
605 632
         child2 = spy(child2);
606 633
         uut.push(child1, new CommandListenerAdapter());
607 634
         uut.push(child2, new CommandListenerAdapter());
608
-        uut.pop(new CommandListenerAdapter());
635
+        uut.pop(Options.EMPTY, new CommandListenerAdapter());
609 636
         verify(child1, times(1)).onViewWillAppear();
610 637
         verify(child2, times(1)).onViewWillDisappear();
611 638
     }
@@ -625,7 +652,7 @@ public class StackControllerTest extends BaseTest {
625 652
                 uut.push(child2, new CommandListenerAdapter() {
626 653
                     @Override
627 654
                     public void onSuccess(String childId) {
628
-                        uut.pop(new CommandListenerAdapter() {
655
+                        uut.pop(Options.EMPTY, new CommandListenerAdapter() {
629 656
                             @Override
630 657
                             public void onSuccess(String childId) {
631 658
                                 verify(uut.getTopBar(), times(1)).hideAnimate(child2.options.animations.pop.topBar);
@@ -653,7 +680,7 @@ public class StackControllerTest extends BaseTest {
653 680
                 uut.push(child2, new CommandListenerAdapter());
654 681
                 assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.VISIBLE);
655 682
 
656
-                uut.pop(new CommandListenerAdapter());
683
+                uut.pop(Options.EMPTY, new CommandListenerAdapter());
657 684
                 verify(uut.getTopBar(), times(0)).hideAnimate(child2.options.animations.pop.topBar);
658 685
                 assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.GONE);
659 686
             }
@@ -673,7 +700,7 @@ public class StackControllerTest extends BaseTest {
673 700
                 verify(child2, times(0)).destroy();
674 701
                 verify(child3, times(0)).destroy();
675 702
 
676
-                uut.popTo(child1, new CommandListenerAdapter() {
703
+                uut.popTo(child1, Options.EMPTY, new CommandListenerAdapter() {
677 704
                     @Override
678 705
                     public void onSuccess(String childId) {
679 706
                         verify(child2, times(1)).destroy();

+ 10
- 10
lib/ios/RNNBridgeModule.m View File

@@ -43,8 +43,8 @@ RCT_EXPORT_METHOD(push:(NSString*)commandId componentId:(NSString*)componentId l
43 43
 	} rejection:reject];
44 44
 }
45 45
 
46
-RCT_EXPORT_METHOD(pop:(NSString*)commandId componentId:(NSString*)componentId options:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
47
-	[_commandsHandler pop:componentId options:(NSDictionary*)options completion:^{
46
+RCT_EXPORT_METHOD(pop:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
47
+	[_commandsHandler pop:componentId mergeOptions:(NSDictionary*)options completion:^{
48 48
 		resolve(componentId);
49 49
 	} rejection:reject];
50 50
 }
@@ -55,14 +55,14 @@ RCT_EXPORT_METHOD(setStackRoot:(NSString*)commandId componentId:(NSString*)compo
55 55
 	} rejection:reject];
56 56
 }
57 57
 
58
-RCT_EXPORT_METHOD(popTo:(NSString*)commandId componentId:(NSString*)componentId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
59
-	[_commandsHandler popTo:componentId completion:^{
58
+RCT_EXPORT_METHOD(popTo:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
59
+	[_commandsHandler popTo:componentId mergeOptions:options completion:^{
60 60
 		resolve(componentId);
61 61
 	} rejection:reject];
62 62
 }
63 63
 
64
-RCT_EXPORT_METHOD(popToRoot:(NSString*)commandId componentId:(NSString*)componentId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
65
-	[_commandsHandler popToRoot:componentId completion:^{
64
+RCT_EXPORT_METHOD(popToRoot:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
65
+	[_commandsHandler popToRoot:componentId mergeOptions:options completion:^{
66 66
 		resolve(componentId);
67 67
 	} rejection:reject];
68 68
 }
@@ -73,14 +73,14 @@ RCT_EXPORT_METHOD(showModal:(NSString*)commandId layout:(NSDictionary*)layout re
73 73
 	}];
74 74
 }
75 75
 
76
-RCT_EXPORT_METHOD(dismissModal:(NSString*)commandId componentId:(NSString*)componentId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
77
-	[_commandsHandler dismissModal:componentId completion:^{
76
+RCT_EXPORT_METHOD(dismissModal:(NSString*)commandId componentId:(NSString*)componentId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
77
+	[_commandsHandler dismissModal:componentId mergeOptions:options completion:^{
78 78
 		resolve(componentId);
79 79
 	}];
80 80
 }
81 81
 
82
-RCT_EXPORT_METHOD(dismissAllModals:(NSString*)commandId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
83
-	[_commandsHandler dismissAllModalsWithCompletion:^{
82
+RCT_EXPORT_METHOD(dismissAllModals:(NSString*)commandId mergeOptions:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
83
+	[_commandsHandler dismissAllModals:options completion:^{
84 84
 		resolve(nil);
85 85
 	}];
86 86
 }

+ 14
- 14
lib/ios/RNNCommandsHandler.h View File

@@ -6,32 +6,32 @@
6 6
 
7 7
 @interface RNNCommandsHandler : NSObject
8 8
 
9
--(instancetype)initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter*)eventEmitter;
9
+- (instancetype)initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter*)eventEmitter;
10 10
 
11
--(void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
11
+- (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;
12 12
 
13
--(void)mergeOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
13
+- (void)mergeOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
14 14
 
15
--(void)setDefaultOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
15
+- (void)setDefaultOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
16 16
 
17
--(void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
17
+- (void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
18 18
 
19
--(void)pop:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
19
+- (void)pop:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
20 20
 
21
--(void)popTo:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
21
+- (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
22 22
 
23
--(void)popToRoot:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
23
+- (void)popToRoot:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
24 24
 
25
--(void)setStackRoot:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
25
+- (void)setStackRoot:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection;
26 26
 
27
--(void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion;
27
+- (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion;
28 28
 
29
--(void)dismissModal:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion;
29
+- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion;
30 30
 
31
--(void)dismissAllModalsWithCompletion:(RNNTransitionCompletionBlock)completion;
31
+- (void)dismissAllModals:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion;
32 32
 
33
--(void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion;
33
+- (void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion;
34 34
 
35
--(void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject;
35
+- (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject;
36 36
 
37 37
 @end

+ 15
- 11
lib/ios/RNNCommandsHandler.m View File

@@ -54,7 +54,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
54 54
 - (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
55 55
 	[self assertReady];
56 56
 	
57
-	[_modalManager dismissAllModals];
57
+	[_modalManager dismissAllModalsAnimated:NO];
58 58
 	
59 59
 	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout[@"root"]];
60 60
 	
@@ -153,11 +153,11 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
153 153
 	} rejection:rejection];
154 154
 }
155 155
 
156
-- (void)pop:(NSString*)componentId options:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
156
+- (void)pop:(NSString*)componentId mergeOptions:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
157 157
 	[self assertReady];
158 158
 	
159 159
 	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
160
-	[vc.options mergeWith:optionsDict];
160
+	[vc.options mergeWith:options];
161 161
 	
162 162
 	UINavigationController *nvc = vc.navigationController;
163 163
 	
@@ -182,9 +182,10 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
182 182
 	}];
183 183
 }
184 184
 
185
-- (void)popTo:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
185
+- (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
186 186
 	[self assertReady];
187 187
 	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
188
+	[vc.options mergeWith:options];
188 189
 	
189 190
 	[_stackManager popTo:vc animated:vc.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
190 191
 		[_eventEmitter sendOnNavigationCommandCompletion:popTo params:@{@"componentId": componentId}];
@@ -193,9 +194,10 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
193 194
 	} rejection:rejection];
194 195
 }
195 196
 
196
--(void) popToRoot:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
197
+- (void)popToRoot:(NSString*)componentId mergeOptions:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
197 198
 	[self assertReady];
198
-	RNNRootViewController *newVc = (RNNRootViewController*)[_store findComponentForId:componentId];
199
+	RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
200
+	[vc.options mergeWith:options];
199 201
 	
200 202
 	[CATransaction begin];
201 203
 	[CATransaction setCompletionBlock:^{
@@ -203,7 +205,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
203 205
 		completion();
204 206
 	}];
205 207
 	
206
-	[_stackManager popToRoot:newVc animated:newVc.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
208
+	[_stackManager popToRoot:vc animated:vc.options.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
207 209
 		[self removePopedViewControllers:poppedViewControllers];
208 210
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
209 211
 		
@@ -222,7 +224,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
222 224
 	}];
223 225
 }
224 226
 
225
-- (void)dismissModal:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion {
227
+- (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary *)options completion:(RNNTransitionCompletionBlock)completion {
226 228
 	[self assertReady];
227 229
 	
228 230
 	[CATransaction begin];
@@ -230,6 +232,8 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
230 232
 		[_eventEmitter sendOnNavigationCommandCompletion:dismissModal params:@{@"componentId": componentId}];
231 233
 	}];
232 234
 	UIViewController<RNNRootViewProtocol> *modalToDismiss = (UIViewController<RNNRootViewProtocol>*)[_store findComponentForId:componentId];
235
+	[modalToDismiss.getLeafViewController.options mergeWith:options];
236
+	
233 237
 	[self removePopedViewControllers:modalToDismiss.navigationController.viewControllers];
234 238
 	
235 239
 	[_modalManager dismissModal:modalToDismiss completion:completion];
@@ -237,7 +241,7 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
237 241
 	[CATransaction commit];
238 242
 }
239 243
 
240
-- (void)dismissAllModalsWithCompletion:(RNNTransitionCompletionBlock)completion {
244
+- (void)dismissAllModals:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
241 245
 	[self assertReady];
242 246
 	
243 247
 	[CATransaction begin];
@@ -245,8 +249,8 @@ static NSString* const setDefaultOptions	= @"setDefaultOptions";
245 249
 		[_eventEmitter sendOnNavigationCommandCompletion:dismissAllModals params:@{}];
246 250
 		completion();
247 251
 	}];
248
-	
249
-	[_modalManager dismissAllModals];
252
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
253
+	[_modalManager dismissAllModalsAnimated:options.animations.dismissModal.enable];
250 254
 	
251 255
 	[CATransaction commit];
252 256
 }

+ 1
- 1
lib/ios/RNNModalManager.h View File

@@ -16,6 +16,6 @@
16 16
 
17 17
 - (void)showModal:(UIViewController*)viewController animated:(BOOL)animated completion:(RNNTransitionWithComponentIdCompletionBlock)completion;
18 18
 - (void)dismissModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion;
19
-- (void)dismissAllModals;
19
+- (void)dismissAllModalsAnimated:(BOOL)animated;
20 20
 
21 21
 @end

+ 2
- 2
lib/ios/RNNModalManager.m View File

@@ -68,9 +68,9 @@
68 68
 	}
69 69
 }
70 70
 
71
--(void)dismissAllModals {
71
+-(void)dismissAllModalsAnimated:(BOOL)animated {
72 72
 	UIViewController *root = UIApplication.sharedApplication.delegate.window.rootViewController;
73
-	[root dismissViewControllerAnimated:YES completion:nil];
73
+	[root dismissViewControllerAnimated:animated completion:nil];
74 74
 	[_delegate dismissedMultipleModals:_presentedModals];
75 75
 	[_pendingModalIdsToDismiss removeAllObjects];
76 76
 	[_presentedModals removeAllObjects];

+ 3
- 3
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m View File

@@ -121,7 +121,7 @@
121 121
 	[self.store setReadyToReceiveCommands:true];
122 122
 	XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method"];
123 123
 
124
-	[self.uut pop:@"vc3" options:nil completion:^{
124
+	[self.uut pop:@"vc3" mergeOptions:nil completion:^{
125 125
 		XCTAssertNil([self.store findComponentForId:@"vc3"]);
126 126
 		XCTAssertNotNil([self.store findComponentForId:@"vc2"]);
127 127
 		XCTAssertNotNil([self.store findComponentForId:@"vc1"]);
@@ -137,7 +137,7 @@
137 137
 	[self.store setReadyToReceiveCommands:true];
138 138
 	XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method"];
139 139
 	_nvc.willReturnVCs = @[self.vc2, self.vc3];
140
-	[self.uut popTo:@"vc1" completion:^{
140
+	[self.uut popTo:@"vc1" mergeOptions:nil completion:^{
141 141
 		XCTAssertNil([self.store findComponentForId:@"vc2"]);
142 142
 		XCTAssertNil([self.store findComponentForId:@"vc3"]);
143 143
 		XCTAssertNotNil([self.store findComponentForId:@"vc1"]);
@@ -151,7 +151,7 @@
151 151
 	[self.store setReadyToReceiveCommands:true];
152 152
 	_nvc.willReturnVCs = @[self.vc2, self.vc3];
153 153
 	XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method"];
154
-	[self.uut popToRoot:@"vc3" completion:^{
154
+	[self.uut popToRoot:@"vc3" mergeOptions:nil completion:^{
155 155
 		XCTAssertNil([self.store findComponentForId:@"vc2"]);
156 156
 		XCTAssertNil([self.store findComponentForId:@"vc3"]);
157 157
 		XCTAssertNotNil([self.store findComponentForId:@"vc1"]);

+ 4
- 4
lib/ios/ReactNativeNavigationTests/RNNModalManagerTest.m View File

@@ -48,7 +48,7 @@
48 48
 	[_modalManager showModal:_vc3 animated:NO completion:nil];
49 49
 	
50 50
 	_modalManager.delegate = self;
51
-	[_modalManager dismissAllModals];
51
+	[_modalManager dismissAllModalsAnimated:NO];
52 52
 	
53 53
 	XCTAssertTrue(_modalDismissedCount == 3);
54 54
 }
@@ -75,7 +75,7 @@
75 75
 	XCTAssertTrue(_modalDismissedCount == 1);
76 76
 }
77 77
 
78
-- (void)testDismissAllModalsAfterDismissingPreviousModal_InvokeDelegateWithCorrectParameters {
78
+- (void)testDismissAllModals_AfterDismissingPreviousModal_InvokeDelegateWithCorrectParameters {
79 79
 	[_modalManager showModal:_vc1 animated:NO completion:nil];
80 80
 	[_modalManager showModal:_vc2 animated:NO completion:nil];
81 81
 	[_modalManager showModal:_vc3 animated:NO completion:nil];
@@ -84,11 +84,11 @@
84 84
 	[_modalManager dismissModal:_vc2 completion:nil];
85 85
 	
86 86
 	XCTAssertTrue(_modalDismissedCount == 1);
87
-	[_modalManager dismissAllModals];
87
+	[_modalManager dismissAllModalsAnimated:NO];
88 88
 	XCTAssertTrue(_modalDismissedCount == 2);
89 89
 }
90 90
 
91
-- (void)testDismissNilModal_doesntCrash {
91
+- (void)testDismissModal_DismissNilModalDoesntCrash {
92 92
 	_modalManager.delegate = self;
93 93
 	[_modalManager dismissModal:nil completion:nil];
94 94
 	

+ 10
- 10
lib/src/Navigation.ts View File

@@ -92,15 +92,15 @@ export class Navigation {
92 92
   /**
93 93
    * Dismiss a modal by componentId. The dismissed modal can be anywhere in the stack.
94 94
    */
95
-  public dismissModal(componentId: string): Promise<any> {
96
-    return this.commands.dismissModal(componentId);
95
+  public dismissModal(componentId: string, mergeOptions?): Promise<any> {
96
+    return this.commands.dismissModal(componentId, mergeOptions);
97 97
   }
98 98
 
99 99
   /**
100 100
    * Dismiss all Modals
101 101
    */
102
-  public dismissAllModals(): Promise<any> {
103
-    return this.commands.dismissAllModals();
102
+  public dismissAllModals(mergeOptions?): Promise<any> {
103
+    return this.commands.dismissAllModals(mergeOptions);
104 104
   }
105 105
 
106 106
   /**
@@ -113,22 +113,22 @@ export class Navigation {
113 113
   /**
114 114
    * Pop a component from the stack, regardless of it's position.
115 115
    */
116
-  public pop(componentId: string, params?): Promise<any> {
117
-    return this.commands.pop(componentId, params);
116
+  public pop(componentId: string, mergeOptions?): Promise<any> {
117
+    return this.commands.pop(componentId, mergeOptions);
118 118
   }
119 119
 
120 120
   /**
121 121
    * Pop the stack to a given component
122 122
    */
123
-  public popTo(componentId: string): Promise<any> {
124
-    return this.commands.popTo(componentId);
123
+  public popTo(componentId: string, mergeOptions?): Promise<any> {
124
+    return this.commands.popTo(componentId, mergeOptions);
125 125
   }
126 126
 
127 127
   /**
128 128
    * Pop the component's stack to root.
129 129
    */
130
-  public popToRoot(componentId: string): Promise<any> {
131
-    return this.commands.popToRoot(componentId);
130
+  public popToRoot(componentId: string, mergeOptions?): Promise<any> {
131
+    return this.commands.popToRoot(componentId, mergeOptions);
132 132
   }
133 133
 
134 134
   /**

+ 8
- 8
lib/src/adapters/NativeCommandsSender.ts View File

@@ -26,12 +26,12 @@ export class NativeCommandsSender {
26 26
     return this.nativeCommandsModule.pop(commandId, componentId, options);
27 27
   }
28 28
 
29
-  popTo(commandId: string, componentId: string) {
30
-    return this.nativeCommandsModule.popTo(commandId, componentId);
29
+  popTo(commandId: string, componentId: string, options: object) {
30
+    return this.nativeCommandsModule.popTo(commandId, componentId, options);
31 31
   }
32 32
 
33
-  popToRoot(commandId: string, componentId: string) {
34
-    return this.nativeCommandsModule.popToRoot(commandId, componentId);
33
+  popToRoot(commandId: string, componentId: string, options: object) {
34
+    return this.nativeCommandsModule.popToRoot(commandId, componentId, options);
35 35
   }
36 36
 
37 37
   setStackRoot(commandId: string, onComponentId: string, layout: object) {
@@ -42,12 +42,12 @@ export class NativeCommandsSender {
42 42
     return this.nativeCommandsModule.showModal(commandId, layout);
43 43
   }
44 44
 
45
-  dismissModal(commandId: string, componentId: string) {
46
-    return this.nativeCommandsModule.dismissModal(commandId, componentId);
45
+  dismissModal(commandId: string, componentId: string, options: object) {
46
+    return this.nativeCommandsModule.dismissModal(commandId, componentId, options);
47 47
   }
48 48
 
49
-  dismissAllModals(commandId: string) {
50
-    return this.nativeCommandsModule.dismissAllModals(commandId);
49
+  dismissAllModals(commandId: string, options: object) {
50
+    return this.nativeCommandsModule.dismissAllModals(commandId, options);
51 51
   }
52 52
 
53 53
   showOverlay(commandId: string, layout: object) {

+ 17
- 17
lib/src/commands/Commands.test.ts View File

@@ -202,9 +202,9 @@ describe('Commands', () => {
202 202
 
203 203
   describe('dismissModal', () => {
204 204
     it('sends command to native', () => {
205
-      uut.dismissModal('myUniqueId');
205
+      uut.dismissModal('myUniqueId', {});
206 206
       expect(mockCommandsSender.dismissModal).toHaveBeenCalledTimes(1);
207
-      expect(mockCommandsSender.dismissModal).toHaveBeenCalledWith('dismissModal+UNIQUE_ID', 'myUniqueId');
207
+      expect(mockCommandsSender.dismissModal).toHaveBeenCalledWith('dismissModal+UNIQUE_ID', 'myUniqueId', {});
208 208
     });
209 209
 
210 210
     it('returns a promise with the id', async () => {
@@ -216,9 +216,9 @@ describe('Commands', () => {
216 216
 
217 217
   describe('dismissAllModals', () => {
218 218
     it('sends command to native', () => {
219
-      uut.dismissAllModals();
219
+      uut.dismissAllModals({});
220 220
       expect(mockCommandsSender.dismissAllModals).toHaveBeenCalledTimes(1);
221
-      expect(mockCommandsSender.dismissAllModals).toHaveBeenCalledWith('dismissAllModals+UNIQUE_ID');
221
+      expect(mockCommandsSender.dismissAllModals).toHaveBeenCalledWith('dismissAllModals+UNIQUE_ID', {});
222 222
     });
223 223
 
224 224
     it('returns a promise with the id', async () => {
@@ -285,9 +285,9 @@ describe('Commands', () => {
285 285
 
286 286
   describe('popTo', () => {
287 287
     it('pops all components until the passed Id is top', () => {
288
-      uut.popTo('theComponentId');
288
+      uut.popTo('theComponentId', {});
289 289
       expect(mockCommandsSender.popTo).toHaveBeenCalledTimes(1);
290
-      expect(mockCommandsSender.popTo).toHaveBeenCalledWith('popTo+UNIQUE_ID', 'theComponentId');
290
+      expect(mockCommandsSender.popTo).toHaveBeenCalledWith('popTo+UNIQUE_ID', 'theComponentId', {});
291 291
     });
292 292
 
293 293
     it('returns a promise that resolves to targetId', async () => {
@@ -299,9 +299,9 @@ describe('Commands', () => {
299 299
 
300 300
   describe('popToRoot', () => {
301 301
     it('pops all components to root', () => {
302
-      uut.popToRoot('theComponentId');
302
+      uut.popToRoot('theComponentId', {});
303 303
       expect(mockCommandsSender.popToRoot).toHaveBeenCalledTimes(1);
304
-      expect(mockCommandsSender.popToRoot).toHaveBeenCalledWith('popToRoot+UNIQUE_ID', 'theComponentId');
304
+      expect(mockCommandsSender.popToRoot).toHaveBeenCalledWith('popToRoot+UNIQUE_ID', 'theComponentId', {});
305 305
     });
306 306
 
307 307
     it('returns a promise that resolves to targetId', async () => {
@@ -428,12 +428,12 @@ describe('Commands', () => {
428 428
         setDefaultOptions: [{}],
429 429
         mergeOptions: ['id', {}],
430 430
         showModal: [{}],
431
-        dismissModal: ['id'],
432
-        dismissAllModals: [],
431
+        dismissModal: ['id', {}],
432
+        dismissAllModals: [{}],
433 433
         push: ['id', {}],
434 434
         pop: ['id', {}],
435
-        popTo: ['id'],
436
-        popToRoot: ['id'],
435
+        popTo: ['id', {}],
436
+        popToRoot: ['id', {}],
437 437
         setStackRoot: ['id', {}],
438 438
         showOverlay: [{}],
439 439
         dismissOverlay: ['id'],
@@ -444,12 +444,12 @@ describe('Commands', () => {
444 444
         setDefaultOptions: { options: {} },
445 445
         mergeOptions: { componentId: 'id', options: {} },
446 446
         showModal: { commandId: 'showModal+UNIQUE_ID', layout: 'parsed' },
447
-        dismissModal: { commandId: 'dismissModal+UNIQUE_ID', componentId: 'id' },
448
-        dismissAllModals: { commandId: 'dismissAllModals+UNIQUE_ID' },
447
+        dismissModal: { commandId: 'dismissModal+UNIQUE_ID', componentId: 'id', mergeOptions: {} },
448
+        dismissAllModals: { commandId: 'dismissAllModals+UNIQUE_ID', mergeOptions: {} },
449 449
         push: { commandId: 'push+UNIQUE_ID', componentId: 'id', layout: 'parsed' },
450
-        pop: { commandId: 'pop+UNIQUE_ID', componentId: 'id', options: {} },
451
-        popTo: { commandId: 'popTo+UNIQUE_ID', componentId: 'id' },
452
-        popToRoot: { commandId: 'popToRoot+UNIQUE_ID', componentId: 'id' },
450
+        pop: { commandId: 'pop+UNIQUE_ID', componentId: 'id', mergeOptions: {} },
451
+        popTo: { commandId: 'popTo+UNIQUE_ID', componentId: 'id', mergeOptions: {} },
452
+        popToRoot: { commandId: 'popToRoot+UNIQUE_ID', componentId: 'id', mergeOptions: {} },
453 453
         setStackRoot: { commandId: 'setStackRoot+UNIQUE_ID', componentId: 'id', layout: 'parsed' },
454 454
         showOverlay: { commandId: 'showOverlay+UNIQUE_ID', layout: 'parsed' },
455 455
         dismissOverlay: { commandId: 'dismissOverlay+UNIQUE_ID', componentId: 'id' },

+ 15
- 15
lib/src/commands/Commands.ts View File

@@ -62,17 +62,17 @@ export class Commands {
62 62
     return result;
63 63
   }
64 64
 
65
-  public dismissModal(componentId) {
65
+  public dismissModal(componentId, mergeOptions?) {
66 66
     const commandId = this.uniqueIdProvider.generate('dismissModal');
67
-    const result = this.nativeCommandsSender.dismissModal(commandId, componentId);
68
-    this.commandsObserver.notify('dismissModal', { commandId, componentId });
67
+    const result = this.nativeCommandsSender.dismissModal(commandId, componentId, mergeOptions);
68
+    this.commandsObserver.notify('dismissModal', { commandId, componentId, mergeOptions});
69 69
     return result;
70 70
   }
71 71
 
72
-  public dismissAllModals() {
72
+  public dismissAllModals(mergeOptions?) {
73 73
     const commandId = this.uniqueIdProvider.generate('dismissAllModals');
74
-    const result = this.nativeCommandsSender.dismissAllModals(commandId);
75
-    this.commandsObserver.notify('dismissAllModals', { commandId });
74
+    const result = this.nativeCommandsSender.dismissAllModals(commandId, mergeOptions);
75
+    this.commandsObserver.notify('dismissAllModals', { commandId, mergeOptions });
76 76
     return result;
77 77
   }
78 78
 
@@ -88,24 +88,24 @@ export class Commands {
88 88
     return result;
89 89
   }
90 90
 
91
-  public pop(componentId, options) {
91
+  public pop(componentId, mergeOptions?) {
92 92
     const commandId = this.uniqueIdProvider.generate('pop');
93
-    const result = this.nativeCommandsSender.pop(commandId, componentId, options);
94
-    this.commandsObserver.notify('pop', { commandId, componentId, options });
93
+    const result = this.nativeCommandsSender.pop(commandId, componentId, mergeOptions);
94
+    this.commandsObserver.notify('pop', { commandId, componentId, mergeOptions });
95 95
     return result;
96 96
   }
97 97
 
98
-  public popTo(componentId) {
98
+  public popTo(componentId, mergeOptions?) {
99 99
     const commandId = this.uniqueIdProvider.generate('popTo');
100
-    const result = this.nativeCommandsSender.popTo(commandId, componentId);
101
-    this.commandsObserver.notify('popTo', { commandId, componentId });
100
+    const result = this.nativeCommandsSender.popTo(commandId, componentId, mergeOptions);
101
+    this.commandsObserver.notify('popTo', { commandId, componentId, mergeOptions });
102 102
     return result;
103 103
   }
104 104
 
105
-  public popToRoot(componentId) {
105
+  public popToRoot(componentId, mergeOptions?) {
106 106
     const commandId = this.uniqueIdProvider.generate('popToRoot');
107
-    const result = this.nativeCommandsSender.popToRoot(commandId, componentId);
108
-    this.commandsObserver.notify('popToRoot', { commandId, componentId });
107
+    const result = this.nativeCommandsSender.popToRoot(commandId, componentId, mergeOptions);
108
+    this.commandsObserver.notify('popToRoot', { commandId, componentId, mergeOptions });
109 109
     return result;
110 110
   }
111 111