blob: ed1c28fdadf4c41cd7431ef58ed68131680e2aa3 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_SEARCH_CONTAINER_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_SEARCH_CONTAINER_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/tabs/organization/tab_declutter_controller.h"
#include "chrome/browser/ui/tabs/organization/tab_declutter_observer.h"
#include "chrome/browser/ui/tabs/organization/tab_organization_observer.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/views/animation/animation_delegate_views.h"
#include "ui/views/mouse_watcher.h"
#include "ui/views/view.h"
enum class Edge;
class BrowserWindowInterface;
class TabStripNudgeButton;
class TabOrganizationService;
class TabSearchButton;
class TabStripController;
class TabStrip;
enum class LockedExpansionMode {
kNone = 0,
kWillShow,
kWillHide,
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(DeclutterTriggerCTRBucket)
enum class DeclutterTriggerCTRBucket {
kShownUnder15Tabs = 0,
kShown15To19TabsUnder2Stale = 1,
kShown15To19Tabs2To4Stale = 2,
kShown15To19Tabs5To7Stale = 3,
kShown15To19TabsOver7Stale = 4,
kShown20To24TabsUnder2Stale = 5,
kShown20To24Tabs2To4Stale = 6,
kShown20To24Tabs5To7Stale = 7,
kShown20To24TabsOver7Stale = 8,
kShownOver24Tabs = 9,
kClickedUnder15Tabs = 10,
kClicked15To19TabsUnder2Stale = 11,
kClicked15To19Tabs2To4Stale = 12,
kClicked15To19Tabs5To7Stale = 13,
kClicked15To19TabsOver7Stale = 14,
kClicked20To24TabsUnder2Stale = 15,
kClicked20To24Tabs2To4Stale = 16,
kClicked20To24Tabs5To7Stale = 17,
kClicked20To24TabsOver7Stale = 18,
kClickedOver24Tabs = 19,
kMaxValue = kClickedOver24Tabs,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/tab/enums.xml:TabOrganizationDeclutterTriggerCTRBucket)
class TabSearchContainer : public views::View,
public views::AnimationDelegateViews,
public TabOrganizationObserver,
public TabDeclutterObserver,
public views::MouseWatcherListener {
METADATA_HEADER(TabSearchContainer, views::View)
public:
class TabOrganizationAnimationSession {
public:
enum class AnimationSessionType { SHOW, HIDE };
TabOrganizationAnimationSession(
TabStripNudgeButton* button,
TabSearchContainer* container,
AnimationSessionType session_type,
base::OnceCallback<void()> on_animation_ended);
~TabOrganizationAnimationSession();
void ApplyAnimationValue(const gfx::Animation* animation);
void MarkAnimationDone(const gfx::Animation* animation);
void Start();
AnimationSessionType session_type() { return session_type_; }
gfx::SlideAnimation* expansion_animation() { return &expansion_animation_; }
void ResetExpansionAnimationForTesting(double value);
void ResetOpacityAnimationForTesting(double value);
void ResetFlatEdgeAnimationForTesting(double value);
void Hide();
TabStripNudgeButton* button() { return button_; }
private:
void ShowOpacityAnimation();
void Show();
raw_ptr<TabStripNudgeButton> button_;
raw_ptr<TabSearchContainer> container_;
gfx::SlideAnimation expansion_animation_;
gfx::SlideAnimation flat_edge_animation_;
gfx::SlideAnimation opacity_animation_;
bool expansion_animation_done_ = false;
bool flat_edge_animation_done_ = false;
bool opacity_animation_done_ = false;
AnimationSessionType session_type_;
// Timer for initiating the opacity animation during show.
base::OneShotTimer opacity_animation_delay_timer_;
// Callback to container after animation has ended.
base::OnceCallback<void()> on_animation_ended_;
};
// TODO(382097906): Pull tabslotcontroller out of tabstrip and pass
// that instead.
TabSearchContainer(TabStripController* tab_strip_controller,
TabStripModel* tab_strip_model,
bool tab_search_before_chips,
View* locked_expansion_view,
BrowserWindowInterface* browser_window_interface,
tabs::TabDeclutterController* tab_declutter_controller,
TabStrip* tab_strip);
TabSearchContainer(const TabSearchContainer&) = delete;
TabSearchContainer& operator=(const TabSearchContainer&) = delete;
~TabSearchContainer() override;
TabStripNudgeButton* auto_tab_group_button() {
return auto_tab_group_button_;
}
TabStripNudgeButton* tab_declutter_button() { return tab_declutter_button_; }
TabSearchButton* tab_search_button() { return tab_search_button_; }
TabOrganizationAnimationSession* animation_session_for_testing() {
return animation_session_.get();
}
TabOrganizationService* tab_organization_service_for_testing() {
return tab_organization_service_;
}
void ShowTabOrganization(TabStripNudgeButton* button);
void HideTabOrganization(TabStripNudgeButton* button);
void SetLockedExpansionModeForTesting(LockedExpansionMode mode,
TabStripNudgeButton* button);
void OnAutoTabGroupButtonClicked();
void OnAutoTabGroupButtonDismissed();
void OnTabDeclutterButtonClicked();
void OnTabDeclutterButtonDismissed();
void OnOrganizeButtonTimeout(TabStripNudgeButton* button);
// views::MouseWatcherListener:
void MouseMovedOutOfHost() override;
// views::AnimationDelegateViews
void AnimationCanceled(const gfx::Animation* animation) override;
void AnimationEnded(const gfx::Animation* animation) override;
void AnimationProgressed(const gfx::Animation* animation) override;
// TabOrganizationObserver
void OnToggleActionUIState(const Browser* browser, bool should_show) override;
// TabDeclutterObserver
void OnTriggerDeclutterUIVisibility() override;
private:
void SetLockedExpansionMode(LockedExpansionMode mode,
TabStripNudgeButton* button);
void ExecuteShowTabOrganization(TabStripNudgeButton* button);
void ExecuteHideTabOrganization(TabStripNudgeButton* button);
void OnAnimationSessionEnded();
std::unique_ptr<TabStripNudgeButton> CreateAutoTabGroupButton(
TabStripController* tab_strip_controller,
bool tab_search_before_chips);
std::unique_ptr<TabStripNudgeButton> CreateTabDeclutterButton(
TabStripController* tab_strip_controller,
bool tab_search_before_chips);
void SetupButtonProperties(TabStripNudgeButton* button,
bool tab_search_before_chips);
DeclutterTriggerCTRBucket GetDeclutterTriggerBucket(bool clicked);
void LogDeclutterTriggerBucket(bool clicked);
// View where, if the mouse is currently over its bounds, the expansion state
// will not change. Changes will be staged until after the mouse exits the
// bounds of this View.
raw_ptr<View, DanglingUntriaged> locked_expansion_view_;
// The button currently holding the lock to be shown/hidden.
raw_ptr<TabStripNudgeButton> locked_expansion_button_ = nullptr;
raw_ptr<TabStripNudgeButton, DanglingUntriaged> auto_tab_group_button_ =
nullptr;
raw_ptr<TabStripNudgeButton> tab_declutter_button_ = nullptr;
raw_ptr<TabSearchButton, DanglingUntriaged> tab_search_button_ = nullptr;
raw_ptr<TabOrganizationService, DanglingUntriaged> tab_organization_service_ =
nullptr;
raw_ptr<tabs::TabDeclutterController> tab_declutter_controller_;
raw_ptr<const Browser> browser_;
const raw_ptr<TabStripModel> tab_strip_model_;
// Timer for hiding tab_organization_button_ after show.
base::OneShotTimer hide_tab_organization_timer_;
// When locked, the container is unable to change its expanded state. Changes
// will be staged until after this is unlocked.
LockedExpansionMode locked_expansion_mode_ = LockedExpansionMode::kNone;
// MouseWatcher is used to lock and unlock the expansion state of this
// container.
std::unique_ptr<views::MouseWatcher> mouse_watcher_;
base::ScopedObservation<TabOrganizationService, TabOrganizationObserver>
tab_organization_observation_{this};
base::ScopedObservation<tabs::TabDeclutterController, TabDeclutterObserver>
tab_declutter_observation_{this};
// Prevents other features from showing tabstrip-modal UI.
std::unique_ptr<ScopedTabStripModalUI> scoped_tab_strip_modal_ui_;
std::unique_ptr<TabOrganizationAnimationSession> animation_session_;
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_SEARCH_CONTAINER_H_