From ef58a6cdeb1c4ea90ff528af50d6d2dc572f9f28 Mon Sep 17 00:00:00 2001 From: Guy Carmeli Date: Tue, 3 Mar 2020 14:11:54 +0200 Subject: [PATCH] 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. --- lib/android/app/build.gradle | 2 +- .../presentation/BottomTabsPresenter.java | 12 ++- .../bottomtabs/BottomTabsController.java | 2 +- .../bottomtabs/BottomTabsControllerTest.java | 74 +++++++++++++------ 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index cb32f1a8026..0ec25726328 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -161,7 +161,7 @@ dependencies { implementation 'androidx.annotation:annotation:1.1.0' implementation 'com.google.android.material:material:1.2.0-alpha03' - implementation 'com.github.wix-playground:ahbottomnavigation:3.1.2' + implementation 'com.github.wix-playground:ahbottomnavigation:3.2.0' implementation 'com.github.wix-playground:reflow-animator:1.0.6' implementation 'com.github.clans:fab:1.6.4' diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java index 13f83ea5955..a9e0e751adb 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java @@ -13,6 +13,8 @@ import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector; import com.reactnativenavigation.views.BottomTabs; +import org.jetbrains.annotations.NotNull; + import java.util.List; import androidx.annotation.IntRange; @@ -118,7 +120,7 @@ private void applyBottomTabsOptions(Options options) { bottomTabs.setLayoutDirection(options.layout.direction); bottomTabs.setPreferLargeIcons(options.bottomTabsOptions.preferLargeIcons.get(false)); - bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(TitleState.SHOW_WHEN_ACTIVE)); + bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.get(getDefaultTitleState())); bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE)); if (bottomTabsOptions.currentTabIndex.hasValue()) { int tabIndex = bottomTabsOptions.currentTabIndex.get(); @@ -148,6 +150,14 @@ private void applyBottomTabsOptions(Options options) { } } + @NotNull + private TitleState getDefaultTitleState() { + for (int i = 0; i < bottomTabs.getItemsCount(); i++) { + if (bottomTabs.getItem(i).hasIcon()) return TitleState.SHOW_WHEN_ACTIVE; + } + return TitleState.ALWAYS_SHOW; + } + public void applyBottomInset(int bottomInset) { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) bottomTabs.getLayoutParams(); lp.bottomMargin = bottomInset; diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java index 80e98d4be04..781039587c1 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java @@ -164,7 +164,7 @@ private List createTabs() { BottomTabOptions options = tab.resolveCurrentOptions().bottomTabOptions; return new AHBottomNavigationItem( options.text.get(""), - imageLoader.loadIcon(getActivity(), options.icon.get()), + imageLoader.loadIcon(getActivity(), options.icon.get(null)), imageLoader.loadIcon(getActivity(), options.selectedIcon.get(null)), options.testId.get("") ); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java index c28d44378ac..e40b23e6699 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java @@ -6,6 +6,7 @@ import android.view.View; import android.view.ViewGroup.MarginLayoutParams; +import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; import com.reactnativenavigation.BaseTest; import com.reactnativenavigation.TestUtils; import com.reactnativenavigation.mocks.ImageLoaderMock; @@ -13,6 +14,7 @@ import com.reactnativenavigation.parse.Options; import com.reactnativenavigation.parse.params.Bool; import com.reactnativenavigation.parse.params.Colour; +import com.reactnativenavigation.parse.params.NullText; import com.reactnativenavigation.parse.params.Number; import com.reactnativenavigation.parse.params.Text; import com.reactnativenavigation.presentation.BottomTabPresenter; @@ -43,6 +45,7 @@ import edu.emory.mathcs.backport.java.util.Collections; import static com.reactnativenavigation.TestUtils.hideBackButton; +import static com.reactnativenavigation.utils.ObjectUtils.perform; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -74,32 +77,9 @@ public class BottomTabsControllerTest extends BaseTest { @Override public void beforeEach() { activity = newActivity(); - bottomTabs = spy(new BottomTabs(activity) { - @Override - public void superCreateItems() { - - } - }); childRegistry = new ChildControllersRegistry(); eventEmitter = Mockito.mock(EventEmitter.class); - - child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions)); - child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions)); - child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions)); - child4 = spy(createStack()); - child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions)); - when(child5.handleBack(any())).thenReturn(true); - tabs = createTabs(); - presenter = spy(new BottomTabsPresenter(tabs, new Options())); - bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options())); - tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter)); - uut = createBottomTabs(); - - uut.setParentController(Mockito.mock(ParentController.class)); - CoordinatorLayout parent = new CoordinatorLayout(activity); - parent.addView(uut.getView()); - activity.setContentView(parent); - + prepareViewsForTests(); StatusBarUtils.saveStatusBarHeight(63); } @@ -110,6 +90,22 @@ public void createView_checkProperStructure() { assertThat(((CoordinatorLayout.LayoutParams) uut.getBottomTabs().getLayoutParams()).gravity).isEqualTo(Gravity.BOTTOM); } + @Test + public void createView_tabsWithoutIconsAreAccepted() { + tabOptions.bottomTabOptions.icon = new NullText(); + prepareViewsForTests(); + assertThat(uut.getBottomTabs().getItemsCount()).isEqualTo(tabs.size()); + } + + @Test + public void createView_showTitlesWhenAllTabsDontHaveIcons() { + tabOptions.bottomTabOptions.icon = new NullText(); + assertThat(tabOptions.bottomTabsOptions.titleDisplayMode.hasValue()).isFalse(); + prepareViewsForTests(); + presenter.applyOptions(Options.EMPTY); + assertThat(bottomTabs.getTitleState()).isEqualTo(AHBottomNavigation.TitleState.ALWAYS_SHOW); + } + @Test(expected = RuntimeException.class) public void setTabs_ThrowWhenMoreThan5() { tabs.add(new SimpleViewController(activity, childRegistry, "6", tabOptions)); @@ -393,6 +389,36 @@ public void destroy() { verify(tabsAttacher).destroy(); } + private void prepareViewsForTests() { + perform(uut, ViewController::destroy); + bottomTabs = spy(new BottomTabs(activity) { + @Override + public void superCreateItems() { + + } + }); + createChildren(); + tabs = createTabs(); + presenter = spy(new BottomTabsPresenter(tabs, new Options())); + bottomTabPresenter = spy(new BottomTabPresenter(activity, tabs, ImageLoaderMock.mock(), new Options())); + tabsAttacher = spy(new BottomTabsAttacher(tabs, presenter)); + uut = createBottomTabs(); + + uut.setParentController(Mockito.mock(ParentController.class)); + CoordinatorLayout parent = new CoordinatorLayout(activity); + parent.addView(uut.getView()); + activity.setContentView(parent); + } + + private void createChildren() { + child1 = spy(new SimpleViewController(activity, childRegistry, "child1", tabOptions)); + child2 = spy(new SimpleViewController(activity, childRegistry, "child2", tabOptions)); + child3 = spy(new SimpleViewController(activity, childRegistry, "child3", tabOptions)); + child4 = spy(createStack()); + child5 = spy(new SimpleViewController(activity, childRegistry, "child5", tabOptions)); + when(child5.handleBack(any())).thenReturn(true); + } + @NonNull private List createTabs() { return Arrays.asList(child1, child2, child3, child4, child5);