Commit 51ca833e authored by Yue Zhang's avatar Yue Zhang Committed by Commit Bot

Add a toolbar menu for TabGridDialog

This CL adds components needed for the toolbar menu in TabGridDialog.
Right now there is no consumer for this part of logic.

Bug: 1000381
Change-Id: I03b51e8bbcefdb0f5ac4fc8224303f3d3debeff8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1785517
Commit-Queue: Yue Zhang <yuezhanggg@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#697047}
parent 9c8c53a5
...@@ -88,6 +88,9 @@ android_library("java") { ...@@ -88,6 +88,9 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tasks/tab_management/SelectableTabGridView.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/SelectableTabGridView.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemProperties.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemCoordinator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemMediator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemMediator.java",
......
...@@ -313,6 +313,10 @@ public class TabGridDialogMediator { ...@@ -313,6 +313,10 @@ public class TabGridDialogMediator {
}; };
} }
private View.OnClickListener getMenuButtonClickListener() {
return TabGridDialogMenuCoordinator.getTabGridDialogMenuOnClickListener(null);
}
private List<Tab> getRelatedTabs(int tabId) { private List<Tab> getRelatedTabs(int tabId) {
return mTabModelSelector.getTabModelFilterProvider() return mTabModelSelector.getTabModelFilterProvider()
.getCurrentTabModelFilter() .getCurrentTabModelFilter()
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management;
import android.app.Activity;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Callback;
import org.chromium.base.LifetimeAssert;
import org.chromium.chrome.R;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.ModelListAdapter;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.widget.AnchoredPopupWindow;
import org.chromium.ui.widget.ViewRectProvider;
/**
* A coordinator for the menu in TabGridDialog toolbar. It is responsible for creating a list of
* menu items, setting up the menu and displaying the menu.
*/
public class TabGridDialogMenuCoordinator {
@IntDef({ListItemType.MENU_ITEM})
public @interface ListItemType {
int MENU_ITEM = 0;
}
private final Context mContext;
private final ComponentCallbacks mComponentCallbacks;
private final Callback<Integer> mOnItemClickedCallback;
private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
private AnchoredPopupWindow mMenuWindow;
/**
* Creates a {@link View.OnClickListener} that creates the menu and shows it when clicked.
* @param onItemClicked The clicked listener callback that handles clicks on menu items.
* @return A {@link View.OnClickListener} for the button that opens up the menu.
*/
static View.OnClickListener getTabGridDialogMenuOnClickListener(
Callback<Integer> onItemClicked) {
return view -> {
Context context = view.getContext();
TabGridDialogMenuCoordinator menu =
new TabGridDialogMenuCoordinator(context, view, onItemClicked);
menu.display();
};
}
private TabGridDialogMenuCoordinator(
Context context, View anchorView, Callback<Integer> onItemClicked) {
mContext = context;
mOnItemClickedCallback = onItemClicked;
mComponentCallbacks = new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mMenuWindow == null || !mMenuWindow.isShowing()) return;
mMenuWindow.dismiss();
}
@Override
public void onLowMemory() {}
};
mContext.registerComponentCallbacks(mComponentCallbacks);
final View contentView = LayoutInflater.from(context).inflate(
R.layout.tab_switcher_action_menu_layout, null);
setupMenu(contentView, anchorView);
}
private void setupMenu(View contentView, View anchorView) {
ListView listView = contentView.findViewById(R.id.tab_switcher_action_menu_list);
ModelList modelList = buildMenuItems(mContext);
ModelListAdapter adapter = new ModelListAdapter(modelList) {
@Override
public long getItemId(int position) {
return ((ListItem) getItem(position))
.model.get(TabGridDialogMenuItemProperties.MENU_ID);
}
};
listView.setAdapter(adapter);
// clang-format off
adapter.registerType(ListItemType.MENU_ITEM,
() -> LayoutInflater.from(listView.getContext())
.inflate(R.layout.tab_switcher_action_menu_item, null),
TabGridDialogMenuItemBinder::binder);
// clang-format on
listView.setOnItemClickListener((p, v, pos, id) -> {
mOnItemClickedCallback.onResult((int) id);
mMenuWindow.dismiss();
});
View decorView = ((Activity) mContext).getWindow().getDecorView();
ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
// Move the rect down by statusBarHeight because we are positioning the rect within the
// TabGridDialog popup window which doesn't include status bar. However, we are showing it
// in the root decor view which includes the status bar. Thus, adding status bar height as a
// offset.
rectProvider.setInsetPx(0, statusBarHeight, 0, statusBarHeight);
mMenuWindow = new AnchoredPopupWindow(mContext, decorView,
ApiCompatibilityUtils.getDrawable(
mContext.getResources(), R.drawable.popup_bg_tinted),
contentView, rectProvider);
mMenuWindow.setFocusable(true);
mMenuWindow.setHorizontalOverlapAnchor(true);
mMenuWindow.setVerticalOverlapAnchor(true);
mMenuWindow.setAnimationStyle(R.style.OverflowMenuAnim);
int popupWidth = mContext.getResources().getDimensionPixelSize(R.dimen.menu_width);
mMenuWindow.setMaxWidth(popupWidth);
// When the menu is dismissed, call destroy to unregister the orientation listener.
mMenuWindow.addOnDismissListener(this::destroy);
}
private void display() {
if (mMenuWindow == null) return;
mMenuWindow.show();
}
private void destroy() {
mContext.unregisterComponentCallbacks(mComponentCallbacks);
// If mLifetimeAssert is GC'ed before this is called, it will throw an exception
// with a stack trace showing the stack during LifetimeAssert.create().
LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
}
private ModelList buildMenuItems(Context context) {
ModelList itemList = new ModelList();
itemList.add(new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(context,
org.chromium.chrome.tab_ui.R.string.tab_grid_dialog_remove_from_group,
R.id.ungroup_tab)));
return itemList;
}
private PropertyModel buildPropertyModel(Context context, int titleId, int menuId) {
return new PropertyModel.Builder(TabGridDialogMenuItemProperties.ALL_KEYS)
.with(TabGridDialogMenuItemProperties.TITLE, context.getString(titleId))
.with(TabGridDialogMenuItemProperties.MENU_ID, menuId)
.build();
}
}
\ No newline at end of file
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management;
import android.view.View;
import android.widget.TextView;
import org.chromium.chrome.R;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
/**
* ViewBinder for menu item in tab grid dialog menu.
*/
public class TabGridDialogMenuItemBinder {
public static void binder(PropertyModel model, View view, PropertyKey propertyKey) {
if (propertyKey == TabGridDialogMenuItemProperties.TITLE) {
TextView textView = view.findViewById(R.id.menu_item_text);
textView.setText(model.get(TabGridDialogMenuItemProperties.TITLE));
}
}
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
/**
* List of properties to designate information about a menu item in tab grid dialog menu.
*/
public class TabGridDialogMenuItemProperties {
public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
public static final WritableIntPropertyKey MENU_ID = new WritableIntPropertyKey();
public static final PropertyKey[] ALL_KEYS = {TITLE, MENU_ID};
}
...@@ -57,10 +57,13 @@ class TabGridPanelProperties { ...@@ -57,10 +57,13 @@ class TabGridPanelProperties {
new PropertyModel.WritableObjectPropertyKey(true); new PropertyModel.WritableObjectPropertyKey(true);
public static final PropertyModel.WritableBooleanPropertyKey IS_MAIN_CONTENT_VISIBLE = public static final PropertyModel.WritableBooleanPropertyKey IS_MAIN_CONTENT_VISIBLE =
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel
.WritableObjectPropertyKey<OnClickListener> MENU_CLICK_LISTENER =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER, public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER,
ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT, ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT,
IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS, IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS,
DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID, DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE, DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE,
INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE}; INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER};
} }
...@@ -40,9 +40,7 @@ class TabGridPanelToolbarCoordinator implements Destroyable { ...@@ -40,9 +40,7 @@ class TabGridPanelToolbarCoordinator implements Destroyable {
PropertyModel toolbarPropertyModel, TabGridDialogParent dialog) { PropertyModel toolbarPropertyModel, TabGridDialogParent dialog) {
mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(context).inflate( mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(context).inflate(
R.layout.bottom_tab_grid_toolbar, contentView, false); R.layout.bottom_tab_grid_toolbar, contentView, false);
if (dialog != null) { mToolbarView.setupToolbarLayout(dialog != null);
mToolbarView.setupDialogToolbarLayout();
}
mModelChangeProcessor = PropertyModelChangeProcessor.create(toolbarPropertyModel, mModelChangeProcessor = PropertyModelChangeProcessor.create(toolbarPropertyModel,
new TabGridPanelViewBinder.ViewHolder(mToolbarView, contentView, dialog), new TabGridPanelViewBinder.ViewHolder(mToolbarView, contentView, dialog),
TabGridPanelViewBinder::bind); TabGridPanelViewBinder::bind);
......
...@@ -16,6 +16,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope ...@@ -16,6 +16,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.INITIAL_SCROLL_INDEX; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.INITIAL_SCROLL_INDEX;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_DIALOG_VISIBLE; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_DIALOG_VISIBLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_MAIN_CONTENT_VISIBLE; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_MAIN_CONTENT_VISIBLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.MENU_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.PRIMARY_COLOR; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.PRIMARY_COLOR;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.SCRIMVIEW_OBSERVER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.SCRIMVIEW_OBSERVER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT;
...@@ -114,6 +115,8 @@ class TabGridPanelViewBinder { ...@@ -114,6 +115,8 @@ class TabGridPanelViewBinder {
.scrollToPositionWithOffset(index, 0); .scrollToPositionWithOffset(index, 0);
} else if (IS_MAIN_CONTENT_VISIBLE == propertyKey) { } else if (IS_MAIN_CONTENT_VISIBLE == propertyKey) {
viewHolder.contentView.setVisibility(View.VISIBLE); viewHolder.contentView.setVisibility(View.VISIBLE);
} else if (MENU_CLICK_LISTENER == propertyKey) {
viewHolder.toolbarView.setMenuButtonOnClickListener(model.get(MENU_CLICK_LISTENER));
} }
} }
} }
...@@ -12,6 +12,7 @@ import android.view.Gravity; ...@@ -12,6 +12,7 @@ import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
...@@ -25,9 +26,10 @@ import org.chromium.ui.widget.ChromeImageView; ...@@ -25,9 +26,10 @@ import org.chromium.ui.widget.ChromeImageView;
public class TabGroupUiToolbarView extends FrameLayout { public class TabGroupUiToolbarView extends FrameLayout {
private ChromeImageView mRightButton; private ChromeImageView mRightButton;
private ChromeImageView mLeftButton; private ChromeImageView mLeftButton;
private ChromeImageView mMenuButton;
private ViewGroup mContainerView; private ViewGroup mContainerView;
private TextView mTitleTextView; private TextView mTitleTextView;
private View mMainContent; private LinearLayout mMainContent;
public TabGroupUiToolbarView(Context context, AttributeSet attrs) { public TabGroupUiToolbarView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
...@@ -52,13 +54,18 @@ public class TabGroupUiToolbarView extends FrameLayout { ...@@ -52,13 +54,18 @@ public class TabGroupUiToolbarView extends FrameLayout {
mRightButton.setOnClickListener(listener); mRightButton.setOnClickListener(listener);
} }
void setMenuButtonOnClickListener(OnClickListener listener) {
mMenuButton.setOnClickListener(listener);
}
ViewGroup getViewContainer() { ViewGroup getViewContainer() {
return mContainerView; return mContainerView;
} }
void setMainContentVisibility(boolean isVisible) { void setMainContentVisibility(boolean isVisible) {
if (mContainerView == null) if (mContainerView == null) {
throw new IllegalStateException("Current Toolbar doesn't have a container view"); throw new IllegalStateException("Current Toolbar doesn't have a container view");
}
for (int i = 0; i < ((ViewGroup) mContainerView).getChildCount(); i++) { for (int i = 0; i < ((ViewGroup) mContainerView).getChildCount(); i++) {
View child = ((ViewGroup) mContainerView).getChildAt(i); View child = ((ViewGroup) mContainerView).getChildAt(i);
...@@ -67,8 +74,9 @@ public class TabGroupUiToolbarView extends FrameLayout { ...@@ -67,8 +74,9 @@ public class TabGroupUiToolbarView extends FrameLayout {
} }
void setTitle(String title) { void setTitle(String title) {
if (mTitleTextView == null) if (mTitleTextView == null) {
throw new IllegalStateException("Current Toolbar doesn't have a title text view"); throw new IllegalStateException("Current Toolbar doesn't have a title text view");
}
mTitleTextView.setText(title); mTitleTextView.setText(title);
} }
...@@ -84,9 +92,15 @@ public class TabGroupUiToolbarView extends FrameLayout { ...@@ -84,9 +92,15 @@ public class TabGroupUiToolbarView extends FrameLayout {
} }
/** /**
* Setup a TabGridDialog-specific toolbar. It is different from the toolbar for TabGridSheet. * Setup the toolbar layout base on the component it belongs to. The toolbars for TabGridSheet
* and TabGridDialog are different.
*/ */
void setupDialogToolbarLayout() { void setupToolbarLayout(boolean isDialog) {
if (!isDialog) {
// We don't support toolbar menu for TabGridSheet.
mMainContent.removeView(mMenuButton);
return;
}
Context context = getContext(); Context context = getContext();
mLeftButton.setImageResource(org.chromium.chrome.R.drawable.ic_arrow_back_24dp); mLeftButton.setImageResource(org.chromium.chrome.R.drawable.ic_arrow_back_24dp);
int topicMargin = int topicMargin =
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
<!-- Tab Actions --> <!-- Tab Actions -->
<item type="id" name="close_tab" /> <item type="id" name="close_tab" />
<item type="id" name="ungroup_tab" />
<!-- InfoBar constants --> <!-- InfoBar constants -->
<item type="id" name="infobar_icon" /> <item type="id" name="infobar_icon" />
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment