diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 076d59fa1acc..9d032047ff3c 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -799,6 +799,16 @@ Or change later at $2brave://settings/ext Reading List + + + Bookmarks manager + + + + + Bookmarks Manager + + diff --git a/app/theme/brave_theme_resources.grd b/app/theme/brave_theme_resources.grd index ebfe896e5415..d6338bfe3cb1 100644 --- a/app/theme/brave_theme_resources.grd +++ b/app/theme/brave_theme_resources.grd @@ -48,6 +48,7 @@ + diff --git a/app/theme/default_100_percent/brave/sidebar_bookmarks_panel_header.png b/app/theme/default_100_percent/brave/sidebar_bookmarks_panel_header.png new file mode 100644 index 000000000000..11ff0bdf11eb Binary files /dev/null and b/app/theme/default_100_percent/brave/sidebar_bookmarks_panel_header.png differ diff --git a/app/theme/default_200_percent/brave/sidebar_bookmarks_panel_header.png b/app/theme/default_200_percent/brave/sidebar_bookmarks_panel_header.png new file mode 100644 index 000000000000..0db2aeee85ab Binary files /dev/null and b/app/theme/default_200_percent/brave/sidebar_bookmarks_panel_header.png differ diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 3f2745086678..af60dce6118c 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -330,6 +330,10 @@ source_set("ui") { "views/page_action/brave_page_action_icon_container_view.h", "views/rounded_separator.cc", "views/rounded_separator.h", + "views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.cc", + "views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h", + "views/side_panel/brave_bookmarks_side_panel_view.cc", + "views/side_panel/brave_bookmarks_side_panel_view.h", "views/side_panel/brave_read_later_side_panel_view.cc", "views/side_panel/brave_read_later_side_panel_view.h", "views/side_panel/brave_side_panel.cc", diff --git a/browser/ui/color/brave_color_id.h b/browser/ui/color/brave_color_id.h index 9ae91bf4a8a9..2c0662641d0f 100644 --- a/browser/ui/color/brave_color_id.h +++ b/browser/ui/color/brave_color_id.h @@ -57,7 +57,9 @@ E_CPONLY(kColorSidebarSeparator) \ E_CPONLY(kColorSidebarPanelHeaderSeparator) \ E_CPONLY(kColorSidebarPanelHeaderBackground) \ - E_CPONLY(kColorSidebarPanelHeaderTitle) + E_CPONLY(kColorSidebarPanelHeaderTitle) \ + E_CPONLY(kColorSidebarPanelHeaderButton) \ + E_CPONLY(kColorSidebarPanelHeaderButtonHovered) #if BUILDFLAG(ENABLE_SPEEDREADER) #define BRAVE_SPEEDREADER_COLOR_IDS \ diff --git a/browser/ui/color/brave_color_mixer.cc b/browser/ui/color/brave_color_mixer.cc index d7d9850f8c5b..0c60bcc2d725 100644 --- a/browser/ui/color/brave_color_mixer.cc +++ b/browser/ui/color/brave_color_mixer.cc @@ -362,6 +362,10 @@ void AddBraveLightThemeColorMixer(ui::ColorProvider* provider, leo::GetColor(leo::Color::kColorContainerBackground, leo::Theme::kLight)}; mixer[kColorSidebarPanelHeaderTitle] = { leo::GetColor(leo::Color::kColorTextSecondary, leo::Theme::kLight)}; + mixer[kColorSidebarPanelHeaderButton] = { + leo::GetColor(leo::Color::kColorIconDefault, leo::Theme::kLight)}; + mixer[kColorSidebarPanelHeaderButtonHovered] = { + leo::GetColor(leo::Color::kColorGray60, leo::Theme::kLight)}; if (HasCustomToolbarColor(key)) { // When custom color for toolbar is set, we can't depend on the color mode. @@ -478,6 +482,10 @@ void AddBraveDarkThemeColorMixer(ui::ColorProvider* provider, mixer[kColorSidebarPanelHeaderBackground] = {gfx::kGoogleGrey900}; mixer[kColorSidebarPanelHeaderTitle] = { leo::GetColor(leo::Color::kColorTextSecondary, leo::Theme::kDark)}; + mixer[kColorSidebarPanelHeaderButton] = { + leo::GetColor(leo::Color::kColorIconDefault, leo::Theme::kDark)}; + mixer[kColorSidebarPanelHeaderButtonHovered] = { + leo::GetColor(leo::Color::kColorGray60, leo::Theme::kDark)}; if (HasCustomToolbarColor(key)) { // When custom color for toolbar is set, we can't depend on the color mode. diff --git a/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.cc b/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.cc new file mode 100644 index 000000000000..23e5a065c2cd --- /dev/null +++ b/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.cc @@ -0,0 +1,41 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h" + +#include "base/functional/bind.h" +#include "brave/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.h" +#include "chrome/browser/ui/views/side_panel/side_panel_entry.h" +#include "chrome/browser/ui/views/side_panel/side_panel_registry.h" +#include "chrome/grit/generated_resources.h" +#include "components/omnibox/browser/vector_icons.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/image_model.h" +#include "ui/views/vector_icons.h" + +BraveBookmarksSidePanelCoordinator::BraveBookmarksSidePanelCoordinator( + Browser* browser) + : BrowserUserData(*browser) {} + +BraveBookmarksSidePanelCoordinator::~BraveBookmarksSidePanelCoordinator() = + default; + +void BraveBookmarksSidePanelCoordinator::CreateAndRegisterEntry( + SidePanelRegistry* global_registry) { + global_registry->Register(std::make_unique( + SidePanelEntry::Id::kBookmarks, + l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE), + ui::ImageModel::FromVectorIcon(omnibox::kStarIcon, ui::kColorIcon), + base::BindRepeating( + &BraveBookmarksSidePanelCoordinator::CreateBookmarksPanelView, + base::Unretained(this)))); +} + +std::unique_ptr +BraveBookmarksSidePanelCoordinator::CreateBookmarksPanelView() { + return std::make_unique(&GetBrowser()); +} + +BROWSER_USER_DATA_KEY_IMPL(BraveBookmarksSidePanelCoordinator); diff --git a/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h b/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h new file mode 100644 index 000000000000..8eefa7e524a4 --- /dev/null +++ b/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BRAVE_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ +#define BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BRAVE_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ + +#include + +#include "chrome/browser/ui/browser_user_data.h" + +class Browser; +class SidePanelRegistry; + +namespace views { +class View; +} // namespace views + +// Introduced to give custom contents view(BraveBookmarksSidePanelView) for +// bookmarks panel entry. That contents view includes bookmarks panel specific +// header view and web view. +// Note that this is not the subclass of upstream BookmarksSidePanelCoordinator. +// As it inherits BrowserUserData, subclassig doesn't work well when its +// instance is created via BrowserUserData<>::CreateForBrowser(). So, new +// coordinator class is introduced and +// BookmarksSidePanelCoordinator::CreateBookmarksWebView() is reused from +// BraveBookmarksSidePanelView. That's why BraveBookmarksSidePanelView is set +// as BookmarksSidePanelCoordinator's friend. +class BraveBookmarksSidePanelCoordinator + : public BrowserUserData { + public: + explicit BraveBookmarksSidePanelCoordinator(Browser* browser); + BraveBookmarksSidePanelCoordinator( + const BraveBookmarksSidePanelCoordinator&) = delete; + BraveBookmarksSidePanelCoordinator& operator=( + const BraveBookmarksSidePanelCoordinator&) = delete; + ~BraveBookmarksSidePanelCoordinator() override; + + void CreateAndRegisterEntry(SidePanelRegistry* global_registry); + + private: + friend class BrowserUserData; + + std::unique_ptr CreateBookmarksPanelView(); + + BROWSER_USER_DATA_KEY_DECL(); +}; + +#endif // BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BRAVE_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ diff --git a/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.cc b/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.cc new file mode 100644 index 000000000000..b6c28d86093a --- /dev/null +++ b/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.cc @@ -0,0 +1,143 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.h" + +#include + +#include "base/memory/raw_ref.h" +#include "brave/browser/ui/color/brave_color_id.h" +#include "brave/components/vector_icons/vector_icons.h" +#include "brave/grit/brave_generated_resources.h" +#include "brave/grit/brave_theme_resources.h" +#include "chrome/browser/ui/singleton_tabs.h" +#include "chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h" +#include "chrome/browser/ui/views/side_panel/read_later_side_panel_web_view.h" +#include "chrome/browser/ui/views/side_panel/side_panel_content_proxy.h" +#include "chrome/browser/ui/views/side_panel/side_panel_util.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/image_model.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/background.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/flex_layout.h" +#include "ui/views/layout/layout_types.h" + +namespace { + +// Renders icon, title and launch button. +class BookmarksSidePanelHeaderView : public views::View { + public: + explicit BookmarksSidePanelHeaderView(Browser* browser) { + constexpr int kHeaderInteriorMargin = 16; + SetLayoutManager(std::make_unique()) + ->SetOrientation(views::LayoutOrientation::kHorizontal) + .SetInteriorMargin(gfx::Insets(kHeaderInteriorMargin)) + .SetMainAxisAlignment(views::LayoutAlignment::kStart) + .SetCrossAxisAlignment(views::LayoutAlignment::kCenter); + + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + auto* header_image = AddChildView( + std::make_unique(ui::ImageModel::FromImageSkia( + *rb.GetImageSkiaNamed(IDR_SIDEBAR_BOOKMARKS_PANEL_HEADER)))); + constexpr int kSpacingBetweenHeaderImageAndLabel = 8; + header_image->SetProperty( + views::kMarginsKey, + gfx::Insets::TLBR(0, 0, 0, kSpacingBetweenHeaderImageAndLabel)); + header_image->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred, + views::MaximumFlexSizeRule::kPreferred)); + + auto* header_label = AddChildView(std::make_unique( + l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE))); + header_label->SetFontList(gfx::FontList("Poppins, Semi-Bold 16px")); + header_label->SetEnabledColorId(kColorSidebarPanelHeaderTitle); + header_label->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred, + views::MaximumFlexSizeRule::kPreferred)); + auto* spacer = AddChildView(std::make_unique()); + spacer->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero, + views::MaximumFlexSizeRule::kUnbounded) + .WithOrder(2)); + // Safe to use Unretained(this) here as |button| will be destroyed before + // this class. + auto* button = AddChildView(std::make_unique( + base::BindRepeating(&BookmarksSidePanelHeaderView::OnButtonPressed, + base::Unretained(this), browser))); + button->SetTooltipText(l10n_util::GetStringUTF16( + IDS_SIDEBAR_READING_LIST_PANEL_HEADER_BOOKMARKS_BUTTON_TOOLTIP)); + + constexpr int kHeaderButtonSize = 20; + button->SetImageModel( + views::Button::STATE_NORMAL, + ui::ImageModel::FromVectorIcon( + kLeoLaunchIcon, kColorSidebarPanelHeaderButton, kHeaderButtonSize)); + button->SetImageModel( + views::Button::STATE_HOVERED, + ui::ImageModel::FromVectorIcon(kLeoLaunchIcon, + kColorSidebarPanelHeaderButtonHovered, + kHeaderButtonSize)); + + SetBackground( + views::CreateThemedSolidBackground(kColorSidebarPanelHeaderBackground)); + } + + ~BookmarksSidePanelHeaderView() override = default; + BookmarksSidePanelHeaderView(const BookmarksSidePanelHeaderView&) = delete; + BookmarksSidePanelHeaderView& operator=(const BookmarksSidePanelHeaderView&) = + delete; + + private: + void OnButtonPressed(Browser* browser, const ui::Event& event) { + ShowSingletonTab(browser, GURL(chrome::kChromeUIBookmarksURL)); + } +}; + +} // namespace + +BraveBookmarksSidePanelView::BraveBookmarksSidePanelView(Browser* browser) { + SetLayoutManager(std::make_unique()) + ->SetOrientation(views::LayoutOrientation::kVertical); + AddChildView(std::make_unique(browser)); + AddChildView(std::make_unique()) + ->SetColorId(kColorSidebarPanelHeaderSeparator); + + // Reuse upstream's bookmarks panl nwebui. + auto* web_view = + AddChildView(BookmarksSidePanelCoordinator::GetOrCreateForBrowser(browser) + ->CreateBookmarksWebView()); + web_view->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred, + views::MaximumFlexSizeRule::kUnbounded)); + + // See the comment in + // BraveReadLaterSidePanelView::BraveReadLaterSidePanelView() about why we do + // this. + SidePanelUtil::GetSidePanelContentProxy(this)->SetAvailable(false); + observation_.Observe(web_view); +} + +BraveBookmarksSidePanelView::~BraveBookmarksSidePanelView() = default; + +void BraveBookmarksSidePanelView::OnViewVisibilityChanged( + views::View* observed_view, + views::View* starting_view) { + if (observed_view->GetVisible()) { + SidePanelUtil::GetSidePanelContentProxy(this)->SetAvailable(true); + observation_.Reset(); + } +} diff --git a/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.h b/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.h new file mode 100644 index 000000000000..ff3e8e836170 --- /dev/null +++ b/browser/ui/views/side_panel/brave_bookmarks_side_panel_view.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BRAVE_BOOKMARKS_SIDE_PANEL_VIEW_H_ +#define BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BRAVE_BOOKMARKS_SIDE_PANEL_VIEW_H_ + +#include "base/functional/callback_forward.h" +#include "base/scoped_observation.h" +#include "ui/views/view.h" +#include "ui/views/view_observer.h" + +class Browser; + +// Gives bookmarks panel specific header view with web view. +class BraveBookmarksSidePanelView : public views::View, + public views::ViewObserver { + public: + explicit BraveBookmarksSidePanelView(Browser* browser); + ~BraveBookmarksSidePanelView() override; + BraveBookmarksSidePanelView(const BraveBookmarksSidePanelView&) = delete; + BraveBookmarksSidePanelView& operator=(const BraveBookmarksSidePanelView&) = + delete; + + private: + void OnViewVisibilityChanged(views::View* observed_view, + views::View* starting_view) override; + + base::ScopedObservation observation_{this}; +}; + +#endif // BRAVE_BROWSER_UI_VIEWS_SIDE_PANEL_BRAVE_BOOKMARKS_SIDE_PANEL_VIEW_H_ diff --git a/chromium_src/chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h b/chromium_src/chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h new file mode 100644 index 000000000000..38ad1e987b04 --- /dev/null +++ b/chromium_src/chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h @@ -0,0 +1,18 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ +#define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ + +#define CreateAndRegisterEntry \ + CreateAndRegisterEntry_UnUsed() {} \ + friend class BraveBookmarksSidePanelView; \ + void CreateAndRegisterEntry + +#include "src/chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h" // IWYU pragma: export + +#undef CreateAndRegisterEntry + +#endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_BOOKMARKS_BOOKMARKS_SIDE_PANEL_COORDINATOR_H_ diff --git a/chromium_src/chrome/browser/ui/views/side_panel/side_panel_util.cc b/chromium_src/chrome/browser/ui/views/side_panel/side_panel_util.cc index dce47edb506e..933f8ef94b4f 100644 --- a/chromium_src/chrome/browser/ui/views/side_panel/side_panel_util.cc +++ b/chromium_src/chrome/browser/ui/views/side_panel/side_panel_util.cc @@ -4,13 +4,17 @@ // you can obtain one at http://mozilla.org/MPL/2.0/. #include "chrome/browser/ui/views/side_panel/side_panel_util.h" +#include "brave/browser/ui/views/side_panel/bookmarks/brave_bookmarks_side_panel_coordinator.h" #include "brave/browser/ui/views/side_panel/playlist/playlist_side_panel_coordinator.h" #include "brave/components/playlist/common/features.h" +#include "chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h" #define PopulateGlobalEntries PopulateGlobalEntries_ChromiumImpl +#define BookmarksSidePanelCoordinator BraveBookmarksSidePanelCoordinator #include "src/chrome/browser/ui/views/side_panel/side_panel_util.cc" +#undef BookmarksSidePanelCoordinator #undef PopulateGlobalEntries // static