diff --git a/browser/ui/sidebar/sidebar_browsertest.cc b/browser/ui/sidebar/sidebar_browsertest.cc index 9e222f0bd5e..bae7b9f9274 100644 --- a/browser/ui/sidebar/sidebar_browsertest.cc +++ b/browser/ui/sidebar/sidebar_browsertest.cc @@ -2223,6 +2223,101 @@ IN_PROC_BROWSER_TEST_F(SidebarBrowserTest, << "No-border resize area width should equal kNoBorderResizeAreaWidth"; } +class ScopedSidePanelUIForTesting { + public: + ScopedSidePanelUIForTesting(SidebarController* controller, SidePanelUI* ui) + : controller_(controller) { + controller_->SetSidePanelUIForTesting(ui); + } + ~ScopedSidePanelUIForTesting() { + controller_->SetSidePanelUIForTesting(nullptr); + } + + private: + raw_ptr controller_; +}; + +class MockSidePanelUI : public SidePanelUI { + public: + MOCK_METHOD(void, + Show, + (SidePanelEntryId, std::optional, bool), + (override)); + MOCK_METHOD(void, + Show, + (SidePanelEntryKey, std::optional, bool), + (override)); + MOCK_METHOD(void, ShowFrom, (SidePanelEntryKey, gfx::Rect), (override)); + MOCK_METHOD(void, + Close, + (SidePanelEntry::PanelType, SidePanelEntryHideReason, bool), + (override)); + MOCK_METHOD(void, + Toggle, + (SidePanelEntryKey, SidePanelOpenTrigger), + (override)); + MOCK_METHOD(std::optional, + GetCurrentEntryId, + (SidePanelEntry::PanelType), + (const, override)); + MOCK_METHOD(int, + GetCurrentEntryDefaultContentWidth, + (SidePanelEntry::PanelType), + (const, override)); + MOCK_METHOD(bool, + IsSidePanelShowing, + (SidePanelEntry::PanelType), + (const, override)); + MOCK_METHOD(bool, + IsSidePanelEntryShowing, + (const SidePanelEntryKey&), + (const, override)); + MOCK_METHOD(bool, + IsSidePanelEntryShowing, + (const SidePanelEntry::Key&, bool), + (const, override)); + MOCK_METHOD(base::CallbackListSubscription, + RegisterSidePanelShown, + (SidePanelEntry::PanelType, ShownCallback), + (override)); + MOCK_METHOD(void, + OnActiveTabChanged, + (content::WebContents*, content::WebContents*, bool), + (override)); + MOCK_METHOD(content::WebContents*, + GetWebContentsForTest, + (SidePanelEntryId), + (override)); + MOCK_METHOD(void, DisableAnimationsForTesting, (), (override)); + MOCK_METHOD(void, SetNoDelaysForTesting, (bool), (override)); +}; + +// Verify suppress_animations is false when opening from a closed state and +// true when switching panels while one is already active. +IN_PROC_BROWSER_TEST_F(SidebarBrowserTest, + SidebarV2ActivatePanelItemSuppressAnimation) { + MockSidePanelUI mock_ui; + ScopedSidePanelUIForTesting scoped_ui(controller(), &mock_ui); + + // No active panel: opening should animate (suppress_animations=false). + ASSERT_FALSE(model()->active_index().has_value()) + << "Expected no active panel before first ActivatePanelItem call"; + EXPECT_CALL(mock_ui, + Show(testing::An(), testing::Eq(std::nullopt), + /*suppress_animations=*/false)); + controller()->ActivatePanelItem(SidebarItem::BuiltInItemType::kBookmarks); + testing::Mock::VerifyAndClearExpectations(&mock_ui); + controller()->UpdateActiveItemState(SidebarItem::BuiltInItemType::kBookmarks); + + // Active panel present: switching panels should suppress animations. + ASSERT_TRUE(model()->active_index().has_value()) + << "Expected active panel after UpdateActiveItemState"; + EXPECT_CALL(mock_ui, + Show(testing::An(), testing::Eq(std::nullopt), + /*suppress_animations=*/true)); + controller()->ActivatePanelItem(SidebarItem::BuiltInItemType::kReadingList); +} + #endif // BUILDFLAG(ENABLE_SIDEBAR_V2) } // namespace sidebar diff --git a/browser/ui/sidebar/sidebar_controller.cc b/browser/ui/sidebar/sidebar_controller.cc index b034d2d965c..b2b2cb5fc77 100644 --- a/browser/ui/sidebar/sidebar_controller.cc +++ b/browser/ui/sidebar/sidebar_controller.cc @@ -10,6 +10,7 @@ #include "base/check.h" #include "base/check_op.h" +#include "brave/browser/ui/sidebar/buildflags/buildflags.h" #include "brave/browser/ui/sidebar/sidebar.h" #include "brave/browser/ui/sidebar/sidebar_model.h" #include "brave/browser/ui/sidebar/sidebar_service_factory.h" @@ -150,17 +151,25 @@ void SidebarController::ActivateItemAt(std::optional index, void SidebarController::ActivatePanelItem( SidebarItem::BuiltInItemType panel_item) { // For panel item activation, SidePanelUI is the single source of truth. - auto* side_panel_ui = browser_->GetFeatures().side_panel_ui(); - if (!side_panel_ui) { - return; - } + auto* side_panel_ui = side_panel_ui_for_testing_ + ? side_panel_ui_for_testing_.get() + : browser_->GetFeatures().side_panel_ui(); CHECK(side_panel_ui); if (panel_item == SidebarItem::BuiltInItemType::kNone) { side_panel_ui->Close(SidePanelEntry::PanelType::kContent); return; } +#if BUILDFLAG(ENABLE_SIDEBAR_V2) + // Suppress opening animation when we have active item. + // When opening another panel while other panel is visible, + // we don't need to open new panel with animation. + const bool suppress_animations = sidebar_model_->active_index().has_value(); + side_panel_ui->Show(sidebar::SidePanelIdFromSideBarItemType(panel_item), + /*open_trigger*/ std::nullopt, suppress_animations); +#else side_panel_ui->Show(sidebar::SidePanelIdFromSideBarItemType(panel_item)); +#endif } void SidebarController::DeactivateCurrentPanel() { diff --git a/browser/ui/sidebar/sidebar_controller.h b/browser/ui/sidebar/sidebar_controller.h index c18e3e9e982..1c8e886768c 100644 --- a/browser/ui/sidebar/sidebar_controller.h +++ b/browser/ui/sidebar/sidebar_controller.h @@ -19,6 +19,7 @@ class Browser; class GURL; class Profile; +class SidePanelUI; class TabStripModel; namespace sidebar { @@ -63,6 +64,10 @@ class SidebarController : public SidebarService::Observer { void ActivatePanelItem(SidebarItem::BuiltInItemType panel_item); void DeactivateCurrentPanel(); + void SetSidePanelUIForTesting(SidePanelUI* side_panel_ui) { + side_panel_ui_for_testing_ = side_panel_ui; + } + // If current browser doesn't have a tab for |url|, active tab will load // |url|. Otherwise, existing tab will be activated. // ShowSingletonTab() has similar functionality but it loads url in the @@ -99,6 +104,7 @@ class SidebarController : public SidebarService::Observer { raw_ptr profile_ = nullptr; raw_ptr browser_ = nullptr; raw_ptr sidebar_ = nullptr; + raw_ptr side_panel_ui_for_testing_ = nullptr; std::unique_ptr sidebar_model_; std::unique_ptr web_panel_controller_;