Commit 155a0be4 authored by Vincent Boisselle's avatar Vincent Boisselle Committed by Commit Bot

Use a overflow menu in the feed header to manage feed settings

Change-Id: Ib2f8514e4c1c54cf92bb25c66109fbe3a243564f
Bug: 1075680
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2145249
Commit-Queue: Vincent Boisselle <vincb@google.com>
Reviewed-by: default avatarDan H <harringtond@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#763341}
parent 4eff6f7a
......@@ -1049,6 +1049,7 @@ chrome_java_resources = [
"java/res/layout/new_tab_page_offline_card.xml",
"java/res/layout/new_tab_page_progress_indicator.xml",
"java/res/layout/new_tab_page_snippets_expandable_header.xml",
"java/res/layout/new_tab_page_snippets_expandable_header_with_menu.xml",
"java/res/layout/new_tab_page_tile_grid_placeholder.xml",
"java/res/layout/new_tab_page_view.xml",
"java/res/layout/omnibox_answer_suggestion.xml",
......
......@@ -96,10 +96,10 @@ class ExploreSurfaceCoordinator implements FeedSurfaceCoordinator.FeedSurfaceDel
sectionHeaderView =
(SectionHeaderView) inflater.inflate(R.layout.ss_feed_header, null, false);
}
FeedSurfaceCoordinator feedSurfaceCoordinator =
new FeedSurfaceCoordinator(mActivity, mActivity.getSnackbarManager(),
mActivity.getTabModelSelector(), mActivity.getActivityTabProvider(), null,
null, sectionHeaderView, exploreSurfaceActionHandler, isInNightMode, this);
FeedSurfaceCoordinator feedSurfaceCoordinator = new FeedSurfaceCoordinator(mActivity,
mActivity.getSnackbarManager(), mActivity.getTabModelSelector(),
mActivity.getActivityTabProvider(), null, null, sectionHeaderView,
exploreSurfaceActionHandler, isInNightMode, this, null);
feedSurfaceCoordinator.getView().setId(R.id.start_surface_explore_view);
return feedSurfaceCoordinator;
// TODO(crbug.com/982018): Customize surface background for incognito and dark mode.
......
......@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.feed.action.FeedActionHandler;
import org.chromium.chrome.browser.feed.library.api.client.stream.Stream;
import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.native_page.ContextMenuManager;
......@@ -96,11 +97,21 @@ public class FeedNewTabPage
FeedProcessScopeFactory.getFeedLoggingBridge(), activity, profile);
LayoutInflater inflater = LayoutInflater.from(activity);
mNewTabPageLayout = (NewTabPageLayout) inflater.inflate(R.layout.new_tab_page_layout, null);
SectionHeaderView sectionHeaderView = (SectionHeaderView) inflater.inflate(
R.layout.new_tab_page_snippets_expandable_header, null, false);
// Determine the feed header to use.
final SectionHeaderView sectionHeaderView;
if (ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_HEADER_MENU)) {
sectionHeaderView = (SectionHeaderView) inflater.inflate(
R.layout.new_tab_page_snippets_expandable_header_with_menu, null, false);
} else {
sectionHeaderView = (SectionHeaderView) inflater.inflate(
R.layout.new_tab_page_snippets_expandable_header, null, false);
}
mCoordinator = new FeedSurfaceCoordinator(activity, snackbarManager, tabModelSelector,
tabProvider, new SnapScrollHelper(mNewTabPageManager, mNewTabPageLayout),
mNewTabPageLayout, sectionHeaderView, actionApi, isInNightMode, this);
mNewTabPageLayout, sectionHeaderView, actionApi, isInNightMode, this,
mNewTabPageManager.getNavigationDelegate());
// Record the timestamp at which the new tab page's construction started.
uma.trackTimeToFirstDraw(mCoordinator.getView(), mConstructedTimeNs);
......
......@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.feed.tooltip.BasicTooltipApi;
import org.chromium.chrome.browser.feed.v2.FeedStreamSurface;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.native_page.ContextMenuManager;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.ntp.NewTabPageLayout;
import org.chromium.chrome.browser.ntp.SnapScrollHelper;
import org.chromium.chrome.browser.ntp.snippets.SectionHeaderView;
......@@ -82,6 +83,7 @@ public class FeedSurfaceCoordinator {
private @Nullable SectionHeaderView mSectionHeaderView;
private @Nullable PersonalizedSigninPromoView mSigninPromoView;
private @Nullable ViewResizer mStreamViewResizer;
private @Nullable NativePageNavigationDelegate mPageNavigationDelegate;
// Used when Feed is disabled by policy.
private @Nullable ScrollView mScrollViewForPolicy;
......@@ -279,12 +281,15 @@ public class FeedSurfaceCoordinator {
* @param actionApi The {@link ActionApi} implementation to handle actions.
* @param showDarkBackground Whether is shown on dark background.
* @param delegate The constructing {@link FeedSurfaceDelegate}.
* @param pageNavigationDelegate The {@link NativePageNavigationDelegate}
* that handles page navigation.
*/
public FeedSurfaceCoordinator(Activity activity, SnackbarManager snackbarManager,
TabModelSelector tabModelSelector, Supplier<Tab> tabProvider,
@Nullable SnapScrollHelper snapScrollHelper, @Nullable View ntpHeader,
@Nullable SectionHeaderView sectionHeaderView, ActionApi actionApi,
boolean showDarkBackground, FeedSurfaceDelegate delegate) {
boolean showDarkBackground, FeedSurfaceDelegate delegate,
@Nullable NativePageNavigationDelegate pageNavigationDelegate) {
mActivity = activity;
mSnackbarManager = snackbarManager;
mNtpHeader = ntpHeader;
......@@ -292,6 +297,7 @@ public class FeedSurfaceCoordinator {
mActionApi = actionApi;
mShowDarkBackground = showDarkBackground;
mDelegate = delegate;
mPageNavigationDelegate = pageNavigationDelegate;
Resources resources = mActivity.getResources();
mDefaultMargin =
......@@ -303,7 +309,7 @@ public class FeedSurfaceCoordinator {
mUiConfig = new UiConfig(mRootView);
// Mediator should be created before any Stream changes.
mMediator = new FeedSurfaceMediator(this, snapScrollHelper);
mMediator = new FeedSurfaceMediator(this, snapScrollHelper, mPageNavigationDelegate);
// Native should already have been loaded because of FeedSurfaceMediator.
if (ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_V2)) {
......
......@@ -8,12 +8,16 @@ import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.chromium.chrome.test.util.ViewUtils.VIEW_NULL;
import static org.chromium.chrome.test.util.ViewUtils.waitForView;
......@@ -26,10 +30,13 @@ import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Swipe;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.filters.MediumTest;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
......@@ -37,6 +44,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterProvider;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
......@@ -52,7 +63,7 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.NewTabPageTestUtils;
......@@ -66,17 +77,18 @@ import org.chromium.components.signin.test.util.AccountManagerTestRule;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.EmbeddedTestServer;
import java.util.Collections;
import java.util.List;
/**
* Tests for {@link FeedNewTabPage} specifically. Other tests can be found in
* {@link org.chromium.chrome.browser.ntp.NewTabPageTest}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags
.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)
public class FeedNewTabPageTest {
@RunWith(ParameterizedRunner.class)
@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)
public class FeedNewTabPageTest {
private static final int ARTICLE_SECTION_HEADER_POSITION = 1;
private static final int SIGNIN_PROMO_POSITION = 2;
......@@ -95,15 +107,31 @@ import java.util.List;
@Rule
public AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
/** Parameter provider for enabling/disabling the signin promo card. */
public static class SigninPromoParams implements ParameterProvider {
@Override
public Iterable<ParameterSet> getParameters() {
return Collections.singletonList(
new ParameterSet().value(true).name("DisableSigninPromo"));
}
}
private Tab mTab;
private FeedNewTabPage mNtp;
private ViewGroup mTileGridLayout;
private FakeMostVisitedSites mMostVisitedSites;
private EmbeddedTestServer mTestServer;
private List<SiteSuggestion> mSiteSuggestions;
private boolean mDisableSigninPromoCard;
@ParameterAnnotations.UseMethodParameterBefore(SigninPromoParams.class)
public void disableSigninPromoCard(boolean disableSigninPromoCard) {
mDisableSigninPromoCard = disableSigninPromoCard;
}
@Before
public void setUp() {
SignInPromo.setDisablePromoForTests(mDisableSigninPromoCard);
mActivityTestRule.startMainActivityWithURL("about:blank");
mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
......@@ -128,6 +156,13 @@ import java.util.List;
FeedProcessScopeFactory.setTestNetworkClient(null);
}
private void waitForPopup(Matcher<View> matcher) {
View mainDecorView = mActivityTestRule.getActivity().getWindow().getDecorView();
onView(isRoot())
.inRoot(withDecorView(not(is(mainDecorView))))
.check(waitForView(matcher, ViewUtils.VIEW_VISIBLE));
}
@Test
@MediumTest
@Feature({"FeedNewTabPage"})
......@@ -235,6 +270,39 @@ import java.util.List;
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
}
@Test
@MediumTest
@Features.EnableFeatures(ChromeFeatureList.FEED_HEADER_MENU)
@Feature({"NewTabPage", "FeedNewTabPage"})
@ParameterAnnotations.UseMethodParameter(SigninPromoParams.class)
public void testArticleSectionHeaderWithMenu(boolean disableSigninPromoCard) throws Exception {
// Scroll to the article section header in case it is not visible.
onView(instanceOf(RecyclerView.class))
.perform(RecyclerViewActions.scrollToPosition(ARTICLE_SECTION_HEADER_POSITION));
waitForView((ViewGroup) mNtp.getView(), allOf(withId(R.id.header_title), isDisplayed()));
View sectionHeaderView = mNtp.getSectionHeaderViewForTesting();
TextView headerStatusView = sectionHeaderView.findViewById(R.id.header_title);
// Assert that the feed is expanded and that the header title text is correct.
Assert.assertTrue(mNtp.getMediatorForTesting().getSectionHeaderForTesting().isExpanded());
Assert.assertEquals(sectionHeaderView.getContext().getString(R.string.ntp_discover_on),
headerStatusView.getText());
// Toggle header on the current tab.
onView(withId(R.id.header_menu)).perform(click());
View mainDecorView = mActivityTestRule.getActivity().getWindow().getDecorView();
waitForPopup(withText(R.string.ntp_turn_off_feed));
onView(withText(R.string.ntp_turn_off_feed))
.inRoot(withDecorView(not(is(mainDecorView))))
.perform(click());
// Assert that the feed is collapsed and that the header title text is correct.
Assert.assertFalse(mNtp.getMediatorForTesting().getSectionHeaderForTesting().isExpanded());
Assert.assertEquals(sectionHeaderView.getContext().getString(R.string.ntp_discover_off),
headerStatusView.getText());
}
@Test
@MediumTest
@Feature({"FeedNewTabPage"})
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 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.
-->
<org.chromium.chrome.browser.ntp.snippets.SectionHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/snippets_article_header_height"
android:orientation="horizontal"
android:paddingStart="@dimen/card_padding"
android:gravity="center_vertical">
<TextView
android:id="@+id/header_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.TextSmall.Secondary" />
<org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
android:id="@+id/header_menu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="@dimen/default_list_row_padding"
android:paddingEnd="@dimen/default_list_row_padding"
android:background="@null"
android:src="@drawable/ic_more_vert_24dp"
app:tint="@color/default_icon_color_tint_list"
tools:ignore="ContentDescription" />
</org.chromium.chrome.browser.ntp.snippets.SectionHeaderView>
......@@ -119,4 +119,10 @@
<item type="id" name="item_animator" />
<item type="id" name="highlight_color" />
<item type="id" name="context_menu_delegate" />
<!-- NTP-->
<item type="id" name="ntp_feed_header_menu_item_activity" />
<item type="id" name="ntp_feed_header_menu_item_interest" />
<item type="id" name="ntp_feed_header_menu_item_learn" />
<item type="id" name="ntp_feed_header_menu_item_toggle_switch" />
</resources>
......@@ -7,10 +7,13 @@ package org.chromium.chrome.browser.ntp.snippets;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.chromium.chrome.browser.ntp.cards.ItemViewType;
import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
import org.chromium.chrome.browser.ntp.cards.OptionalLeaf;
import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
/**
* Represents the data for a header of a group of snippets.
......@@ -19,6 +22,13 @@ public class SectionHeader extends OptionalLeaf {
/** The header text to be shown. */
private String mHeaderText;
/** The model of the menu items to show in the overflow menu to manage the feed. */
@Nullable
private ModelList mMenuModelList;
@Nullable
private ListMenu.Delegate mListMenuDelegate;
private Runnable mToggleCallback;
private boolean mIsExpanded;
......@@ -60,6 +70,22 @@ public class SectionHeader extends OptionalLeaf {
notifyItemChanged(0, SectionHeaderViewHolder::updateVisuals);
}
public ModelList getMenuModelList() {
return mMenuModelList;
}
public void setMenuModelList(ModelList modelList) {
mMenuModelList = modelList;
}
public ListMenu.Delegate getListMenuDelegate() {
return mListMenuDelegate;
}
public void setListMenuDelegate(ListMenu.Delegate delegate) {
mListMenuDelegate = delegate;
}
/**
* @return Whether or not the header is expandable.
*/
......
......@@ -14,14 +14,29 @@ import androidx.annotation.Nullable;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.suggestions.SuggestionsMetrics;
import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.widget.RectProvider;
import org.chromium.ui.widget.ViewRectProvider;
/**
* View for the header of a section of cards.
* View for the header of the personalized feed that has a context menu to
* manage the feed.
*/
public class SectionHeaderView extends LinearLayout implements View.OnClickListener {
// Views in the header layout that are set during inflate.
private TextView mTitleView;
private TextView mStatusView;
private @Nullable SectionHeader mHeader;
private ListMenuButton mMenuView;
// Properties that are set after construction & inflate using setters.
@Nullable
private SectionHeader mHeader;
private boolean mHasMenu;
public SectionHeaderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
......@@ -31,8 +46,17 @@ public class SectionHeaderView extends LinearLayout implements View.OnClickListe
protected void onFinishInflate() {
super.onFinishInflate();
mTitleView = findViewById(org.chromium.chrome.R.id.header_title);
mStatusView = findViewById(org.chromium.chrome.R.id.header_status);
mTitleView = findViewById(R.id.header_title);
mStatusView = findViewById(R.id.header_status);
mMenuView = findViewById(R.id.header_menu);
// Use the menu instead of the status text when the menu is available from the inflated
// layout.
mHasMenu = mMenuView != null;
if (mHasMenu) {
mMenuView.setOnClickListener((View v) -> { displayMenu(); });
}
}
@Override
......@@ -48,6 +72,13 @@ public class SectionHeaderView extends LinearLayout implements View.OnClickListe
mHeader = header;
if (mHeader == null) return;
// Set visuals with the menu view when present.
if (mHasMenu) {
updateVisuals();
return;
}
// Set visuals with the status view when no menu.
mStatusView.setVisibility(mHeader.isExpandable() ? View.VISIBLE : View.GONE);
updateVisuals();
setOnClickListener(mHeader.isExpandable() ? this : null);
......@@ -60,9 +91,51 @@ public class SectionHeaderView extends LinearLayout implements View.OnClickListe
mTitleView.setText(mHeader.getHeaderText());
if (mHeader.isExpandable()) {
mStatusView.setText(mHeader.isExpanded() ? R.string.hide : R.string.show);
if (!mHasMenu) {
mStatusView.setText(mHeader.isExpanded() ? R.string.hide : R.string.show);
}
setBackgroundResource(
mHeader.isExpanded() ? 0 : R.drawable.hairline_border_card_background);
}
}
private void displayMenu() {
if (mMenuView == null) {
assert false : "No menu view to display the menu";
return;
}
ModelList listItems = mHeader.getMenuModelList();
if (listItems == null) {
assert false : "No list items model to display the menu";
return;
}
ListMenu.Delegate listMenuDelegate = mHeader.getListMenuDelegate();
if (listMenuDelegate == null) {
assert false : "No list menu delegate for the menu";
return;
}
BasicListMenu listMenu =
new BasicListMenu(mMenuView.getContext(), listItems, listMenuDelegate);
ListMenuButtonDelegate delegate = new ListMenuButtonDelegate() {
@Override
public ListMenu getListMenu() {
return listMenu;
}
@Override
public RectProvider getRectProvider(View listMenuButton) {
ViewRectProvider rectProvider = new ViewRectProvider(listMenuButton);
rectProvider.setIncludePadding(true);
rectProvider.setInsetPx(0, 0, 0, 0);
return rectProvider;
}
};
mMenuView.setDelegate(delegate);
mMenuView.showMenu();
}
}
......@@ -8,6 +8,7 @@ import android.content.res.Resources;
import android.view.LayoutInflater;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
......@@ -20,8 +21,10 @@ public class SectionHeaderViewHolder extends NewTabPageViewHolder {
public SectionHeaderViewHolder(final SuggestionsRecyclerView recyclerView, UiConfig config) {
super(LayoutInflater.from(recyclerView.getContext())
.inflate(R.layout.new_tab_page_snippets_expandable_header, recyclerView,
false));
.inflate(ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_HEADER_MENU)
? R.layout.new_tab_page_snippets_expandable_header_with_menu
: R.layout.new_tab_page_snippets_expandable_header,
recyclerView, false));
mSectionHeaderView = (SectionHeaderView) itemView;
Resources resources = recyclerView.getResources();
......
......@@ -95,6 +95,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&feed::kInterestFeedFeedback,
&feed::kInterestFeedV2,
&feed::kReportFeedUserActions,
&feed::kFeedHeaderMenu,
&kAdjustWebApkInstallationSpace,
&kAllowNewIncognitoTabIntents,
&kAllowRemoteContextForNotifications,
......
......@@ -275,6 +275,7 @@ public abstract class ChromeFeatureList {
public static final String EPHEMERAL_TAB_USING_BOTTOM_SHEET = "EphemeralTabUsingBottomSheet";
public static final String EXPLICIT_LANGUAGE_ASK = "ExplicitLanguageAsk";
public static final String EXPLORE_SITES = "ExploreSites";
public static final String FEED_HEADER_MENU = "FeedHeaderMenu";
public static final String FOCUS_OMNIBOX_IN_INCOGNITO_TAB_INTENTS =
"FocusOmniboxInIncognitoTabIntents";
public static final String GRANT_NOTIFICATIONS_TO_DSE = "GrantNotificationsToDSE";
......
......@@ -2295,6 +2295,24 @@ To change this setting, <ph name="BEGIN_LINK">&lt;resetlink&gt;</ph>reset sync<p
<message name="IDS_NTP_SUGGESTIONS_FETCH_NO_NEW_SUGGESTIONS" desc="Snackbar text shown when the user presses the More button to get more suggestions, the fetch succeeds but provides no new suggestions.">
No new suggestions
</message>
<message name="IDS_NTP_MANAGE_MY_ACTIVITY" desc="Content description to manage my activity from the feed header overflow menu.">
Manage activity
</message>
<message name="IDS_NTP_MANAGE_INTERESTS" desc="Content description to manage settings from the feed header overflow menu.">
Manage interests
</message>
<message name="IDS_NTP_TURN_OFF_FEED" desc="Content description to turn off the feed from the feed header overflow menu.">
Turn off
</message>
<message name="IDS_NTP_TURN_ON_FEED" desc="Content description to turn on the feed from the feed header overflow menu.">
Turn on
</message>
<message name="IDS_NTP_DISCOVER_ON" desc="Title in the feed header when the feed is turned on.">
Discover
</message>
<message name="IDS_NTP_DISCOVER_OFF" desc="Title in the feed header when the feed is turned off.">
Discover - off
</message>
<!-- Explore sites strings -->
<message name="IDS_EXPLORE_SITES_TITLE" desc="Title of a section showing different categories, each with a number of popular websites">
......
5eb377ee9b03dc495d26a0e4ab3e5f5bc8ecf8fa
\ No newline at end of file
b50a0477ecd0de8710fdcba36b0e1e853fe2322c
\ No newline at end of file
7986ee4e0b976b2e72ee2815c06482e2259b5c65
\ No newline at end of file
e28c630238abf328ccbb631bcefa90c973f9503c
\ No newline at end of file
a158e708eff8220880c91d7f2b9477ae002975c9
\ No newline at end of file
cb5e04ce299f66d3426a2875e6891c5223ee13c3
\ No newline at end of file
......@@ -33,4 +33,9 @@ const base::Feature kReportFeedUserActions{"ReportFeedUserActions",
const base::Feature kInterestFeedV2{"InterestFeedV2",
base::FEATURE_DISABLED_BY_DEFAULT};
// Use a contextual menu in the feed header positioned on the right to manage
// the feed that replaces the status text.
const base::Feature kFeedHeaderMenu{"FeedHeaderMenu",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace feed
......@@ -30,6 +30,8 @@ extern const base::Feature kReportFeedUserActions;
extern const base::Feature kInterestFeedV2;
extern const base::Feature kFeedHeaderMenu;
} // namespace feed
#endif // COMPONENTS_FEED_FEED_FEATURE_LIST_H_
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