Commit bc8c6fa6 authored by Mei Liang's avatar Mei Liang Committed by Commit Bot

[TabSelectionEditor] Adaptive toolbar and list of tabs

This CL enables configuring toolbar properties for TabSelectionEditor,
as well as shows the TabSelectionEditor with the given tabs.

Change-Id: I2945e2fc8f4762b4bde6efb7ed02356e812eed5a
Bug: 1004570
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1814547Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarYue Zhang <yuezhanggg@chromium.org>
Commit-Queue: Mei Liang <meiliang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699960}
parent 42029a61
...@@ -32,14 +32,28 @@ class TabSelectionEditorCoordinator { ...@@ -32,14 +32,28 @@ class TabSelectionEditorCoordinator {
*/ */
interface TabSelectionEditorController { interface TabSelectionEditorController {
/** /**
* Shows the TabSelectionEditor. * Shows the TabSelectionEditor with the given {@link Tab}s.
* @param tabs List of {@link Tab}s to show.
*/ */
void show(); void show(List<Tab> tabs);
/** /**
* @return Whether or not the TabSelectionEditor consumed the event. * @return Whether or not the TabSelectionEditor consumed the event.
*/ */
boolean handleBackPressed(); boolean handleBackPressed();
/**
* Configure the Toolbar for TabSelectionEditor. The default button text is "Group".
* @param actionButtonText Button text for the action button.
* @param actionButtonOnClickListener Click listener for the action button.
* @param actionButtonEnablingThreshold The minimum threshold to enable the action button.
* If it's -1 use the default value.
* @param navigationButtonOnClickListener Click listener for the navigation button.
*/
void configureToolbar(@Nullable String actionButtonText,
@Nullable View.OnClickListener actionButtonOnClickListener,
int actionButtonEnablingThreshold,
@Nullable View.OnClickListener navigationButtonOnClickListener);
} }
private final Context mContext; private final Context mContext;
......
...@@ -25,9 +25,9 @@ public class TabSelectionEditorLayoutBinder { ...@@ -25,9 +25,9 @@ public class TabSelectionEditorLayoutBinder {
} else { } else {
view.hide(); view.hide();
} }
} else if (TabSelectionEditorProperties.TOOLBAR_GROUP_BUTTON_LISTENER == propertyKey) { } else if (TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_LISTENER == propertyKey) {
view.getToolbar().setActionButtonOnClickListener( view.getToolbar().setActionButtonOnClickListener(
model.get(TabSelectionEditorProperties.TOOLBAR_GROUP_BUTTON_LISTENER)); model.get(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_LISTENER));
} else if (TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER == propertyKey) { } else if (TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER == propertyKey) {
view.getToolbar().setNavigationOnClickListener( view.getToolbar().setNavigationOnClickListener(
model.get(TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER)); model.get(TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER));
...@@ -42,6 +42,13 @@ public class TabSelectionEditorLayoutBinder { ...@@ -42,6 +42,13 @@ public class TabSelectionEditorLayoutBinder {
} else if (TabSelectionEditorProperties.TOOLBAR_TEXT_APPEARANCE == propertyKey) { } else if (TabSelectionEditorProperties.TOOLBAR_TEXT_APPEARANCE == propertyKey) {
view.getToolbar().setTextAppearance( view.getToolbar().setTextAppearance(
model.get(TabSelectionEditorProperties.TOOLBAR_TEXT_APPEARANCE)); model.get(TabSelectionEditorProperties.TOOLBAR_TEXT_APPEARANCE));
} else if (TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_TEXT == propertyKey) {
view.getToolbar().setActionButtonText(
model.get(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_TEXT));
} else if (TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD
== propertyKey) {
view.getToolbar().setActionButtonEnablingThreshold(model.get(
TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD));
} }
} }
} }
...@@ -100,7 +100,7 @@ class TabSelectionEditorMediator ...@@ -100,7 +100,7 @@ class TabSelectionEditorMediator
mModel.set( mModel.set(
TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER, mNavigationClickListener); TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER, mNavigationClickListener);
mModel.set(TabSelectionEditorProperties.TOOLBAR_GROUP_BUTTON_LISTENER, mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_LISTENER,
mGroupButtonOnClickListener); mGroupButtonOnClickListener);
mTabModelObserver = new TabModelSelectorTabModelObserver(mTabModelSelector) { mTabModelObserver = new TabModelSelectorTabModelObserver(mTabModelSelector) {
...@@ -175,15 +175,34 @@ class TabSelectionEditorMediator ...@@ -175,15 +175,34 @@ class TabSelectionEditorMediator
} }
@Override @Override
public void show() { public void show(List<Tab> tabs) {
List<Tab> nonGroupedTabs = mTabModelSelector.getTabModelFilterProvider() mResetHandler.resetWithListOfTabs(tabs);
.getCurrentTabModelFilter()
.getTabsWithNoOtherRelatedTabs();
mResetHandler.resetWithListOfTabs(nonGroupedTabs);
mSelectionDelegate.setSelectionModeEnabledForZeroItems(true); mSelectionDelegate.setSelectionModeEnabledForZeroItems(true);
mModel.set(TabSelectionEditorProperties.IS_VISIBLE, true); mModel.set(TabSelectionEditorProperties.IS_VISIBLE, true);
} }
@Override
public void configureToolbar(@Nullable String actionButtonText,
@Nullable View.OnClickListener actionButtonOnClickListener,
int actionButtonEnablingThreshold,
@Nullable View.OnClickListener navigationButtonOnClickListener) {
if (actionButtonText != null) {
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_TEXT, actionButtonText);
}
if (actionButtonOnClickListener != null) {
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_LISTENER,
actionButtonOnClickListener);
}
if (actionButtonEnablingThreshold != -1) {
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD,
actionButtonEnablingThreshold);
}
if (navigationButtonOnClickListener != null) {
mModel.set(TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER,
navigationButtonOnClickListener);
}
}
@Override @Override
public boolean handleBackPressed() { public boolean handleBackPressed() {
if (!isEditorVisible()) return false; if (!isEditorVisible()) return false;
......
...@@ -18,9 +18,16 @@ public class TabSelectionEditorProperties { ...@@ -18,9 +18,16 @@ public class TabSelectionEditorProperties {
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel public static final PropertyModel
.WritableObjectPropertyKey<View.OnClickListener> TOOLBAR_GROUP_BUTTON_LISTENER = .WritableObjectPropertyKey<View.OnClickListener> TOOLBAR_ACTION_BUTTON_LISTENER =
new PropertyModel.WritableObjectPropertyKey<>(); new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel.WritableObjectPropertyKey<String> TOOLBAR_ACTION_BUTTON_TEXT =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel
.WritableIntPropertyKey TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD =
new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel public static final PropertyModel
.WritableObjectPropertyKey<View.OnClickListener> TOOLBAR_NAVIGATION_LISTENER = .WritableObjectPropertyKey<View.OnClickListener> TOOLBAR_NAVIGATION_LISTENER =
new PropertyModel.WritableObjectPropertyKey<>(); new PropertyModel.WritableObjectPropertyKey<>();
...@@ -39,6 +46,7 @@ public class TabSelectionEditorProperties { ...@@ -39,6 +46,7 @@ public class TabSelectionEditorProperties {
new PropertyModel.WritableIntPropertyKey(); new PropertyModel.WritableIntPropertyKey();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_VISIBLE, public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_VISIBLE,
TOOLBAR_GROUP_BUTTON_LISTENER, TOOLBAR_NAVIGATION_LISTENER, PRIMARY_COLOR, TOOLBAR_ACTION_BUTTON_LISTENER, TOOLBAR_ACTION_BUTTON_TEXT,
TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD, TOOLBAR_NAVIGATION_LISTENER, PRIMARY_COLOR,
TOOLBAR_BACKGROUND_COLOR, TOOLBAR_GROUP_BUTTON_TINT, TOOLBAR_TEXT_APPEARANCE}; TOOLBAR_BACKGROUND_COLOR, TOOLBAR_GROUP_BUTTON_TINT, TOOLBAR_TEXT_APPEARANCE};
} }
...@@ -27,6 +27,7 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> { ...@@ -27,6 +27,7 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> {
private Button mGroupButton; private Button mGroupButton;
@ColorInt @ColorInt
private int mBackgroundColor; private int mBackgroundColor;
private int mActionButtonEnablingThreshold = 2;
public TabSelectionEditorToolbar(Context context, AttributeSet attrs) { public TabSelectionEditorToolbar(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
...@@ -55,7 +56,7 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> { ...@@ -55,7 +56,7 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> {
@Override @Override
public void onSelectionStateChange(List<Integer> selectedItems) { public void onSelectionStateChange(List<Integer> selectedItems) {
super.onSelectionStateChange(selectedItems); super.onSelectionStateChange(selectedItems);
mGroupButton.setEnabled(selectedItems.size() > 1); mGroupButton.setEnabled(selectedItems.size() >= mActionButtonEnablingThreshold);
} }
@Override @Override
...@@ -110,4 +111,20 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> { ...@@ -110,4 +111,20 @@ class TabSelectionEditorToolbar extends SelectableListToolbar<Integer> {
public void setTextAppearance(int resId) { public void setTextAppearance(int resId) {
mNumberRollView.setTextAppearance(resId); mNumberRollView.setTextAppearance(resId);
} }
/**
* Set action button text.
* @param text The text to display.
*/
public void setActionButtonText(String text) {
mGroupButton.setText(text);
}
/**
* Set the action button enabling threshold.
* @param threshold New threshold.
*/
public void setActionButtonEnablingThreshold(int threshold) {
mActionButtonEnablingThreshold = threshold;
}
} }
...@@ -55,6 +55,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -55,6 +55,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
private final TabGridDialogCoordinator mTabGridDialogCoordinator; private final TabGridDialogCoordinator mTabGridDialogCoordinator;
private final TabSelectionEditorCoordinator mTabSelectionEditorCoordinator; private final TabSelectionEditorCoordinator mTabSelectionEditorCoordinator;
private final UndoGroupSnackbarController mUndoGroupSnackbarController; private final UndoGroupSnackbarController mUndoGroupSnackbarController;
private final TabModelSelector mTabModelSelector;
private final MenuOrKeyboardActionController private final MenuOrKeyboardActionController
.MenuOrKeyboardActionHandler mTabSwitcherMenuActionHandler = .MenuOrKeyboardActionHandler mTabSwitcherMenuActionHandler =
...@@ -62,7 +63,10 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -62,7 +63,10 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
@Override @Override
public boolean handleMenuOrKeyboardAction(int id, boolean fromMenu) { public boolean handleMenuOrKeyboardAction(int id, boolean fromMenu) {
if (id == R.id.menu_group_tabs) { if (id == R.id.menu_group_tabs) {
mTabSelectionEditorCoordinator.getController().show(); mTabSelectionEditorCoordinator.getController().show(
mTabModelSelector.getTabModelFilterProvider()
.getCurrentTabModelFilter()
.getTabsWithNoOtherRelatedTabs());
RecordUserAction.record("MobileMenuGroupTabs"); RecordUserAction.record("MobileMenuGroupTabs");
return true; return true;
} }
...@@ -78,6 +82,8 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -78,6 +82,8 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
MenuOrKeyboardActionController menuOrKeyboardActionController, MenuOrKeyboardActionController menuOrKeyboardActionController,
SnackbarManager.SnackbarManageable snackbarManageable, ViewGroup container, SnackbarManager.SnackbarManageable snackbarManageable, ViewGroup container,
@TabListCoordinator.TabListMode int mode) { @TabListCoordinator.TabListMode int mode) {
mTabModelSelector = tabModelSelector;
PropertyModel containerViewModel = new PropertyModel(TabListContainerProperties.ALL_KEYS); PropertyModel containerViewModel = new PropertyModel(TabListContainerProperties.ALL_KEYS);
mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator( mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(
......
// 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.support.annotation.NonNull;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.chrome.tab_ui.R;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ui.DummyUiActivityTestCase;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
/**
* Tests for {@link TabSelectionEditorLayoutBinder}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
public class TabSelectionEditorLayoutBinderTest extends DummyUiActivityTestCase {
private TabSelectionEditorLayout mEditorLayoutView;
private PropertyModel mModel = new PropertyModel(TabSelectionEditorProperties.ALL_KEYS);
private PropertyModelChangeProcessor mMCP;
private SelectionDelegate<Integer> mSelectionDelegate = new SelectionDelegate<>();
@Override
public void setUpTest() throws Exception {
super.setUpTest();
ViewGroup view = new LinearLayout(getActivity());
TestThreadUtils.runOnUiThreadBlocking(() -> {
getActivity().setContentView(view);
mEditorLayoutView =
(TabSelectionEditorLayout) getActivity().getLayoutInflater().inflate(
R.layout.tab_selection_editor_layout, null);
mEditorLayoutView.initialize(view, null, new RecyclerView.Adapter() {
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(
@NonNull ViewGroup viewGroup, int i) {
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {}
@Override
public int getItemCount() {
return 0;
}
}, mSelectionDelegate);
});
mMCP = PropertyModelChangeProcessor.create(
mModel, mEditorLayoutView, TabSelectionEditorLayoutBinder::bind);
}
@Override
public void tearDownTest() throws Exception {
mMCP.destroy();
super.tearDownTest();
}
@Test
@SmallTest
@UiThreadTest
public void testBindViews() {
// TODO(1005929): test other properties as well.
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_TEXT, "Test");
Assert.assertEquals("Test",
((TextView) mEditorLayoutView.findViewById(R.id.action_button))
.getText()
.toString());
}
@Test
@SmallTest
@UiThreadTest
public void testBindActionButtonClickListener() {
AtomicBoolean actionButtonClicked = new AtomicBoolean(false);
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_LISTENER,
v -> { actionButtonClicked.set(true); });
mEditorLayoutView.findViewById(R.id.action_button).performClick();
assertTrue(actionButtonClicked.get());
}
@Test
@MediumTest
@UiThreadTest
public void testActionButtonEnabling() {
Button button = mEditorLayoutView.findViewById(R.id.action_button);
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD, 1);
assertFalse(button.isEnabled());
HashSet<Integer> selectedItem = new HashSet<>(Arrays.asList(1));
mSelectionDelegate.setSelectedItems(selectedItem);
assertTrue(button.isEnabled());
mModel.set(TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD, 2);
mSelectionDelegate.setSelectedItems(selectedItem);
assertFalse(button.isEnabled());
}
}
\ No newline at end of file
...@@ -26,6 +26,7 @@ tab_management_test_java_sources = [ ...@@ -26,6 +26,7 @@ tab_management_test_java_sources = [
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorLayoutBinderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java",
] ]
......
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