[Customize Chrome] Add Brave Rewards to toolbar customization panel in new "Url bar" category (#30227)
This commit extends the toolbar customization feature to support Brave Rewards placement in the url bar by introducing a new "Url bar" category and implementing the necessary infrastructure. Key changes: - Add new "Url bar" category (CategoryId::kUrlBar) to organize url bar-specific actions - Implement kShowReward action for toggling Brave Rewards visibility - Integrate Brave Rewards with existing preference system (brave_rewards::prefs::kShowLocationBarButton) - Add dynamic category management that only shows "Url bar" category when Brave Rewards is supported for the current profile Technical implementation: - Extended customize_toolbar.mojom with new ActionId::kShowReward and CategoryId::kUrlBar enums - Implemented AppendBraveSpecificCategories() function to conditionally add Url bar category based on Brave Rewards availability - Enhanced list action modifiers to handle URL bar actions alongside existing navigation actions - Added comprehensive unit tests covering both enabled and disabled states for Brave Rewards <!-- Add brave-browser issue below that this PR will resolve --> Resolves https://github.com/brave/brave-browser/issues/47820 <img width="332" height="189" alt="image" src="https://github.com/user-attachments/assets/af8b7b9b-03e2-4451-8a34-df6ae797cce6" />
This commit is contained in:
@@ -14,14 +14,17 @@ source_set("customize_chrome") {
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//brave/browser/brave_rewards:util",
|
||||
"//brave/components/ai_chat/core/browser",
|
||||
"//brave/components/ai_chat/core/common",
|
||||
"//brave/components/brave_rewards/core",
|
||||
"//brave/components/brave_vpn/common/buildflags",
|
||||
"//brave/components/brave_wallet/browser:pref_names",
|
||||
"//brave/components/brave_wallet/common",
|
||||
"//brave/components/constants",
|
||||
"//brave/components/resources:strings_grit",
|
||||
"//brave/components/vector_icons",
|
||||
"//chrome/browser/profiles:profile",
|
||||
"//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
|
||||
"//chrome/browser/ui/webui/util",
|
||||
"//components/prefs",
|
||||
@@ -61,8 +64,10 @@ source_set("unit_tests") {
|
||||
deps = [
|
||||
":customize_chrome",
|
||||
"//base",
|
||||
"//brave/browser/brave_rewards:util",
|
||||
"//brave/components/ai_chat/core/browser",
|
||||
"//brave/components/ai_chat/core/common",
|
||||
"//brave/components/brave_rewards/core",
|
||||
"//brave/components/brave_vpn/common/buildflags",
|
||||
"//brave/components/brave_wallet/common",
|
||||
"//brave/components/vector_icons",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "brave/components/ai_chat/core/common/pref_names.h"
|
||||
#include "brave/components/brave_rewards/core/pref_names.h"
|
||||
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
|
||||
#include "brave/components/brave_wallet/browser/pref_names.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
@@ -70,6 +71,15 @@ inline constexpr BraveAction kShowVPNAction = {
|
||||
.icon = kLeoProductVpnIcon};
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
|
||||
inline constexpr BraveAction kShowReward = {
|
||||
.id = side_panel::customize_chrome::mojom::ActionId::kShowReward,
|
||||
.display_name_resource_id = IDS_CUSTOMIZE_TOOLBAR_TOGGLE_REWARD,
|
||||
.anchor = side_panel::customize_chrome::mojom::ActionId::
|
||||
kShowReward, // assign id of itself to append to the end of the list
|
||||
.category = side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
|
||||
.pref_name = brave_rewards::prefs::kShowLocationBarButton,
|
||||
.icon = kLeoProductBatOutlineIcon};
|
||||
|
||||
inline constexpr auto kBraveActions =
|
||||
base::MakeFixedFlatMap<side_panel::customize_chrome::mojom::ActionId,
|
||||
const BraveAction*>({
|
||||
@@ -79,6 +89,7 @@ inline constexpr auto kBraveActions =
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
{kShowVPNAction.id, &kShowVPNAction},
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
{kShowReward.id, &kShowReward},
|
||||
});
|
||||
|
||||
} // namespace customize_chrome
|
||||
|
||||
+47
-5
@@ -12,10 +12,12 @@
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/fixed_flat_set.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brave/browser/brave_rewards/rewards_util.h"
|
||||
#include "brave/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/brave_action.h"
|
||||
#include "brave/components/ai_chat/core/browser/utils.h"
|
||||
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
|
||||
#include "brave/components/brave_wallet/common/common_utils.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/webui/util/image_util.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/user_prefs/user_prefs.h"
|
||||
@@ -32,8 +34,42 @@
|
||||
|
||||
namespace customize_chrome {
|
||||
|
||||
namespace {
|
||||
|
||||
void AddActionsForAddressBarCategory(Profile* profile,
|
||||
std::vector<BraveAction>& brave_actions) {
|
||||
if (brave_rewards::IsSupportedForProfile(profile)) {
|
||||
brave_actions.push_back(kShowReward);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using side_panel::customize_chrome::mojom::ActionId;
|
||||
using side_panel::customize_chrome::mojom::ActionPtr;
|
||||
using side_panel::customize_chrome::mojom::Category;
|
||||
using side_panel::customize_chrome::mojom::CategoryId;
|
||||
using side_panel::customize_chrome::mojom::CategoryPtr;
|
||||
|
||||
std::vector<CategoryPtr> AppendBraveSpecificCategories(
|
||||
content::WebContents& web_contents,
|
||||
std::vector<CategoryPtr> categories) {
|
||||
// Add a new "Address bar" category.
|
||||
std::vector<BraveAction> brave_actions;
|
||||
AddActionsForAddressBarCategory(
|
||||
Profile::FromBrowserContext(web_contents.GetBrowserContext()),
|
||||
brave_actions);
|
||||
if (brave_actions.empty()) {
|
||||
// In case we don't have any Brave actions for Address bar category, we
|
||||
// don't need to add the category.
|
||||
return categories;
|
||||
}
|
||||
|
||||
categories.push_back(Category::New(
|
||||
CategoryId::kAddressBar,
|
||||
l10n_util::GetStringUTF8(IDS_CUSTOMIZE_TOOLBAR_CATEGORY_ADDRESS_BAR)));
|
||||
return categories;
|
||||
}
|
||||
|
||||
std::vector<ActionPtr> FilterUnsupportedChromiumActions(
|
||||
std::vector<ActionPtr> actions) {
|
||||
@@ -109,6 +145,8 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
|
||||
// kShowWallet,
|
||||
// kShowAIChat,
|
||||
// kShowVPN,
|
||||
// Address bar
|
||||
// kShowReward
|
||||
auto* prefs = user_prefs::UserPrefs::Get(web_contents.GetBrowserContext());
|
||||
CHECK(prefs) << "Browser context does not have prefs";
|
||||
|
||||
@@ -131,12 +169,15 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
|
||||
brave_actions.push_back(kShowWalletAction);
|
||||
}
|
||||
|
||||
AddActionsForAddressBarCategory(
|
||||
Profile::FromBrowserContext(web_contents.GetBrowserContext()),
|
||||
brave_actions);
|
||||
|
||||
for (const auto& brave_action : brave_actions) {
|
||||
// Find the anchor action.
|
||||
// Find the anchor action. If anchor action is not found, just append to the
|
||||
// end of the list.
|
||||
auto anchor_it =
|
||||
std::ranges::find(actions, brave_action.anchor, get_action_id);
|
||||
CHECK(anchor_it != actions.end()) << "action to anchor not found: "
|
||||
<< static_cast<int>(brave_action.anchor);
|
||||
|
||||
// Create the new action.
|
||||
auto new_action = Action::New(
|
||||
@@ -147,8 +188,9 @@ std::vector<ActionPtr> ApplyBraveSpecificModifications(
|
||||
/*has_enterprise_controlled_pinned_state=*/false, brave_action.category,
|
||||
get_icon_url(brave_action.icon));
|
||||
|
||||
// Insert the new action after the anchor.
|
||||
actions.insert(anchor_it + 1, std::move(new_action));
|
||||
// Insert the new action after the anchor or end of the list.
|
||||
actions.insert(anchor_it == actions.end() ? actions.end() : anchor_it + 1,
|
||||
std::move(new_action));
|
||||
}
|
||||
|
||||
return actions;
|
||||
|
||||
+10
@@ -16,6 +16,14 @@ class WebContents;
|
||||
|
||||
namespace customize_chrome {
|
||||
|
||||
// Append Brave-specific categories to the list of categories.
|
||||
// * We have our own "Address bar" category that contains actions like
|
||||
// `kShowReward`.
|
||||
std::vector<side_panel::customize_chrome::mojom::CategoryPtr>
|
||||
AppendBraveSpecificCategories(
|
||||
content::WebContents& web_contents,
|
||||
std::vector<side_panel::customize_chrome::mojom::CategoryPtr> categories);
|
||||
|
||||
// Removes unsupported Chromium actions from the list of actions.
|
||||
std::vector<side_panel::customize_chrome::mojom::ActionPtr>
|
||||
FilterUnsupportedChromiumActions(
|
||||
@@ -32,6 +40,8 @@ FilterUnsupportedChromiumActions(
|
||||
// 3. Adds Brave-specific actions.
|
||||
// e.g. In 'Navigation' category:
|
||||
// `kShowSidePanel`, `kShowWallet`, `kShowAIChat`, `kShowVPN`.
|
||||
// In 'Address bar' category:
|
||||
// `kShowReward`.
|
||||
std::vector<side_panel::customize_chrome::mojom::ActionPtr>
|
||||
ApplyBraveSpecificModifications(
|
||||
content::WebContents& web_contents,
|
||||
|
||||
+74
-4
@@ -9,8 +9,10 @@
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/fixed_flat_set.h"
|
||||
#include "brave/browser/brave_rewards/rewards_util.h"
|
||||
#include "brave/components/ai_chat/core/browser/utils.h"
|
||||
#include "brave/components/ai_chat/core/common/pref_names.h"
|
||||
#include "brave/components/brave_rewards/core/pref_names.h"
|
||||
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
|
||||
#include "brave/components/brave_wallet/common/common_utils.h"
|
||||
#include "brave/components/brave_wallet/common/features.h"
|
||||
@@ -72,6 +74,12 @@ class ListActionModifiersUnitTest : public testing::Test {
|
||||
side_panel::customize_chrome::mojom::CategoryId::kTools;
|
||||
actions.push_back(std::move(tab_search_action));
|
||||
|
||||
auto dev_tools_action = side_panel::customize_chrome::mojom::Action::New();
|
||||
dev_tools_action->id = ActionId::kDevTools;
|
||||
dev_tools_action->category =
|
||||
side_panel::customize_chrome::mojom::CategoryId::kTools;
|
||||
actions.push_back(std::move(dev_tools_action));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -275,6 +283,33 @@ TEST_F(ListActionModifiersUnitTest,
|
||||
EXPECT_EQ(wallet_action_it, modified_actions.end());
|
||||
}
|
||||
|
||||
TEST_F(ListActionModifiersUnitTest,
|
||||
ApplyBraveSpecificModifications_RewardsShouldNotBeAddedWhenDisabled) {
|
||||
// Rewards should be added by default(Rewards enabled by default)
|
||||
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
|
||||
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
|
||||
auto modified_actions = customize_chrome::ApplyBraveSpecificModifications(
|
||||
*web_contents_, GetBasicActions());
|
||||
auto rewards_action_it =
|
||||
std::ranges::find(modified_actions, ActionId::kShowReward,
|
||||
&side_panel::customize_chrome::mojom::Action::id);
|
||||
ASSERT_NE(rewards_action_it, modified_actions.end());
|
||||
|
||||
// Disable Rewards using managed pref
|
||||
prefs()->SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
ASSERT_TRUE(
|
||||
prefs()->IsManagedPreference(brave_rewards::prefs::kDisabledByPolicy));
|
||||
|
||||
modified_actions = customize_chrome::ApplyBraveSpecificModifications(
|
||||
*web_contents_, GetBasicActions());
|
||||
rewards_action_it =
|
||||
std::ranges::find(modified_actions, ActionId::kShowReward,
|
||||
&side_panel::customize_chrome::mojom::Action::id);
|
||||
// Show Rewards action should not be present
|
||||
EXPECT_EQ(rewards_action_it, modified_actions.end());
|
||||
}
|
||||
|
||||
TEST_F(ListActionModifiersUnitTest,
|
||||
ApplyBraveSpecificModifications_ComprehensiveOrderTest) {
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
@@ -282,6 +317,8 @@ TEST_F(ListActionModifiersUnitTest,
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
ASSERT_TRUE(ai_chat::IsAIChatEnabled(prefs()));
|
||||
ASSERT_TRUE(brave_wallet::IsNativeWalletEnabled());
|
||||
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
|
||||
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
|
||||
|
||||
auto modified_actions = customize_chrome::ApplyBraveSpecificModifications(
|
||||
*web_contents_, GetBasicActions());
|
||||
@@ -289,10 +326,43 @@ TEST_F(ListActionModifiersUnitTest,
|
||||
testing::ElementsAre(
|
||||
EqId(ActionId::kNewIncognitoWindow),
|
||||
EqId(ActionId::kShowSidePanel), EqId(ActionId::kTabSearch),
|
||||
EqId(ActionId::kShowWallet), EqId(ActionId::kShowAIChat)
|
||||
EqId(ActionId::kShowWallet), EqId(ActionId::kShowAIChat),
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
,
|
||||
EqId(ActionId::kShowVPN)
|
||||
EqId(ActionId::kShowVPN),
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
));
|
||||
EqId(ActionId::kDevTools), EqId(ActionId::kShowReward)));
|
||||
}
|
||||
|
||||
TEST_F(ListActionModifiersUnitTest, AppendBraveSpecificCategories) {
|
||||
// Create a vector of categories
|
||||
std::vector<side_panel::customize_chrome::mojom::CategoryPtr> categories;
|
||||
|
||||
// Append Brave specific categories
|
||||
categories = customize_chrome::AppendBraveSpecificCategories(
|
||||
*web_contents_, std::move(categories));
|
||||
|
||||
// Verify "Address bar" category is added with expected actions
|
||||
ASSERT_TRUE(brave_rewards::IsSupportedForProfile(
|
||||
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
|
||||
auto it = std::ranges::find(
|
||||
categories, side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
|
||||
&side_panel::customize_chrome::mojom::Category::id);
|
||||
EXPECT_NE(it, categories.end());
|
||||
|
||||
// When Brave Rewards isn't supported, the Address bar category should not be
|
||||
// added
|
||||
prefs()->SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
ASSERT_TRUE(
|
||||
prefs()->IsManagedPreference(brave_rewards::prefs::kDisabledByPolicy));
|
||||
ASSERT_FALSE(brave_rewards::IsSupportedForProfile(
|
||||
Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
|
||||
|
||||
categories.clear();
|
||||
categories = customize_chrome::AppendBraveSpecificCategories(
|
||||
*web_contents_, std::move(categories));
|
||||
it = std::ranges::find(
|
||||
categories, side_panel::customize_chrome::mojom::CategoryId::kAddressBar,
|
||||
&side_panel::customize_chrome::mojom::Category::id);
|
||||
EXPECT_EQ(it, categories.end());
|
||||
}
|
||||
|
||||
+9
@@ -7,8 +7,17 @@ module side_panel.customize_chrome.mojom;
|
||||
|
||||
[BraveExtend]
|
||||
enum ActionId {
|
||||
// Actions in the "Navigation" category.
|
||||
kShowWallet,
|
||||
kShowAIChat,
|
||||
kShowVPN,
|
||||
kShowSidePanel,
|
||||
|
||||
// Actions in the "Address bar" category.
|
||||
kShowReward,
|
||||
};
|
||||
|
||||
[BraveExtend]
|
||||
enum CategoryId {
|
||||
kAddressBar,
|
||||
};
|
||||
|
||||
+14
-4
@@ -14,8 +14,9 @@
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "components/grit/brave_components_strings.h"
|
||||
|
||||
#define ListActions ListActionsChromium
|
||||
#define PinAction PinActionChromium
|
||||
#define ListCategories ListCategories_ChromiumImpl
|
||||
#define ListActions ListActions_ChromiumImpl
|
||||
#define PinAction PinAction_ChromiumImpl
|
||||
|
||||
// pref_change_registrar_.Init() in constructor
|
||||
#define Init(...) \
|
||||
@@ -35,9 +36,18 @@
|
||||
#undef Init
|
||||
#undef PinAction
|
||||
#undef ListActions
|
||||
#undef ListCategories
|
||||
|
||||
void CustomizeToolbarHandler::ListCategories(ListCategoriesCallback callback) {
|
||||
ListCategories_ChromiumImpl(
|
||||
base::BindOnce(
|
||||
&customize_chrome::AppendBraveSpecificCategories,
|
||||
base::Unretained(base::raw_ref<content::WebContents>(*web_contents_)))
|
||||
.Then(std::move(callback)));
|
||||
}
|
||||
|
||||
void CustomizeToolbarHandler::ListActions(ListActionsCallback callback) {
|
||||
ListActionsChromium(
|
||||
ListActions_ChromiumImpl(
|
||||
base::BindOnce(&customize_chrome::FilterUnsupportedChromiumActions)
|
||||
.Then(base::BindOnce(
|
||||
&customize_chrome::ApplyBraveSpecificModifications,
|
||||
@@ -57,7 +67,7 @@ void CustomizeToolbarHandler::PinAction(
|
||||
return;
|
||||
}
|
||||
|
||||
PinActionChromium(action_id, pin);
|
||||
PinAction_ChromiumImpl(action_id, pin);
|
||||
}
|
||||
|
||||
void CustomizeToolbarHandler::ObserveBraveActions() {
|
||||
|
||||
+14
-10
@@ -8,21 +8,25 @@
|
||||
|
||||
#include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom.h"
|
||||
|
||||
#define ListActions \
|
||||
ListActionsChromium(ListActionsCallback callback); \
|
||||
void ListActions
|
||||
#define ListCategories(...) \
|
||||
ListCategories_ChromiumImpl(__VA_ARGS__); \
|
||||
void ListCategories(__VA_ARGS__)
|
||||
|
||||
#define PinAction \
|
||||
PinActionChromium(side_panel::customize_chrome::mojom::ActionId action_id, \
|
||||
bool pin); \
|
||||
void ObserveBraveActions(); \
|
||||
void OnBraveActionPinnedChanged( \
|
||||
side_panel::customize_chrome::mojom::ActionId action_id); \
|
||||
void PinAction
|
||||
#define ListActions(...) \
|
||||
ListActions_ChromiumImpl(__VA_ARGS__); \
|
||||
void ListActions(__VA_ARGS__)
|
||||
|
||||
#define PinAction(...) \
|
||||
PinAction_ChromiumImpl(__VA_ARGS__); \
|
||||
void ObserveBraveActions(); \
|
||||
void OnBraveActionPinnedChanged( \
|
||||
side_panel::customize_chrome::mojom::ActionId action_id); \
|
||||
void PinAction(__VA_ARGS__)
|
||||
|
||||
#include <chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h> // IWYU pragma: export
|
||||
|
||||
#undef PinAction
|
||||
#undef ListActions
|
||||
#undef ListCategories
|
||||
|
||||
#endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_WEBUI_SIDE_PANEL_CUSTOMIZE_CHROME_CUSTOMIZE_TOOLBAR_CUSTOMIZE_TOOLBAR_HANDLER_H_
|
||||
|
||||
@@ -15,4 +15,10 @@
|
||||
<message name="IDS_CUSTOMIZE_TOOLBAR_CATEGORY_TOOLBAR" desc="Title for the toolbar category in the customize toolbar page">
|
||||
Toolbar
|
||||
</message>
|
||||
<message name="IDS_CUSTOMIZE_TOOLBAR_CATEGORY_ADDRESS_BAR" desc="Title for the address bar category in the customize toolbar page">
|
||||
Address bar
|
||||
</message>
|
||||
<message name="IDS_CUSTOMIZE_TOOLBAR_TOGGLE_REWARD" desc="Title for a toggle button to show or hide rewards">
|
||||
Rewards
|
||||
</message>
|
||||
</grit-part>
|
||||
|
||||
Reference in New Issue
Block a user