Skip to content

Commit

Permalink
[TIMOB-26354] Android: Refactor TabGroup and introduce new style (#10358
Browse files Browse the repository at this point in the history
)

* Refactoring of TabGroup - getting rid of the deprecated ActionBar Tabs UI and replacing it with TabLayout. Introducing a new style.

* Rename TiUIAbstractTab to not be Abstract anymore (it is not now).
Remove the Lifecycle Interface implementation from TiUIAbstractTabGroup.
Fix removing of Tabs before AND after opening the TabGroup.
Add titleColor and activeTitleColor properties of Tab parity for Android.
Add support for disabling shiftMode for BottomNavigationView (not yet exposed in the JS).
Prevent double selection of items in the TabGroup controller.

* Expose the shiftMode property.
Fix the smoothScrollOnTabClick.

* Docs - extend Ti.UI.Window instead of Ti.UI.View.

* Fix animation for opening TabGroup. Now works the same way as Window.
Clean up listener for tab changes.
Fix focus/blur and select/unselect events for TabGroup and Tabs.

* Remove some unused code.
Optimize the handling of tabs swiping.
Fix disabling of tab navigation.
Format code.

* Fix formatting for controllers.

* Add constants for styles in Ti.UI.Android.
Guard agains API level.
Guard for closing the group before drawing it.
Cleanup a bit of code and imports.
Lint unit tests and format code.
Add docs.

* Remove unnecessary field. The value is the same as the default for the ViewPager. Possible problem on API 16?

* Mimic the auto selection of the first tab added in TabLayou in BottomNavigationView implementation.

* Remove the null set of the tabs field.
Extract common work done in fillIntent() in TiWindowProxy.
Support theme property for TabGroup.
Add support for backgroundColor property.
Replace hash codes for IDs with atomic longs.

* Allow overriding of the tabs max width property for bottom navigation style.

* Revert "Allow overriding of the tabs max width property for bottom navigation style."

This reverts commit 8abad8e.

* Replace property backgroundColor with tabsBackgroundColor.

* Clean up imports.

* Fix icon loading for TiUITabLayoutTabGroup.

* Fix definition.

* Fix indentation.

* Keep linting.
  • Loading branch information
ypbnv authored and lokeshchdhry committed Dec 11, 2018
1 parent 4af828c commit 8d7a199
Show file tree
Hide file tree
Showing 19 changed files with 1,209 additions and 850 deletions.
22 changes: 0 additions & 22 deletions android/modules/ui/res/layout/titanium_tabgroup.xml

This file was deleted.

Expand Up @@ -3,11 +3,11 @@
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.proxy.ActivityProxy;

import ti.modules.titanium.ui.widget.tabgroup.TiUIAbstractTab;
import ti.modules.titanium.ui.widget.tabgroup.TiUITab;

/**
* A special view for the content of a tab.
* @see {@link TiUIAbstractTab#getContentView()}
* @see {@link TiUITab#getContentView()}
*/
@Kroll.proxy(parentModule = UIModule.class)
public class TabContentViewProxy extends ViewProxy
Expand Down
108 changes: 50 additions & 58 deletions android/modules/ui/src/java/ti/modules/titanium/ui/TabGroupProxy.java
Expand Up @@ -25,10 +25,14 @@
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.util.TiUIHelper;

import ti.modules.titanium.ui.android.AndroidModule;
import ti.modules.titanium.ui.widget.tabgroup.TiUIAbstractTabGroup;
import ti.modules.titanium.ui.widget.tabgroup.TiUIActionBarTabGroup;
import ti.modules.titanium.ui.widget.tabgroup.TiUIBottomNavigationTabGroup;
import ti.modules.titanium.ui.widget.tabgroup.TiUITabLayoutTabGroup;

import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Message;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
Expand All @@ -37,7 +41,6 @@
@Kroll.proxy(creatableInModule = UIModule.class,
propertyAccessors = {
TiC.PROPERTY_TABS_BACKGROUND_COLOR,
TiC.PROPERTY_ACTIVE_TAB_BACKGROUND_COLOR,
TiC.PROPERTY_SWIPEABLE,
TiC.PROPERTY_EXIT_ON_CLOSE,
TiC.PROPERTY_SMOOTH_SCROLL_ON_TAB_CLICK
Expand Down Expand Up @@ -150,7 +153,7 @@ public void disableTabNavigation(boolean disable)

private void handleDisableTabNavigation(boolean disable)
{
TiUIActionBarTabGroup tabGroup = (TiUIActionBarTabGroup) view;
TiUIAbstractTabGroup tabGroup = (TiUIAbstractTabGroup) view;
if (tabGroup != null) {
tabGroup.disableTabNavigation(disable);
}
Expand Down Expand Up @@ -204,12 +207,17 @@ public void removeTab(TabProxy tab)

public void handleRemoveTab(TabProxy tab)
{
int indexToRemove = tabs.indexOf(tab);
// Guard for trying to remove a Tab that has not been added.
if (indexToRemove < 0) {
return;
}
tabs.remove(tab);

TiUIAbstractTabGroup tabGroup = (TiUIAbstractTabGroup) view;
if (tabGroup != null) {
tabGroup.removeTab(tab);
tabGroup.removeTabAt(indexToRemove);
}

tabs.remove(tab);
}

@Kroll.method
Expand Down Expand Up @@ -237,7 +245,6 @@ protected void handleSetActiveTab(TabProxy tab)
// Once the change is completed onTabSelected() will be
// called to fire events and update the active tab.
tabGroup.selectTab(tab);

} else {
// Mark this tab to be selected when the tab group opens.
selectedTab = tab;
Expand Down Expand Up @@ -280,7 +287,11 @@ private TabProxy parseTab(Object tabOrIndex)

private void handleSetTabs(Object obj)
{
tabs.clear();
if (tabs != null) {
tabs.clear();
} else {
tabs = new ArrayList<TabProxy>();
}
if (obj instanceof Object[]) {
Object[] objArray = (Object[]) obj;
for (Object tabProxy : objArray) {
Expand Down Expand Up @@ -364,7 +375,24 @@ protected void handleOpen(KrollDict options)
intent.putExtra(TiC.INTENT_PROPERTY_USE_ACTIVITY_WINDOW, true);
intent.putExtra(TiC.INTENT_PROPERTY_WINDOW_ID, windowId);

topActivity.startActivity(intent);
boolean animated = TiConvert.toBoolean(options, TiC.PROPERTY_ANIMATED, true);
if (!animated) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
topActivity.startActivity(intent);
topActivity.overridePendingTransition(0, 0);
} else if (options.containsKey(TiC.PROPERTY_ACTIVITY_ENTER_ANIMATION)
|| options.containsKey(TiC.PROPERTY_ACTIVITY_EXIT_ANIMATION)) {
topActivity.startActivity(intent);
int enterAnimation = TiConvert.toInt(options.get(TiC.PROPERTY_ACTIVITY_ENTER_ANIMATION), 0);
int exitAnimation = TiConvert.toInt(options.get(TiC.PROPERTY_ACTIVITY_EXIT_ANIMATION), 0);
topActivity.overridePendingTransition(enterAnimation, exitAnimation);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
topActivity.startActivity(intent, createActivityOptionsBundle(topActivity));
} else {
topActivity.startActivity(intent);
}
}
}

@Override
Expand All @@ -375,11 +403,12 @@ public void windowCreated(TiBaseActivity activity, Bundle savedInstanceState)
activity.setLayoutProxy(this);
setActivity(activity);

if (activity.getSupportActionBar() != null) {
view = new TiUIActionBarTabGroup(this, activity, savedInstanceState);
// Currently only two styles. Introducing new ones will work with a switch statement.
if (getProperty(TiC.PROPERTY_STYLE) == null
|| ((Integer) getProperty(TiC.PROPERTY_STYLE)) == AndroidModule.TABS_STYLE_DEFAULT) {
view = new TiUITabLayoutTabGroup(this, activity);
} else {
Log.e(TAG, "ActionBar not available for TabGroup");
return;
view = new TiUIBottomNavigationTabGroup(this, activity);
}

setModelListener(view);
Expand Down Expand Up @@ -416,7 +445,7 @@ protected void handlePostOpen()

TabProxy activeTab = handleGetActiveTab();
if (activeTab != null) {
selectedTab = null;
selectedTab = activeTab;
// If tabHost's selected tab is same as the active tab, we need
// to invoke onTabSelected so focus/blur event fire appropriately
if (tg.getSelectedTab() == activeTab) {
Expand Down Expand Up @@ -456,7 +485,7 @@ public void closeFromActivity(boolean activityIsFinishing)
for (TabProxy tab : tabs) {
tab.close(activityIsFinishing);
}

tabs.clear();
// Call super to fire the close event on the tab group.
// This event must fire after each tab has been closed.
super.closeFromActivity(activityIsFinishing);
Expand Down Expand Up @@ -487,6 +516,11 @@ public void onWindowFocusChange(boolean focused)
selectedTab.onFocusChanged(focused, null);
}

public void onTabSelected(int position)
{
onTabSelected(tabs.get(position));
}

/**
* Invoked when a tab in the group is selected.
*
Expand Down Expand Up @@ -519,50 +553,8 @@ public void onTabSelected(TabProxy tabProxy)
}
selectedTab.onSelectionChanged(true);
selectedTab.onFocusChanged(true, focusEventData);
}

private void fillIntent(Activity activity, Intent intent)
{
int windowFlags = 0;
if (hasProperty(TiC.PROPERTY_WINDOW_FLAGS)) {
windowFlags = TiConvert.toInt(getProperty(TiC.PROPERTY_WINDOW_FLAGS), 0);
}

//Set the fullscreen flag
if (hasProperty(TiC.PROPERTY_FULLSCREEN)) {
boolean flagVal = TiConvert.toBoolean(getProperty(TiC.PROPERTY_FULLSCREEN), false);
if (flagVal) {
windowFlags = windowFlags | WindowManager.LayoutParams.FLAG_FULLSCREEN;
}
}

//Set the secure flag
if (hasProperty(TiC.PROPERTY_FLAG_SECURE)) {
boolean flagVal = TiConvert.toBoolean(getProperty(TiC.PROPERTY_FLAG_SECURE), false);
if (flagVal) {
windowFlags = windowFlags | WindowManager.LayoutParams.FLAG_SECURE;
}
}

//Stuff flags in intent
intent.putExtra(TiC.PROPERTY_WINDOW_FLAGS, windowFlags);

if (hasProperty(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE)) {
intent.putExtra(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE,
TiConvert.toInt(getProperty(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE), -1));
}

if (hasProperty(TiC.PROPERTY_EXTEND_SAFE_AREA)) {
boolean value = TiConvert.toBoolean(getProperty(TiC.PROPERTY_EXTEND_SAFE_AREA), false);
intent.putExtra(TiC.PROPERTY_EXTEND_SAFE_AREA, value);
}

if (hasProperty(TiC.PROPERTY_EXIT_ON_CLOSE)) {
intent.putExtra(TiC.INTENT_PROPERTY_FINISH_ROOT,
TiConvert.toBoolean(getProperty(TiC.PROPERTY_EXIT_ON_CLOSE), false));
} else {
intent.putExtra(TiC.INTENT_PROPERTY_FINISH_ROOT, activity.isTaskRoot());
}
tabProxy.fireEvent(TiC.EVENT_SELECTED, null, false);
}

@Override
Expand Down
42 changes: 2 additions & 40 deletions android/modules/ui/src/java/ti/modules/titanium/ui/TabProxy.java
Expand Up @@ -16,7 +16,7 @@
import org.appcelerator.titanium.util.TiUIHelper;
import org.appcelerator.titanium.view.TiUIView;

import ti.modules.titanium.ui.widget.tabgroup.TiUIAbstractTab;
import ti.modules.titanium.ui.widget.tabgroup.TiUITab;
import android.app.Activity;
// clang-format off
@Kroll.proxy(creatableInModule = UIModule.class,
Expand Down Expand Up @@ -172,44 +172,6 @@ public void releaseViewsForActivityForcedToDestroy()
}
}

/**
* Get the color of the tab when it is active.
*
* @return the active color if specified, otherwise returns zero.
*/
public int getActiveTabColor()
{
Object color = getProperty(TiC.PROPERTY_BACKGROUND_SELECTED_COLOR);
if (color == null) {
color = tabGroupProxy.getProperty(TiC.PROPERTY_ACTIVE_TAB_BACKGROUND_COLOR);
}

if (color != null) {
return TiConvert.toColor(color.toString());
}

return 0;
}

/**
* Get the color of the tab when it is inactive.
*
* @return the inactive color if specified, otherwise returns zero.
*/
public int getTabColor()
{
Object color = getProperty(TiC.PROPERTY_BACKGROUND_COLOR);
if (color == null) {
color = tabGroupProxy.getProperty(TiC.PROPERTY_TABS_BACKGROUND_COLOR);
}

if (color != null) {
return TiConvert.toColor(color.toString());
}

return 0;
}

void onFocusChanged(boolean focused, KrollDict eventData)
{
// Windows are lazily opened when the tab is first focused.
Expand Down Expand Up @@ -255,7 +217,7 @@ void onSelectionChanged(boolean selected)
}
}

((TiUIAbstractTab) view).onSelectionChange(selected);
((TiUITab) view).onSelectionChange(selected);
}

@Override
Expand Down
Expand Up @@ -315,42 +315,9 @@ protected Activity getWindowActivity()
return (windowActivity != null) ? windowActivity.get() : null;
}

private void fillIntent(Activity activity, Intent intent)
protected void fillIntent(Activity activity, Intent intent)
{
int windowFlags = 0;
if (hasProperty(TiC.PROPERTY_WINDOW_FLAGS)) {
windowFlags = TiConvert.toInt(getProperty(TiC.PROPERTY_WINDOW_FLAGS), 0);
}

//Set the fullscreen flag
if (hasProperty(TiC.PROPERTY_FULLSCREEN)) {
boolean flagVal = TiConvert.toBoolean(getProperty(TiC.PROPERTY_FULLSCREEN), false);
if (flagVal) {
windowFlags = windowFlags | WindowManager.LayoutParams.FLAG_FULLSCREEN;
}
}

//Set the secure flag
if (hasProperty(TiC.PROPERTY_FLAG_SECURE)) {
boolean flagVal = TiConvert.toBoolean(getProperty(TiC.PROPERTY_FLAG_SECURE), false);
if (flagVal) {
windowFlags = windowFlags | WindowManager.LayoutParams.FLAG_SECURE;
}
}

//Stuff flags in intent
intent.putExtra(TiC.PROPERTY_WINDOW_FLAGS, windowFlags);

if (hasProperty(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE)) {
intent.putExtra(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE,
TiConvert.toInt(getProperty(TiC.PROPERTY_WINDOW_SOFT_INPUT_MODE), -1));
}
if (hasProperty(TiC.PROPERTY_EXIT_ON_CLOSE)) {
intent.putExtra(TiC.INTENT_PROPERTY_FINISH_ROOT,
TiConvert.toBoolean(getProperty(TiC.PROPERTY_EXIT_ON_CLOSE), false));
} else {
intent.putExtra(TiC.INTENT_PROPERTY_FINISH_ROOT, activity.isTaskRoot());
}
super.fillIntent(activity, intent);

boolean modal = false;
if (hasProperty(TiC.PROPERTY_MODAL)) {
Expand All @@ -377,19 +344,6 @@ private void fillIntent(Activity activity, Intent intent)
intent.putExtra(TiC.PROPERTY_EXTEND_SAFE_AREA, value);
}

// Set the theme property
if (hasProperty(TiC.PROPERTY_THEME)) {
String theme = TiConvert.toString(getProperty(TiC.PROPERTY_THEME));
if (theme != null) {
try {
intent.putExtra(TiC.PROPERTY_THEME,
TiRHelper.getResource("style." + theme.replaceAll("[^A-Za-z0-9_]", "_")));
} catch (Exception e) {
Log.w(TAG, "Cannot find the theme: " + theme);
}
}
}

// Set the splitActionBar property
if (hasProperty(TiC.PROPERTY_SPLIT_ACTIONBAR)) {
boolean splitActionBar = TiConvert.toBoolean(getProperty(TiC.PROPERTY_SPLIT_ACTIONBAR), false);
Expand Down
Expand Up @@ -182,6 +182,11 @@ public class AndroidModule extends KrollModule
@Kroll.constant
public static final int GRAVITY_VERTICAL_GRAVITY_MASK = Gravity.VERTICAL_GRAVITY_MASK;

@Kroll.constant
public static final int TABS_STYLE_DEFAULT = 0;
@Kroll.constant
public static final int TABS_STYLE_BOTTOM_NAVIGATION = 1;

@Kroll.constant
public static final int TRANSITION_NONE = TiUIView.TRANSITION_NONE;
@Kroll.constant
Expand Down

0 comments on commit 8d7a199

Please sign in to comment.