зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1056920 - Create grid based layout for tabs (r=lucasr)
This commit is contained in:
Родитель
a8c5728bf6
Коммит
760aed223b
|
@ -1322,7 +1322,7 @@ public class BrowserApp extends GeckoApp
|
||||||
if (mMainLayoutAnimator != null)
|
if (mMainLayoutAnimator != null)
|
||||||
mMainLayoutAnimator.stop();
|
mMainLayoutAnimator.stop();
|
||||||
|
|
||||||
boolean isSideBar = (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE);
|
boolean isSideBar = !NewTabletUI.isEnabled(this) && (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE);
|
||||||
final int sidebarWidth = getResources().getDimensionPixelSize(R.dimen.tabs_sidebar_width);
|
final int sidebarWidth = getResources().getDimensionPixelSize(R.dimen.tabs_sidebar_width);
|
||||||
|
|
||||||
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mTabsPanel.getLayoutParams();
|
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mTabsPanel.getLayoutParams();
|
||||||
|
|
|
@ -395,6 +395,7 @@ gbjar.sources += [
|
||||||
'tabs/RemoteTabsSetupPanel.java',
|
'tabs/RemoteTabsSetupPanel.java',
|
||||||
'tabs/RemoteTabsVerificationPanel.java',
|
'tabs/RemoteTabsVerificationPanel.java',
|
||||||
'tabs/TabCurve.java',
|
'tabs/TabCurve.java',
|
||||||
|
'tabs/TabsGridLayout.java',
|
||||||
'tabs/TabsLayoutAdapter.java',
|
'tabs/TabsLayoutAdapter.java',
|
||||||
'tabs/TabsLayoutItemView.java',
|
'tabs/TabsLayoutItemView.java',
|
||||||
'tabs/TabsListLayout.java',
|
'tabs/TabsListLayout.java',
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
<item name="menuItemActionViewStyle">@style/Widget.MenuItemActionView</item>
|
<item name="menuItemActionViewStyle">@style/Widget.MenuItemActionView</item>
|
||||||
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
|
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
|
||||||
<item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
|
<item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
|
||||||
|
<item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
<!-- Style for the PanelGridView -->
|
<!-- Style for the PanelGridView -->
|
||||||
<attr name="panelGridViewStyle" format="reference" />
|
<attr name="panelGridViewStyle" format="reference" />
|
||||||
|
|
||||||
|
<!-- Style for the TabsGridLayout -->
|
||||||
|
<attr name="tabGridLayoutViewStyle" format="reference" />
|
||||||
|
|
||||||
<!-- Default style for the TopSitesGridView -->
|
<!-- Default style for the TopSitesGridView -->
|
||||||
<attr name="topSitesGridViewStyle" format="reference" />
|
<attr name="topSitesGridViewStyle" format="reference" />
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,9 @@
|
||||||
<!-- PanelGridView dimensions -->
|
<!-- PanelGridView dimensions -->
|
||||||
<dimen name="panel_grid_view_column_width">150dp</dimen>
|
<dimen name="panel_grid_view_column_width">150dp</dimen>
|
||||||
|
|
||||||
|
<!-- TabsGridView dimensions -->
|
||||||
|
<dimen name="tabs_grid_view_column_width">200dp</dimen>
|
||||||
|
|
||||||
<!-- PanelItemView dimensions -->
|
<!-- PanelItemView dimensions -->
|
||||||
<dimen name="panel_article_item_height">95dp</dimen>
|
<dimen name="panel_article_item_height">95dp</dimen>
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,18 @@
|
||||||
<item name="android:drawSelectorOnTop">true</item>
|
<item name="android:drawSelectorOnTop">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.TabsGridLayout" parent="Widget.GridView">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">match_parent</item>
|
||||||
|
<item name="android:paddingTop">0dp</item>
|
||||||
|
<item name="android:stretchMode">columnWidth</item>
|
||||||
|
<item name="android:numColumns">auto_fit</item>
|
||||||
|
<item name="android:columnWidth">@dimen/tabs_grid_view_column_width</item>
|
||||||
|
<item name="android:horizontalSpacing">2dp</item>
|
||||||
|
<item name="android:verticalSpacing">2dp</item>
|
||||||
|
<item name="android:drawSelectorOnTop">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Widget.BookmarkItemView" parent="Widget.TwoLinePageRow"/>
|
<style name="Widget.BookmarkItemView" parent="Widget.TwoLinePageRow"/>
|
||||||
|
|
||||||
<style name="Widget.BookmarksListView" parent="Widget.HomeListView"/>
|
<style name="Widget.BookmarksListView" parent="Widget.HomeListView"/>
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<item name="android:windowBackground">@android:color/white</item>
|
<item name="android:windowBackground">@android:color/white</item>
|
||||||
<item name="bookmarksListViewStyle">@style/Widget.BookmarksListView</item>
|
<item name="bookmarksListViewStyle">@style/Widget.BookmarksListView</item>
|
||||||
<item name="floatingHintEditTextStyle">@style/FloatingHintEditText</item>
|
<item name="floatingHintEditTextStyle">@style/FloatingHintEditText</item>
|
||||||
|
<item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
|
||||||
<item name="geckoMenuListViewStyle">@style/Widget.GeckoMenuListView</item>
|
<item name="geckoMenuListViewStyle">@style/Widget.GeckoMenuListView</item>
|
||||||
<item name="homeListViewStyle">@style/Widget.HomeListView</item>
|
<item name="homeListViewStyle">@style/Widget.HomeListView</item>
|
||||||
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
|
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko.tabs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.animation.ViewHelper;
|
||||||
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
|
import org.mozilla.gecko.GeckoEvent;
|
||||||
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.Tab;
|
||||||
|
import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
|
||||||
|
import org.mozilla.gecko.Tabs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.GridView;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tabs layout implementation for the tablet redesign (bug 1014156).
|
||||||
|
* Expected to replace TabsListLayout once complete.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TabsGridLayout extends GridView
|
||||||
|
implements TabsLayout,
|
||||||
|
Tabs.OnTabsChangedListener {
|
||||||
|
private static final String LOGTAG = "Gecko" + TabsGridLayout.class.getSimpleName();
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private TabsPanel mTabsPanel;
|
||||||
|
|
||||||
|
final private boolean mIsPrivate;
|
||||||
|
|
||||||
|
private TabsLayoutAdapter mTabsAdapter;
|
||||||
|
|
||||||
|
public TabsGridLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs, R.attr.tabGridLayoutViewStyle);
|
||||||
|
mContext = context;
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsTray);
|
||||||
|
mIsPrivate = (a.getInt(R.styleable.TabsTray_tabs, 0x0) == 1);
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
mTabsAdapter = new TabsGridLayoutAdapter(mContext);
|
||||||
|
setAdapter(mTabsAdapter);
|
||||||
|
|
||||||
|
setRecyclerListener(new RecyclerListener() {
|
||||||
|
@Override
|
||||||
|
public void onMovedToScrapHeap(View view) {
|
||||||
|
TabsLayoutItemView item = (TabsLayoutItemView) view.getTag();
|
||||||
|
item.thumbnail.setImageDrawable(null);
|
||||||
|
item.close.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TabsGridLayoutAdapter extends TabsLayoutAdapter {
|
||||||
|
|
||||||
|
final private Button.OnClickListener mCloseClickListener;
|
||||||
|
final private View.OnClickListener mSelectClickListener;
|
||||||
|
|
||||||
|
public TabsGridLayoutAdapter (Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
mCloseClickListener = new Button.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
TabsLayoutItemView itemView = (TabsLayoutItemView) v.getTag();
|
||||||
|
Tab tab = Tabs.getInstance().getTab(itemView.id);
|
||||||
|
Tabs.getInstance().closeTab(tab);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mSelectClickListener = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
TabsLayoutItemView tab = (TabsLayoutItemView) v.getTag();
|
||||||
|
Tabs.getInstance().selectTab(tab.id);
|
||||||
|
TabsGridLayout.this.autoHidePanel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View newView(int position, ViewGroup parent) {
|
||||||
|
View view = super.newView(position, parent);
|
||||||
|
|
||||||
|
// This is nasty and once we change TabsLayoutItemView to an actual view
|
||||||
|
// we can get rid of it.
|
||||||
|
TabsLayoutItemView item = (TabsLayoutItemView) view.getTag();
|
||||||
|
item.close.setOnClickListener(mCloseClickListener);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindView(View view, Tab tab) {
|
||||||
|
super.bindView(view, tab);
|
||||||
|
|
||||||
|
view.setOnClickListener(mSelectClickListener);
|
||||||
|
|
||||||
|
// If we're recycling this view, there's a chance it was transformed during
|
||||||
|
// the close animation. Remove any of those properties.
|
||||||
|
TabsGridLayout.this.resetTransforms(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTabsPanel(TabsPanel panel) {
|
||||||
|
mTabsPanel = panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void show() {
|
||||||
|
setVisibility(View.VISIBLE);
|
||||||
|
Tabs.getInstance().refreshThumbnails();
|
||||||
|
Tabs.registerOnTabsChangedListener(this);
|
||||||
|
refreshTabsData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hide() {
|
||||||
|
setVisibility(View.GONE);
|
||||||
|
Tabs.unregisterOnTabsChangedListener(this);
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Screenshot:Cancel",""));
|
||||||
|
mTabsAdapter.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldExpand() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void autoHidePanel() {
|
||||||
|
mTabsPanel.autoHidePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
|
||||||
|
switch (msg) {
|
||||||
|
case ADDED:
|
||||||
|
// Refresh the list to make sure the new tab is added in the right position.
|
||||||
|
refreshTabsData();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLOSED:
|
||||||
|
if (tab.isPrivate() == mIsPrivate && mTabsAdapter.getCount() > 0) {
|
||||||
|
if (mTabsAdapter.removeTab(tab)) {
|
||||||
|
int selected = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||||
|
updateSelectedStyle(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SELECTED:
|
||||||
|
// Update the selected position, then fall through...
|
||||||
|
updateSelectedPosition();
|
||||||
|
case UNSELECTED:
|
||||||
|
// We just need to update the style for the unselected tab...
|
||||||
|
case THUMBNAIL:
|
||||||
|
case TITLE:
|
||||||
|
case RECORDING_CHANGE:
|
||||||
|
View view = getChildAt(mTabsAdapter.getPositionForTab(tab) - getFirstVisiblePosition());
|
||||||
|
if (view == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TabsLayoutItemView item = (TabsLayoutItemView) view.getTag();
|
||||||
|
item.assignValues(tab);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the selected position in the list so that it will be scrolled to the right place.
|
||||||
|
private void updateSelectedPosition() {
|
||||||
|
int selected = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||||
|
updateSelectedStyle(selected);
|
||||||
|
|
||||||
|
if (selected != -1) {
|
||||||
|
setSelection(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the selected/unselected style for the tabs.
|
||||||
|
*
|
||||||
|
* @param selected position of the selected tab
|
||||||
|
*/
|
||||||
|
private void updateSelectedStyle(int selected) {
|
||||||
|
for (int i = 0; i < mTabsAdapter.getCount(); i++) {
|
||||||
|
setItemChecked(i, (i == selected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshTabsData() {
|
||||||
|
// Store a different copy of the tabs, so that we don't have to worry about
|
||||||
|
// accidentally updating it on the wrong thread.
|
||||||
|
ArrayList<Tab> tabData = new ArrayList<>();
|
||||||
|
|
||||||
|
Iterable<Tab> allTabs = Tabs.getInstance().getTabsInOrder();
|
||||||
|
for (Tab tab : allTabs) {
|
||||||
|
if (tab.isPrivate() == mIsPrivate)
|
||||||
|
tabData.add(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTabsAdapter.setTabs(tabData);
|
||||||
|
updateSelectedPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetTransforms(View view) {
|
||||||
|
ViewHelper.setAlpha(view, 1);
|
||||||
|
ViewHelper.setTranslationX(view, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeAll() {
|
||||||
|
|
||||||
|
autoHidePanel();
|
||||||
|
|
||||||
|
if (getChildCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
|
||||||
|
for (Tab tab : tabs) {
|
||||||
|
// In the normal panel we want to close all tabs (both private and normal),
|
||||||
|
// but in the private panel we only want to close private tabs.
|
||||||
|
if (!mIsPrivate || tab.isPrivate()) {
|
||||||
|
Tabs.getInstance().closeTab(tab, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче