diff --git a/browser/brave_local_state_prefs.cc b/browser/brave_local_state_prefs.cc index e41dd1e68c77..2d964cc9c2a7 100644 --- a/browser/brave_local_state_prefs.cc +++ b/browser/brave_local_state_prefs.cc @@ -180,6 +180,9 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { misc_metrics::GeneralBrowserUsage::RegisterPrefs(registry); playlist::PlaylistServiceFactory::RegisterLocalStatePrefs(registry); + + registry->RegisterBooleanPref(kBraveCustomSyncUrlEnabled, false); + registry->RegisterStringPref(kBraveCustomSyncUrl, std::string()); } } // namespace brave diff --git a/browser/brave_profile_prefs.cc b/browser/brave_profile_prefs.cc index 826995ac8dfd..7b802c717a70 100644 --- a/browser/brave_profile_prefs.cc +++ b/browser/brave_profile_prefs.cc @@ -237,7 +237,6 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref(kTabMuteIndicatorNotClickable, false); brave_sync::Prefs::RegisterProfilePrefs(registry); - registry->RegisterBooleanPref(kBraveCustomSyncUrlEnabled, false); brave_shields::RegisterShieldsP3AProfilePrefs(registry); diff --git a/browser/extensions/api/settings_private/brave_prefs_util.cc b/browser/extensions/api/settings_private/brave_prefs_util.cc index 9b76ee35655e..89b01b6a6b03 100644 --- a/browser/extensions/api/settings_private/brave_prefs_util.cc +++ b/browser/extensions/api/settings_private/brave_prefs_util.cc @@ -229,6 +229,7 @@ const PrefsUtil::TypedPrefMap& BravePrefsUtil::GetAllowlistedKeys() { // Sync prefs (*s_brave_allowlist)[kBraveCustomSyncUrlEnabled] = settings_api::PrefType::kBoolean; + (*s_brave_allowlist)[kBraveCustomSyncUrl] = settings_api::PrefType::kUrl; // WebTorrent pref (*s_brave_allowlist)[kWebTorrentEnabled] = settings_api::PrefType::kBoolean; diff --git a/browser/resources/settings/brave_overrides/basic_page.ts b/browser/resources/settings/brave_overrides/basic_page.ts index 037efbe7c093..d885f3f0234f 100644 --- a/browser/resources/settings/brave_overrides/basic_page.ts +++ b/browser/resources/settings/brave_overrides/basic_page.ts @@ -254,7 +254,9 @@ RegisterPolymerTemplateModifications({ 'braveSync', 'braveSync', 'settings-brave-sync-page', - {} + { + prefs: '{{prefs}}' + } )) const sectionShields = document.createElement('template') sectionShields.setAttribute('is', 'dom-if') diff --git a/browser/resources/settings/brave_sync_page/brave_sync_browser_proxy.ts b/browser/resources/settings/brave_sync_page/brave_sync_browser_proxy.ts index e3372d42751c..218be01a1245 100644 --- a/browser/resources/settings/brave_sync_page/brave_sync_browser_proxy.ts +++ b/browser/resources/settings/brave_sync_page/brave_sync_browser_proxy.ts @@ -5,6 +5,7 @@ import {SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js'; import {sendWithPromise} from 'chrome://resources/js/cr.js'; +import {loadTimeData} from '../i18n_setup.js'; export type BraveDeviceInfo = { name: string @@ -56,6 +57,15 @@ export class BraveSyncBrowserProxy { getWordsCount(syncCode: string): Promise { return sendWithPromise('SyncGetWordsCount', syncCode); } + + wasCustomSyncUrlEnabledAtStartup(): boolean { + return loadTimeData.getBoolean('customSyncUrlEnabledAtStartup'); + } + + validateSyncUrl(url: string) { + return sendWithPromise('validateSyncUrl', url); + } + static getInstance() { return instance || (instance = new BraveSyncBrowserProxy()) } diff --git a/browser/resources/settings/brave_sync_page/brave_sync_page.html b/browser/resources/settings/brave_sync_page/brave_sync_page.html index 3281c28720f0..b79b9e24ff91 100644 --- a/browser/resources/settings/brave_sync_page/brave_sync_page.html +++ b/browser/resources/settings/brave_sync_page/brave_sync_page.html @@ -1,41 +1,36 @@
- +
- - + + diff --git a/browser/resources/settings/brave_sync_page/brave_sync_page.ts b/browser/resources/settings/brave_sync_page/brave_sync_page.ts index 8697370ddded..bc3c5bd842b6 100644 --- a/browser/resources/settings/brave_sync_page/brave_sync_page.ts +++ b/browser/resources/settings/brave_sync_page/brave_sync_page.ts @@ -9,6 +9,7 @@ import 'chrome://resources/cr_elements/icons.html.js'; import '../settings_page/settings_animated_pages.js'; import '../settings_page/settings_subpage.js'; import '../settings_shared.css.js'; +import './sync_url_input.js'; import '../settings_vars.css.js'; import './brave_sync_subpage.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.js'; @@ -22,6 +23,7 @@ import { PrefsMixin, PrefsMixinInterface } from '/shared/settings/prefs/prefs_mi import { BaseMixin } from '../base_mixin.js'; import { Route, Router } from '../router.js'; +import { RelaunchMixin, RestartType } from '../relaunch_mixin.js'; import { BraveSyncBrowserProxy, BraveSyncStatus } from './brave_sync_browser_proxy.js'; import { getTemplate } from './brave_sync_page.html.js'; @@ -32,10 +34,7 @@ import { getTemplate } from './brave_sync_page.html.js'; * custom sync. */ -const SettingsBraveSyncPageElementBase = - I18nMixin(WebUiListenerMixin(PrefsMixin(BaseMixin(PolymerElement)))) as { - new(): PolymerElement & PrefsMixinInterface & WebUiListenerMixinInterface & I18nMixinInterface - } +const SettingsBraveSyncPageElementBase = RelaunchMixin(PrefsMixin(I18nMixin(WebUiListenerMixin((BaseMixin(PolymerElement)))))); export class SettingsBraveSyncPageElement extends SettingsBraveSyncPageElementBase { static get is() { @@ -74,11 +73,11 @@ export class SettingsBraveSyncPageElement extends SettingsBraveSyncPageElementBa computeSyncLabel_() { if (this.syncStatus_ !== undefined && - this.syncStatus_.hasSyncWordsDecryptionError) { - return this.i18n('braveSyncCouldNotSyncActionLabel'); + this.syncStatus_.hasSyncWordsDecryptionError) { + return this.i18n('braveSyncCouldNotSyncActionLabel'); } const isAlreadySetup = this.syncStatus_ !== undefined && - !this.syncStatus_.firstSetupInProgress; + !this.syncStatus_.firstSetupInProgress; const key = isAlreadySetup ? 'braveSyncManageActionLabel' : 'braveSyncSetupActionLabel'; return this.i18n(key); } @@ -87,7 +86,7 @@ export class SettingsBraveSyncPageElement extends SettingsBraveSyncPageElementBa super.connectedCallback() const onSyncStatus = this.handleSyncStatus_.bind(this) this.braveBrowserProxy_.getSyncStatus().then( - (status: BraveSyncStatus) => onSyncStatus(status)); + (status: BraveSyncStatus) => onSyncStatus(status)); this.addWebUiListener( 'sync-prefs-changed', this.handleSyncPrefsChanged_.bind(this)); this.addWebUiListener('sync-status-changed', onSyncStatus); @@ -96,7 +95,7 @@ export class SettingsBraveSyncPageElement extends SettingsBraveSyncPageElementBa onSyncTap_() { // Users can go to sync subpage regardless of sync status. const router = Router.getInstance(); - router.navigateTo((router.getRoutes() as {BRAVE_SYNC_SETUP: Route}).BRAVE_SYNC_SETUP); + router.navigateTo((router.getRoutes() as { BRAVE_SYNC_SETUP: Route }).BRAVE_SYNC_SETUP); } /** @@ -116,12 +115,28 @@ export class SettingsBraveSyncPageElement extends SettingsBraveSyncPageElementBa await this.browserProxy_.setDecryptionPassphrase(pureSyncCode); } else if (!this.isEncryptionSet_) { this.browserProxy_.setEncryptionPassphrase(pureSyncCode) - .then(successfullySet => { - this.isEncryptionSet_ = successfullySet - }) + .then(successfullySet => { + this.isEncryptionSet_ = successfullySet + }) } } } + + /** + * @param enabled Whether custom sync url is currently enabled. + */ + private shouldShowRestart_(enabled: boolean): boolean { + const proxy = BraveSyncBrowserProxy.getInstance(); + // TODO: Also need to add a logic when URL is changed. + return enabled !== proxy.wasCustomSyncUrlEnabledAtStartup(); + } + + private onRestartClick_(e: Event) { + // Prevent event from bubbling up to the toggle button. + e.stopPropagation(); + this.performRestart(RestartType.RESTART); + } + } customElements.define( diff --git a/browser/resources/settings/brave_sync_page/sync_url_input.html b/browser/resources/settings/brave_sync_page/sync_url_input.html new file mode 100644 index 000000000000..72b82ae1f036 --- /dev/null +++ b/browser/resources/settings/brave_sync_page/sync_url_input.html @@ -0,0 +1,31 @@ + + + + + diff --git a/browser/resources/settings/brave_sync_page/sync_url_input.ts b/browser/resources/settings/brave_sync_page/sync_url_input.ts new file mode 100644 index 000000000000..17696b6d6f45 --- /dev/null +++ b/browser/resources/settings/brave_sync_page/sync_url_input.ts @@ -0,0 +1,160 @@ +/* Copyright (c) 2024 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/. */ + + +/** + * @fileoverview `sync-url-input` is a single-line text field that is used + * for setting up custom sync server url. It is based on + * `home-url-input`. + */ +import '/shared/settings/prefs/prefs.js'; +import 'chrome://resources/cr_elements/cr_textarea/cr_textarea.js'; + +import type { CrInputElement } from 'chrome://resources/cr_elements/cr_input/cr_input.js'; +import { PolymerElement } from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import { assert } from 'chrome://resources/js/assert.js'; +import { PrefControlMixin } from '/shared/settings/controls/pref_control_mixin.js'; +import { PrefsMixin, PrefsMixinInterface } from '/shared/settings/prefs/prefs_mixin.js'; + +import { BraveSyncBrowserProxy } from './brave_sync_browser_proxy.js'; + +import { getTemplate } from './sync_url_input.html.js'; + +export interface SyncUrlInputElement { + $: { + input: CrInputElement, + }; +} +const SyncUrlInputElementBase = + PrefsMixin(PrefControlMixin(PolymerElement)) as + { new(): PolymerElement & PrefsMixinInterface }; + + + +export class SyncUrlInputElement extends SyncUrlInputElementBase { + static get is() { + return 'sync-url-input'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + /* + * The value of the input field. + */ + value: String, + + /** + * The preference object to control. + */ + pref: { observer: 'prefChanged_' }, + + /* + * Whether |errorText| should be displayed beneath the input field. + */ + showError_: { type: Boolean, computed: 'isInvalid_(errorText_)' }, + + /** + * The error text to display beneath the input field when |showError_| is + * true. + */ + errorText_: { type: String, value: '' }, + }; + } + + value: string; + pref: chrome.settingsPrivate.PrefObject | undefined; + invalid: boolean = false; + private readonly showError_: string; + private errorText_: string; + + private browserProxy_: BraveSyncBrowserProxy = + BraveSyncBrowserProxy.getInstance(); + + private onKeyPress_(e: KeyboardEvent) { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + this.validate_(); + } + } + + /** + * This function ensures that while the user is entering input, especially + * after pressing Enter, the input is not prematurely marked as invalid. + */ + private onInput_() { + this.errorText_ = ''; + } + + private validate_() { + console.log('validate_ : ', this.value); + + if (this.value === '') { + this.invalid = false; + return; + } + + this.browserProxy_.validateSyncUrl(this.value).then(isValid => { + this.invalid = !isValid; + }); + } + + /** + * Polymer changed observer for |pref|. + */ + private prefChanged_() { + if (!this.pref) { + return; + } + + this.setInputValueFromPref_(); + } + + private setInputValueFromPref_() { + assert(this.pref!.type === chrome.settingsPrivate.PrefType.URL); + this.value = this.pref!.value; + } + + private onChange_() { + if (this.invalid) { + this.resetValue_(); + return; + } + + assert(this.pref!.type === chrome.settingsPrivate.PrefType.URL); + this.set('pref.value', this.value); + } + + private resetValue_() { + this.invalid = false; + this.setInputValueFromPref_(); + this.$.input.blur(); + } + + /** + * Focus the custom dns input field. + */ + override focus() { + this.$.input.focusInput(); + } + + /** + * @return whether an error is being shown. + */ + private isInvalid_(): boolean { + return this.invalid; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'sync-url-input': SyncUrlInputElement; + } +} + +customElements.define(SyncUrlInputElement.is, SyncUrlInputElement); diff --git a/browser/resources/settings/sources.gni b/browser/resources/settings/sources.gni index 338fb4306176..15e67d661232 100644 --- a/browser/resources/settings/sources.gni +++ b/browser/resources/settings/sources.gni @@ -36,6 +36,7 @@ brave_settings_web_component_files = [ "brave_sync_page/brave_sync_page.ts", "brave_sync_page/brave_sync_setup.ts", "brave_sync_page/brave_sync_subpage.ts", + "brave_sync_page/sync_url_input.ts", "brave_system_page/brave_performance_page.ts", "brave_tor_page/brave_tor_bridges_dialog.ts", "brave_tor_page/brave_tor_snowflake_install_failed_dialog.ts", diff --git a/browser/ui/webui/brave_settings_ui.cc b/browser/ui/webui/brave_settings_ui.cc index 0822aaa1b20a..8a843a02fb02 100644 --- a/browser/ui/webui/brave_settings_ui.cc +++ b/browser/ui/webui/brave_settings_ui.cc @@ -34,12 +34,14 @@ #include "brave/components/commander/common/features.h" #include "brave/components/commands/common/commands.mojom.h" #include "brave/components/commands/common/features.h" +#include "brave/components/constants/pref_names.h" #include "brave/components/ntp_background_images/browser/view_counter_service.h" #include "brave/components/playlist/common/buildflags/buildflags.h" #include "brave/components/speedreader/common/buildflags/buildflags.h" #include "brave/components/tor/buildflags/buildflags.h" #include "brave/components/version_info/version_info.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/settings/metrics_reporting_handler.h" #include "components/sync/base/command_line_switches.h" @@ -215,6 +217,10 @@ void BraveSettingsUI::AddResources(content::WebUIDataSource* html_source, html_source->AddBoolean( "isSharedPinnedTabsEnabled", base::FeatureList::IsEnabled(tabs::features::kBraveSharedPinnedTabs)); + + html_source->AddBoolean( + "customSyncUrlEnabledAtStartup", + g_browser_process->local_state()->GetBoolean(kBraveCustomSyncUrlEnabled)); } // static 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 5eeb155e27fa..e54cf8fa82e5 100644 --- a/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc +++ b/browser/ui/webui/settings/brave_settings_localized_strings_provider.cc @@ -322,7 +322,6 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source, {"braveCustomSyncUrlEnableLabel", IDS_SETTINGS_BRAVE_CUSTOM_SYNC_URL_ENABLE_LABEL}, {"enterCustomSyncUrl", IDS_SETTINGS_ENTER_CUSTOM_SYNC_URL}, - {"enterCustomSyncUrl", IDS_SETTINGS_ENTER_CUSTOM_SYNC_URL}, {"braveSyncWordCount", IDS_SETTINGS_BRAVE_SYNC_WORD_COUNT}, {"braveSyncCopied", IDS_SETTINGS_BRAVE_SYNC_COPIED_TEXT}, {"braveSyncQRCodeAlt", IDS_SETTINGS_BRAVE_SYNC_QR_IMAGE_ALT}, diff --git a/browser/ui/webui/settings/brave_sync_handler.cc b/browser/ui/webui/settings/brave_sync_handler.cc index f85763f0a408..e2b66861f4a1 100644 --- a/browser/ui/webui/settings/brave_sync_handler.cc +++ b/browser/ui/webui/settings/brave_sync_handler.cc @@ -24,6 +24,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/device_info_sync_service_factory.h" #include "chrome/browser/sync/sync_service_factory.h" +#include "chrome/browser/ui/webui/settings/settings_utils.h" #include "components/qr_code_generator/bitmap_generator.h" #include "components/sync/engine/sync_protocol_error.h" #include "components/sync/service/sync_user_settings.h" @@ -100,6 +101,10 @@ void BraveSyncHandler::RegisterMessages() { "SyncGetWordsCount", base::BindRepeating(&BraveSyncHandler::HandleSyncGetWordsCount, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "validateSyncUrl", + base::BindRepeating(&BraveSyncHandler::HandleValidateSyncUrl, + base::Unretained(this))); } void BraveSyncHandler::OnJavascriptAllowed() { @@ -116,8 +121,9 @@ void BraveSyncHandler::OnJavascriptDisallowed() { } void BraveSyncHandler::OnDeviceInfoChange() { - if (IsJavascriptAllowed()) + if (IsJavascriptAllowed()) { FireWebUIListener("device-info-changed", GetSyncDeviceList()); + } } void BraveSyncHandler::HandleGetDeviceList(const base::Value::List& args) { @@ -132,8 +138,9 @@ void BraveSyncHandler::HandleGetSyncCode(const base::Value::List& args) { auto* sync_service = GetSyncService(); std::string sync_code; - if (sync_service) + if (sync_service) { sync_code = sync_service->GetOrCreateSyncCode(); + } auto time_limited_sync_code = TimeLimitedWords::GenerateForNow(sync_code); if (time_limited_sync_code.has_value()) { @@ -153,8 +160,9 @@ void BraveSyncHandler::HandleGetPureSyncCode(const base::Value::List& args) { auto* sync_service = GetSyncService(); std::string sync_code; - if (sync_service) + if (sync_service) { sync_code = sync_service->GetOrCreateSyncCode(); + } ResolveJavascriptCallback(args[0], base::Value(sync_code)); } @@ -407,3 +415,13 @@ void BraveSyncHandler::HandleSyncGetWordsCount(const base::Value::List& args) { args[0].Clone(), base::Value(TimeLimitedWords::GetWordsCount(time_limited_sync_code))); } + +void BraveSyncHandler::HandleValidateSyncUrl(const base::Value::List& args) { + CHECK_EQ(args.size(), 2U); + const base::Value& callback_id = args[0]; + const std::string& url_string = args[1].GetString(); + AllowJavascript(); + + bool valid = settings_utils::FixupAndValidateStartupPage(url_string, nullptr); + ResolveJavascriptCallback(callback_id, base::Value(valid)); +} diff --git a/browser/ui/webui/settings/brave_sync_handler.h b/browser/ui/webui/settings/brave_sync_handler.h index 99112d6a7599..aa925e29eaf2 100644 --- a/browser/ui/webui/settings/brave_sync_handler.h +++ b/browser/ui/webui/settings/brave_sync_handler.h @@ -48,6 +48,7 @@ class BraveSyncHandler : public settings::SettingsPageUIHandler, void HandleDeleteDevice(const base::Value::List& args); void HandlePermanentlyDeleteAccount(const base::Value::List& args); void HandleSyncGetWordsCount(const base::Value::List& args); + void HandleValidateSyncUrl(const base::Value::List& args); void OnResetDone(base::Value callback_id); void OnAccountPermanentlyDeleted(base::Value callback_id, diff --git a/components/constants/pref_names.h b/components/constants/pref_names.h index 9c5377ddbae9..f9f575c85113 100644 --- a/components/constants/pref_names.h +++ b/components/constants/pref_names.h @@ -162,7 +162,7 @@ inline constexpr char kBraveSuggestedSiteSuggestionsEnabled[] = "brave.brave_suggested_site_suggestions_enabled"; #endif -inline constexpr char kBraveCustomSyncUrlEnabled[] = - "brave.custom_sync_url_enabled"; +inline constexpr char np[] = "brave.custom_sync_url_enabled"; +inline constexpr char kBraveCustomSyncUrl[] = "brave.custom_sync_url"; #endif // BRAVE_COMPONENTS_CONSTANTS_PREF_NAMES_H_