diff --git a/app/brave_settings_strings.grdp b/app/brave_settings_strings.grdp index e1d1f1e8a4b8..72d1b7f6afc6 100644 --- a/app/brave_settings_strings.grdp +++ b/app/brave_settings_strings.grdp @@ -423,6 +423,18 @@ Show full list + + Update lists + + + Update failed - Retry + + + Lists updated + + + Lists updating + Enter filter list URL diff --git a/browser/resources/settings/default_brave_shields_page/brave_adblock_browser_proxy.ts b/browser/resources/settings/default_brave_shields_page/brave_adblock_browser_proxy.ts index 44c146b96ab3..df24e2c75d90 100644 --- a/browser/resources/settings/default_brave_shields_page/brave_adblock_browser_proxy.ts +++ b/browser/resources/settings/default_brave_shields_page/brave_adblock_browser_proxy.ts @@ -10,6 +10,7 @@ import { sendWithPromise, addWebUiListener } from 'chrome://resources/js/cr.js'; export interface BraveAdblockBrowserProxy { getRegionalLists(): Promise // TODO(petemill): Define the expected type enableFilterList(uuid: string, enabled: boolean) + updateFilterList(uuid: string): Promise getListSubscriptions(): Promise // TODO(petemill): Define the expected type getCustomFilters(): Promise // TODO(petemill): Define the expected type setSubscriptionEnabled(url: string, enabled: boolean) @@ -44,6 +45,11 @@ export class BraveAdblockBrowserProxyImpl implements BraveAdblockBrowserProxy { chrome.send('brave_adblock.enableFilterList', [uuid, enabled]) } + /** @returns {Promise} */ + updateFilterLists () { + return sendWithPromise('brave_adblock.updateFilterLists') + } + setSubscriptionEnabled (url, enabled) { chrome.send('brave_adblock.setSubscriptionEnabled', [url, enabled]) } diff --git a/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.html b/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.html index 20168a3606a0..59dae4112601 100644 --- a/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.html +++ b/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.html @@ -86,8 +86,18 @@ font-weight: 500; } - .show-list-button-box { + .list-actions-box { + display: flex; margin-bottom: 10px; + gap: 8px; + } + + .update-lists-updated { + --leo-button-color: var(--leo-color-systemfeedback-success-text); + } + + .update-lists-failed { + --leo-button-color: var(--leo-color-systemfeedback-error-text); } .subscribe-url-form { @@ -186,11 +196,38 @@ - +
diff --git a/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.ts b/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.ts index 73a121cf86b9..604a64df3ce4 100644 --- a/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.ts +++ b/browser/resources/settings/default_brave_shields_page/brave_adblock_subpage.ts @@ -36,6 +36,7 @@ class AdBlockSubpage extends AdBlockSubpageBase { subscriptionList_: Array, customFilters_: String, subscribeUrl_: String, + listsUpdatingState_: String, hasListExpanded_: { type: Boolean, value: false @@ -47,6 +48,9 @@ class AdBlockSubpage extends AdBlockSubpageBase { ready() { super.ready() + + this.listsUpdatingState_ = '' + this.browserProxy_.getRegionalLists().then(value => { this.filterList_ = value }) @@ -71,6 +75,20 @@ class AdBlockSubpage extends AdBlockSubpageBase { } } + handleUpdateLists_() { + if (this.listsUpdatingState_ === 'updating') { + return + } + + this.listsUpdatingState_ = 'updating' + + this.browserProxy_.updateFilterLists().then(() => { + this.listsUpdatingState_ = 'updated' + }, () => { + this.listsUpdatingState_ = 'failed' + }) + } + searchListBy_(title) { if (!title) { this.hasListExpanded_ = false diff --git a/browser/ui/webui/settings/brave_adblock_handler.cc b/browser/ui/webui/settings/brave_adblock_handler.cc index 3e2d42a36579..a6c89347f967 100644 --- a/browser/ui/webui/settings/brave_adblock_handler.cc +++ b/browser/ui/webui/settings/brave_adblock_handler.cc @@ -42,6 +42,11 @@ void BraveAdBlockHandler::RegisterMessages() { base::BindRepeating(&BraveAdBlockHandler::EnableFilterList, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "brave_adblock.updateFilterLists", + base::BindRepeating(&BraveAdBlockHandler::UpdateFilterLists, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "brave_adblock.getListSubscriptions", base::BindRepeating(&BraveAdBlockHandler::GetListSubscriptions, @@ -123,6 +128,23 @@ void BraveAdBlockHandler::EnableFilterList(const base::Value::List& args) { ->EnableFilterList(uuid, enabled); } +void BraveAdBlockHandler::UpdateFilterLists(const base::Value::List& args) { + AllowJavascript(); + + DCHECK_EQ(args.size(), 1U); + if (!args[0].is_string()) { + return; + } + + std::string callback_id = args[0].GetString(); + + g_brave_browser_process->ad_block_service() + ->component_service_manager() + ->UpdateFilterLists( + base::BindOnce(&BraveAdBlockHandler::OnFilterListsUpdated, + weak_factory_.GetWeakPtr(), std::move(callback_id))); +} + void BraveAdBlockHandler::GetListSubscriptions(const base::Value::List& args) { AllowJavascript(); ResolveJavascriptCallback(args[0], GetSubscriptions()); @@ -284,3 +306,12 @@ base::Value::List BraveAdBlockHandler::GetSubscriptions() { return list_value; } + +void BraveAdBlockHandler::OnFilterListsUpdated(std::string callback_id, + bool success) { + if (success) { + ResolveJavascriptCallback(base::Value(callback_id), base::Value()); + } else { + RejectJavascriptCallback(base::Value(callback_id), base::Value()); + } +} diff --git a/browser/ui/webui/settings/brave_adblock_handler.h b/browser/ui/webui/settings/brave_adblock_handler.h index fc88dbacb659..d4c84ec4deb2 100644 --- a/browser/ui/webui/settings/brave_adblock_handler.h +++ b/browser/ui/webui/settings/brave_adblock_handler.h @@ -6,9 +6,12 @@ #ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_ADBLOCK_HANDLER_H_ #define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_ADBLOCK_HANDLER_H_ +#include + #include "base/scoped_observation.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "brave/components/brave_shields/content/browser/ad_block_subscription_service_manager.h" #include "brave/components/brave_shields/content/browser/ad_block_subscription_service_manager_observer.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" @@ -37,6 +40,7 @@ class BraveAdBlockHandler : public settings::SettingsPageUIHandler, void GetRegionalLists(const base::Value::List& args); void EnableFilterList(const base::Value::List& args); + void UpdateFilterLists(const base::Value::List& args); void GetListSubscriptions(const base::Value::List& args); void GetCustomFilters(const base::Value::List& args); void AddSubscription(const base::Value::List& args); @@ -50,11 +54,15 @@ class BraveAdBlockHandler : public settings::SettingsPageUIHandler, base::Value::List GetSubscriptions(); + void OnFilterListsUpdated(std::string callback_id, bool success); + raw_ptr profile_ = nullptr; base::ScopedObservation service_observer_{this}; + + base::WeakPtrFactory weak_factory_{this}; }; #endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_ADBLOCK_HANDLER_H_ diff --git a/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc b/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc index 90e0a7f32567..2b58e44bb108 100644 --- a/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc +++ b/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc @@ -689,6 +689,14 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source, {"adblockAddListsButtonLabel", IDS_BRAVE_ADBLOCK_ADD_LISTS_BUTTON_LABEL}, {"adblockShowFullListsButtonLabel", IDS_BRAVE_ADBLOCK_SHOW_FULL_LISTS_BUTTON_LABEL}, + {"adblockUpdateListsButtonLabel", + IDS_BRAVE_ADBLOCK_UPDATE_LISTS_BUTTON_LABEL}, + {"adblockUpdateListsRetryButtonLabel", + IDS_BRAVE_ADBLOCK_UPDATE_LISTS_RETRY_BUTTON_LABEL}, + {"adblockUpdateListsUpdatedButtonLabel", + IDS_BRAVE_ADBLOCK_UPDATE_LISTS_UPDATED_BUTTON_LABEL}, + {"adblockUpdateListsUpdatingButtonLabel", + IDS_BRAVE_ADBLOCK_UPDATE_LISTS_UPDATING_BUTTON_LABEL}, {"adblockFilterListsInputURLPlaceholder", IDS_BRAVE_ADBLOCK_CUSTOM_FILTER_LISTS_INPUT_PLACEHOLDER}, {"adblockContentFiltersLabel", IDS_BRAVE_ADBLOCK_CONTENT_FILTERS}, diff --git a/chromium_src/components/component_updater/component_updater_service.h b/chromium_src/components/component_updater/component_updater_service.h index af32ea3f2215..c2dd91b28572 100644 --- a/chromium_src/components/component_updater/component_updater_service.h +++ b/chromium_src/components/component_updater/component_updater_service.h @@ -14,14 +14,19 @@ class BraveComponentUpdaterAndroid; } } // namespace chrome +namespace brave_shields { +class AdBlockComponentFiltersProvider; +} + #define BRAVE_COMPONENT_UPDATER_SERVICE_H_ \ friend class ::IPFSDOMHandler; \ friend class ::chrome::android::BraveComponentUpdaterAndroid; -#define BRAVE_COMPONENT_UPDATER_SERVICE_H_ON_DEMAND_UPDATER \ - private: \ - friend void BraveOnDemandUpdate(const std::string&); \ - \ +#define BRAVE_COMPONENT_UPDATER_SERVICE_H_ON_DEMAND_UPDATER \ + private: \ + friend void BraveOnDemandUpdate(const std::string&); \ + friend class brave_shields::AdBlockComponentFiltersProvider; \ + \ public: #include "src/components/component_updater/component_updater_service.h" // IWYU pragma: export #undef BRAVE_COMPONENT_UPDATER_SERVICE_H_ON_DEMAND_UPDATER diff --git a/components/brave_shields/core/browser/ad_block_component_filters_provider.cc b/components/brave_shields/core/browser/ad_block_component_filters_provider.cc index b7ec5ef594be..47475aaf6072 100644 --- a/components/brave_shields/core/browser/ad_block_component_filters_provider.cc +++ b/components/brave_shields/core/browser/ad_block_component_filters_provider.cc @@ -125,4 +125,21 @@ void AdBlockComponentFiltersProvider::LoadFilterSet( base::BindOnce(&OnReadDATFileData, std::move(cb), permission_mask_)); } +void AdBlockComponentFiltersProvider::UpdateComponent( + base::OnceCallback callback) { + if (!component_updater_service_) { + std::move(callback).Run(false); + return; + } + + auto on_updated = [](decltype(callback) cb, update_client::Error error) { + std::move(cb).Run(error == update_client::Error::NONE || + error == update_client::Error::UPDATE_IN_PROGRESS); + }; + + component_updater_service_->GetOnDemandUpdater().OnDemandUpdate( + component_id_, component_updater::OnDemandUpdater::Priority::FOREGROUND, + base::BindOnce(on_updated, std::move(callback))); +} + } // namespace brave_shields diff --git a/components/brave_shields/core/browser/ad_block_component_filters_provider.h b/components/brave_shields/core/browser/ad_block_component_filters_provider.h index f26eeab47802..bea848a65e2f 100644 --- a/components/brave_shields/core/browser/ad_block_component_filters_provider.h +++ b/components/brave_shields/core/browser/ad_block_component_filters_provider.h @@ -55,6 +55,10 @@ class AdBlockComponentFiltersProvider : public AdBlockFiltersProvider { base::OnceCallback*)>)>) override; + // Updates the component, and when complete executes the specified callback + // with a value indicating success or failure. + void UpdateComponent(base::OnceCallback callback); + // Remove the component. This will force it to be redownloaded next time it // is registered. void UnregisterComponent(); diff --git a/components/brave_shields/core/browser/ad_block_component_service_manager.cc b/components/brave_shields/core/browser/ad_block_component_service_manager.cc index fa88b7b2c15d..98dc3b009c9b 100644 --- a/components/brave_shields/core/browser/ad_block_component_service_manager.cc +++ b/components/brave_shields/core/browser/ad_block_component_service_manager.cc @@ -9,9 +9,11 @@ #include #include +#include "base/barrier_callback.h" #include "base/feature_list.h" #include "base/memory/raw_ref.h" #include "base/metrics/histogram_macros.h" +#include "base/ranges/algorithm.h" #include "base/values.h" #include "brave/components/brave_shields/core/browser/ad_block_component_filters_provider.h" #include "brave/components/brave_shields/core/browser/ad_block_filters_provider_manager.h" @@ -252,6 +254,35 @@ void AdBlockComponentServiceManager::EnableFilterList(const std::string& uuid, UpdateFilterListPrefs(uuid, enabled); } +void AdBlockComponentServiceManager::UpdateFilterLists( + base::OnceCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // If there are currently no components to update, then run the callback with + // a success value in a future turn. + if (component_filters_providers_.empty()) { + std::move(callback).Run(true); + return; + } + + // This callback will be executed by our barrier callback once all filter + // list components have been updated. + auto on_all_updated = [](decltype(callback) cb, std::vector results) { + std::move(cb).Run( + base::ranges::all_of(results, [](bool result) { return result; })); + }; + + // This barrier callback maintains a "completed count". When it has been + // called the expected number of times, it will execute `on_all_updated`. + auto barrier_callback = base::BarrierCallback( + component_filters_providers_.size(), + base::BindOnce(on_all_updated, std::move(callback))); + + for (auto& [key, provider] : component_filters_providers_) { + provider->UpdateComponent(barrier_callback); + } +} + void AdBlockComponentServiceManager::SetFilterListCatalog( std::vector catalog) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); diff --git a/components/brave_shields/core/browser/ad_block_component_service_manager.h b/components/brave_shields/core/browser/ad_block_component_service_manager.h index ad47efd913c7..f9288fcc9217 100644 --- a/components/brave_shields/core/browser/ad_block_component_service_manager.h +++ b/components/brave_shields/core/browser/ad_block_component_service_manager.h @@ -54,6 +54,8 @@ class AdBlockComponentServiceManager bool IsFilterListEnabled(const std::string& uuid) const; void EnableFilterList(const std::string& uuid, bool enabled); + void UpdateFilterLists(base::OnceCallback callback); + // AdBlockFilterListCatalogProvider::Observer void OnFilterListCatalogLoaded(const std::string& catalog_json) override; diff --git a/ui/webui/resources/leo/web_components.ts b/ui/webui/resources/leo/web_components.ts index e823d58f7d6a..fdee632353e7 100644 --- a/ui/webui/resources/leo/web_components.ts +++ b/ui/webui/resources/leo/web_components.ts @@ -8,6 +8,7 @@ import '@brave/leo/web-components/button' import '@brave/leo/web-components/dropdown' import '@brave/leo/web-components/checkbox' +import '@brave/leo/web-components/progressRing' import '@brave/leo/web-components/toggle' import { setIconBasePath } from '@brave/leo/web-components/icon' import iconsMeta from '@brave/leo/icons/meta'