Browse Source

Support tabs without icons on Android (#5978)

This commit introduces parity with iOS which allows the user to show tabs without icons. While there's no real production use case for this feature, it's helpful when getting started with a new project.
Guy Carmeli 5 years ago
parent
commit
ef58a6cdeb
No account linked to committer's email address

+ 1
- 1
lib/android/app/build.gradle View File

161
     implementation 'androidx.annotation:annotation:1.1.0'
161
     implementation 'androidx.annotation:annotation:1.1.0'
162
     implementation 'com.google.android.material:material:1.2.0-alpha03'
162
     implementation 'com.google.android.material:material:1.2.0-alpha03'
163
 
163
 
164
-    implementation 'com.github.wix-playground:ahbottomnavigation:3.1.2'
164
+    implementation 'com.github.wix-playground:ahbottomnavigation:3.2.0'
165
     implementation 'com.github.wix-playground:reflow-animator:1.0.6'
165
     implementation 'com.github.wix-playground:reflow-animator:1.0.6'
166
     implementation 'com.github.clans:fab:1.6.4'
166
     implementation 'com.github.clans:fab:1.6.4'
167
 
167
 

+ 11
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java View File

13
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
13
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
14
 import com.reactnativenavigation.views.BottomTabs;
14
 import com.reactnativenavigation.views.BottomTabs;
15
 
15
 
16
+import org.jetbrains.annotations.NotNull;
17
+
16
 import java.util.List;
18
 import java.util.List;
17
 
19
 
18
 import androidx.annotation.IntRange;
20
 import androidx.annotation.IntRange;
118
 
120
 
119
         bottomTabs.setLayoutDirection(options.layout.direction);
121
         bottomTabs.setLayoutDirection(options.layout.direction);
120
         bottomTabs.setPreferLargeIcons(options.bottomTabsOptions.preferLargeIcons.get(false));
122
         bottomTabs.setPreferLargeIcons(options.bottomTabsOptions.preferLargeIcons.get(false));
121
-        bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(TitleState.SHOW_WHEN_ACTIVE));
123
+        bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(getDefaultTitleState()));
122
         bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE));
124
         bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE));
123
         if (bottomTabsOptions.currentTabIndex.hasValue()) {
125
         if (bottomTabsOptions.currentTabIndex.hasValue()) {
124
             int tabIndex = bottomTabsOptions.currentTabIndex.get();
126
             int tabIndex = bottomTabsOptions.currentTabIndex.get();
148
         }
150
         }
149
     }
151
     }
150
 
152
 
153
+    @NotNull
154
+    private TitleState getDefaultTitleState() {
155
+        for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
156
+            if (bottomTabs.getItem(i).hasIcon()) return TitleState.SHOW_WHEN_ACTIVE;
157
+        }
158
+        return TitleState.ALWAYS_SHOW;
159
+    }
160
+
151
     public void applyBottomInset(int bottomInset) {
161
     public void applyBottomInset(int bottomInset) {
152
         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) bottomTabs.getLayoutParams();
162
         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) bottomTabs.getLayoutParams();
153
         lp.bottomMargin = bottomInset;
163
         lp.bottomMargin = bottomInset;

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

164
             BottomTabOptions options = tab.resolveCurrentOptions().bottomTabOptions;
164
             BottomTabOptions options = tab.resolveCurrentOptions().bottomTabOptions;
165
             return new AHBottomNavigationItem(
165
             return new AHBottomNavigationItem(
166
                     options.text.get(""),
166
                     options.text.get(""),
167
-                    imageLoader.loadIcon(getActivity(), options.icon.get()),
167
+                    imageLoader.loadIcon(getActivity(), options.icon.get(null)),
168
                     imageLoader.loadIcon(getActivity(), options.selectedIcon.get(null)),
168
                     imageLoader.loadIcon(getActivity(), options.selectedIcon.get(null)),
169
                     options.testId.get("")
169
                     options.testId.get("")
170
             );
170
             );

+ 50
- 24
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java View File

6
 import android.view.View;
6
 import android.view.View;
7
 import android.view.ViewGroup.MarginLayoutParams;
7
 import android.view.ViewGroup.MarginLayoutParams;
8
 
8
 
9
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
9
 import com.reactnativenavigation.BaseTest;
10
 import com.reactnativenavigation.BaseTest;
10
 import com.reactnativenavigation.TestUtils;
11
 import com.reactnativenavigation.TestUtils;
11
 import com.reactnativenavigation.mocks.ImageLoaderMock;
12
 import com.reactnativenavigation.mocks.ImageLoaderMock;
13
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.parse.params.Colour;
16
 import com.reactnativenavigation.parse.params.Colour;
17
+import com.reactnativenavigation.parse.params.NullText;
16
 import com.reactnativenavigation.parse.params.Number;
18
 import com.reactnativenavigation.parse.params.Number;
17
 import com.reactnativenavigation.parse.params.Text;
19
 import com.reactnativenavigation.parse.params.Text;
18
 import com.reactnativenavigation.presentation.BottomTabPresenter;
20
 import com.reactnativenavigation.presentation.BottomTabPresenter;
43
 import edu.emory.mathcs.backport.java.util.Collections;
45
 import edu.emory.mathcs.backport.java.util.Collections;
44
 
46
 
45
 import static com.reactnativenavigation.TestUtils.hideBackButton;
47
 import static com.reactnativenavigation.TestUtils.hideBackButton;
48
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
46
 import static org.assertj.core.api.Java6Assertions.assertThat;
49
 import static org.assertj.core.api.Java6Assertions.assertThat;
47
 import static org.mockito.ArgumentMatchers.any;
50
 import static org.mockito.ArgumentMatchers.any;
48
 import static org.mockito.ArgumentMatchers.eq;
51
 import static org.mockito.ArgumentMatchers.eq;
74
     @Override
77
     @Override
75
     public void beforeEach() {
78
     public void beforeEach() {
76
         activity = newActivity();
79
         activity = newActivity();
77
-        bottomTabs = spy(new BottomTabs(activity) {
78
-            @Override
79
-            public void superCreateItems() {
80
-
81
-            }
82
-        });
83
         childRegistry = new ChildControllersRegistry();
80
         childRegistry = new ChildControllersRegistry();
84
         eventEmitter = Mockito.mock(EventEmitter.class);
81
         eventEmitter = Mockito.mock(EventEmitter.class);
85
-
86
-        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
87
-        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
88
-        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
89
-        child4 = spy(createStack());
90
-        child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
91
-        when(child5.handleBack(any())).thenReturn(true);
92
-        tabs = createTabs();
93
-        presenter = spy(new BottomTabsPresenter(tabs, new Options()));
94
-        bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options()));
95
-        tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter));
96
-        uut = createBottomTabs();
97
-
98
-        uut.setParentController(Mockito.mock(ParentController.class));
99
-        CoordinatorLayout parent = new CoordinatorLayout(activity);
100
-        parent.addView(uut.getView());
101
-        activity.setContentView(parent);
102
-
82
+        prepareViewsForTests();
103
         StatusBarUtils.saveStatusBarHeight(63);
83
         StatusBarUtils.saveStatusBarHeight(63);
104
     }
84
     }
105
 
85
 
110
         assertThat(((CoordinatorLayout.LayoutParams) uut.getBottomTabs().getLayoutParams()).gravity).isEqualTo(Gravity.BOTTOM);
90
         assertThat(((CoordinatorLayout.LayoutParams) uut.getBottomTabs().getLayoutParams()).gravity).isEqualTo(Gravity.BOTTOM);
111
     }
91
     }
112
 
92
 
93
+    @Test
94
+    public void createView_tabsWithoutIconsAreAccepted() {
95
+        tabOptions.bottomTabOptions.icon = new NullText();
96
+        prepareViewsForTests();
97
+        assertThat(uut.getBottomTabs().getItemsCount()).isEqualTo(tabs.size());
98
+    }
99
+
100
+    @Test
101
+    public void createView_showTitlesWhenAllTabsDontHaveIcons() {
102
+        tabOptions.bottomTabOptions.icon = new NullText();
103
+        assertThat(tabOptions.bottomTabsOptions.titleDisplayMode.hasValue()).isFalse();
104
+        prepareViewsForTests();
105
+        presenter.applyOptions(Options.EMPTY);
106
+        assertThat(bottomTabs.getTitleState()).isEqualTo(AHBottomNavigation.TitleState.ALWAYS_SHOW);
107
+    }
108
+
113
     @Test(expected = RuntimeException.class)
109
     @Test(expected = RuntimeException.class)
114
     public void setTabs_ThrowWhenMoreThan5() {
110
     public void setTabs_ThrowWhenMoreThan5() {
115
         tabs.add(new SimpleViewController(activity, childRegistry, "6", tabOptions));
111
         tabs.add(new SimpleViewController(activity, childRegistry, "6", tabOptions));
393
         verify(tabsAttacher).destroy();
389
         verify(tabsAttacher).destroy();
394
     }
390
     }
395
 
391
 
392
+    private void prepareViewsForTests() {
393
+        perform(uut, ViewController::destroy);
394
+        bottomTabs = spy(new BottomTabs(activity) {
395
+            @Override
396
+            public void superCreateItems() {
397
+
398
+            }
399
+        });
400
+        createChildren();
401
+        tabs = createTabs();
402
+        presenter = spy(new BottomTabsPresenter(tabs, new Options()));
403
+        bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options()));
404
+        tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter));
405
+        uut = createBottomTabs();
406
+
407
+        uut.setParentController(Mockito.mock(ParentController.class));
408
+        CoordinatorLayout parent = new CoordinatorLayout(activity);
409
+        parent.addView(uut.getView());
410
+        activity.setContentView(parent);
411
+    }
412
+
413
+    private void createChildren() {
414
+        child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions));
415
+        child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions));
416
+        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions));
417
+        child4 = spy(createStack());
418
+        child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions));
419
+        when(child5.handleBack(any())).thenReturn(true);
420
+    }
421
+
396
     @NonNull
422
     @NonNull
397
     private List<ViewController> createTabs() {
423
     private List<ViewController> createTabs() {
398
         return Arrays.asList(child1, child2, child3, child4, child5);
424
         return Arrays.asList(child1, child2, child3, child4, child5);