Browse Source

Bottom tabs visible (#2779)

* Rename BottomTabOptionsPresenter

* Set currentTabIndex in BottomTabsPresenter

* implement BottomTabs visible
Guy Carmeli 6 years ago
parent
commit
5fec0182ec
No account linked to committer's email address

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

6
 import com.reactnativenavigation.utils.ImageLoader;
6
 import com.reactnativenavigation.utils.ImageLoader;
7
 import com.reactnativenavigation.utils.NoOpPromise;
7
 import com.reactnativenavigation.utils.NoOpPromise;
8
 import com.reactnativenavigation.utils.TypefaceLoader;
8
 import com.reactnativenavigation.utils.TypefaceLoader;
9
-import com.reactnativenavigation.viewcontrollers.BottomTabsController;
9
+import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController;
10
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
10
 import com.reactnativenavigation.viewcontrollers.ComponentViewController;
11
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
11
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
12
 import com.reactnativenavigation.viewcontrollers.StackController;
12
 import com.reactnativenavigation.viewcontrollers.StackController;

lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabOptionsPresenter.java → lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsOptionsPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
-import android.support.annotation.IntRange;
4
-
5
 import com.reactnativenavigation.parse.BottomTabOptions;
3
 import com.reactnativenavigation.parse.BottomTabOptions;
6
 import com.reactnativenavigation.parse.BottomTabsOptions;
4
 import com.reactnativenavigation.parse.BottomTabsOptions;
7
 import com.reactnativenavigation.parse.Options;
5
 import com.reactnativenavigation.parse.Options;
6
+import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
8
 import com.reactnativenavigation.views.BottomTabs;
7
 import com.reactnativenavigation.views.BottomTabs;
9
 
8
 
10
-public class BottomTabOptionsPresenter {
9
+public class BottomTabsOptionsPresenter {
11
     private BottomTabs bottomTabs;
10
     private BottomTabs bottomTabs;
11
+    private BottomTabFinder bottomTabFinder;
12
 
12
 
13
-    public BottomTabOptionsPresenter(BottomTabs bottomTabs) {
13
+    public BottomTabsOptionsPresenter(BottomTabs bottomTabs, BottomTabFinder bottomTabFinder) {
14
         this.bottomTabs = bottomTabs;
14
         this.bottomTabs = bottomTabs;
15
+        this.bottomTabFinder = bottomTabFinder;
15
     }
16
     }
16
 
17
 
17
     public void present(Options options) {
18
     public void present(Options options) {
18
         applyBottomTabsOptions(options.bottomTabsOptions);
19
         applyBottomTabsOptions(options.bottomTabsOptions);
19
     }
20
     }
20
 
21
 
21
-    public void present(Options options, @IntRange(from = 0) int bottomTabIndex) {
22
-        applyBottomTabOptions(options.bottomTabOptions, bottomTabIndex);
22
+    public void present(Options options, int tabIndex) {
23
+        applyBottomTabOptions(options.bottomTabOptions, tabIndex);
23
     }
24
     }
24
 
25
 
25
-    private void applyBottomTabOptions(BottomTabOptions options, int bottomTabIndex) {
26
+    private void applyBottomTabOptions(BottomTabOptions options, int tabIndex) {
26
         if (options.badge.hasValue()) {
27
         if (options.badge.hasValue()) {
27
-            bottomTabs.setBadge(bottomTabIndex, options.badge);
28
+            bottomTabs.setBadge(tabIndex, options.badge);
28
         }
29
         }
29
     }
30
     }
30
 
31
 
44
         if (options.tabColor.hasValue()) {
45
         if (options.tabColor.hasValue()) {
45
             bottomTabs.setInactiveColor(options.tabColor.get());
46
             bottomTabs.setInactiveColor(options.tabColor.get());
46
         }
47
         }
48
+        if (options.currentTabId.hasValue()) {
49
+            int tabIndex = bottomTabFinder.findByControllerId(options.currentTabId.get());
50
+            if (tabIndex >= 0) bottomTabs.setCurrentItem(tabIndex);
51
+        }
52
+        if (options.visible.isTrueOrUndefined()) {
53
+            bottomTabs.restoreBottomNavigation(options.animate.isTrueOrUndefined());
54
+        }
55
+        if (options.visible.isFalse()) {
56
+            bottomTabs.hideBottomNavigation(options.animate.isTrueOrUndefined());
57
+        }
47
     }
58
     }
48
 }
59
 }

+ 36
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabFinder.java View File

1
+package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
+
3
+import android.support.annotation.IntRange;
4
+
5
+import com.reactnativenavigation.viewcontrollers.ViewController;
6
+import com.reactnativenavigation.views.ReactComponent;
7
+
8
+import java.util.List;
9
+
10
+public class BottomTabFinder {
11
+    private List<ViewController> tabs;
12
+
13
+    @IntRange(from = -1)
14
+    public int findByComponent(ReactComponent component) {
15
+        for (int i = 0; i < tabs.size(); i++) {
16
+            if (tabs.get(i).containsComponent(component)) {
17
+                return i;
18
+            }
19
+        }
20
+        return -1;
21
+    }
22
+
23
+    @IntRange(from = -1)
24
+    public int findByControllerId(String id) {
25
+        for (int i = 0; i < tabs.size(); i++) {
26
+            if (tabs.get(i).findControllerById(id) != null) {
27
+                return i;
28
+            }
29
+        }
30
+        return -1;
31
+    }
32
+
33
+    void setTabs(List<ViewController> tabs) {
34
+        this.tabs = tabs;
35
+    }
36
+}

lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java → lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java View File

1
-package com.reactnativenavigation.viewcontrollers;
1
+package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.graphics.drawable.Drawable;
4
 import android.graphics.drawable.Drawable;
5
-import android.support.annotation.IntRange;
6
 import android.support.annotation.NonNull;
5
 import android.support.annotation.NonNull;
7
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
8
 import android.widget.RelativeLayout;
7
 import android.widget.RelativeLayout;
11
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
10
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
12
 import com.reactnativenavigation.parse.BottomTabOptions;
11
 import com.reactnativenavigation.parse.BottomTabOptions;
13
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.Options;
14
-import com.reactnativenavigation.parse.params.Text;
15
-import com.reactnativenavigation.presentation.BottomTabOptionsPresenter;
13
+import com.reactnativenavigation.presentation.BottomTabsOptionsPresenter;
16
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
14
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
17
 import com.reactnativenavigation.utils.ImageLoader;
15
 import com.reactnativenavigation.utils.ImageLoader;
16
+import com.reactnativenavigation.viewcontrollers.ParentController;
17
+import com.reactnativenavigation.viewcontrollers.ViewController;
18
 import com.reactnativenavigation.views.BottomTabs;
18
 import com.reactnativenavigation.views.BottomTabs;
19
 import com.reactnativenavigation.views.ReactComponent;
19
 import com.reactnativenavigation.views.ReactComponent;
20
 
20
 
31
 	private BottomTabs bottomTabs;
31
 	private BottomTabs bottomTabs;
32
 	private List<ViewController> tabs = new ArrayList<>();
32
 	private List<ViewController> tabs = new ArrayList<>();
33
     private ImageLoader imageLoader;
33
     private ImageLoader imageLoader;
34
+    private BottomTabFinder bottomTabFinder = new BottomTabFinder();
34
 
35
 
35
     public BottomTabsController(final Activity activity, ImageLoader imageLoader, final String id, Options initialOptions) {
36
     public BottomTabsController(final Activity activity, ImageLoader imageLoader, final String id, Options initialOptions) {
36
 		super(activity, id, initialOptions);
37
 		super(activity, id, initialOptions);
52
     @Override
53
     @Override
53
     public void applyOptions(Options options) {
54
     public void applyOptions(Options options) {
54
         super.applyOptions(options);
55
         super.applyOptions(options);
55
-        new BottomTabOptionsPresenter(bottomTabs).present(options);
56
+        new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(options);
56
     }
57
     }
57
 
58
 
58
     @Override
59
     @Override
59
     public void applyOptions(Options options, ReactComponent childComponent) {
60
     public void applyOptions(Options options, ReactComponent childComponent) {
60
         super.applyOptions(options, childComponent);
61
         super.applyOptions(options, childComponent);
61
-        int tabIndex = findTabContainingComponent(childComponent);
62
-        if (tabIndex >= 0) new BottomTabOptionsPresenter(bottomTabs).present(options, tabIndex);
62
+        int tabIndex = bottomTabFinder.findByComponent(childComponent);
63
+        if (tabIndex >= 0) new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(this.options, tabIndex);
63
         applyOnParentController(parentController ->
64
         applyOnParentController(parentController ->
64
                 ((ParentController) parentController).applyOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), childComponent)
65
                 ((ParentController) parentController).applyOptions(this.options.copy().clearBottomTabsOptions().clearBottomTabOptions(), childComponent)
65
         );
66
         );
91
 			throw new RuntimeException("Too many tabs!");
92
 			throw new RuntimeException("Too many tabs!");
92
 		}
93
 		}
93
 		this.tabs = tabs;
94
 		this.tabs = tabs;
94
-		getView();
95
+        bottomTabFinder.setTabs(tabs);
96
+        getView();
95
 		for (int i = 0; i < tabs.size(); i++) {
97
 		for (int i = 0; i < tabs.size(); i++) {
96
 		    tabs.get(i).setParentController(this);
98
 		    tabs.get(i).setParentController(this);
97
 			createTab(i, tabs.get(i).options.bottomTabOptions);
99
 			createTab(i, tabs.get(i).options.bottomTabOptions);
121
         params.addRule(ABOVE, bottomTabs.getId());
123
         params.addRule(ABOVE, bottomTabs.getId());
122
 	}
124
 	}
123
 
125
 
124
-    int getSelectedIndex() {
126
+    public int getSelectedIndex() {
125
 		return bottomTabs.getCurrentItem();
127
 		return bottomTabs.getCurrentItem();
126
 	}
128
 	}
127
 
129
 
134
 	@Override
136
 	@Override
135
 	public void mergeOptions(Options options) {
137
 	public void mergeOptions(Options options) {
136
         this.options = this.options.mergeWith(options);
138
         this.options = this.options.mergeWith(options);
137
-        if (options.bottomTabsOptions.currentTabIndex.hasValue()) {
138
-            selectTabAtIndex(options.bottomTabsOptions.currentTabIndex.get());
139
-        }
140
-        if (options.bottomTabsOptions.currentTabId.hasValue()) {
141
-            Text id = options.bottomTabsOptions.currentTabId;
142
-            for (ViewController controller : tabs) {
143
-                if (controller.getId().equals(id.get())) {
144
-                    selectTabAtIndex(tabs.indexOf(controller));
145
-                }
146
-                if (controller instanceof StackController) {
147
-                    if (hasControlWithId((StackController) controller, id.get())) {
148
-                        selectTabAtIndex(tabs.indexOf(controller));
149
-                    }
150
-                }
151
-            }
152
-        }
139
+        new BottomTabsOptionsPresenter(bottomTabs, bottomTabFinder).present(this.options);
153
     }
140
     }
154
 
141
 
155
-    void selectTabAtIndex(final int newIndex) {
142
+    public void selectTabAtIndex(final int newIndex) {
156
         getView().removeView(getCurrentView());
143
         getView().removeView(getCurrentView());
157
         bottomTabs.setCurrentItem(newIndex, false);
144
         bottomTabs.setCurrentItem(newIndex, false);
158
         getView().addView(getCurrentView());
145
         getView().addView(getCurrentView());
162
     private ViewGroup getCurrentView() {
149
     private ViewGroup getCurrentView() {
163
         return tabs.get(bottomTabs.getCurrentItem()).getView();
150
         return tabs.get(bottomTabs.getCurrentItem()).getView();
164
     }
151
     }
165
-
166
-    private boolean hasControlWithId(StackController controller, String id) {
167
-		for (ViewController child : controller.getChildControllers()) {
168
-			if (id.equals(child.getId())) {
169
-				return true;
170
-			}
171
-			if (child instanceof StackController) {
172
-				return hasControlWithId((StackController) child, id);
173
-			}
174
-		}
175
-		return false;
176
-	}
177
-
178
-	@IntRange(from = -1)
179
-    private int findTabContainingComponent(ReactComponent component) {
180
-        for (int i = 0; i < tabs.size(); i++) {
181
-            if (tabs.get(i).containsComponent(component)) {
182
-                return i;
183
-            }
184
-        }
185
-        return -1;
186
-    }
187
 }
152
 }

+ 6
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java View File

2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
+import android.support.annotation.IntRange;
5
 
6
 
6
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
7
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
7
 import com.reactnativenavigation.parse.params.Text;
8
 import com.reactnativenavigation.parse.params.Text;
24
     public void setBadge(int bottomTabIndex, Text badge) {
25
     public void setBadge(int bottomTabIndex, Text badge) {
25
         setNotification(badge.get(), bottomTabIndex);
26
         setNotification(badge.get(), bottomTabIndex);
26
     }
27
     }
28
+
29
+    @Override
30
+    public void setCurrentItem(@IntRange(from = 0) int position) {
31
+        super.setCurrentItem(position);
32
+    }
27
 }
33
 }

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

10
 import com.reactnativenavigation.mocks.SimpleViewController;
10
 import com.reactnativenavigation.mocks.SimpleViewController;
11
 import com.reactnativenavigation.parse.params.Color;
11
 import com.reactnativenavigation.parse.params.Color;
12
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.Options;
13
+import com.reactnativenavigation.parse.params.Number;
13
 import com.reactnativenavigation.utils.ImageLoader;
14
 import com.reactnativenavigation.utils.ImageLoader;
14
 import com.reactnativenavigation.utils.OptionHelper;
15
 import com.reactnativenavigation.utils.OptionHelper;
16
+import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController;
15
 import com.reactnativenavigation.views.BottomTabs;
17
 import com.reactnativenavigation.views.BottomTabs;
16
 import com.reactnativenavigation.views.ReactComponent;
18
 import com.reactnativenavigation.views.ReactComponent;
17
 
19
 
44
     public void beforeEach() {
46
     public void beforeEach() {
45
         super.beforeEach();
47
         super.beforeEach();
46
         activity = newActivity();
48
         activity = newActivity();
47
-        uut = new BottomTabsController(activity, imageLoaderMock, "uut", new Options());
49
+        uut = spy(new BottomTabsController(activity, imageLoaderMock, "uut", new Options()));
48
         child1 = spy(new SimpleViewController(activity, "child1", tabOptions));
50
         child1 = spy(new SimpleViewController(activity, "child1", tabOptions));
49
         child2 = spy(new SimpleViewController(activity, "child2", tabOptions));
51
         child2 = spy(new SimpleViewController(activity, "child2", tabOptions));
50
         child3 = spy(new SimpleViewController(activity, "child3", tabOptions));
52
         child3 = spy(new SimpleViewController(activity, "child3", tabOptions));
140
         assertThat(optionsCaptor.getValue().bottomTabsOptions.tabColor.hasValue()).isFalse();
142
         assertThat(optionsCaptor.getValue().bottomTabsOptions.tabColor.hasValue()).isFalse();
141
     }
143
     }
142
 
144
 
145
+    @Test
146
+    public void mergeOptions_currentTabIndex() throws Exception {
147
+        List<ViewController> tabs = createTabs();
148
+        uut.setTabs(tabs);
149
+        uut.ensureViewIsCreated();
150
+
151
+        Options options = new Options();
152
+        options.bottomTabsOptions.currentTabIndex = new Number(1);
153
+        uut.mergeOptions(options);
154
+        verify(uut, times(1)).selectTabAtIndex(1);
155
+    }
156
+
143
     @Test
157
     @Test
144
     public void buttonPressInvokedOnCurrentTab() throws Exception {
158
     public void buttonPressInvokedOnCurrentTab() throws Exception {
145
         uut.setTabs(createTabs());
159
         uut.setTabs(createTabs());

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

13
 import com.reactnativenavigation.utils.CompatUtils;
13
 import com.reactnativenavigation.utils.CompatUtils;
14
 import com.reactnativenavigation.utils.ImageLoader;
14
 import com.reactnativenavigation.utils.ImageLoader;
15
 import com.reactnativenavigation.utils.OptionHelper;
15
 import com.reactnativenavigation.utils.OptionHelper;
16
+import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController;
16
 
17
 
17
 import org.junit.Test;
18
 import org.junit.Test;
18
 
19