Browse Source

Implement statusBarBackgroundColor

* Set default statusBarBackgroundColor to Black
* Component and Parent controllers now extend ChildController
* Implement return to front logic for ChildControllers
* Apply statusBar color when view appears and returns to front
Guy Carmeli 6 years ago
parent
commit
46f9b65617
34 changed files with 341 additions and 96 deletions
  1. 5
    4
      docs/docs/styling.md
  2. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java
  3. 10
    5
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  4. 1
    2
      lib/android/app/src/main/java/com/reactnativenavigation/parse/StatusBarOptions.java
  5. 13
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  6. 1
    0
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  7. 44
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildController.java
  8. 28
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildControllersRegistry.java
  9. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  10. 10
    10
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  11. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  12. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/SideMenuController.java
  13. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  14. 7
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackControllerBuilder.java
  15. 3
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  16. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  17. 6
    3
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  18. 2
    2
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleComponentViewController.java
  19. 5
    4
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java
  20. 9
    7
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java
  21. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ComponentViewControllerTest.java
  22. 5
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/FloatingActionButtonTest.java
  23. 13
    10
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  24. 1
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  25. 11
    9
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java
  26. 5
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/SideMenuControllerTest.java
  27. 7
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  28. 6
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  29. 4
    2
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java
  30. 39
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java
  31. 47
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java
  32. 19
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java
  33. 7
    4
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java
  34. 17
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/overlay/OverlayManagerTest.java

+ 5
- 4
docs/docs/styling.md View File

@@ -56,12 +56,13 @@ Navigation.mergeOptions(this.props.componentId, {
56 56
 
57 57
 ```js
58 58
 {
59
-  statusBarHidden: false,
59
+  statusBarHidden: false, // iOS only
60
+  statusBarBackgroundColor: 'red', // Android only
61
+  statusBarHideWithTopBar: false, // iOS only
62
+  statusBarBlur: true, // iOS only
63
+  statusBarStyle: 'light', // iOS only
60 64
   screenBackgroundColor: 'white',
61 65
   orientation: ['portrait', 'landscape'],
62
-  statusBarBlur: true,
63
-  statusBarHideWithTopBar: false,
64
-  statusBarStyle: 'light',
65 66
   popGesture: true,
66 67
   backgroundImage: require('background.png'),
67 68
   rootBackgroundImage: require('rootBackground.png'),

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java View File

@@ -10,6 +10,7 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
10 10
 import com.reactnativenavigation.presentation.OverlayManager;
11 11
 import com.reactnativenavigation.react.ReactGateway;
12 12
 import com.reactnativenavigation.utils.CommandListenerAdapter;
13
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
13 14
 import com.reactnativenavigation.viewcontrollers.Navigator;
14 15
 
15 16
 public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
@@ -18,7 +19,7 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
18 19
     @Override
19 20
     protected void onCreate(@Nullable Bundle savedInstanceState) {
20 21
         super.onCreate(savedInstanceState);
21
-        navigator = new Navigator(this, new OverlayManager());
22
+        navigator = new Navigator(this, new ChildControllersRegistry(), new OverlayManager());
22 23
         getReactGateway().onActivityCreated(this);
23 24
         getReactGateway().addReloadListener(navigator);
24 25
         setContentView(navigator.getView());

+ 10
- 5
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java View File

@@ -7,6 +7,7 @@ import com.reactnativenavigation.react.EventEmitter;
7 7
 import com.reactnativenavigation.utils.CommandListenerAdapter;
8 8
 import com.reactnativenavigation.utils.ImageLoader;
9 9
 import com.reactnativenavigation.utils.TypefaceLoader;
10
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
10 11
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
11 12
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
12 13
 import com.reactnativenavigation.viewcontrollers.StackController;
@@ -31,15 +32,17 @@ import java.util.Map;
31 32
 public class LayoutFactory {
32 33
 
33 34
 	private final Activity activity;
35
+    private final ChildControllersRegistry childRegistry;
34 36
 	private final ReactInstanceManager reactInstanceManager;
35 37
     private EventEmitter eventEmitter;
36 38
     private Map<String, ExternalComponentCreator> externalComponentCreators;
37 39
     private Options defaultOptions;
38 40
     private final TypefaceLoader typefaceManager;
39 41
 
40
-    public LayoutFactory(Activity activity, final ReactInstanceManager reactInstanceManager, EventEmitter eventEmitter, Map<String, ExternalComponentCreator> externalComponentCreators, Options defaultOptions) {
42
+    public LayoutFactory(Activity activity, ChildControllersRegistry childRegistry, final ReactInstanceManager reactInstanceManager, EventEmitter eventEmitter, Map<String, ExternalComponentCreator> externalComponentCreators, Options defaultOptions) {
41 43
 		this.activity = activity;
42
-		this.reactInstanceManager = reactInstanceManager;
44
+        this.childRegistry = childRegistry;
45
+        this.reactInstanceManager = reactInstanceManager;
43 46
         this.eventEmitter = eventEmitter;
44 47
         this.externalComponentCreators = externalComponentCreators;
45 48
         this.defaultOptions = defaultOptions;
@@ -72,7 +75,7 @@ public class LayoutFactory {
72 75
 	}
73 76
 
74 77
     private ViewController createSideMenuRoot(LayoutNode node) {
75
-        SideMenuController sideMenuController = new SideMenuController(activity, node.id, parseNodeOptions(node));
78
+        SideMenuController sideMenuController = new SideMenuController(activity, childRegistry, node.id, parseNodeOptions(node));
76 79
 		for (LayoutNode child : node.children) {
77 80
 			ViewController childController = create(child);
78 81
             childController.setParentController(sideMenuController);
@@ -109,6 +112,7 @@ public class LayoutFactory {
109 112
 		String id = node.id;
110 113
 		String name = node.data.optString("name");
111 114
         return new ComponentViewController(activity,
115
+                childRegistry,
112 116
                 id,
113 117
                 name,
114 118
                 new ComponentViewCreator(reactInstanceManager),
@@ -129,6 +133,7 @@ public class LayoutFactory {
129 133
 
130 134
 	private ViewController createStack(LayoutNode node) {
131 135
         StackController stackController = new StackControllerBuilder(activity)
136
+                .setChildRegistry(childRegistry)
132 137
                 .setTopBarButtonCreator(new TitleBarButtonCreator(reactInstanceManager))
133 138
                 .setTitleBarReactViewCreator(new TitleBarReactViewCreator(reactInstanceManager))
134 139
                 .setTopBarBackgroundViewController(new TopBarBackgroundViewController(activity, new TopBarBackgroundViewCreator(reactInstanceManager)))
@@ -147,7 +152,7 @@ public class LayoutFactory {
147 152
     }
148 153
 
149 154
     private ViewController createBottomTabs(LayoutNode node) {
150
-        final BottomTabsController tabsComponent = new BottomTabsController(activity, eventEmitter, new ImageLoader(), node.id, parseNodeOptions(node));
155
+        final BottomTabsController tabsComponent = new BottomTabsController(activity, childRegistry, eventEmitter, new ImageLoader(), node.id, parseNodeOptions(node));
151 156
 		List<ViewController> tabs = new ArrayList<>();
152 157
 		for (int i = 0; i < node.children.size(); i++) {
153 158
             tabs.add(create(node.children.get(i)));
@@ -164,7 +169,7 @@ public class LayoutFactory {
164 169
             options.setTopTabIndex(i);
165 170
             tabs.add(tabController);
166 171
         }
167
-        return new TopTabsController(activity, node.id, tabs, new TopTabsLayoutCreator(activity, tabs), parseNodeOptions(node));
172
+        return new TopTabsController(activity, childRegistry, node.id, tabs, new TopTabsLayoutCreator(activity, tabs), parseNodeOptions(node));
168 173
     }
169 174
 
170 175
     private Options parseNodeOptions(LayoutNode node) {

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

@@ -1,7 +1,6 @@
1 1
 package com.reactnativenavigation.parse;
2 2
 
3 3
 import com.reactnativenavigation.parse.params.Color;
4
-import com.reactnativenavigation.parse.params.NullColor;
5 4
 import com.reactnativenavigation.parse.parsers.ColorParser;
6 5
 
7 6
 import org.json.JSONObject;
@@ -16,7 +15,7 @@ public class StatusBarOptions {
16 15
         return result;
17 16
     }
18 17
 
19
-    public Color backgroundColor = new NullColor();
18
+    public Color backgroundColor = new Color(android.graphics.Color.BLACK);
20 19
 
21 20
     public void mergeWith(StatusBarOptions other) {
22 21
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;

+ 13
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java View File

@@ -1,11 +1,14 @@
1 1
 package com.reactnativenavigation.presentation;
2 2
 
3 3
 import android.app.Activity;
4
+import android.os.Build;
4 5
 import android.view.View;
5 6
 
6 7
 import com.reactnativenavigation.parse.Options;
7 8
 import com.reactnativenavigation.parse.OrientationOptions;
9
+import com.reactnativenavigation.parse.StatusBarOptions;
8 10
 
11
+@SuppressWarnings("FieldCanBeLocal")
9 12
 public class OptionsPresenter {
10 13
 
11 14
     private Activity activity;
@@ -17,6 +20,7 @@ public class OptionsPresenter {
17 20
     public void present(View view, Options options) {
18 21
         applyOrientation(options.orientationOptions);
19 22
         applyViewOptions(view, options);
23
+        applyStatusBarOptions(options.statusBar);
20 24
     }
21 25
 
22 26
     private void applyOrientation(OrientationOptions options) {
@@ -29,4 +33,13 @@ public class OptionsPresenter {
29 33
         }
30 34
     }
31 35
 
36
+    public void onViewBroughtToFront(Options options) {
37
+        applyStatusBarOptions(options.statusBar);
38
+    }
39
+
40
+    private void applyStatusBarOptions(StatusBarOptions statusBar) {
41
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
42
+            activity.getWindow().setStatusBarColor(statusBar.backgroundColor.get());
43
+        }
44
+    }
32 45
 }

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

@@ -139,6 +139,7 @@ public class NavigationModule extends ReactContextBaseJavaModule {
139 139
 	@NonNull
140 140
 	private LayoutFactory newLayoutFactory() {
141 141
 		return new LayoutFactory(activity(),
142
+                navigator().getChildRegistry(),
142 143
                 reactInstanceManager,
143 144
                 eventEmitter,
144 145
                 externalComponentCreator(),

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

@@ -0,0 +1,44 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import android.app.Activity;
4
+import android.view.ViewGroup;
5
+
6
+import com.reactnativenavigation.parse.Options;
7
+import com.reactnativenavigation.presentation.OptionsPresenter;
8
+
9
+public abstract class ChildController<T extends ViewGroup> extends ViewController<T>  {
10
+    private final OptionsPresenter presenter;
11
+    private final ChildControllersRegistry childRegistry;
12
+
13
+    public ChildControllersRegistry getChildRegistry() {
14
+        return childRegistry;
15
+    }
16
+
17
+    public ChildController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
18
+        super(activity, id, initialOptions);
19
+        presenter = new OptionsPresenter(activity);
20
+        this.childRegistry = childRegistry;
21
+    }
22
+
23
+    @Override
24
+    public void onViewAppeared() {
25
+        super.onViewAppeared();
26
+        childRegistry.onViewAppeared(this);
27
+    }
28
+
29
+    @Override
30
+    public void onViewDisappear() {
31
+        super.onViewDisappear();
32
+        childRegistry.onViewDisappear(this);
33
+    }
34
+
35
+    public void onViewBroughtToFront() {
36
+        presenter.onViewBroughtToFront(options);
37
+    }
38
+
39
+    @Override
40
+    public void applyOptions(Options options) {
41
+        super.applyOptions(options);
42
+        presenter.present(getView(), options);
43
+    }
44
+}

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

@@ -0,0 +1,28 @@
1
+package com.reactnativenavigation.viewcontrollers;
2
+
3
+import java.util.ArrayDeque;
4
+
5
+public class ChildControllersRegistry {
6
+    private ArrayDeque<ChildController> children = new ArrayDeque<>();
7
+
8
+    public void onViewAppeared(ChildController child) {
9
+        children.push(child);
10
+    }
11
+
12
+    public void onViewDisappear(ChildController child) {
13
+        if (isTopChild(child)) {
14
+            children.pop();
15
+            if (!children.isEmpty()) children.peek().onViewBroughtToFront();
16
+        } else {
17
+            children.remove(child);
18
+        }
19
+    }
20
+
21
+    private boolean isTopChild(ChildController child) {
22
+        return children.peek().equals(child);
23
+    }
24
+
25
+    public int size() {
26
+        return children.size();
27
+    }
28
+}

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

@@ -7,18 +7,19 @@ import com.reactnativenavigation.parse.Options;
7 7
 import com.reactnativenavigation.views.ComponentLayout;
8 8
 import com.reactnativenavigation.views.ReactComponent;
9 9
 
10
-public class ComponentViewController extends ViewController<ComponentLayout> {
10
+public class ComponentViewController extends ChildController<ComponentLayout> {
11 11
 
12 12
     private final String componentName;
13 13
 
14 14
     private final ReactViewCreator viewCreator;
15 15
 
16 16
     public ComponentViewController(final Activity activity,
17
+                                   final ChildControllersRegistry childRegistry,
17 18
                                    final String id,
18 19
                                    final String componentName,
19 20
                                    final ReactViewCreator viewCreator,
20 21
                                    final Options initialOptions) {
21
-        super(activity, id, initialOptions);
22
+        super(activity, childRegistry, id, initialOptions);
22 23
         this.componentName = componentName;
23 24
         this.viewCreator = viewCreator;
24 25
     }

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

@@ -32,8 +32,16 @@ public class Navigator extends ParentController implements JsDevReloadHandler.Re
32 32
     private final OverlayManager overlayManager;
33 33
     private Options defaultOptions = new Options();
34 34
 
35
-    public Navigator(final Activity activity, OverlayManager overlayManager) {
36
-        super(activity, "navigator" + CompatUtils.generateViewId(), new Options());
35
+    public void setDefaultOptions(Options defaultOptions) {
36
+        this.defaultOptions = defaultOptions;
37
+    }
38
+
39
+    public Options getDefaultOptions() {
40
+        return defaultOptions;
41
+    }
42
+
43
+    public Navigator(final Activity activity, ChildControllersRegistry childRegistry, OverlayManager overlayManager) {
44
+        super(activity, childRegistry,"navigator" + CompatUtils.generateViewId(), new Options());
37 45
         modalStack = new ModalStack(new ModalPresenter(new ModalAnimator(activity)));
38 46
         this.overlayManager = overlayManager;
39 47
     }
@@ -108,14 +116,6 @@ public class Navigator extends ParentController implements JsDevReloadHandler.Re
108 116
         }
109 117
     }
110 118
 
111
-    public void setDefaultOptions(Options defaultOptions) {
112
-        this.defaultOptions = defaultOptions;
113
-    }
114
-
115
-    public Options getDefaultOptions() {
116
-        return defaultOptions;
117
-    }
118
-
119 119
     public void mergeOptions(final String componentId, Options options) {
120 120
         ViewController target = findControllerById(componentId);
121 121
         if (target != null) {

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

@@ -12,10 +12,10 @@ import com.reactnativenavigation.views.Component;
12 12
 
13 13
 import java.util.Collection;
14 14
 
15
-public abstract class ParentController<T extends ViewGroup> extends ViewController {
15
+public abstract class ParentController<T extends ViewGroup> extends ChildController {
16 16
 
17
-	public ParentController(final Activity activity, final String id, Options initialOptions) {
18
-		super(activity, id, initialOptions);
17
+	public ParentController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
18
+		super(activity, childRegistry, id, initialOptions);
19 19
 	}
20 20
 
21 21
 	@NonNull

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

@@ -22,8 +22,8 @@ public class SideMenuController extends ParentController<DrawerLayout> {
22 22
 	private ViewController leftController;
23 23
 	private ViewController rightController;
24 24
 
25
-	public SideMenuController(final Activity activity, final String id, Options initialOptions) {
26
-		super(activity, id, initialOptions);
25
+	public SideMenuController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
26
+		super(activity, childRegistry, id, initialOptions);
27 27
 	}
28 28
 
29 29
 	@NonNull

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

@@ -31,8 +31,8 @@ public class StackController extends ParentController<StackLayout> {
31 31
     private TopBarBackgroundViewController topBarBackgroundViewController;
32 32
     private TopBarController topBarController;
33 33
 
34
-    public StackController(final Activity activity, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarBackgroundViewController topBarBackgroundViewController, TopBarController topBarController, NavigationAnimator animator, String id, Options initialOptions) {
35
-        super(activity, id, initialOptions);
34
+    public StackController(Activity activity, ChildControllersRegistry childRegistry, ReactViewCreator topBarButtonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarBackgroundViewController topBarBackgroundViewController, TopBarController topBarController, NavigationAnimator animator, String id, Options initialOptions) {
35
+        super(activity, childRegistry, id, initialOptions);
36 36
         this.topBarController = topBarController;
37 37
         this.topBarButtonCreator = topBarButtonCreator;
38 38
         this.titleBarReactViewCreator = titleBarReactViewCreator;

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

@@ -10,6 +10,7 @@ import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
10 10
 
11 11
 public class StackControllerBuilder {
12 12
     private Activity activity;
13
+    private ChildControllersRegistry childRegistry;
13 14
     private ReactViewCreator topBarButtonCreator;
14 15
     private TitleBarReactViewCreator titleBarReactViewCreator;
15 16
     private TopBarBackgroundViewController topBarBackgroundViewController;
@@ -23,6 +24,11 @@ public class StackControllerBuilder {
23 24
         animator = new NavigationAnimator(activity);
24 25
     }
25 26
 
27
+    public StackControllerBuilder setChildRegistry(ChildControllersRegistry childRegistry) {
28
+        this.childRegistry = childRegistry;
29
+        return this;
30
+    }
31
+
26 32
     public StackControllerBuilder setTopBarButtonCreator(ReactViewCreator topBarButtonCreator) {
27 33
         this.topBarButtonCreator = topBarButtonCreator;
28 34
         return this;
@@ -59,6 +65,6 @@ public class StackControllerBuilder {
59 65
     }
60 66
 
61 67
     public StackController createStackController() {
62
-        return new StackController(activity, topBarButtonCreator, titleBarReactViewCreator, topBarBackgroundViewController, topBarController, animator, id, initialOptions);
68
+        return new StackController(activity, childRegistry, topBarButtonCreator, titleBarReactViewCreator, topBarBackgroundViewController, topBarController, animator, id, initialOptions);
63 69
     }
64 70
 }

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

@@ -12,7 +12,6 @@ import android.view.ViewTreeObserver;
12 12
 
13 13
 import com.reactnativenavigation.parse.Options;
14 14
 import com.reactnativenavigation.presentation.FabOptionsPresenter;
15
-import com.reactnativenavigation.presentation.OptionsPresenter;
16 15
 import com.reactnativenavigation.utils.CommandListener;
17 16
 import com.reactnativenavigation.utils.StringUtils;
18 17
 import com.reactnativenavigation.utils.Task;
@@ -43,13 +42,11 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
43 42
     private boolean isShown;
44 43
     private boolean isDestroyed;
45 44
     private ViewVisibilityListener viewVisibilityListener = new ViewVisibilityListenerAdapter();
46
-    private OptionsPresenter presenter;
47 45
     FabOptionsPresenter fabOptionsPresenter;
48 46
 
49 47
     public ViewController(Activity activity, String id, Options initialOptions) {
50 48
         this.activity = activity;
51 49
         this.id = id;
52
-        presenter = new OptionsPresenter(activity);
53 50
         fabOptionsPresenter = new FabOptionsPresenter();
54 51
         this.initialOptions = initialOptions;
55 52
         options = initialOptions.copy();
@@ -79,7 +76,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
79 76
 
80 77
     @CallSuper
81 78
     public void applyOptions(Options options) {
82
-        presenter.present(getView(), options);
79
+
83 80
     }
84 81
 
85 82
     public Activity getActivity() {
@@ -157,6 +154,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
157 154
 
158 155
     }
159 156
 
157
+    @CallSuper
160 158
     public void onViewAppeared() {
161 159
         isShown = true;
162 160
         applyOptions(options);
@@ -170,6 +168,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
170 168
 
171 169
     }
172 170
 
171
+    @CallSuper
173 172
     public void onViewDisappear() {
174 173
         isShown = false;
175 174
     }

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java View File

@@ -14,6 +14,7 @@ import com.reactnativenavigation.presentation.BottomTabsOptionsPresenter;
14 14
 import com.reactnativenavigation.react.EventEmitter;
15 15
 import com.reactnativenavigation.utils.CommandListener;
16 16
 import com.reactnativenavigation.utils.ImageLoader;
17
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
17 18
 import com.reactnativenavigation.viewcontrollers.ParentController;
18 19
 import com.reactnativenavigation.viewcontrollers.ViewController;
19 20
 import com.reactnativenavigation.views.BottomTabs;
@@ -36,8 +37,8 @@ public class BottomTabsController extends ParentController implements AHBottomNa
36 37
     private BottomTabsOptionsPresenter presenter;
37 38
     private final BottomTabFinder bottomTabFinder = new BottomTabFinder();
38 39
 
39
-    public BottomTabsController(final Activity activity, EventEmitter eventEmitter, ImageLoader imageLoader, final String id, Options initialOptions) {
40
-		super(activity, id, initialOptions);
40
+    public BottomTabsController(Activity activity, ChildControllersRegistry childRegistry, EventEmitter eventEmitter, ImageLoader imageLoader, String id, Options initialOptions) {
41
+		super(activity, childRegistry, id, initialOptions);
41 42
         this.eventEmitter = eventEmitter;
42 43
         this.imageLoader = imageLoader;
43 44
     }

+ 6
- 3
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

@@ -6,6 +6,7 @@ import android.view.View;
6 6
 
7 7
 import com.reactnativenavigation.parse.Options;
8 8
 import com.reactnativenavigation.utils.Task;
9
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
9 10
 import com.reactnativenavigation.viewcontrollers.ParentController;
10 11
 import com.reactnativenavigation.viewcontrollers.ViewController;
11 12
 import com.reactnativenavigation.viewcontrollers.ViewVisibilityListenerAdapter;
@@ -21,8 +22,8 @@ public class TopTabsController extends ParentController<TopTabsViewPager> {
21 22
     private List<ViewController> tabs;
22 23
     private TopTabsLayoutCreator viewCreator;
23 24
 
24
-    public TopTabsController(Activity activity, String id, List<ViewController> tabs, TopTabsLayoutCreator viewCreator, Options options) {
25
-        super(activity, id, options);
25
+    public TopTabsController(Activity activity, ChildControllersRegistry childRegistry, String id, List<ViewController> tabs, TopTabsLayoutCreator viewCreator, Options options) {
26
+        super(activity, childRegistry, id, options);
26 27
         this.viewCreator = viewCreator;
27 28
         this.tabs = tabs;
28 29
         for (ViewController tab : tabs) {
@@ -51,7 +52,7 @@ public class TopTabsController extends ParentController<TopTabsViewPager> {
51 52
 
52 53
     @Override
53 54
     public void onViewAppeared() {
54
-        applyOptions(options);
55
+        super.onViewAppeared();
55 56
         applyOnParentController(parentController -> ((ParentController) parentController).setupTopTabsWithViewPager(getView()));
56 57
         performOnCurrentTab(ViewController::onViewAppeared);
57 58
     }
@@ -63,6 +64,7 @@ public class TopTabsController extends ParentController<TopTabsViewPager> {
63 64
 
64 65
     @Override
65 66
     public void onViewDisappear() {
67
+        super.onViewDisappear();
66 68
         performOnCurrentTab(ViewController::onViewDisappear);
67 69
         applyOnParentController(parentController -> ((ParentController) parentController).clearTopTabs());
68 70
     }
@@ -74,6 +76,7 @@ public class TopTabsController extends ParentController<TopTabsViewPager> {
74 76
 
75 77
     @Override
76 78
     public void applyOptions(Options options) {
79
+        super.applyOptions(options);
77 80
         getView().applyOptions(options);
78 81
     }
79 82
 

+ 2
- 2
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleComponentViewController.java View File

@@ -6,7 +6,7 @@ import com.reactnativenavigation.parse.*;
6 6
 import com.reactnativenavigation.viewcontrollers.*;
7 7
 
8 8
 public class SimpleComponentViewController extends ComponentViewController {
9
-    public SimpleComponentViewController(final Activity activity, final String id, Options initialOptions) {
10
-        super(activity, id, "theComponentName", new TestComponentViewCreator(), initialOptions);
9
+    public SimpleComponentViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Options initialOptions) {
10
+        super(activity, childRegistry,id, "theComponentName", new TestComponentViewCreator(), initialOptions);
11 11
     }
12 12
 }

+ 5
- 4
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java View File

@@ -9,17 +9,18 @@ import android.widget.FrameLayout;
9 9
 
10 10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
11 11
 import com.reactnativenavigation.parse.Options;
12
-import com.reactnativenavigation.viewcontrollers.ViewController;
12
+import com.reactnativenavigation.viewcontrollers.ChildController;
13
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
13 14
 import com.reactnativenavigation.views.Component;
14 15
 import com.reactnativenavigation.views.ReactComponent;
15 16
 import com.reactnativenavigation.views.topbar.TopBar;
16 17
 
17
-public class SimpleViewController extends ViewController<FrameLayout> {
18
+public class SimpleViewController extends ChildController<FrameLayout> {
18 19
 
19 20
     private SimpleView simpleView;
20 21
 
21
-    public SimpleViewController(final Activity activity, String id, Options options) {
22
-        super(activity, id, options);
22
+    public SimpleViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Options options) {
23
+        super(activity, childRegistry, id, options);
23 24
     }
24 25
 
25 26
     @Override

+ 9
- 7
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/BottomTabsControllerTest.java View File

@@ -50,17 +50,19 @@ public class BottomTabsControllerTest extends BaseTest {
50 50
     private Options tabOptions = OptionHelper.createBottomTabOptions();
51 51
     private ImageLoader imageLoaderMock = ImageLoaderMock.mock();
52 52
     private EventEmitter eventEmitter;
53
+    private ChildControllersRegistry childRegistry;
53 54
 
54 55
     @Override
55 56
     public void beforeEach() {
56 57
         activity = newActivity();
58
+        childRegistry = new ChildControllersRegistry();
57 59
         eventEmitter = Mockito.mock(EventEmitter.class);
58
-        uut = spy(new BottomTabsController(activity, eventEmitter, imageLoaderMock, "uut", new Options()));
59
-        child1 = spy(new SimpleViewController(activity, "child1", tabOptions));
60
-        child2 = spy(new SimpleViewController(activity, "child2", tabOptions));
61
-        child3 = spy(new SimpleViewController(activity, "child3", tabOptions));
62
-        child4 = spy(new SimpleViewController(activity, "child4", tabOptions));
63
-        child5 = spy(new SimpleViewController(activity, "child5", tabOptions));
60
+        uut = spy(new BottomTabsController(activity, childRegistry, eventEmitter, imageLoaderMock, "uut", new Options()));
61
+        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
62
+        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
63
+        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
64
+        child4 = spy(new SimpleViewController(activity, childRegistry, "child4", tabOptions));
65
+        child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
64 66
     }
65 67
 
66 68
     @Test
@@ -72,7 +74,7 @@ public class BottomTabsControllerTest extends BaseTest {
72 74
     @Test(expected = RuntimeException.class)
73 75
     public void setTabs_ThrowWhenMoreThan5() {
74 76
         List<ViewController> tabs = createTabs();
75
-        tabs.add(new SimpleViewController(activity, "6", tabOptions));
77
+        tabs.add(new SimpleViewController(activity, childRegistry, "6", tabOptions));
76 78
         uut.setTabs(tabs);
77 79
     }
78 80
 

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

@@ -38,7 +38,7 @@ public class ComponentViewControllerTest extends BaseTest {
38 38
                 .setId("stack")
39 39
                 .setInitialOptions(new Options())
40 40
                 .createStackController();
41
-        uut = new ComponentViewController(activity, "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
41
+        uut = new ComponentViewController(activity, new ChildControllersRegistry(), "componentId1", "componentName", (activity1, componentId, componentName) -> view, new Options());
42 42
         uut.setParentController(parentController);
43 43
         parentController.ensureViewIsCreated();
44 44
     }

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

@@ -32,11 +32,13 @@ public class FloatingActionButtonTest extends BaseTest {
32 32
     private SimpleViewController childFab;
33 33
     private SimpleViewController childNoFab;
34 34
     private Activity activity;
35
+    private ChildControllersRegistry childRegistry;
35 36
 
36 37
     @Override
37 38
     public void beforeEach() {
38 39
         super.beforeEach();
39 40
         activity = newActivity();
41
+        childRegistry = new ChildControllersRegistry();
40 42
         stackController = new StackControllerBuilder(activity)
41 43
                 .setTopBarButtonCreator(new TopBarButtonCreatorMock())
42 44
                 .setTitleBarReactViewCreator(new TitleBarReactViewCreatorMock())
@@ -46,8 +48,8 @@ public class FloatingActionButtonTest extends BaseTest {
46 48
                 .setInitialOptions(new Options())
47 49
                 .createStackController();
48 50
         Options options = getOptionsWithFab();
49
-        childFab = new SimpleViewController(activity, "child1", options);
50
-        childNoFab = new SimpleViewController(activity, "child2", new Options());
51
+        childFab = new SimpleViewController(activity, childRegistry, "child1", options);
52
+        childNoFab = new SimpleViewController(activity, childRegistry, "child2", new Options());
51 53
     }
52 54
 
53 55
     @NonNull
@@ -129,7 +131,7 @@ public class FloatingActionButtonTest extends BaseTest {
129 131
 
130 132
     @Test
131 133
     public void hasChildren() {
132
-        childFab = new SimpleViewController(activity, "child1", getOptionsWithFabActions());
134
+        childFab = new SimpleViewController(activity, childRegistry, "child1", getOptionsWithFabActions());
133 135
         stackController.push(childFab, new CommandListenerAdapter());
134 136
         childFab.onViewAppeared();
135 137
         assertThat(hasFab()).isTrue();

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

@@ -39,6 +39,7 @@ import static org.mockito.Mockito.when;
39 39
 
40 40
 public class NavigatorTest extends BaseTest {
41 41
     private TestActivity activity;
42
+    private ChildControllersRegistry childRegistry;
42 43
     private Navigator uut;
43 44
     private StackController parentController;
44 45
     private SimpleViewController child1;
@@ -54,21 +55,22 @@ public class NavigatorTest extends BaseTest {
54 55
 
55 56
     @Override
56 57
     public void beforeEach() {
58
+        childRegistry = new ChildControllersRegistry();
57 59
         eventEmitter = Mockito.mock(EventEmitter.class);
58 60
         overlayManager = Mockito.mock(OverlayManager.class);
59 61
         imageLoaderMock = ImageLoaderMock.mock();
60 62
         activityController = newActivityController(TestActivity.class);
61 63
         activity = activityController.create().get();
62
-        uut = new Navigator(activity, overlayManager);
64
+        uut = new Navigator(activity, childRegistry, overlayManager);
63 65
         activity.setNavigator(uut);
64 66
 
65 67
         parentController = spy(newStack());
66 68
         parentController.ensureViewIsCreated();
67
-        child1 = new SimpleViewController(activity, "child1", tabOptions);
68
-        child2 = new SimpleViewController(activity, "child2", tabOptions);
69
-        child3 = new SimpleViewController(activity, "child3", tabOptions);
70
-        child4 = new SimpleViewController(activity, "child4", tabOptions);
71
-        child5 = new SimpleViewController(activity, "child5", tabOptions);
69
+        child1 = new SimpleViewController(activity, childRegistry, "child1", tabOptions);
70
+        child2 = new SimpleViewController(activity, childRegistry, "child2", tabOptions);
71
+        child3 = new SimpleViewController(activity, childRegistry, "child3", tabOptions);
72
+        child4 = new SimpleViewController(activity, childRegistry, "child4", tabOptions);
73
+        child5 = new SimpleViewController(activity, childRegistry, "child5", tabOptions);
72 74
         activity.setContentView(uut.getView());
73 75
 
74 76
         activityController.visible();
@@ -91,7 +93,7 @@ public class NavigatorTest extends BaseTest {
91 93
     @Test
92 94
     public void hasUniqueId() {
93 95
         assertThat(uut.getId()).startsWith("navigator");
94
-        assertThat(new Navigator(activity, overlayManager).getId()).isNotEqualTo(uut.getId());
96
+        assertThat(new Navigator(activity, childRegistry, overlayManager).getId()).isNotEqualTo(uut.getId());
95 97
     }
96 98
 
97 99
     @Test
@@ -126,7 +128,7 @@ public class NavigatorTest extends BaseTest {
126 128
         bottomTabsController.setTabs(Arrays.asList(stack1, stack2));
127 129
         uut.setRoot(bottomTabsController, new CommandListenerAdapter());
128 130
 
129
-        SimpleViewController newChild = new SimpleViewController(activity, "new child", tabOptions);
131
+        SimpleViewController newChild = new SimpleViewController(activity, childRegistry, "new child", tabOptions);
130 132
         uut.push(child2.getId(), newChild, new CommandListenerAdapter());
131 133
 
132 134
         assertThat(stack1.getChildControllers()).doesNotContain(newChild);
@@ -257,7 +259,7 @@ public class NavigatorTest extends BaseTest {
257 259
 
258 260
     @Test
259 261
     public void mergeOptions_CallsApplyNavigationOptions() {
260
-        ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
262
+        ComponentViewController componentVc = new SimpleComponentViewController(activity, childRegistry, "theId", new Options());
261 263
         componentVc.setParentController(parentController);
262 264
         assertThat(componentVc.options.topBar.title.text.get("")).isEmpty();
263 265
         uut.setRoot(componentVc, new CommandListenerAdapter());
@@ -276,12 +278,13 @@ public class NavigatorTest extends BaseTest {
276 278
 
277 279
     @NonNull
278 280
     private BottomTabsController newTabs() {
279
-        return new BottomTabsController(activity, eventEmitter, imageLoaderMock, "tabsController", new Options());
281
+        return new BottomTabsController(activity, childRegistry, eventEmitter, imageLoaderMock, "tabsController", new Options());
280 282
     }
281 283
 
282 284
     @NonNull
283 285
     private StackController newStack() {
284 286
         return new StackControllerBuilder(activity)
287
+                .setChildRegistry(childRegistry)
285 288
                 .setTopBarButtonCreator(new TopBarButtonCreatorMock())
286 289
                 .setTitleBarReactViewCreator(new TitleBarReactViewCreatorMock())
287 290
                 .setTopBarBackgroundViewController(new TopBarBackgroundViewController(activity, new TopBarBackgroundViewCreatorMock()))

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

@@ -48,6 +48,7 @@ public class OptionsApplyingTest extends BaseTest {
48 48
         view = spy(new TestComponentLayout(activity, new TestReactView(activity)));
49 49
         view.asView().setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
50 50
         uut = new ComponentViewController(activity,
51
+                new ChildControllersRegistry(),
51 52
                 "componentId1",
52 53
                 "componentName",
53 54
                 (activity1, componentId, componentName) -> view,

+ 11
- 9
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java View File

@@ -33,6 +33,7 @@ public class ParentControllerTest extends BaseTest {
33 33
 
34 34
     private static final String INITIAL_TITLE = "initial title";
35 35
     private Activity activity;
36
+    private ChildControllersRegistry childRegistry;
36 37
     private List<ViewController> children;
37 38
     private ParentController uut;
38 39
 
@@ -40,10 +41,11 @@ public class ParentControllerTest extends BaseTest {
40 41
     public void beforeEach() {
41 42
         super.beforeEach();
42 43
         activity = newActivity();
44
+        childRegistry = new ChildControllersRegistry();
43 45
         children = new ArrayList<>();
44 46
         Options initialOptions = new Options();
45 47
         initialOptions.topBar.title.text = new Text(INITIAL_TITLE);
46
-        uut = spy(new ParentController(activity, "uut", initialOptions) {
48
+        uut = spy(new ParentController(activity, childRegistry, "uut", initialOptions) {
47 49
 
48 50
             @NonNull
49 51
             @Override
@@ -81,8 +83,8 @@ public class ParentControllerTest extends BaseTest {
81 83
 
82 84
     @Test
83 85
     public void findControllerById_ChildById() {
84
-        SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
85
-        SimpleViewController child2 = new SimpleViewController(activity, "child2", new Options());
86
+        SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options());
87
+        SimpleViewController child2 = new SimpleViewController(activity, childRegistry, "child2", new Options());
86 88
         children.add(child1);
87 89
         children.add(child2);
88 90
 
@@ -93,8 +95,8 @@ public class ParentControllerTest extends BaseTest {
93 95
     @Test
94 96
     public void findControllerById_Recursive() {
95 97
         StackController stackController = createStack();
96
-        SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
97
-        SimpleViewController child2 = new SimpleViewController(activity, "child2", new Options());
98
+        SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options());
99
+        SimpleViewController child2 = new SimpleViewController(activity, childRegistry, "child2", new Options());
98 100
         stackController.push(child1, new CommandListenerAdapter());
99 101
         stackController.push(child2, new CommandListenerAdapter());
100 102
         children.add(stackController);
@@ -104,7 +106,7 @@ public class ParentControllerTest extends BaseTest {
104 106
 
105 107
     @Test
106 108
     public void destroy_DestroysChildren() {
107
-        ViewController child1 = spy(new SimpleViewController(activity, "child1", new Options()));
109
+        ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", new Options()));
108 110
         children.add(child1);
109 111
 
110 112
         verify(child1, times(0)).destroy();
@@ -115,7 +117,7 @@ public class ParentControllerTest extends BaseTest {
115 117
     @Test
116 118
     public void optionsAreClearedWhenChildIsAppeared() {
117 119
         StackController stackController = spy(createStack());
118
-        SimpleViewController child1 = new SimpleViewController(activity, "child1", new Options());
120
+        SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options());
119 121
         stackController.push(child1, new CommandListenerAdapter());
120 122
 
121 123
         child1.onViewAppeared();
@@ -126,7 +128,7 @@ public class ParentControllerTest extends BaseTest {
126 128
     public void mergeOptions_optionsAreMergedWhenChildAppears() {
127 129
         Options options = new Options();
128 130
         options.topBar.title.text = new Text("new title");
129
-        ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
131
+        ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", options));
130 132
         children.add(child1);
131 133
         uut.ensureViewIsCreated();
132 134
 
@@ -144,7 +146,7 @@ public class ParentControllerTest extends BaseTest {
144 146
     public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() {
145 147
         Options options = new Options();
146 148
         options.topBar.title.text = new Text("new title");
147
-        ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
149
+        ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", options));
148 150
         children.add(child1);
149 151
 
150 152
         uut.ensureViewIsCreated();

+ 5
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/SideMenuControllerTest.java View File

@@ -15,16 +15,18 @@ import static org.assertj.core.api.Java6Assertions.assertThat;
15 15
 public class SideMenuControllerTest extends BaseTest {
16 16
     private SideMenuController uut;
17 17
     private Activity activity;
18
+    private ChildControllersRegistry childRegistry;
18 19
 
19 20
     @Override
20 21
     public void beforeEach() {
21 22
         activity = newActivity();
22
-        uut = new SideMenuController(activity, "sideMenu", new Options());
23
+        childRegistry = new ChildControllersRegistry();
24
+        uut = new SideMenuController(activity, childRegistry, "sideMenu", new Options());
23 25
     }
24 26
 
25 27
     @Test
26 28
     public void mergeOptions_openLeftSideMenu() {
27
-        uut.setLeftController(new SimpleComponentViewController(activity, "left", new Options()));
29
+        uut.setLeftController(new SimpleComponentViewController(activity, childRegistry, "left", new Options()));
28 30
 
29 31
         Options options = new Options();
30 32
         options.sideMenuRootOptions.left.visible = new Bool(true);
@@ -35,7 +37,7 @@ public class SideMenuControllerTest extends BaseTest {
35 37
 
36 38
     @Test
37 39
     public void mergeOptions_openRightSideMenu() {
38
-        uut.setRightController(new SimpleComponentViewController(activity, "right", new Options()));
40
+        uut.setRightController(new SimpleComponentViewController(activity, childRegistry, "right", new Options()));
39 41
 
40 42
         Options options = new Options();
41 43
         options.sideMenuRootOptions.right.visible = new Bool(true);

+ 7
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java View File

@@ -41,6 +41,7 @@ import static org.mockito.Mockito.verify;
41 41
 public class StackControllerTest extends BaseTest {
42 42
 
43 43
     private Activity activity;
44
+    private ChildControllersRegistry childRegistry;
44 45
     private StackController uut;
45 46
     private ViewController child1;
46 47
     private ViewController child2;
@@ -54,11 +55,12 @@ public class StackControllerTest extends BaseTest {
54 55
         super.beforeEach();
55 56
         animator = Mockito.mock(NavigationAnimator.class);
56 57
         activity = newActivity();
58
+        childRegistry = new ChildControllersRegistry();
57 59
         uut = createStackController();
58
-        child1 = spy(new SimpleViewController(activity, "child1", new Options()));
59
-        child2 = spy(new SimpleViewController(activity, "child2", new Options()));
60
-        child3 = spy(new SimpleViewController(activity, "child3", new Options()));
61
-        child4 = spy(new SimpleViewController(activity, "child4", new Options()));
60
+        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", new Options()));
61
+        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", new Options()));
62
+        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", new Options()));
63
+        child4 = spy(new SimpleViewController(activity, childRegistry, "child4", new Options()));
62 64
     }
63 65
 
64 66
     @Test
@@ -728,6 +730,7 @@ public class StackControllerTest extends BaseTest {
728 730
             }
729 731
         });
730 732
         return new StackControllerBuilder(activity)
733
+                .setChildRegistry(childRegistry)
731 734
                 .setTopBarButtonCreator(new TopBarButtonCreatorMock())
732 735
                 .setTitleBarReactViewCreator(new TitleBarReactViewCreatorMock())
733 736
                 .setTopBarBackgroundViewController(new TopBarBackgroundViewController(activity, new TopBarBackgroundViewCreatorMock()))

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

@@ -48,19 +48,21 @@ public class TopTabsViewControllerTest extends BaseTest {
48 48
     private final Options options = new Options();
49 49
     private TopTabsViewPager topTabsLayout;
50 50
     private Activity activity;
51
+    private ChildControllersRegistry childRegistry;
51 52
 
52 53
     @Override
53 54
     public void beforeEach() {
54 55
         super.beforeEach();
55 56
 
56 57
         activity = newActivity();
58
+        childRegistry = new ChildControllersRegistry();
57 59
         tabOptions = createOptions();
58 60
         tabControllers = createTabsControllers(activity, tabOptions);
59 61
 
60 62
         topTabsLayout = spy(new TopTabsViewPager(activity, tabControllers, new TopTabsAdapter(tabControllers)));
61 63
         TopTabsLayoutCreator layoutCreator = Mockito.mock(TopTabsLayoutCreator.class);
62 64
         Mockito.when(layoutCreator.create()).thenReturn(topTabsLayout);
63
-        uut = spy(new TopTabsController(activity, "componentId", tabControllers, layoutCreator, options));
65
+        uut = spy(new TopTabsController(activity, childRegistry, "componentId", tabControllers, layoutCreator, options));
64 66
         tabControllers.forEach(viewController -> viewController.setParentController(uut));
65 67
 
66 68
         parentController = spy(createStackController("stackId"));
@@ -97,6 +99,7 @@ public class TopTabsViewControllerTest extends BaseTest {
97 99
         for (int i = 0; i < SIZE; i++) {
98 100
             ComponentViewController viewController = new ComponentViewController(
99 101
                     activity,
102
+                    childRegistry,
100 103
                     "idTab" + i,
101 104
                     "theComponentName",
102 105
                     new TestComponentViewCreator(),
@@ -233,6 +236,7 @@ public class TopTabsViewControllerTest extends BaseTest {
233 236
         StackController stackController = spy(createStackController("stack"));
234 237
         ComponentViewController first = new ComponentViewController(
235 238
                 activity,
239
+                childRegistry,
236 240
                 "firstScreen",
237 241
                 "comp1",
238 242
                 new TestComponentViewCreator(),
@@ -259,6 +263,7 @@ public class TopTabsViewControllerTest extends BaseTest {
259 263
     @Test
260 264
     public void onNavigationButtonPressInvokedOnCurrentTab() {
261 265
         uut.ensureViewIsCreated();
266
+        uut.onViewAppeared();
262 267
         uut.switchToTab(1);
263 268
         uut.sendOnNavigationButtonPressed("btn1");
264 269
         verify(tabControllers.get(1), times(1)).sendOnNavigationButtonPressed("btn1");

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

@@ -32,12 +32,14 @@ public class ViewControllerTest extends BaseTest {
32 32
 
33 33
     private ViewController uut;
34 34
     private Activity activity;
35
+    private ChildControllersRegistry childRegistry;
35 36
 
36 37
     @Override
37 38
     public void beforeEach() {
38 39
         super.beforeEach();
39 40
         activity = newActivity();
40
-        uut = new SimpleViewController(activity, "uut", new Options());
41
+        childRegistry = new ChildControllersRegistry();
42
+        uut = new SimpleViewController(activity, childRegistry, "uut", new Options());
41 43
     }
42 44
 
43 45
     @Test
@@ -161,7 +163,7 @@ public class ViewControllerTest extends BaseTest {
161 163
 
162 164
     @Test
163 165
     public void onDestroy_RemovesGlobalLayoutListener() throws Exception {
164
-        new SimpleViewController(activity, "ensureNotNull", new Options()).destroy();
166
+        new SimpleViewController(activity, childRegistry, "ensureNotNull", new Options()).destroy();
165 167
 
166 168
         ViewController spy = spy(uut);
167 169
         View view = spy.getView();

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

@@ -0,0 +1,39 @@
1
+package com.reactnativenavigation.viewcontrollers.child;
2
+
3
+import com.reactnativenavigation.BaseTest;
4
+import com.reactnativenavigation.mocks.SimpleViewController;
5
+import com.reactnativenavigation.parse.Options;
6
+import com.reactnativenavigation.viewcontrollers.ChildController;
7
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
8
+
9
+import org.junit.Test;
10
+
11
+import static org.mockito.Mockito.spy;
12
+import static org.mockito.Mockito.times;
13
+import static org.mockito.Mockito.verify;
14
+
15
+public class ChildControllerTest extends BaseTest {
16
+
17
+    private ChildController uut;
18
+    private ChildControllersRegistry childRegistry;
19
+
20
+    @Override
21
+    public void beforeEach() {
22
+        childRegistry = spy(new ChildControllersRegistry());
23
+        uut = new SimpleViewController(newActivity(), childRegistry, "childId", new Options());
24
+    }
25
+
26
+    @Test
27
+    public void onViewAppeared() {
28
+        uut.onViewAppeared();
29
+        verify(childRegistry, times(1)).onViewAppeared(uut);
30
+    }
31
+
32
+    @Test
33
+    public void onViewDisappear() {
34
+        uut.onViewAppeared();
35
+
36
+        uut.onViewDisappear();
37
+        verify(childRegistry, times(1)).onViewDisappear(uut);
38
+    }
39
+}

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

@@ -0,0 +1,47 @@
1
+package com.reactnativenavigation.viewcontrollers.child;
2
+
3
+import android.app.Activity;
4
+
5
+import com.reactnativenavigation.BaseTest;
6
+import com.reactnativenavigation.mocks.SimpleViewController;
7
+import com.reactnativenavigation.parse.Options;
8
+import com.reactnativenavigation.viewcontrollers.ChildController;
9
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
10
+
11
+import org.junit.Test;
12
+
13
+import static org.assertj.core.api.Java6Assertions.assertThat;
14
+import static org.mockito.Mockito.spy;
15
+import static org.mockito.Mockito.times;
16
+import static org.mockito.Mockito.verify;
17
+
18
+public class ChildControllersRegistryTest extends BaseTest {
19
+    private ChildControllersRegistry uut;
20
+    private ChildController child1;
21
+    private ChildController child2;
22
+
23
+    @Override
24
+    public void beforeEach() {
25
+        Activity activity = newActivity();
26
+        uut = new ChildControllersRegistry();
27
+        child1 = spy(new SimpleViewController(activity, uut, "child1", new Options()));
28
+        child2 = spy(new SimpleViewController(activity, uut, "child2", new Options()));
29
+    }
30
+
31
+    @Test
32
+    public void onViewAppeared() {
33
+        child1.onViewAppeared();
34
+        verify(child1, times(0)).onViewBroughtToFront();
35
+        assertThat(uut.size()).isOne();
36
+    }
37
+
38
+    @Test
39
+    public void onViewDisappear() {
40
+        child1.onViewAppeared();
41
+        child2.onViewAppeared();
42
+        assertThat(uut.size()).isEqualTo(2);
43
+        child2.onViewDisappear();
44
+        verify(child1, times(1)).onViewBroughtToFront();
45
+        assertThat(uut.size()).isOne();
46
+    }
47
+}

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

@@ -11,6 +11,8 @@ import com.reactnativenavigation.parse.ModalPresentationStyle;
11 11
 import com.reactnativenavigation.parse.Options;
12 12
 import com.reactnativenavigation.utils.CommandListener;
13 13
 import com.reactnativenavigation.utils.CommandListenerAdapter;
14
+import com.reactnativenavigation.viewcontrollers.ChildController;
15
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
14 16
 import com.reactnativenavigation.viewcontrollers.ParentController;
15 17
 import com.reactnativenavigation.viewcontrollers.ViewController;
16 18
 
@@ -29,16 +31,18 @@ public class ModalPresenterTest extends BaseTest {
29 31
     private static final String MODAL_ID_1 = "modalId1";
30 32
     private static final String MODAL_ID_2 = "modalId2";
31 33
 
32
-    private ViewController modal1;
33
-    private ViewController modal2;
34
+    private ChildController modal1;
35
+    private ChildController modal2;
34 36
     private ModalPresenter uut;
35 37
     private FrameLayout contentLayout;
36 38
     private ModalAnimator animator;
37 39
     private ViewController rootController;
40
+    private ChildControllersRegistry childRegistry;
38 41
 
39 42
     @Override
40 43
     public void beforeEach() {
41 44
         Activity activity = newActivity();
45
+        childRegistry = new ChildControllersRegistry();
42 46
 
43 47
         ViewGroup root = new FrameLayout(activity);
44 48
         rootController = Mockito.mock(ParentController.class);
@@ -50,8 +54,8 @@ public class ModalPresenterTest extends BaseTest {
50 54
         animator = spy(new ModalAnimator(activity));
51 55
         uut = new ModalPresenter(animator);
52 56
         uut.setContentLayout(contentLayout);
53
-        modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
54
-        modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
57
+        modal1 = spy(new SimpleViewController(activity, childRegistry, MODAL_ID_1, new Options()));
58
+        modal2 = spy(new SimpleViewController(activity, childRegistry, MODAL_ID_2, new Options()));
55 59
     }
56 60
 
57 61
     @Test
@@ -130,6 +134,17 @@ public class ModalPresenterTest extends BaseTest {
130 134
         verify(spy, times(1)).addView(modal2.getView(), 0);
131 135
     }
132 136
 
137
+    @Test
138
+    public void dismissModal_onViewBroughtToFront_invokedOnPreviousView() {
139
+        disableShowModalAnimation(modal1, modal2);
140
+        disableDismissModalAnimation(modal1, modal2);
141
+
142
+        uut.showModal(modal1, rootController, new CommandListenerAdapter());
143
+        uut.showModal(modal2, rootController, new CommandListenerAdapter());
144
+        uut.dismissModal(modal2, modal1, new CommandListenerAdapter());
145
+        verify(modal1, times(1)).onViewBroughtToFront();
146
+    }
147
+
133 148
     @Test
134 149
     public void dismissModal_noAnimation() {
135 150
         disableShowModalAnimation(modal1);

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

@@ -10,6 +10,7 @@ import com.reactnativenavigation.mocks.SimpleViewController;
10 10
 import com.reactnativenavigation.parse.Options;
11 11
 import com.reactnativenavigation.utils.CommandListener;
12 12
 import com.reactnativenavigation.utils.CommandListenerAdapter;
13
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
13 14
 import com.reactnativenavigation.viewcontrollers.ParentController;
14 15
 import com.reactnativenavigation.viewcontrollers.ViewController;
15 16
 
@@ -39,6 +40,7 @@ public class ModalStackTest extends BaseTest {
39 40
     private ViewController modal2;
40 41
     private ViewController modal3;
41 42
     private Activity activity;
43
+    private ChildControllersRegistry childRegistry;
42 44
     private ModalPresenter presenter;
43 45
     private ModalAnimator animator;
44 46
     private ViewController rootController;
@@ -46,6 +48,7 @@ public class ModalStackTest extends BaseTest {
46 48
     @Override
47 49
     public void beforeEach() {
48 50
         activity = newActivity();
51
+        childRegistry = new ChildControllersRegistry();
49 52
 
50 53
         ViewGroup root = new FrameLayout(activity);
51 54
         rootController = Mockito.mock(ParentController.class);
@@ -58,9 +61,9 @@ public class ModalStackTest extends BaseTest {
58 61
         presenter = spy(new ModalPresenter(animator));
59 62
         uut = new ModalStack(presenter);
60 63
         uut.setContentLayout(activityContentView);
61
-        modal1 = spy(new SimpleViewController(activity, MODAL_ID_1, new Options()));
62
-        modal2 = spy(new SimpleViewController(activity, MODAL_ID_2, new Options()));
63
-        modal3 = spy(new SimpleViewController(activity, MODAL_ID_3, new Options()));
64
+        modal1 = spy(new SimpleViewController(activity, childRegistry, MODAL_ID_1, new Options()));
65
+        modal2 = spy(new SimpleViewController(activity, childRegistry, MODAL_ID_2, new Options()));
66
+        modal3 = spy(new SimpleViewController(activity, childRegistry, MODAL_ID_3, new Options()));
64 67
     }
65 68
 
66 69
     @Test
@@ -224,7 +227,7 @@ public class ModalStackTest extends BaseTest {
224 227
 
225 228
     @Test
226 229
     public void handleBack_ViewControllerTakesPrecedenceOverModal() {
227
-        ViewController backHandlingModal = spy(new SimpleViewController(activity, "stack", new Options()){
230
+        ViewController backHandlingModal = spy(new SimpleViewController(activity, childRegistry, "stack", new Options()){
228 231
             @Override
229 232
             public boolean handleBack(CommandListener listener) {
230 233
                 return true;

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

@@ -9,6 +9,7 @@ import com.reactnativenavigation.parse.Options;
9 9
 import com.reactnativenavigation.presentation.OverlayManager;
10 10
 import com.reactnativenavigation.utils.CommandListener;
11 11
 import com.reactnativenavigation.utils.CommandListenerAdapter;
12
+import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
12 13
 
13 14
 import org.junit.Test;
14 15
 
@@ -20,8 +21,11 @@ import static org.mockito.Mockito.verify;
20 21
 
21 22
 public class OverlayManagerTest extends BaseTest {
22 23
     private static final String OVERLAY_ID_1 = "OVERLAY_1";
24
+    private static final String OVERLAY_ID_2 = "OVERLAY_2";
25
+
23 26
     private OverlayManager uut;
24 27
     private SimpleViewController overlay1;
28
+    private SimpleViewController overlay2;
25 29
     private FrameLayout root;
26 30
 
27 31
     @Override
@@ -31,7 +35,9 @@ public class OverlayManagerTest extends BaseTest {
31 35
         root.layout(0, 0, 1000, 1000);
32 36
         activity.setContentView(root);
33 37
 
34
-        overlay1 = spy(new SimpleViewController(activity, OVERLAY_ID_1, new Options()));
38
+        ChildControllersRegistry childRegistry = new ChildControllersRegistry();
39
+        overlay1 = spy(new SimpleViewController(activity, childRegistry, OVERLAY_ID_1, new Options()));
40
+        overlay2 = spy(new SimpleViewController(activity, childRegistry, OVERLAY_ID_2, new Options()));
35 41
         uut = new OverlayManager();
36 42
     }
37 43
 
@@ -60,4 +66,14 @@ public class OverlayManagerTest extends BaseTest {
60 66
         uut.dismiss(overlay1.getId(), listener);
61 67
         verify(listener, times(1)).onError(any());
62 68
     }
69
+
70
+    @Test
71
+    public void dismiss_onViewReturnedToFront() {
72
+        uut.show(root, overlay1, new CommandListenerAdapter());
73
+        uut.show(root, overlay2, new CommandListenerAdapter());
74
+        verify(overlay1, times(0)).onViewBroughtToFront();
75
+
76
+        uut.dismiss(OVERLAY_ID_2, new CommandListenerAdapter());
77
+        verify(overlay1, times(1)).onViewBroughtToFront();
78
+    }
63 79
 }