[iOS][TGS][1/N] Show snackbar when closing tab groups

This CL shows a snackbar when closing a group from the tab grid view.
Tapping on the CTA opens the Tab Groups panel.

Bug: 358351829
Change-Id: I34860cc127fc635488d057ac4c5921be2150825f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5777142
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Ewann Pellé <ewannpv@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1340835}
diff --git a/ios/chrome/browser/shared/public/commands/tab_grid_commands.h b/ios/chrome/browser/shared/public/commands/tab_grid_commands.h
index 448b773..4a339943 100644
--- a/ios/chrome/browser/shared/public/commands/tab_grid_commands.h
+++ b/ios/chrome/browser/shared/public/commands/tab_grid_commands.h
@@ -23,6 +23,9 @@
 // Shows the recent tabs panel searching for `text`.
 - (void)showRecentTabsForText:(NSString*)text;
 
+// Shows the tab groups panel.
+- (void)showTabGroupsPanel;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_TAB_GRID_COMMANDS_H_
diff --git a/ios/chrome/browser/shared/public/commands/tab_groups_commands.h b/ios/chrome/browser/shared/public/commands/tab_groups_commands.h
index 213f4327..ca1df4d 100644
--- a/ios/chrome/browser/shared/public/commands/tab_groups_commands.h
+++ b/ios/chrome/browser/shared/public/commands/tab_groups_commands.h
@@ -48,6 +48,9 @@
                                     group:(const TabGroup*)tabGroup
                          sourceButtonItem:(UIBarButtonItem*)sourceButtonItem;
 
+// Displays a snackbar after closing tab groups locally.
+- (void)showTabGroupSnackbarAfterClosingGroups:(int)numberOfClosedGroups;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_TAB_GROUPS_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/BUILD.gn
index 9de708a..fb1fb83 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/BUILD.gn
@@ -15,8 +15,10 @@
     ":grid_ui",
     ":tab_group_grid_ui",
     "//base",
+    "//components/feature_engagement/public",
     "//components/strings",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/feature_engagement/model",
     "//ios/chrome/browser/shared/coordinator/alert",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/model/browser",
@@ -24,12 +26,14 @@
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/public/features",
+    "//ios/chrome/browser/shared/ui/util:snackbar_util",
     "//ios/chrome/browser/ui/tab_switcher:tab_group_confirmation",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu:tab_item",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/tab_groups",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/tab_groups:tab_group_creation",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/tab_groups:tab_groups_ui",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/transitions",
+    "//ios/third_party/material_components_ios",
     "//ios/web/public",
   ]
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_coordinator.mm
index 82af6be..4cb6cdc8 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_coordinator.mm
@@ -2,16 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#import <MaterialComponents/MaterialSnackbar.h>
+
 #import "base/check.h"
+#import "base/strings/sys_string_conversions.h"
+#import "components/feature_engagement/public/feature_constants.h"
+#import "components/feature_engagement/public/tracker.h"
 #import "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/shared/model/web_state_list/tab_group.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
+#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
 #import "ios/chrome/browser/shared/public/commands/tab_grid_commands.h"
 #import "ios/chrome/browser/shared/public/commands/tab_grid_toolbar_commands.h"
 #import "ios/chrome/browser/shared/public/commands/tab_group_confirmation_commands.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
+#import "ios/chrome/browser/shared/ui/util/snackbar_util.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_view_controller.h"
@@ -311,6 +319,43 @@
       self.browser->GetCommandDispatcher(), TabGroupConfirmationCommands);
 }
 
+- (void)showTabGroupSnackbarAfterClosingGroups:(int)numberOfClosedGroups {
+  if (!IsTabGroupSyncEnabled()) {
+    return;
+  }
+
+  // Don't show the snackbar if the IPH will be presented.
+  feature_engagement::Tracker* tracker =
+      feature_engagement::TrackerFactory::GetForBrowserState(
+          self.browser->GetBrowserState());
+  if (tracker->WouldTriggerHelpUI(
+          feature_engagement::kIPHiOSSavedTabGroupClosed)) {
+    return;
+  }
+
+  // Create the "Open Tab Groups" action.
+  CommandDispatcher* dispatcher = self.browser->GetCommandDispatcher();
+  __weak id<TabGridCommands> tabGridHandler =
+      HandlerForProtocol(dispatcher, TabGridCommands);
+  void (^openTabGroupPanelAction)() = ^{
+    [tabGridHandler showTabGroupsPanel];
+  };
+
+  // Create and config the snackbar.
+  NSString* messageLabel =
+      base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
+          IDS_IOS_TAB_GROUP_SNACKBAR_LABEL, numberOfClosedGroups));
+  MDCSnackbarMessage* message = CreateSnackbarMessage(messageLabel);
+  MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init];
+  action.handler = openTabGroupPanelAction;
+  action.title = l10n_util::GetNSString(IDS_IOS_TAB_GROUP_SNACKBAR_ACTION);
+  message.action = action;
+
+  id<SnackbarCommands> snackbarCommandsHandler =
+      HandlerForProtocol(dispatcher, SnackbarCommands);
+  [snackbarCommandsHandler showSnackbarMessage:message];
+}
+
 #pragma mark - CreateOrEditTabGroupCoordinatorDelegate
 
 - (void)createOrEditTabGroupCoordinatorDidDismiss:
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm
index 8931727..197bfd9 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/base_grid_mediator.mm
@@ -453,7 +453,7 @@
   }
 
   if (IsTabGroupSyncEnabled() && !deleteGroup) {
-    // TODO(crbug.com/329627077): Add a mechanism to show it only once.
+    [self.tabGroupsHandler showTabGroupSnackbarAfterClosingGroups:1];
     [self.tabGridToolbarHandler showSavedTabGroupIPH];
     tab_groups::TabGroupSyncService* syncService =
         tab_groups::TabGroupSyncServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index 0796b2d6..f48d8609 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -1642,6 +1642,12 @@
                                                animated:YES];
 }
 
+- (void)showTabGroupsPanel {
+  CHECK(IsTabGroupSyncEnabled());
+  [self.baseViewController setCurrentPageAndPageControl:TabGridPageTabGroups
+                                               animated:YES];
+}
+
 #pragma mark - SnackbarCoordinatorDelegate
 
 - (CGFloat)snackbarCoordinatorBottomOffsetForCurrentlyPresentedView: