[NTP XDTR] Add dismiss button

Added dismiss button. Module will be hidden until a new tab is available
to be shown.

Screenshot: http://screenshot/3fkRbHVkAMRcEyh

Bug: 1523652
Change-Id: I54457aec0d01ac796e5378b4a3b76d7ab01a40e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5249518
Commit-Queue: Marlon Facey <[email protected]>
Reviewed-by: Nico Weber <[email protected]>
Reviewed-by: Roman Arora <[email protected]>
Reviewed-by: Ken Buchanan <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1258058}
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom
index 1464441..04520a8 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom
@@ -9,4 +9,10 @@
 interface PageHandler {
   // Queries for tabs.
   GetTabs() => (array<history.mojom.Tab> tabs);
+
+  // Dismisses module until new tabs are found.
+  DismissModule(array<url.mojom.Url> urls);
+
+  // Restores the module immediately.
+  RestoreModule();
 };
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
index 8bf9bce..c776bb9 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
@@ -46,6 +46,8 @@
 namespace {
 // Maximum number of sessions we're going to display on the NTP
 const size_t kMaxSessionsToShow = 10;
+// Name of preference to track list of dismissed tabs.
+const char kDismissedTabsPrefName[] = "NewTabPage.TabResumption.DismissedTabs";
 
 std::u16string FormatRelativeTime(const base::Time& time) {
   // Return a time like "1 hour ago", "2 days ago", etc.
@@ -193,8 +195,19 @@
     }
   }
 
-  for (auto i : scored_tab_indices) {
-    scored_tabs.push_back(std::move(tabs[i]));
+  bool new_url_found = false;
+  for (auto index : scored_tab_indices) {
+    if (IsNewURL(tabs[index]->url)) {
+      new_url_found = true;
+    }
+    scored_tabs.push_back(std::move(tabs[index]));
+  }
+
+  // Bail if module is still dismissed.
+  if (profile_->GetPrefs()->GetList(kDismissedTabsPrefName).size() > 0 &&
+      !new_url_found) {
+    std::move(callback).Run(std::vector<history::mojom::TabPtr>());
+    return;
   }
 
   std::sort(scored_tabs.begin(), scored_tabs.end(), CompareTabsByTime);
@@ -239,6 +252,12 @@
 }
 
 // static
+void TabResumptionPageHandler::RegisterProfilePrefs(
+    PrefRegistrySimple* registry) {
+  registry->RegisterListPref(kDismissedTabsPrefName, base::Value::List());
+}
+
+// static
 sync_sessions::OpenTabsUIDelegate*
 TabResumptionPageHandler::GetOpenTabsUIDelegate() {
   sync_sessions::SessionSyncService* service =
@@ -278,3 +297,28 @@
   }
   return tabs_mojom;
 }
+
+void TabResumptionPageHandler::DismissModule(const std::vector<GURL>& urls) {
+  base::Value::List url_list;
+  for (const auto& url : urls) {
+    url_list.Append(url.spec());
+  }
+  profile_->GetPrefs()->SetList(kDismissedTabsPrefName, std::move(url_list));
+}
+
+void TabResumptionPageHandler::RestoreModule() {
+  profile_->GetPrefs()->SetList(kDismissedTabsPrefName, base::Value::List());
+}
+
+bool TabResumptionPageHandler::IsNewURL(GURL url) {
+  const base::Value::List& cached_urls =
+      profile_->GetPrefs()->GetList(kDismissedTabsPrefName);
+  auto it = std::find_if(cached_urls.begin(), cached_urls.end(),
+                         [url](const base::Value& cached_url) {
+                           return cached_url.GetString() == url.spec();
+                         });
+  if (it == cached_urls.end()) {
+    return true;
+  }
+  return false;
+}
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
index 9f2a3ba..831474e5 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/history/profile_based_browsing_history_driver.h"
 #include "chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -47,6 +48,8 @@
   // tab_resumption::mojom::PageHandler:
   void GetTabs(GetTabsCallback callback) override;
 
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
   sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate();
 
   std::vector<history::mojom::TabPtr> GetForeignTabs();
@@ -63,7 +66,13 @@
       GetTabsCallback callback,
       const std::vector<history::AnnotatedVisit> annotated_visits);
 
+  void DismissModule(const std::vector<GURL>& urls) override;
+  void RestoreModule() override;
+
  private:
+  // Method to determine if a url is in the list of previously dismissed urls.
+  bool IsNewURL(GURL url);
+
   // The task tracker for the HistoryService callbacks.
   base::CancelableTaskTracker task_tracker_;
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 690f748..8e10086 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -281,6 +281,7 @@
 #include "chrome/browser/new_tab_page/modules/photos/photos_service.h"
 #include "chrome/browser/new_tab_page/modules/recipes/recipes_service.h"
 #include "chrome/browser/new_tab_page/modules/safe_browsing/safe_browsing_handler.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h"
 #include "chrome/browser/new_tab_page/promos/promo_service.h"
 #include "chrome/browser/policy/developer_tools_policy_handler.h"
 #include "chrome/browser/search/background/ntp_custom_background_service.h"
@@ -1865,6 +1866,7 @@
   send_tab_to_self::RegisterProfilePrefs(registry);
   signin::RegisterProfilePrefs(registry);
   StartupBrowserCreator::RegisterProfilePrefs(registry);
+  TabResumptionPageHandler::RegisterProfilePrefs(registry);
   tab_organization_prefs::RegisterProfilePrefs(registry);
   tab_search_prefs::RegisterProfilePrefs(registry);
   ThemeColorPickerHandler::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.html b/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.html
index 3511ed4..9e4543b 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.html
@@ -125,6 +125,7 @@
                                   'modulesMoreActions',
                                   'modulesDriveSentence')]]"
     on-disable-button-click="onDisableButtonClick_"
+    on-dismiss-button-click="onDismissButtonClick_"
     on-info-button-click="onInfoButtonClick_"
     on-menu-button-click="onMenuButtonClick_">
 </ntp-module-header-v2>
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.ts b/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.ts
index c3e5584..66b53ae 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_resumption/module.ts
@@ -53,6 +53,11 @@
     return [
       [
         {
+          action: 'dismiss',
+          icon: 'modules:thumb_down',
+          text: this.i18n('modulesTabResumptionDismissButton'),
+        },
+        {
           action: 'disable',
           icon: 'modules:block',
           text: this.i18nRecursive(
@@ -109,6 +114,22 @@
         },
         Number(e.model.item.relativeTime.microseconds / 1000n));
   }
+
+  private onDismissButtonClick_() {
+    const urls = this.tabs.map((tab: Tab) => tab.url);
+    TabResumptionProxyImpl.getInstance().handler.dismissModule(urls);
+    this.dispatchEvent(new CustomEvent('dismiss-module-instance', {
+      bubbles: true,
+      composed: true,
+      detail: {
+        message: loadTimeData.getStringF(
+            'dismissModuleToastMessage',
+            loadTimeData.getString('modulesTabResumptionSentence')),
+        restoreCallback: () =>
+            TabResumptionProxyImpl.getInstance().handler.restoreModule(),
+      },
+    }));
+  }
 }
 
 customElements.define(
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index e1c366c..29f5386 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -548,8 +548,11 @@
       {"modulesJourneysCartTileLabelDefault",
        IDS_NTP_MODULES_QUEST_CART_TILE_LABEL_DEFAULT},
       {"modulesMoreActions", IDS_NTP_MODULES_MORE_ACTIONS},
+      {"modulesTabResumptionDismissButton",
+       IDS_NTP_MODULES_TAB_RESUMPTION_DISMISS_BUTTON},
       {"modulesTabResumptionTitle", IDS_NTP_TAB_RESUMPTION_TITLE},
       {"modulesTabResumptionInfo", IDS_NTP_MODULES_TAB_RESUMPTION_INFO},
+      {"modulesTabResumptionSentence", IDS_NTP_MODULES_TAB_RESUMPTION_SENTENCE},
 
       // Middle slot promo.
       {"undoDismissPromoButtonToast", IDS_NTP_UNDO_DISMISS_PROMO_BUTTON_TOAST},