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") {
"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/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/TabGridIphItemCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemMediator.java",
......
......@@ -313,6 +313,10 @@ public class TabGridDialogMediator {
};
}
private View.OnClickListener getMenuButtonClickListener() {
return TabGridDialogMenuCoordinator.getTabGridDialogMenuOnClickListener(null);
}
private List<Tab> getRelatedTabs(int tabId) {
return mTabModelSelector.getTabModelFilterProvider()
.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 {
new PropertyModel.WritableObjectPropertyKey(true);
public static final PropertyModel.WritableBooleanPropertyKey IS_MAIN_CONTENT_VISIBLE =
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,
ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT,
IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS,
DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
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 {
PropertyModel toolbarPropertyModel, TabGridDialogParent dialog) {
mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(context).inflate(
R.layout.bottom_tab_grid_toolbar, contentView, false);
if (dialog != null) {
mToolbarView.setupDialogToolbarLayout();
}
mToolbarView.setupToolbarLayout(dialog != null);
mModelChangeProcessor = PropertyModelChangeProcessor.create(toolbarPropertyModel,
new TabGridPanelViewBinder.ViewHolder(mToolbarView, contentView, dialog),
TabGridPanelViewBinder::bind);
......
......@@ -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.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.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.SCRIMVIEW_OBSERVER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT;
......@@ -114,6 +115,8 @@ class TabGridPanelViewBinder {
.scrollToPositionWithOffset(index, 0);
} else if (IS_MAIN_CONTENT_VISIBLE == propertyKey) {
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;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
......@@ -25,9 +26,10 @@ import org.chromium.ui.widget.ChromeImageView;
public class TabGroupUiToolbarView extends FrameLayout {
private ChromeImageView mRightButton;
private ChromeImageView mLeftButton;
private ChromeImageView mMenuButton;
private ViewGroup mContainerView;
private TextView mTitleTextView;
private View mMainContent;
private LinearLayout mMainContent;
public TabGroupUiToolbarView(Context context, AttributeSet attrs) {
super(context, attrs);
......@@ -52,13 +54,18 @@ public class TabGroupUiToolbarView extends FrameLayout {
mRightButton.setOnClickListener(listener);
}
void setMenuButtonOnClickListener(OnClickListener listener) {
mMenuButton.setOnClickListener(listener);
}
ViewGroup getViewContainer() {
return mContainerView;
}
void setMainContentVisibility(boolean isVisible) {
if (mContainerView == null)
if (mContainerView == null) {
throw new IllegalStateException("Current Toolbar doesn't have a container view");
}
for (int i = 0; i < ((ViewGroup) mContainerView).getChildCount(); i++) {
View child = ((ViewGroup) mContainerView).getChildAt(i);
......@@ -67,8 +74,9 @@ public class TabGroupUiToolbarView extends FrameLayout {
}
void setTitle(String title) {
if (mTitleTextView == null)
if (mTitleTextView == null) {
throw new IllegalStateException("Current Toolbar doesn't have a title text view");
}
mTitleTextView.setText(title);
}
......@@ -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();
mLeftButton.setImageResource(org.chromium.chrome.R.drawable.ic_arrow_back_24dp);
int topicMargin =
......
......@@ -20,6 +20,7 @@
<!-- Tab Actions -->
<item type="id" name="close_tab" />
<item type="id" name="ungroup_tab" />
<!-- InfoBar constants -->
<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