diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 05c685a37e91..04e9999a9e42 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -523,3 +523,5 @@ brave_java_base_module_deps = [ "//third_party/androidx:androidx_core_core_java", "//third_party/androidx:androidx_lifecycle_lifecycle_viewmodel_java", ] + +brave_java_base_module_deps += brave_java_base_module_billing_deps diff --git a/android/java/org/chromium/chrome/browser/vpn/billing/sources.gni b/android/java/org/chromium/chrome/browser/vpn/billing/sources.gni index 6b289a7fe564..74ceb4964835 100644 --- a/android/java/org/chromium/chrome/browser/vpn/billing/sources.gni +++ b/android/java/org/chromium/chrome/browser/vpn/billing/sources.gni @@ -10,3 +10,8 @@ brave_app_vpn_billing_sources = [ brave_app_vpn_billing_deps = [ "//brave/third_party/android_deps:com_android_billingclient_java" ] + +brave_java_base_module_billing_deps = [ + "//brave/third_party/android_deps:com_google_android_datatransport_transport_backend_cct_java", + "//brave/third_party/android_deps:com_google_android_datatransport_transport_runtime_java", +] diff --git a/android/java/proguard.flags b/android/java/proguard.flags index c49ada0a6673..d2eee9c07dbd 100644 --- a/android/java/proguard.flags +++ b/android/java/proguard.flags @@ -1,5 +1,3 @@ --keep class com.google.android.datatransport.runtime.scheduling.** { *; } - -keep class com.google.android.material.bottomsheet.BottomSheetBehavior { *; } -keep class com.google.android.material.behavior.HideBottomViewOnScrollBehavior { *; } diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 1022a358c950..4ee5945a2139 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -1012,9 +1012,6 @@ Or change later at $2brave://settings/ext Show VPN Tray Icon - - Hide VPN Tray Icon - Send Feedback @@ -1032,9 +1029,6 @@ Or change later at $2brave://settings/ext Show VPN tray icon - - Hide VPN tray icon - Send feedback diff --git a/app/resources/chromium_strings_af.xtb b/app/resources/chromium_strings_af.xtb index 8b33958617d4..e948e864ba40 100644 --- a/app/resources/chromium_strings_af.xtb +++ b/app/resources/chromium_strings_af.xtb @@ -414,4 +414,4 @@ Brave kan nie jou instellings herwin nie. {COUNT,plural, =0{Jou administrateur vra dat jy Brave herbegin om hierdie opdatering toe te pas}=1{Jou administrateur vra dat jy Brave herbegin om hierdie opdatering toe te pas. Jou incognitovenster sal nie weer oopgemaak word nie.}other{Jou administrateur vra dat jy Brave herbegin om hierdie opdatering toe te pas. Jou # incognitovensters sal nie weer oopgemaak word nie.}} {COUNT,plural, =0{Jou administrateur vereis dat jy Brave herbegin om 'n opdatering toe te pas}=1{Jou administrateur vereis dat jy Brave herbegin om 'n opdatering toe te pas. Jou incognitovenster sal nie weer oopgemaak word nie.}other{Jou administrateur vereis dat jy Brave herbegin om 'n opdatering toe te pas. Jou # incognitovensters sal nie weer oopgemaak word nie.}} U kan u aangetekende Brave-sinchroniseerkettings bestuur. U Brave-sinchroniseerkettings word gebruik vir die blaaier, Play Store, Gmail en meer. Indien u ’n rekeninge vir iemand anders wil toevoeg, soos ’n gesinslid, voeg liewer ’n nuwe profiel tot u toe. Leer meer - \ No newline at end of file + diff --git a/app/resources/chromium_strings_am.xtb b/app/resources/chromium_strings_am.xtb index 9bb3faf822da..f8d16e2479bd 100644 --- a/app/resources/chromium_strings_am.xtb +++ b/app/resources/chromium_strings_am.xtb @@ -415,4 +415,4 @@ Brave ቅንብሮችዎን ማስመለስ አልቻለም። በመለያ የገቡ Brave የማመሳሰል ሰንሰለቶችን ማቀናበር ይችላሉ። የእርስዎ Brave የማመሳሰል ሰንሰለቶች ለBrave አሳሽ ፣ ለ Play መደብር ፣ ለጂሜይል እና ለሌሎችም ያገለግላሉ። ለሌላ ሰው መለያ ማከል ከፈለጉ ፣ እንደ የቤተሰብ አባል ፣ አዲስ መገለጫ ወደ እርስዎ ያክሉ instead. Learn more በአድራሻ አሞሌው ወይም የፍለጋ ሳጥን ላይ ሲተይቡ፣ Brave የተሻሉ ጥቆማዎችን ለማግኘት በእርስዎ ነባሪ የፍለጋ ሞተር የተየቡትን ይልካል። ይህ በግላዊነት ውስጥ ይጠፋል። በአድራሻ አሊሌው ወይም የፍለጋ ሳጥን ላይ ሲተይቡ፣ Brave የተሻሉ ጥቆማዎችን ለማግኘት በGoogle Drive የተየቡትን ይልካል። ይህ በግላዊነት ውስጥ ይጠፋል። - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ar.xtb b/app/resources/chromium_strings_ar.xtb index 56bed9e3ad60..6db96dfaf24f 100644 --- a/app/resources/chromium_strings_ar.xtb +++ b/app/resources/chromium_strings_ar.xtb @@ -414,4 +414,4 @@ يمكنك إدارة سلاسل مزامنة تسجيل الدخول إلى Brave الخاصة بك تُستخدم سلاسل مزامنة Brave الخاصة بك لأجل متصفح Brave، ومتجر Play، وGmail، وأكثر. إذا رغبت في إضافة حساب لشخص آخر، كأحد أفراد الأسرة، فأضف ملف تعريف جديدًا إلى الخاص بك بدلاً من. معرفة المزيد عندما تكتب في شريط العناوين أو مربع البحث، فإن Brave يرسل ما تكتبه إلى محرك البحث الافتراضي للحصول على اقتراحات أفضل. هذا متوقف في الوضع الخاص. عندما تكتب في شريط العناوين أو مربع البحث، فإن Brave يرسل ما تكتبه إلى Google Drive للحصول على اقتراحات العناصر. هذا متوقف في الوضع الخاص. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_as.xtb b/app/resources/chromium_strings_as.xtb index ef38c324ad62..2198b5511012 100644 --- a/app/resources/chromium_strings_as.xtb +++ b/app/resources/chromium_strings_as.xtb @@ -416,4 +416,4 @@ Braveএ আপোনাৰ ছেটিংসমূহ পুনৰুদ্ধ {COUNT,plural, =0{আপোনাৰ প্ৰশাসকে আপোনাক এই আপডে’টটো প্ৰযোজ্য কৰিবলৈ আপোনাক Brave পুনৰ লঞ্চ কৰিবলৈ কৈছে}=1{আপোনাৰ প্ৰশাসকে এই আপডে’টটো প্ৰযোজ্য কৰিবলৈ আপোনাক Brave পুনৰ লঞ্চ কৰিবলৈ কৈছে। আপোনাৰ.ইনক’গনিট' ৱিণ্ড'খন পুনৰ খুলিব নোৱাৰিব।}one{আপোনাৰ প্ৰশাসকে এই আপডে’টটো প্ৰযোজ্য কৰিবলৈ আপোনাক Brave পুনৰ লঞ্চ কৰিবলৈ কৈছে। আপোনাৰ #খন.ইনক’গনিট' ৱিণ্ড' পুনৰ খুলিব নোৱাৰিব।}other{আপোনাৰ প্ৰশাসকে এই আপডে’টটো প্ৰযোজ্য কৰিবলৈ আপোনাক Brave পুনৰ লঞ্চ কৰিবলৈ কৈছে। আপোনাৰ #খন.ইনক’গনিট' ৱিণ্ড' পুনৰ খুলিব নোৱাৰিব।}} {COUNT,plural, =0{আপোনাৰ প্ৰশাসকে কোনো আপডে’ট প্ৰয়োগ কৰিবলৈ আপুনি Brave পুনৰ লঞ্চ কৰাটো বিচাৰে}=1{আপোনাৰ প্ৰশাসকে কোনো আপডে’ট প্ৰয়োগ কৰিবলৈ আপুনি Brave পুনৰ লঞ্চ কৰাটো বিচাৰে। আপোনাৰ.ইনক’গনিট' ৱিণ্ড'খন পুনৰ খুলিব নোৱাৰিব।}one{আপোনাৰ প্ৰশাসকে কোনো আপডে’ট প্ৰয়োগ কৰিবলৈ আপুনি Brave পুনৰ লঞ্চ কৰাটো বিচাৰে। আপোনাৰ #খন.ইনক’গনিট' ৱিণ্ড' পুনৰ খুলিব নোৱাৰিব।}other{আপোনাৰ প্ৰশাসকে কোনো আপডে’ট প্ৰয়োগ কৰিবলৈ আপুনি Brave পুনৰ লঞ্চ কৰাটো বিচাৰে। আপোনাৰ #খন.ইনক’গনিট' ৱিণ্ড' পুনৰ খুলিব নোৱাৰিব।}} আপুনি নিজৰ ছাইন ইন কৰি ৰখা Brave একাউণ্টসমূহ পৰিচালনা কৰিব পাৰে। আপোনাৰ Brave একাউণ্টসমূহ Brave ব্ৰাউজাৰ, Play Store, Gmail আৰু বহুতো প্ৰ’ডাক্টত ব্যৱহাৰ কৰা হয়। যদি আপুনি অন্য কাৰোবাৰ বাবে এটা একাউণ্ট যোগ দিব খোজে, যেনে পৰিয়ালৰ কোনো সদস্যৰ বাবে, তাৰ সলনি আপোনাৰ ত এগৰাকী নতুন ব্যক্তি যোগ দিয়ক। অধিক জানক - \ No newline at end of file + diff --git a/app/resources/chromium_strings_az.xtb b/app/resources/chromium_strings_az.xtb index dc8e5a84ab97..382a94cc083a 100644 --- a/app/resources/chromium_strings_az.xtb +++ b/app/resources/chromium_strings_az.xtb @@ -411,4 +411,4 @@ Bəzi funksiyalar əlçatmaz ola bilər. Xüsusi profil direktoriyası göstəri Brave Müəllifləri Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_be.xtb b/app/resources/chromium_strings_be.xtb index 3311c3f5d2bf..c599d489b23f 100644 --- a/app/resources/chromium_strings_be.xtb +++ b/app/resources/chromium_strings_be.xtb @@ -415,4 +415,4 @@ {COUNT,plural, =0{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення}=1{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення. Акно ў рэжыме інкогніта не будзе адкрыта паўторна.}one{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення. # акно ў рэжыме інкогніта не будзе адкрыта паўторна.}few{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення. # акны ў рэжыме інкогніта не будуць адкрыты паўторна.}many{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення. # вокнаў у рэжыме інкогніта не будуць адкрыты паўторна.}other{Ваш адміністратар просіць перазапусціць Brave для ўсталявання абнаўлення. # акна ў рэжыме інкогніта не будуць адкрыты паўторна.}} {COUNT,plural, =0{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення}=1{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення. Акно ў рэжыме інкогніта не будзе адкрыта паўторна.}one{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення. # акно ў рэжыме інкогніта не будзе адкрыта паўторна.}few{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення. # акны ў рэжыме інкогніта не будуць адкрыты паўторна.}many{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення. # вокнаў у рэжыме інкогніта не будуць адкрыты паўторна.}other{Ваш адміністратар патрабуе перазапусціць Brave для ўсталявання абнаўлення. # акна ў рэжыме інкогніта не будуць адкрыты паўторна.}} У гэтым раздзеле можна кіраваць Уліковымі запісамі Brave, у якія вы ўвайшлі. Вашы Уліковыя запісы Brave выкарыстоўваюцца ў браўзеры Brave, Краме Play, пошце Gmail і іншых сэрвісах. Калі вы хочаце дадаць уліковы запіс для каго-небудзь яшчэ (напрыклад, для ўдзельніка сямейнай групы), дадайце на прыладу "" новага карыстальніка. Даведацца больш - \ No newline at end of file + diff --git a/app/resources/chromium_strings_bg.xtb b/app/resources/chromium_strings_bg.xtb index 4c46e736aa3f..2d7990bcddb3 100644 --- a/app/resources/chromium_strings_bg.xtb +++ b/app/resources/chromium_strings_bg.xtb @@ -408,4 +408,4 @@ Можете да управлявате регистираните вериги на Brave за синхронизиране. Вашите вериги за синхронизиране на Brave се използват за браузъра Brave, Play Store, Gmail и др. Ако искате да добавите акаунт за някой друг, например член на семейството, вместо това добавете нов профил в . Научете повече Когато пишете в адресната лента или полето за търсене, Brave автоматично изпраща написаното към Вашата търсачка по подразбиране, за да получите по-добри предложения. Тази функция е изключена в режим Личен. Когато пишете в адресната лента или полето за търсене, Brave автоматично изпраща написаното към Google Drive, за да получите предложения. Тази функция е изключена в режим Личен. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_bn.xtb b/app/resources/chromium_strings_bn.xtb index 90b72323276d..8ed18cbf0c20 100644 --- a/app/resources/chromium_strings_bn.xtb +++ b/app/resources/chromium_strings_bn.xtb @@ -412,4 +412,4 @@ Brave আপনার সেটিংস পুনরুদ্ধার কর আপনি Brave সিঙ্ক চেইনে আপনার সাইন-ইন নিয়ন্ত্রণ করতে পারেন। আপনার Brave সিঙ্ক চেইনগুলো Brave ব্রাউজার, Play Store, Gmail এবং আরও অনেক কিছুর জন্য ব্যবহৃত হয়। আপনি পরিবারের সদস্যের মতো অন্য কারও জন্য একটি অ্যাকাউন্ট যোগ করতে চাইলে, অ্যাকাউন্টের বদলে আপনার -এ একটা নতুন প্রোফাইল যোগ করুন। আরও জানুন আপনি যখন অ্যাড্রেস বারে বা সন্ধানের বক্সে টাইপ করেন তখন আরো ভালো পরামর্শ পেতে Brave, আপনি যা টাইপ করেন সেটিকে আপনার ডিফল্ট সন্ধানের ইঞ্জিনে পাঠায়। ব্যক্তিগত-তে এটি বন্ধ। আপনি যখন অ্যাড্রেস বারে বা সন্ধান বক্সে টাইপ করেন তখন আইটেমের পরামর্শ পেতে Brave, আপনি যা টাইপ করেন সেটিকে Google Drive-এ পাঠায়। ব্যক্তিগত-তে এটি বন্ধ। - \ No newline at end of file + diff --git a/app/resources/chromium_strings_bs.xtb b/app/resources/chromium_strings_bs.xtb index 37f946cb2270..042f9f526fd3 100644 --- a/app/resources/chromium_strings_bs.xtb +++ b/app/resources/chromium_strings_bs.xtb @@ -416,4 +416,4 @@ Odobrenja koja ste već dali web lokacijama i aplikacijama se mogu primjenjivati {COUNT,plural, =0{Vaš administrator traži da ponovo pokrenete Brave radi primjene ovog ažuriranja}=1{Vaš administrator traži da ponovo pokrenete Brave radi primjene ovog ažuriranja. Vaš anonimni prozor se neće ponovo otvoriti.}one{Vaš administrator traži da ponovo pokrenete Brave radi primjene ovog ažuriranja. Vaš # anonimni prozor se neće ponovo otvoriti.}few{Vaš administrator traži da ponovo pokrenete Brave radi primjene ovog ažuriranja. Vaša # anonimna prozora se neće ponovo otvoriti.}other{Vaš administrator traži da ponovo pokrenete Brave radi primjene ovog ažuriranja. Vaših # anonimnih prozora se neće ponovo otvoriti.}} {COUNT,plural, =0{Administrator traži da ponovo pokrenete Brave radi primjene ažuriranja}=1{Administrator traži da ponovo pokrenete Brave radi primjene ažuriranja. Vaš anonimni prozor se neće ponovo otvoriti.}one{Administrator traži da ponovo pokrenete Brave radi primjene ažuriranja. Vaš # anonimni prozor se neće ponovo otvoriti.}few{Administrator traži da ponovo pokrenete Brave radi primjene ažuriranja. Vaša # anonimna prozora se neće ponovo otvoriti.}other{Administrator traži da ponovo pokrenete Brave radi primjene ažuriranja. Vaših # anonimnih prozora se neće ponovo otvoriti.}} Možete upravljati Brave računima na koje ste prijavljeni. Vaši Brave računi se koriste za preglednik Brave, Play trgovinu, Gmail i drugo. Ako želite dodati račun za nekog drugog, kao što je član porodice, umjesto računa dodajte novu osobu na svoj uređaj . Saznajte više - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ca.xtb b/app/resources/chromium_strings_ca.xtb index 25f941611186..cc252138a8d5 100644 --- a/app/resources/chromium_strings_ca.xtb +++ b/app/resources/chromium_strings_ca.xtb @@ -414,4 +414,4 @@ Els permisos que ja heu donat als llocs web i a les aplicacions poden aplicar-se Pots gestionar les teves cadenes de sincronització de Brave en què hagis iniciat sessió. Les cadenes de sincronització de Brave s'utilitzen per al navegador de Brave, Play Store, Gmail, etc. Si vols afegir un compte per una altra persona, com ara un familiar, afegeix un perfil nou al teu instead. Més informació Quan escrius a la barra d'adreces o al quadre de cerca, Brave envia el que escrius al motor de cerca predeterminat per obtenir millors suggeriments. Aquesta opció està desactivada en el mode d'incògnit. Quan escrius a la barra d'adreces o al quadre de cerca, Brave envia el que escrius a Google Drive per a obtenir suggeriments d'articles. Aquesta opció està desactivada en el mode d'incògnit. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_cs.xtb b/app/resources/chromium_strings_cs.xtb index 203e3e22269d..40039b68f0b2 100644 --- a/app/resources/chromium_strings_cs.xtb +++ b/app/resources/chromium_strings_cs.xtb @@ -416,4 +416,4 @@ Na tento účet se mohou vztahovat oprávnění, která jste již udělili webov Můžete spravovat přihlášené synchronizační řetězce Brave. Vaše synchronizační řetězce Brave se používají pro prohlížeč Brave, obchod Play, Store Gmail a další služby. Pokud chcete přidat účet pro někoho jiného, například člena rodiny, přidejte nový profil do svého zařízení . Více informací Když zadáváte text do adresního řádku nebo vyhledávacího pole, Brave zasílá vámi psaný text do vašeho výchozího vyhledávače, aby byla zobrazena lepší doporučení. To je v soukromém režimu vypnuto. Když zadáváte text do adresního řádku nebo vyhledávacího pole, Brave zasílá vámi psaný text na disk Google, aby byla získána doporučení položek. To je v soukromém režimu vypnuto. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_cy.xtb b/app/resources/chromium_strings_cy.xtb index 5926a395c719..84c3a3e12dc0 100644 --- a/app/resources/chromium_strings_cy.xtb +++ b/app/resources/chromium_strings_cy.xtb @@ -416,4 +416,4 @@ Mae'n bosib y bydd caniatadau rydych eisoes wedi'u rhoi i wefannau ac apiau yn b {COUNT,plural, =0{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn}=1{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn. Ni fydd eich ffenestr Anhysbys yn ailagor.}two{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn. Ni fydd eich # ffenestr Anhysbys yn ailagor.}few{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn. Ni fydd eich # ffenestr Anhysbys yn ailagor.}many{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn. Ni fydd eich # ffenestr Anhysbys yn ailagor.}other{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso'r diweddariad hwn. Ni fydd eich # ffenestr Anhysbys yn ailagor.}} {COUNT,plural, =0{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad}=1{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad. Ni fydd eich ffenestr Anhysbys yn ailagor.}two{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad. Ni fydd eich # ffenestr Anhysbys yn ailagor.}few{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad. Ni fydd eich # ffenestr Anhysbys yn ailagor.}many{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad. Ni fydd eich # ffenestr Anhysbys yn ailagor.}other{Mae eich gweinyddwr yn gofyn i chi ail-lansio Brave i gymhwyso diweddariad. Ni fydd eich # ffenestr Anhysbys yn ailagor.}} Gallwch reoli'ch Cyfrifon Brave sydd wedi'u mewngofnodi. Defnyddir eich Cyfrifon Brave ar gyfer porwr Brave, Play Store, Gmail, a rhagor. Os ydych am ychwanegu cyfrif ar gyfer rhywun arall, megis aelod o'r teulu, ychwanegwch berson newydd at eich yn lle. Dysgu rhagor - \ No newline at end of file + diff --git a/app/resources/chromium_strings_da.xtb b/app/resources/chromium_strings_da.xtb index 72eb416b3e23..455b0cd2b868 100644 --- a/app/resources/chromium_strings_da.xtb +++ b/app/resources/chromium_strings_da.xtb @@ -414,4 +414,4 @@ Tilladelser, som du allerede har givet til websider og apps kan være gældende Du kan tilpasse dine synkroniseringskæder, når du er logget ind i Brave. Dine Brave-synkroniseringskæder bruges til Brave-browseren, Play Store, Gmail og andet. Hvis du vil tilføje en konto for en anden, f.eks. et familiemedlem, skal du tilføje en ny profil til instead. Learn more Når du skriver noget i adresselinjen eller søgefeltet, sender Brave de indtastede værdier til din primære søgemaskine for at få bedre forslag. Dette er slået fra i Privat-tilstand. Når du skriver noget i adresselinjen eller søgefeltet, sender Brave de indtastede værdier til Google Drive for at modtage forslag til elementer. Dette er slået fra i Privat-tilstand. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_de.xtb b/app/resources/chromium_strings_de.xtb index 0c353417cf54..9a9a8b051479 100644 --- a/app/resources/chromium_strings_de.xtb +++ b/app/resources/chromium_strings_de.xtb @@ -407,4 +407,4 @@ Berechtigungen, die Sie Websites und Apps bereits erteilt haben, gelten möglich Sie können Ihre angemeldeten Brave-Sync-Ketten verwalten. Ihre Brave-Sync-Ketten werden für den Brave Browser, den Play Store, Gmail und mehr verwendet. Wenn Sie ein Konto für jemand anderes (wie etwa ein Familienmitglied) hinzufügen möchten, fügen Sie stattdessen ein neues Profil auf Ihrem hinzu. Mehr erfahren Wenn Sie etwas in die Adressleiste oder das Suchfeld eingeben, sendet Brave Ihre Eingabe an Ihre Standardsuchmaschine, um bessere Vorschläge zu erhalten. Dies ist im Privatmodus deaktiviert. Wenn Sie etwas in die Adressleiste oder das Suchfeld eingeben, sendet Brave Ihre Eingabe an Google Drive, um Artikelvorschläge zu erhalten. Dies ist im Privatmodus deaktiviert. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_el.xtb b/app/resources/chromium_strings_el.xtb index c51b7109fc01..c0355f9383b4 100644 --- a/app/resources/chromium_strings_el.xtb +++ b/app/resources/chromium_strings_el.xtb @@ -423,4 +423,4 @@ Μπορείτε να διαχειρίζεστε τις αλυσίδες συγχρονισμού Brave που βρίσκονται σε σύνδεση. Οι αλυσίδες συγχρονισμού Brave χρησιμοποιούνται για το πρόγραμμα περιήγησης Brave, το Play Store, το Gmail και άλλα. Αν θέλετε να προσθέσετε έναν λογαριασμό για κάποιον άλλο, όπως ένα μέλος οικογένειας, αντί για νέο λογαριασμό, προσθέστε ένα νέο προφίλ στο δικό σας . Μάθετε περισσότερα Όταν πληκτρολογείτε κάτι στη γραμμή διευθύνσεων ή στο πλαίσιο αναζήτησης, το Brave στέλνει το περιεχόμενο που πληκτρολογείτε στην προεπιλεγμένη μηχανή αναζήτησής σας για να λαμβάνετε καλύτερες προτάσεις. Αυτή η επιλογή είναι απενεργοποιημένη στην Ιδιωτική λειτουργία. Όταν πληκτρολογείτε κάτι στη γραμμή διευθύνσεων ή στο πλαίσιο αναζήτησης, το Brave στέλνει το περιεχόμενο που πληκτρολογείτε στο Google Drive για να λαμβάνετε προτάσεις στοιχείων. Αυτή η επιλογή είναι απενεργοποιημένη στην Ιδιωτική λειτουργία. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_en-GB.xtb b/app/resources/chromium_strings_en-GB.xtb index 070466e7a839..46a9a77f6e0c 100644 --- a/app/resources/chromium_strings_en-GB.xtb +++ b/app/resources/chromium_strings_en-GB.xtb @@ -415,4 +415,4 @@ Permissions you've already given to websites and apps may apply to this account. You can manage your signed-in Brave sync chains. Your Brave sync chains are used for Brave browser, Play Store, Gmail and more. If you want to add an account for someone else, like a family member, add a new profile to your instead. Learn more When you type in the address bar or search box, Brave sends what you type to your default search engine to get better suggestions. This is off in Private. When you type in the address bar or search box, Brave sends what you type to Google Drive to get item suggestions. This is off in Private. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_es-419.xtb b/app/resources/chromium_strings_es-419.xtb index 6f76aca4d92e..f9e5fc647071 100644 --- a/app/resources/chromium_strings_es-419.xtb +++ b/app/resources/chromium_strings_es-419.xtb @@ -408,4 +408,4 @@ Es posible que los permisos para sitios web y aplicaciones que ya hayas concedid Puedes administrar tus cadenas de sincronización de Brave conectadas. Tus cadenas de sincronización de Brave se usan en el navegador de Brave, en Play Store, en Gmail, etc. Si quieres agregar una cuenta de otra persona, como un familiar, agrega un perfil nuevo en tu . Más información Cuando escribes en la barra de direcciones o en el cuadro de búsqueda, Brave envía lo que escribes a tu motor de búsqueda predeterminado para obtener mejores sugerencias. Esto está desactivado en el modo de incógnito. Cuando escribes en la barra de direcciones o en el cuadro de búsqueda, Brave envía lo que escribes a Google Drive para obtener sugerencias de elementos. Esto está desactivado en el modo de incógnito. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_es.xtb b/app/resources/chromium_strings_es.xtb index 4a8304ccceae..0148fa490418 100644 --- a/app/resources/chromium_strings_es.xtb +++ b/app/resources/chromium_strings_es.xtb @@ -425,4 +425,4 @@ Es posible que los permisos para sitios web y aplicaciones que ya hayas concedid Puedes administrar tus cadenas de sincronización de Brave conectadas. Tus cadenas de sincronización de Brave se usan en el navegador de Brave, en Play Store, Gmail y muchas más plataformas. Si quieres añadir la cuenta de otra persona, como puede ser un familiar, añade un nuevo perfil en tu . Más información Cuando escribes en la barra de direcciones o en el cuadro de búsqueda, Brave envía lo que escribes a tu motor de búsqueda predeterminado para obtener mejores sugerencias. Esta función está desactivada en el modo de incógnito. Cuando escribes en la barra de direcciones o en el cuadro de búsqueda, Brave envía lo que escribes a Google Drive para obtener sugerencias de elementos. Esta función está desactivada en el modo de incógnito. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_et.xtb b/app/resources/chromium_strings_et.xtb index 0ef75c482b9a..373b65fc8580 100644 --- a/app/resources/chromium_strings_et.xtb +++ b/app/resources/chromium_strings_et.xtb @@ -413,4 +413,4 @@ Selle konto suhtes võivad kehtida õigused, mille olete veebisaitidele ja raken Saate hallata oma Brave'i sünkroonimisahelaid, kuhu olete sisse loginud. Brave'i sünkroonimisahelaid kasutatakse Brave'i brauseri, Play Store'i, Gmaili ja muu jaoks. Kui soovite lisada konto kellelegi teisele, näiteks pereliikmele, lisage oma hoopis uus profiil. Lisateave Kui sisestate midagi aadressiribale või otsingukasti, saadab Brave sisestatava teie vaikeotsingumootorile, et saada paremaid soovitusi. Privaatses režiimis on see välja lülitatud. Kui sisestate midagi aadressiribale või otsingukasti, saadab Brave sisestatava Google Drive’i, et saada paremaid soovitusi. Privaatses režiimis on see välja lülitatud. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_eu.xtb b/app/resources/chromium_strings_eu.xtb index 4963ec5c71e6..42db3c0053a0 100644 --- a/app/resources/chromium_strings_eu.xtb +++ b/app/resources/chromium_strings_eu.xtb @@ -415,4 +415,4 @@ Baliteke webguneei eta aplikazioei emandako baimenak kontu honi aplikatzea. Brav {COUNT,plural, =0{Brave berrabiarazteko eskatu dizu administratzaileak, eguneratzea aplikatzeko}=1{Brave berrabiarazteko eskatu dizu administratzaileak, eguneratzea aplikatzeko. Ezkutuko moduko leihoa ez da berriro irekiko.}other{Brave berrabiarazteko eskatu dizu administratzaileak, eguneratzea aplikatzeko. Ezkutuko moduko # leihoak ez dira berriro irekiko.}} {COUNT,plural, =0{Brave berrabiaraz dezazun behar du administratzaileak, eguneratzea aplikatzeko}=1{Brave berrabiaraz dezazun behar du administratzaileak, eguneratzea aplikatzeko. Ezkutuko moduko leihoa ez da berriro irekiko.}other{Brave berrabiaraz dezazun behar du administratzaileak, eguneratzea aplikatzeko. Ezkutuko moduko # leihoak ez dira berriro irekiko.}} Saioa hasita daukaten Brave-ko kontuak kudea ditzakezu. Brave-ko kontuak Brave arakatzaile, Play Store, Gmail eta abarrerako erabiltzen dira. Kontu bat beste norbaitentzat gehitu nahi baduzu (adibidez, familiako kide batentzat), gehitu beste pertsona bat gailuan. Lortu informazio gehiago - \ No newline at end of file + diff --git a/app/resources/chromium_strings_fa.xtb b/app/resources/chromium_strings_fa.xtb index e009598d0118..dc9db24dd972 100644 --- a/app/resources/chromium_strings_fa.xtb +++ b/app/resources/chromium_strings_fa.xtb @@ -411,4 +411,4 @@ Brave قادر به بازیابی تنظیمات شما نیست. می‌توانید زنجیره‌های همگام‌سازی Brave واردشده به سیستم خود را مدیریت کنید. از زنجیره‌های همگام‌سازی Brave شما برای مرورگر Brave،‏ Play Store،‏ Gmail و موارد دیگر استفاده می‌شود. اگر می‌خواهید حسابی را برای شخص دیگری، مثل اعضای خانواده، اضافه کنید، به‌جای آن، نمایه جدیدی به خود اضافه کنید. بیشتر بدانید وقتی در نوار آدرس یا کادر جستجو تایپ می‌کنید، Brave آنچه را که تایپ می‌کنید به موتور جستجوی پیش‌فرض شما ارسال می‌کند تا پیشنهادات بهتری دریافت کند. این قابلیت در حالت «خصوصی» خاموش است. وقتی در نوار آدرس یا کادر جستجو تایپ می‌کنید، Brave آنچه را که تایپ می‌کنید به Google Drive می‌فرستد تا پیشنهادات مورد را دریافت کند. این قابلیت در حالت «خصوصی» خاموش است. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_fi.xtb b/app/resources/chromium_strings_fi.xtb index 56ad8ec4ea0d..1e3ec962949d 100644 --- a/app/resources/chromium_strings_fi.xtb +++ b/app/resources/chromium_strings_fi.xtb @@ -414,4 +414,4 @@ Verkkosivustoille ja sovelluksille aiemmin antamasi käyttöoikeudet voivat kosk Voit hallita sisäänkirjautuneita Brave-synkronointiketjujasi. Brave-synkronointiketjujasi käytetään Brave-selaimelle, Play-kaupalle, Gmailille ja muille. Jos haluat lisätä tilin toiselle käyttäjälle, esim. perheenjäsenelle, lisää uusi profiili kohteeseen sen sijaan. Lue lisää Kun kirjoitat tekstiä osoitepalkkiin tai hakukenttään, Brave lähettää kirjoittamasi tekstin oletushakukoneeseesi, jotta saat parempia ehdotuksia. Tämä on pois päältä yksityisessä tilassa. Kun kirjoitat tekstiä osoitepalkkiin tai hakukenttään, Brave lähettää kirjoittamasi tekstin Google Driveen, jotta saat kohde-ehdotuksia. Tämä on pois päältä yksityisessä tilassa. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_fil.xtb b/app/resources/chromium_strings_fil.xtb index 8a3bf72fdc31..6d304648a62c 100644 --- a/app/resources/chromium_strings_fil.xtb +++ b/app/resources/chromium_strings_fil.xtb @@ -416,4 +416,4 @@ Maaaring malapat sa account na ito ang mga pahintulot na naibigay mo na sa mga w Maaari mong pamahalaan ang iyong mga naka-sign in na chain ng pag-sync ng Brave. Ginagamit ang iyong mga chain ng pag-sync ng Brave para sa Brave browser, Play Store, Gmail, at higit pa. Kung gusto mong magdagdag ng account para sa iba pang tao, tulad ng miyembro ng pamilya, magdagdag na lang ng bagong profile sa iyong . Matuto pa Kapag nag-type ka sa address bar o box para sa paghahanap, ipinapadala ng Brave ang tina-type mo sa iyong default na search engine para makakuha ng mas mahuhusay na suhestyon. Naka-off ito sa Pribado. Kapag nag-type ka sa address bar o box para sa paghahanap, ipinapadala ng Brave ang tina-type mo sa Google Drive para makakuha ng mga suhestyon sa item. Naka-off ito sa Pribado. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_fr-CA.xtb b/app/resources/chromium_strings_fr-CA.xtb index af571490c9f8..8d3f7de18cda 100644 --- a/app/resources/chromium_strings_fr-CA.xtb +++ b/app/resources/chromium_strings_fr-CA.xtb @@ -409,4 +409,4 @@ Les autorisations que vous avez déjà accordées aux sites Web et aux applicati Vous pouvez gérer vos chaînes de synchronisation Brave connectées. Vos chaînes de synchronisation Brave sont utilisées pour le navigateur Brave, la boutique Play Store, Gmail et plus encore. Si vous souhaitez ajouter un compte pour une autre personne, comme un membre de votre famille, ajoutez plutôt un nouveau profil à votre . En savoir plus Lorsque vous tapez dans la barre d'adresse ou la zone de recherche, Brave envoie ce que vous saisissez à votre moteur de recherche par défaut pour obtenir de meilleures suggestions. Cette fonctionnalité est désactivée en mode de navigation privée. Lorsque vous tapez dans la barre d'adresse ou la zone de recherche, Brave envoie ce que vous saisissez à Google Disque pour obtenir des suggestions. Cette fonctionnalité est désactivée en mode de navigation privée. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_fr.xtb b/app/resources/chromium_strings_fr.xtb index 63fc0b8d0da8..78da3dddd598 100644 --- a/app/resources/chromium_strings_fr.xtb +++ b/app/resources/chromium_strings_fr.xtb @@ -415,4 +415,4 @@ Les autorisations que vous avez déjà accordées à des sites Web et à des app Vous pouvez gérer vos chaînes de synchronisation Brave connectées. Vos chaînes de synchronisation Brave sont utilisées pour le navigateur Brave, le Play Store, Gmail et plus encore. Si vous souhaitez ajouter un compte pour une autre personne, comme un membre de votre famille, ajoutez plutôt un nouveau profil à votre . En savoir plus Lorsque vous tapez dans la barre d'adresse ou la zone de recherche, Brave envoie ce que vous saisissez à votre moteur de recherche par défaut pour obtenir de meilleures suggestions. Cette fonctionnalité est désactivée en mode de navigation privée. Lorsque vous tapez dans la barre d'adresse ou la zone de recherche, Brave envoie ce que vous saisissez à Google Drive pour obtenir des suggestions. Cette fonctionnalité est désactivée en mode de navigation privée. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_gl.xtb b/app/resources/chromium_strings_gl.xtb index 90b98f1ac412..cd940c73f742 100644 --- a/app/resources/chromium_strings_gl.xtb +++ b/app/resources/chromium_strings_gl.xtb @@ -415,4 +415,4 @@ Brave non pode recuperar a túa configuración. Podes xestionar as túas cadeas de sincronización de Brave conectadas. As túas cadeas de sincronización de Brave empréganse no navegador de Brave, Play Store, Gmail e noutras moitas plataformas. Se desexas engadir a conta doutra persoa, como pode ser un familiar, engade un novo perfil no teu . Máis información Cando escribas na barra de enderezos ou na caixa de busca, Brave enviará o que escribas ao teu motor de busca predeterminado para obter mellores suxestións. Esta opción está desactivada na opción Privado. Cando escribas na barra de enderezos ou na caixa de busca, Brave enviará o que escribas en Google Drive para obter suxestións de artigos. Esta opción está desactivada na opción Privado. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_gu.xtb b/app/resources/chromium_strings_gu.xtb index 84ed8569588c..bf6550d6245d 100644 --- a/app/resources/chromium_strings_gu.xtb +++ b/app/resources/chromium_strings_gu.xtb @@ -416,4 +416,4 @@ Brave તમારા સેટિંગને રિકવર શકતું {COUNT,plural, =0{આ અપડેટ લાગુ કરવા માટે Brave ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપકનું કહેવું છે}=1{આ અપડેટ લાગુ કરવા માટે Brave ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપકનું કહેવું છે. તમારી છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}one{આ અપડેટ લાગુ કરવા માટે Brave ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપકનું કહેવું છે. તમારી # છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}other{આ અપડેટ લાગુ કરવા માટે Brave ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપકનું કહેવું છે. તમારી # છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}} {COUNT,plural, =0{અપડેટ લાગુ કરવા માટે તમે Braveને ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપક ઇચ્છે છે}=1{અપડેટ લાગુ કરવા માટે તમે Braveને ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપક ઇચ્છે છે. તમારી છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}one{અપડેટ લાગુ કરવા માટે તમે Braveને ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપક ઇચ્છે છે. તમારી # છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}other{અપડેટ લાગુ કરવા માટે તમે Braveને ફરીથી લૉન્ચ કરો એવું તમારા વ્યવસ્થાપક ઇચ્છે છે. તમારી # છુપી વિન્ડો ફરીથી ખૂલશે નહીં.}} તમે તમારા સાઇન ઇન કરેલા હોય એવા Brave એકાઉન્ટ મેનેજ કરી શકો છો. તમારા Brave એકાઉન્ટનો ઉપયોગ Brave બ્રાઉઝર, Play Store, Gmail અને વધુ માટે થાય છે. જો તમે કોઈ બીજા, જેમકે તમારા કુટુંબના સભ્ય માટે એકાઉન્ટ ઉમેરવા માંગતા હો, તો તેના બદલે નવી વ્યક્તિને તમારા માં ઉમેરો. વધુ જાણો - \ No newline at end of file + diff --git a/app/resources/chromium_strings_hi.xtb b/app/resources/chromium_strings_hi.xtb index b8a372efe4f9..5863f17f43d3 100644 --- a/app/resources/chromium_strings_hi.xtb +++ b/app/resources/chromium_strings_hi.xtb @@ -414,4 +414,4 @@ Brave आपकी सेटिंग बहाल नहीं कर सकत आप अपने साइन-इन किए हुए Brave सिंक चेन को मैनेज कर सकते हैं. आपकी Brave सिंक चेन का उपयोग Brave ब्राउज़र, Play Store, Gmail, और बहुत कुछ के लिए किया जाता है. अगर आप किसी और जैसे की परिवार के किसी सदस्य के लिए अकाउंट जोड़ना चाहते हैं, तो अपने बजाए. और जानें जब आप पता बार या खोज बॉक्स में टाइप करते हैं, तो बेहतर सुझाव पाने के लिए, आप जो कुछ टाइप करते हैं Brave उसे आपके डिफ़ॉल्ट खोज इंजन पर भेजता है। यह 'निजी' में बंद रहता है। जब आप पता बार या खोज बॉक्स में टाइप करते हैं, तो आइटम के सुझाव पाने के लिए, आप जो कुछ टाइप करते हैं Brave उसे Google Drive पर भेजता है। यह 'निजी' में बंद रहता है। - \ No newline at end of file + diff --git a/app/resources/chromium_strings_hr.xtb b/app/resources/chromium_strings_hr.xtb index 1f3eb856db65..584d38d808fb 100644 --- a/app/resources/chromium_strings_hr.xtb +++ b/app/resources/chromium_strings_hr.xtb @@ -414,4 +414,4 @@ Dopuštenja koja ste već dali mrežnim mjestima i aplikacijama mogu se primijen Možete upravljati svojim prijavljenim sinkroniziranim lancima Brave. Vaši sinkronizirani lanci Brave upotrebljavaju se za preglednik Brave, trgovinu Play Store, uslugu Gmail i više. Ako želite dodati račun za nekog drugog kao primjerice člana obitelji, dodajte novi profil svom . Saznaj više Kada upisujete u adresnu traku ili okvir za pretraživanje, Brave šalje što upisujete zadanoj tražilici za dobivanje boljih prijedloga. To je isključeno u privatnom načinu rada. Kada upisujete u adresnu traku ili okvir za pretraživanje, Brave šalje što upisujete usluzi Google Drive za dobivanje prijedloga stavki. To je isključeno u privatnom načinu rada. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_hu.xtb b/app/resources/chromium_strings_hu.xtb index 99dd8fa832c4..e085784fa4bc 100644 --- a/app/resources/chromium_strings_hu.xtb +++ b/app/resources/chromium_strings_hu.xtb @@ -412,4 +412,4 @@ A webhelyeknek és alkalmazásoknak már megadott engedélyek vonatkozhatnak err Kezelheti a bejelentkezett Brave-láncait. A Brave szinkronizációs láncokat a Brave böngésző, a Play Áruház, a Gmail, és még sok más alkalmazás használja. Ha valaki más számára is szeretne fiókot hozzáadni, például egy családtagnak, akkor adjon hozzá egy új profilt ehhez: . Tudjon meg többet Amikor szöveget ír a címsávba vagy keresőmezőbe, a Brave elküldi a beírt szöveget az alapértelmezett keresőmotornak a javaslatok fejlesztése érdekében. Ez Privát módban ki van kapcsolva. Amikor szöveget ír a címsávba vagy keresőmezőbe, a Brave elküldi a beírt szöveget a Google Drive-nak a tételjavaslatok érdekében. Ez Privát módban ki van kapcsolva. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_hy.xtb b/app/resources/chromium_strings_hy.xtb index f84ecddaa578..062301dcdf53 100644 --- a/app/resources/chromium_strings_hy.xtb +++ b/app/resources/chromium_strings_hy.xtb @@ -415,4 +415,4 @@ Brave-ին չհաջողվեց վերականգնել ձեր կարգավորու {COUNT,plural, =0{Այս թարմացումը կիրառելու համար ադմինիստրատորը խնդրում է վերագործարկել Brave-ը}=1{Այս թարմացումը կիրառելու համար ադմինիստրատորը խնդրում է վերագործարկել Brave-ը։ Ձեր ինկոգնիտո պատուհանը նորից չի բացվի։}one{Այս թարմացումը կիրառելու համար ադմինիստրատորը խնդրում է վերագործարկել Brave-ը։ Ձեր # ինկոգնիտո պատուհանը նորից չի բացվի։}other{Այս թարմացումը կիրառելու համար ադմինիստրատորը խնդրում է վերագործարկել Brave-ը։ Ձեր # ինկոգնիտո պատուհանները նորից չեն բացվի։}} {COUNT,plural, =0{Թարմացումը կիրառելու համար ադմինիստրատորը պահանջում է վերագործարկել Brave-ը}=1{Թարմացումը կիրառելու համար ադմինիստրատորը պահանջում է վերագործարկել Brave-ը։ Ձեր ինկոգնիտո պատուհանը նորից չի բացվի։}one{Թարմացումը կիրառելու համար ադմինիստրատորը պահանջում է վերագործարկել Brave-ը։ Ձեր # ինկոգնիտո պատուհանը նորից չի բացվի։}other{Թարմացումը կիրառելու համար ադմինիստրատորը պահանջում է վերագործարկել Brave-ը։ Ձեր # ինկոգնիտո պատուհանները նորից չեն բացվի։}} Դուք կարող եք կառավարել ձեր Brave հաշիվները, որոնցում մուտք եք գործել։ Դրանք օգտագործվում են Brave դիտարկիչում, Play Խանութում, Gmail-ում և այլ ծառայություններում։ Եթե ուզում եք ընտանեկան խմբի անդամի կամ մեկ ուրիշի համար հաշիվ ավելացնել, սարքում ավելացրեք նոր օգտատեր։ Իմանալ ավելին - \ No newline at end of file + diff --git a/app/resources/chromium_strings_id.xtb b/app/resources/chromium_strings_id.xtb index ca7dff2c43b4..2fd82915f47d 100644 --- a/app/resources/chromium_strings_id.xtb +++ b/app/resources/chromium_strings_id.xtb @@ -414,4 +414,4 @@ Izin yang telah Anda berikan ke situs web dan aplikasi dapat berlaku untuk akun Anda dapat mengatur rantai sinkronisasi Brave yang Anda masuki. Rantai sinkronisasi Brave Anda digunakan untuk peramban Brave, Play Store, Gmail, dan banyak lagi. Jika Anda ingin menambahkan akun untuk orang lain, misalnya anggota keluarga, tambahkan profil baru ke Anda. Pelajari lebih lanjut Ketika Anda mengetik di bilah alamat atau kotak pencarian, Brave mengirim hal yang Anda ketik ke mesin pencarian bawaan Anda untuk mendapatkan usulan yang lebih baik. Ini dinonaktifkan di mode Privat. Ketika Anda mengetik di bilah alamat atau kotak pencarian, Brave mengirim hal yang Anda ketik ke Google Drive untuk mendapatkan usulan. Ini dinonaktifkan di mode Privat. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_is.xtb b/app/resources/chromium_strings_is.xtb index 5b86d5281628..1e3959215a6e 100644 --- a/app/resources/chromium_strings_is.xtb +++ b/app/resources/chromium_strings_is.xtb @@ -416,4 +416,4 @@ Brave getur ekki endurheimt stillingarnar þínar. Höfundar Brave Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_it.xtb b/app/resources/chromium_strings_it.xtb index 1d9db12104bb..71fbb38c3c89 100644 --- a/app/resources/chromium_strings_it.xtb +++ b/app/resources/chromium_strings_it.xtb @@ -413,4 +413,4 @@ Le autorizzazioni già concesse a siti web e app possono essere applicate a ques Puoi gestire le catene di sincronizzazione di Brave per cui hai eseguito l’accesso. Le catene di sincronizzazione di Brave sono utilizzate per il browser di Brave, per Play Store, per Gmail e altro ancora. Se invece vuoi aggiungere un account per un’altra persona, per esempio per un familiare, aggiungi un nuovo profilo al tuo . Scopri di più Quando digiti qualcosa nella barra degli indirizzi o nella casella di ricerca, Brave invia il testo digitato al tuo motore di ricerca predefinito per ottenere suggerimenti migliori. Questa opzione è disattivata nella modalità privata. Quando digiti qualcosa nella barra degli indirizzi o nella casella di ricerca, Brave invia il testo digitato a Google Drive per ottenere suggerimenti. Questa opzione è disattivata nella modalità privata. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_iw.xtb b/app/resources/chromium_strings_iw.xtb index a759dcc9dbf8..efa6df28e0bb 100644 --- a/app/resources/chromium_strings_iw.xtb +++ b/app/resources/chromium_strings_iw.xtb @@ -406,4 +406,4 @@ Brave לא יכול לשחזר את ההגדרות שלך. באפשרותך לנהל את שרשראות הסנכרון המחוברות שלך ב-Brave. שרשראות הסנכרון שלך ב-Brave משמשות עבור דפדפן Brave, חנות Play,‏ Gmail ועוד. אם ברצונך להוסיף חשבון עבור אדם אחר, כגון בן משפחה, הוסיף פרופיל חדש ל- שלך במקום זאת. למידע נוסף כשאתה מקליד בשורת הכתובת או בתיבת החיפוש, Brave שולח את מה שאתה מקליד למנוע החיפוש המוגדר כברירת מחדל כדי לקבל הצעות טובות יותר. זה לא פעיל בפרטי. כשאתה מקליד בשורת הכתובת או בתיבת החיפוש, Brave שולח את מה שאתה מקליד ל-Google Drive כדי לקבל הצעות לפריטים. זה לא פעיל בפרטי. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ja.xtb b/app/resources/chromium_strings_ja.xtb index 15650fa4a1c9..79bb1a859931 100644 --- a/app/resources/chromium_strings_ja.xtb +++ b/app/resources/chromium_strings_ja.xtb @@ -407,4 +407,4 @@ サインイン済みのBrave同期チェーンを管理できます。Brave同期チェーンは、Braveブラウザ、Play ストア、Gmailなどに使用されます。家族など、他のユーザー用にアカウントを追加するには、にプロフィールを新規追加します。詳細 アドレスバーや検索ボックスに文字を入力すると、Braveは入力した文字をデフォルトの検索エンジンに送信し、より良い候補を取得します。これはプライベートではオフになっています。 アドレスバーや検索ボックスに文字を入力すると、Braveは入力した内容をGoogleドライブに送信し、アイテムの候補を取得します。これはプライベートではオフになっています。 - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ka.xtb b/app/resources/chromium_strings_ka.xtb index ef141cecbcda..9a63ef226e24 100644 --- a/app/resources/chromium_strings_ka.xtb +++ b/app/resources/chromium_strings_ka.xtb @@ -415,4 +415,4 @@ Brave ვერ შეძლებს თქვენი პარამეტ {COUNT,plural, =0{ამ განახლების მისასადაგებლად ადმინისტრატორი გთხოვთ Brave-ის ხელახლა გაშვებას}=1{ამ განახლების მისასადაგებლად ადმინისტრატორი გთხოვთ Brave-ის ხელახლა გაშვებას. თქვენი ინკოგნიტო ფანჯარა ხელახლა არ გაიხსნება.}other{ამ განახლების მისასადაგებლად ადმინისტრატორი გთხოვთ Brave-ის ხელახლა გაშვებას. თქვენი # ინკოგნიტო ფანჯარა ხელახლა არ გაიხსნება.}} {COUNT,plural, =0{განახლების მისასადაგებლად თქვენი ადმინისტრატორი მოითხოვს Brave-ის ხელახლა გაშვებას}=1{განახლების მისასადაგებლად თქვენი ადმინისტრატორი მოითხოვს Brave-ის ხელახლა გაშვებას. თქვენი ინკოგნიტო ფანჯარა ხელახლა არ გაიხსნება.}other{განახლების მისასადაგებლად თქვენი ადმინისტრატორი მოითხოვს Brave-ის ხელახლა გაშვებას. თქვენი # ინკოგნიტო ფანჯარა ხელახლა არ გაიხსნება.}} შეგიძლიათ მართოთ თქვენი სისტემაში შესული Brave ანგარიშები. თქვენი Brave ანგარიშები გამოიყენება Brave ბრაუზერისთვის, Play Store-ისთვის, Gmail-ისთვის და სხვა პროდუქტებისთვის. თუ სხვისი, მაგალითად, ოჯახის წევრის, ანგარიშის დამატება გსურთ, სანაცვლოდ დაამატეთ ახალი პიროვნება თქვენს -ს. შეიტყვეთ მეტი - \ No newline at end of file + diff --git a/app/resources/chromium_strings_kk.xtb b/app/resources/chromium_strings_kk.xtb index f14294ac3134..f41d28acb267 100644 --- a/app/resources/chromium_strings_kk.xtb +++ b/app/resources/chromium_strings_kk.xtb @@ -415,4 +415,4 @@ Brave параметрлеріңізді қалпына келтіре алма Brave Software Inc Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_km.xtb b/app/resources/chromium_strings_km.xtb index 98b53c46a8fa..3f866d02b129 100644 --- a/app/resources/chromium_strings_km.xtb +++ b/app/resources/chromium_strings_km.xtb @@ -417,4 +417,4 @@ Brave មិនអាចសង្គ្រោះការកំណត់រប {COUNT,plural, =0{អ្នក​គ្រប់គ្រង​របស់អ្នក​ស្នើឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មីនេះ}=1{អ្នក​គ្រប់គ្រង​របស់អ្នក​ស្នើឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មីនេះ។ ផ្ទាំងឯកជនរបស់អ្នក​នឹង​មិនបើកឡើងវិញទេ។}other{អ្នក​គ្រប់គ្រង​របស់អ្នក​ស្នើឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មីនេះ។ ផ្ទាំងឯកជន # របស់អ្នក​នឹងមិន​បើកឡើងវិញទេ។}} {COUNT,plural, =0{អ្នក​គ្រប់គ្រង​របស់អ្នក​តម្រូវឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មី}=1{អ្នក​គ្រប់គ្រង​របស់អ្នក​តម្រូវឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មី។ ផ្ទាំងឯកជនរបស់អ្នក​នឹង​មិនបើកឡើងវិញទេ។}other{អ្នក​គ្រប់គ្រង​របស់អ្នក​តម្រូវឱ្យអ្នក​ចាប់ផ្ដើម Brave ឡើងវិញ​ ដើម្បីប្រើ​កំណែថ្មី។ ផ្ទាំងឯកជន # របស់អ្នក​នឹងមិន​បើកឡើងវិញទេ។}} អ្នកអាចគ្រប់គ្រង​គណនី Brave ដែលអ្នកចូល។ គណនី Brave របស់អ្នក​ត្រូវបានប្រើ​សម្រាប់​កម្មវិធីរុករកតាមអ៊ីនធឺណិត Brave, Play Store, Gmail និងអ្វីៗជាច្រើនទៀត។ ប្រសិនបើអ្នក​ចង់បញ្ចូល​គណនីសម្រាប់​អ្នកផ្សេងទៀត​ដូចជា សមាជិកគ្រួសារជាដើម សូមបញ្ចូលមនុស្សថ្មី​ទៅក្នុង របស់អ្នក​ជំនួសវិញ។ ស្វែងយល់បន្ថែម - \ No newline at end of file + diff --git a/app/resources/chromium_strings_kn.xtb b/app/resources/chromium_strings_kn.xtb index c82f90c6ef4e..2cd9743fe767 100644 --- a/app/resources/chromium_strings_kn.xtb +++ b/app/resources/chromium_strings_kn.xtb @@ -407,4 +407,4 @@ ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಮಾಡಲಾದ Brave ಸಿಂಕ್ ಚೈನ್‌ಗಳನ್ನು ನೀವು ನಿರ್ವಹಿಸಬಹುದು. ನಿಮ್ಮ Brave ಸಿಂಕ್ ಚೈನ್‌ಗಳನ್ನು Brave ಬ್ರೌಸರ್, Play Store, Gmail ಮತ್ತು ಹೆಚ್ಚಿನವುಗಳಿಗೆ ಬಳಸಲಾಗುತ್ತದೆ. ಕುಟುಂಬದ ಸದಸ್ಯರಂತಹ ಬೇರೆ ಯಾರಿಗಾದರೂ ಖಾತೆಯನ್ನು ಸೇರಿಸಲು ನೀವು ಬಯಸಿದರೆ, ಬದಲಿಗೆ ನಿಮ್ಮ ಗೆ ಹೊಸ ಪ್ರೊಫೈಲ್ ಸೇರಿಸಿ. ಹೆಚ್ಚು ತಿಳಿಯಿರಿ ನೀವು ವಿಳಾಸ ಬಾರ್ ಅಥವಾ ಹುಡುಕಾಟ ಬಾಕ್ಸ್‌ನಲ್ಲಿ ಟೈಪ್ ಮಾಡಿದಾಗ, ಉತ್ತಮ ಸಲಹೆಗಳನ್ನು ಪಡೆಯುವುದಕ್ಕಾಗಿ ನೀವು ಟೈಪ್ ಮಾಡುವುದನ್ನು ನಿಮ್ಮ ಡೀಫಾಲ್ಟ್ ಹುಡುಕಾಟ ಇಂಜಿನ್‌ಗೆ Brave ಕಳುಹಿಸುತ್ತದೆ. ಇದು ಖಾಸಗಿ ಎಂಬಲ್ಲಿ ಆಫ್ ಆಗಿದೆ. ನೀವು ವಿಳಾಸ ಬಾರ್ ಅಥವಾ ಹುಡುಕಾಟ ಬಾಕ್ಸ್‌ನಲ್ಲಿ ಟೈಪ್ ಮಾಡಿದಾಗ, ಐಟಂ ಸಲಹೆಗಳನ್ನು ಪಡೆಯುವುದಕ್ಕಾಗಿ ನೀವು ಟೈಪ್ ಮಾಡುವುದನ್ನು Google Drive ಗೆ Brave ಕಳುಹಿಸುತ್ತದೆ. ಇದು ಖಾಸಗಿ ಎಂಬಲ್ಲಿ ಆಫ್ ಆಗಿದೆ. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ko.xtb b/app/resources/chromium_strings_ko.xtb index 0960b7847c30..e86401e213f4 100644 --- a/app/resources/chromium_strings_ko.xtb +++ b/app/resources/chromium_strings_ko.xtb @@ -416,4 +416,4 @@ Brave에서 설정을 복구할 수 없습니다. 귀하의 로그인된 Brave 동기화 체인을 관리할 수 있습니다. Brave 동기화 체인은 Brave 브라우저, Play 스토어, Gmail 등에 사용됩니다. 가족 구성원 등 다른 사람을 위한 계정을 추가하려면 에 새 프로필을 추가하세요. 자세히 알아보기 주소창이나 검색창에 입력하면 입력하신 내용을 Brave가 기본 검색 엔진으로 보내 추천 결과를 개선합니다. 비공개 모드에서는 꺼집니다. 주소창이나 검색창에 입력하면 입력하신 내용을 Brave가 Google 드라이브로 보내 항목 추천 결과를 개선합니다. 비공개 모드에서는 꺼집니다. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ky.xtb b/app/resources/chromium_strings_ky.xtb index 7e765126094c..bd3b0e87da11 100644 --- a/app/resources/chromium_strings_ky.xtb +++ b/app/resources/chromium_strings_ky.xtb @@ -416,4 +416,4 @@ Brave параметрлериңизди калыбына келтире алб Brave'дун авторлору Google Chrome Бета Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_lo.xtb b/app/resources/chromium_strings_lo.xtb index 26e8d4236402..995d00c39555 100644 --- a/app/resources/chromium_strings_lo.xtb +++ b/app/resources/chromium_strings_lo.xtb @@ -416,4 +416,4 @@ Brave ບໍ່ສາມາດກູ້ການຕັ້ງຄ່າຂອງ ຜູ້ຂຽນ Brave Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_lt.xtb b/app/resources/chromium_strings_lt.xtb index b9ead99f24a0..95243a53037a 100644 --- a/app/resources/chromium_strings_lt.xtb +++ b/app/resources/chromium_strings_lt.xtb @@ -416,4 +416,4 @@ Kai kurios funkcijos gali būti nepasiekiamos. Nurodykite kitą profilio katalog Galite tvarkyti savo registruotas „Brave“ sinchronizavimo grandines. Jūsų „Brave“ sinchronizavimo grandinės naudojamos „Brave“ naršyklei, „Play Store“, „Gmail“ ir kt. Jei norite pridėti paskyrą kam nors kitam, pavyzdžiui, šeimos nariui, vietoj to įtraukite naują profilį į savo . Sužinoti daugiau Siekiant užtikrinti, kad gausite tinkamiausius pasiūlymus, užklausa, kurią įvedate adreso juostoje arba paieškos lauke, perduodama numatytajai paieškos sistemai. Ši funkcija išjungta naršant privačiuoju režimu. Ieškant rezultatų užklausa, kurią įvedate adreso juostoje arba paieškos lauke, perduodama „Google Drive“. Ši funkcija išjungta naršant privačiuoju režimu. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_lv.xtb b/app/resources/chromium_strings_lv.xtb index d4e2cd8a07b5..175d382db06b 100644 --- a/app/resources/chromium_strings_lv.xtb +++ b/app/resources/chromium_strings_lv.xtb @@ -411,4 +411,4 @@ Atļaujas, ko jau esat piešķīris vietnēm un lietotnēm, var attiekties uz š Varat pārvaldīt savas pierakstītās Brave sinhronizācijas ķēdes. Jūsu Brave sinhronizācijas ķēdes tiek izmantotas Brave pārlūkā, Play veikalā, Gmail un citur. Ja vēlaties pievienot kontu kādam citam, piemēram, ģimenes loceklim, tā vietā pievienojiet jaunu profilu savam . Uzzināt vairāk Kad rakstāt adreses joslā vai meklēšanas lodziņā, to, ko rakstāt, Brave nosūta uz jūsu noklusējuma meklētājprogrammu, lai iegūtu labākus ieteikumus. Inkognito režīmā šī opcija ir izslēgta. Kad rakstāt adreses joslā vai meklēšanas lodziņā, to, ko rakstāt, Brave nosūta uz Google Drive, lai iegūtu vienumu ieteikumus. Inkognito režīmā šī opcija ir izslēgta. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_mk.xtb b/app/resources/chromium_strings_mk.xtb index 405c8f225aab..91eaaed6b1e3 100644 --- a/app/resources/chromium_strings_mk.xtb +++ b/app/resources/chromium_strings_mk.xtb @@ -416,4 +416,4 @@ Brave не може да ги обнови вашите поставки.Автори на Brave Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ml.xtb b/app/resources/chromium_strings_ml.xtb index afd19feaffef..39f80a9edc8a 100644 --- a/app/resources/chromium_strings_ml.xtb +++ b/app/resources/chromium_strings_ml.xtb @@ -416,4 +416,4 @@ {COUNT,plural, =0{ഈ അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു}=1{ഈ അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു. നിങ്ങളുടെ അദൃശ്യ വിൻഡോ വീണ്ടും തുറക്കില്ല.}other{ഈ അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു. നിങ്ങളുടെ # അദൃശ്യ വിൻഡോകൾ വീണ്ടും തുറക്കില്ല.}} {COUNT,plural, =0{അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു}=1{അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു. നിങ്ങളുടെ അദൃശ്യ വിൻഡോ വീണ്ടും തുറക്കില്ല.}other{അപ്‌ഡേറ്റ് പ്രയോഗിക്കുന്നതിന് Brave വീണ്ടും ആരംഭിക്കാൻ നിങ്ങളുടെ അഡ്‌മിൻ ആവശ്യപ്പെടുന്നു. നിങ്ങളുടെ # അദൃശ്യ വിൻഡോകൾ വീണ്ടും തുറക്കില്ല.}} സൈൻ ഇൻ ചെയ്‌തിരിക്കുന്ന Brave അക്കൗണ്ടുകൾ നിങ്ങൾക്ക് മാനേജ് ചെയ്യാം. Brave ബ്രൗസർ, Play Store, Gmail എന്നിവയ്ക്കും മറ്റുമായി നിങ്ങളുടെ Brave അക്കൗണ്ടുകൾ ഉപയോഗിക്കുന്നു. കുടുംബാംഗത്തെ പോലുള്ള മറ്റാർക്കെങ്കിലും വേണ്ടി ഒരു അക്കൗണ്ട് ചേർക്കണമെങ്കിൽ, പകരം നിങ്ങളുടെ എന്നതിലേക്ക് പുതിയൊരു വ്യക്തിയെ ചേർക്കുക. കൂടുതലറിയുക - \ No newline at end of file + diff --git a/app/resources/chromium_strings_mn.xtb b/app/resources/chromium_strings_mn.xtb index 86b0a457511a..0de80e3203ab 100644 --- a/app/resources/chromium_strings_mn.xtb +++ b/app/resources/chromium_strings_mn.xtb @@ -412,4 +412,4 @@ {COUNT,plural, =0{Энэ шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас хүсэж байна}=1{Энэ шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас хүсэж байна. Таны нууцлалтай цонхыг дахин нээхгүй.}other{Энэ шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас хүсэж байна. Таны # нууцлалтай цонхыг дахин нээхгүй.}} {COUNT,plural, =0{Шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас шаардаж байна}=1{Шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас шаардаж байна. Таны нууцлалтай цонхыг дахин нээхгүй.}other{Шинэчлэлтийг хэрэгжүүлэхийн тулд Brave-г дахин ачаалахыг таны администратор танаас шаардаж байна. Таны # нууцлалтай цонхыг дахин нээхгүй.}} Та нэвтэрсэн Brave Бүртгэлүүдээ удирдах боломжтой. Таны Brave Бүртгэлүүдийг Brave хөтөч, Play Store, Gmail болон бусад дээр ашигладаг. Хэрэв та гэр бүлийн гишүүн зэрэг өөр хэн нэгний бүртгэлийг нэмэхийг хүсвэл оронд нь өөрийн -д шинэ хүн нэмнэ үү. Нэмэлт мэдээлэл авах - \ No newline at end of file + diff --git a/app/resources/chromium_strings_mr.xtb b/app/resources/chromium_strings_mr.xtb index 5e98046a2256..2b478786d114 100644 --- a/app/resources/chromium_strings_mr.xtb +++ b/app/resources/chromium_strings_mr.xtb @@ -415,4 +415,4 @@ Brave तुमची सेटिंग्ज रिकव्हर करू {COUNT,plural, =0{तुमच्या ॲडमिनिस्ट्रेटरने तुम्हाला हे अपडेट लागू करण्यासाठी Brave पुन्हा लाँच करण्यास सांगितले आहे}=1{तुमच्या ॲडमिनिस्ट्रेटरने तुम्हाला हे अपडेट लागू करण्यासाठी Brave पुन्हा लाँच करण्यास सांगितले आहे. तुमची गुप्त विंडो पुन्हा उघडणार नाही.}other{तुमच्या ॲडमिनिस्ट्रेटरने तुम्हाला हे अपडेट लागू करण्यासाठी Brave पुन्हा लाँच करण्यास सांगितले आहे. तुमच्या # गुप्त विंडो पुन्हा उघडणार नाहीत.}} {COUNT,plural, =0{अपडेट लागू करता यावे यासाठी तुम्ही Brave पुन्हा लाँच करण्याची तुमच्या ॲडमिनिस्ट्रेटरला गरज आहे}=1{अपडेट लागू करता यावे यासाठी तुम्ही Brave पुन्हा लाँच करण्याची तुमच्या ॲडमिनिस्ट्रेटरला गरज आहे. तुमची गुप्त विंडो पुन्हा उघडणार नाही.}other{अपडेट लागू करता यावे यासाठी तुम्ही Brave पुन्हा लाँच करण्याची तुमच्या ॲडमिनिस्ट्रेटरला गरज आहे. तुमच्या # गुप्त विंडो पुन्हा उघडणार नाहीत.}} तुम्ही तुमची साइन इन केलेली Brave खाती व्यवस्थापित करू शकता. तुमची Brave खाती Brave ब्राउझर, Play Store, Gmail आणि बर्‍याच गोष्टींसाठी वापरली जातात. तुम्हाला कुटुंब सदस्यासारख्या इतर कोणासाठी खाते जोडायचे असल्यास, त्याऐवजी तुमच्या वर नवीन व्यक्ती जोडा. अधिक जाणून घ्या - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ms.xtb b/app/resources/chromium_strings_ms.xtb index e596c4ac84a1..61fee56e5208 100644 --- a/app/resources/chromium_strings_ms.xtb +++ b/app/resources/chromium_strings_ms.xtb @@ -414,4 +414,4 @@ Keizinan yang telah anda berikan kepada laman web dan apl mungkin digunakan pada Anda boleh menguruskan rantaian penyegerakan Brave yang anda daftar masuk. Rantaian penyegerakan Brave anda digunakan untuk pelayar Brave, Play Store, Gmail dan banyak lagi. Sekiranya anda ingin menambah akaun untuk orang lain, seperti ahli keluarga, tambahkan profil baharu ke anda. Ketahui lebih lanjut Apabila anda menaipkan maklumat ke dalam bar alamat atau kotak carian, Brave menghantar maklumat yang anda taipkan kepada enjin carian lalai anda untuk mendapatkan cadangan lebih baik. Ciri ini dimatikan dalam penyemak imbas Peribadi. Apabila anda menaipkan maklumat ke dalam bar alamat atau kotak carian, Brave menghantar maklumat yang anda taipkan kepada Google Drive untuk mendapatkan cadangan item. Ciri ini dimatikan dalam penyemak imbas Peribadi. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_my.xtb b/app/resources/chromium_strings_my.xtb index 1bc8eaf3d159..ae3f2dfe119e 100644 --- a/app/resources/chromium_strings_my.xtb +++ b/app/resources/chromium_strings_my.xtb @@ -418,4 +418,4 @@ Brave သည်သင့်ကြိုတင်ချိန်ညှိချ Brave စာရေးသူများ Google Chrome စမ်းသပ် Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ne.xtb b/app/resources/chromium_strings_ne.xtb index 8bb712dc0d50..85133dbe8a93 100644 --- a/app/resources/chromium_strings_ne.xtb +++ b/app/resources/chromium_strings_ne.xtb @@ -408,4 +408,4 @@ Brave ले तपाइँका सेटिङहरू पुनर्प Brave लेखकहरू Google Chrome बिटा Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_nl.xtb b/app/resources/chromium_strings_nl.xtb index 10ebbc879a78..4654176645ae 100644 --- a/app/resources/chromium_strings_nl.xtb +++ b/app/resources/chromium_strings_nl.xtb @@ -415,4 +415,4 @@ Rechten die u al hebt verleend aan websites en apps zijn mogelijk van toepassing Je kunt je ingelogde Brave-synchronisatieketens beheren. Je Brave-synchronisatieketens worden gebruikt voor de Brave-browser, Play Store, Gmail en meer. Als je een account voor iemand anders wil toevoegen, zoals een familielid, voeg dan in plaats daarvan een nieuw profiel toe aan je . Meer informatie Wanneer u iets in de adresbalk of het zoekveld typt, stuurt Brave dat naar uw standaard zoekmachine voor betere suggesties. Dit is uitgeschakeld in Privé. Wanneer u iets in de adresbalk of het zoekveld typt, stuurt Brave dat naar Google Drive voor itemsuggesties. Dit is uitgeschakeld in Privé. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_no.xtb b/app/resources/chromium_strings_no.xtb index 9356163dad82..caea3ad0d8c3 100644 --- a/app/resources/chromium_strings_no.xtb +++ b/app/resources/chromium_strings_no.xtb @@ -413,4 +413,4 @@ Tillatelser du allerede har gitt til nettsteder og apper kan også være gjelden Du kan administrere innloggede Brave-synkroniseringskjeder. Brave-synkroniseringskjedene brukes for Brave-nettleseren, Play Store, Gmail med mer. Hvis du vil legge inn en konto for noen andre, for eksempel en i familien, må du legge til en ny profil i instead. Finn ut mer Når du skriver i adressefeltet eller søkefeltet, sender Brave det du skriver inn, til søkemotoren du har som standard, for å få opp bedre forslag. Dette er deaktivert i Privat modus. Når du skriver i adressefeltet eller søkefeltet, sender Brave det du skriver inn, til Google Drive for å få opp bedre forslag. Dette er deaktivert i Privat modus. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_or.xtb b/app/resources/chromium_strings_or.xtb index 4460daeb1b5d..81adb4d47beb 100644 --- a/app/resources/chromium_strings_or.xtb +++ b/app/resources/chromium_strings_or.xtb @@ -409,4 +409,4 @@ Brave ଆପଣଙ୍କ ସେଟିଂସ୍‌କୁ ପୁନରୁଦ୍ଧ {COUNT,plural, =0{ଆପଣଙ୍କର ଆଡ୍‌ମିନିଷ୍ଟ୍ରେଟର୍ କହୁଛନ୍ତି ଯେ ଏହି ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବାକୁ ଆପଣ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ}=1{ଆପଣଙ୍କର ଆଡ୍‌ମିନିଷ୍ଟ୍ରେଟର୍ କହୁଛନ୍ତି ଯେ ଏହି ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବାକୁ ଆପଣ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ। ଆପଣଙ୍କର ଇନ୍‌କଗ୍ନିଟୋ ୱିଣ୍ଡୋ ପୁଣି ଖୋଲିବ ନାହିଁ।}other{ଆପଣଙ୍କର ଆଡ୍‌ମିନିଷ୍ଟ୍ରେଟର୍ କହୁଛନ୍ତି ଯେ ଏହି ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବାକୁ ଆପଣ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ। ଆପଣଙ୍କର #ଟି ଇନ୍‌କଗ୍ନିଟୋ ୱିଣ୍ଡୋ ପୁଣି ଖୋଲିବ ନାହିଁ।}} {COUNT,plural, =0{ଆପଣଙ୍କର ଆଡ୍‍ମିନିଷ୍ଟ୍ରେଟର୍ ଚାହୁଁଛନ୍ତି ଯେ ଆପଣ ଏକ ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବା ପାଇଁ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ}=1{ଆପଣଙ୍କର ଆଡ୍‍ମିନିଷ୍ଟ୍ରେଟର୍ ଚାହୁଁଛନ୍ତି ଯେ ଆପଣ ଏକ ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବା ପାଇଁ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ ଆପଣଙ୍କର ଇନ୍‌କଗ୍ନିଟୋ ୱିଣ୍ଡୋ ପୁଣି ଖୋଲିବ ନାହିଁ।}other{ଆପଣଙ୍କର ଆଡ୍‍ମିନିଷ୍ଟ୍ରେଟର୍ ଚାହୁଁଛନ୍ତି ଯେ ଆପଣ ଏକ ଅପ୍‌ଡେଟ୍ ଲାଗୁ କରିବା ପାଇଁ Braveକୁ ପୁଣି ଲଞ୍ଚ କରନ୍ତୁ ଆପଣଙ୍କର #ଟି ଇନ୍‌କଗ୍ନିଟୋ ୱିଣ୍ଡୋ ପୁଣି ଖୋଲିବ ନାହିଁ।}} ଆପଣ ଆପଣଙ୍କ ସାଇନ୍-ଇନ୍ କରାଯାଇଥିବା Brave ଆକାଉଣ୍ଟଗୁଡ଼ିକୁ ପରିଚାଳନା କରିପାରିବେ। ଆପଣଙ୍କ Brave ଆକାଉଣ୍ଟଗୁଡ଼ିକ Brave ବ୍ରାଉଜର୍, Play Store, Gmail ଏବଂ ଆହୁରି ଅନେକ କିଛି ପାଇଁ ବ୍ୟବହାର କରାଯାଇଛି। ଯଦି ଆପଣ ଜଣେ ପରିବାର ସଦସ୍ୟଙ୍କ ପରି ଅନ୍ୟ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ପାଇଁ ଏକ ଆକାଉଣ୍ଟ ଯୋଗ କରିବାକୁ ଚାହୁଁଛନ୍ତି, ତେବେ ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ରେ ଜଣେ ନୂଆ ବ୍ୟକ୍ତିଙ୍କୁ ଯୋଗ କରନ୍ତୁ। ଅଧିକ ଜାଣନ୍ତୁ - \ No newline at end of file + diff --git a/app/resources/chromium_strings_pa.xtb b/app/resources/chromium_strings_pa.xtb index 9d750a10ae45..2d23f26f184d 100644 --- a/app/resources/chromium_strings_pa.xtb +++ b/app/resources/chromium_strings_pa.xtb @@ -416,4 +416,4 @@ Brave ਤੁਹਾਡੀਆਂ ਸੈਟਿੰਗਾਂ ਮੁੜ-ਹਾਸਲ {COUNT,plural, =0{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਕਹਿੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਇਸ ਅੱਪਡੇਟ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ}=1{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਕਹਿੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਇਸ ਅੱਪਡੇਟ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ। ਤੁਹਾਡੀ ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋ ਦੁਬਾਰਾ ਨਹੀਂ ਖੁੱਲ੍ਹੇਗੀ।}other{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਕਹਿੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਇਸ ਅੱਪਡੇਟ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ। ਤੁਹਾਡੀਆਂ # ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋ ਦੁਬਾਰਾ ਨਹੀਂ ਖੁੱਲ੍ਹਣਗੀਆਂ।}} {COUNT,plural, =0{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਚਾਹੁੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਅੱਪਡੇਟ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ}=1{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਚਾਹੁੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਅੱਪਡੇਟ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ। ਤੁਹਾਡੀ ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋ ਦੁਬਾਰਾ ਨਹੀਂ ਖੁੱਲ੍ਹੇਗੀ।}other{ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਚਾਹੁੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਅੱਪਡੇਟ ਲਾਗੂ ਕਰਨ ਲਈ Brave ਨੂੰ ਮੁੜ-ਲਾਂਚ ਕਰੋ। ਤੁਹਾਡੀਆਂ # ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋ ਦੁਬਾਰਾ ਨਹੀਂ ਖੁੱਲ੍ਹਣਗੀਆਂ।}} ਤੁਸੀਂ ਆਪਣੇ ਸਾਈਨ-ਇਨ ਕੀਤੇ ਗਏ Brave ਖਾਤਿਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ। ਤੁਹਾਡੇ Brave ਖਾਤਿਆਂ ਦੀ ਵਰਤੋਂ Brave ਬ੍ਰਾਊਜ਼ਰ, Play Store, Gmail ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਜੇ ਤੁਸੀਂ ਕਿਸੇ ਹੋਰ ਲਈ ਇੱਕ ਖਾਤਾ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਜਿਵੇਂ ਕਿ ਕਿਸੇ ਪਰਿਵਾਰਕ ਮੈਂਬਰ ਲਈ, ਤਾਂ ਇਸਦੀ ਬਜਾਏ ਆਪਣੀ ਵਿੱਚ ਕੋਈ ਨਵਾਂ ਵਿਅਕਤੀ ਸ਼ਾਮਲ ਕਰੋ। ਹੋਰ ਜਾਣੋ - \ No newline at end of file + diff --git a/app/resources/chromium_strings_pl.xtb b/app/resources/chromium_strings_pl.xtb index 198640092237..df8d7f481a8e 100644 --- a/app/resources/chromium_strings_pl.xtb +++ b/app/resources/chromium_strings_pl.xtb @@ -410,4 +410,4 @@ Uprawnienia, które już nadano witrynom i aplikacjom, mogą mieć zastosowanie Możesz zarządzać łańcuchami synchronizacji, do których się logujesz. Twoje łańcuchy synchronizacji Brave są używane także w przeglądarce Brave, sklepie Play, Gmailu i w innych miejscach. Jeśli chcesz dodać konto innego użytkownika, np. członka rodziny, dodaj nowy profil do Twojego instead. Więcej informacji Kiedy wpisujesz tekst w pasku adresu lub polu wyszukiwania, Brave wysyła wpisywany tekst do domyślnej wyszukiwarki w celu uzyskania lepszych wyników. Ta funkcja jest wyłączona w przeglądaniu prywatnym. Kiedy wpisujesz tekst w pasku adresu lub polu wyszukiwania, Brave wysyła wpisywany tekst do dysku Google Drive w celu uzyskania sugestii dotyczących elementów. Ta funkcja jest wyłączona w przeglądaniu prywatnym. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_pt-BR.xtb b/app/resources/chromium_strings_pt-BR.xtb index c4fe928f4ca6..97aee34edd53 100644 --- a/app/resources/chromium_strings_pt-BR.xtb +++ b/app/resources/chromium_strings_pt-BR.xtb @@ -411,4 +411,4 @@ As permissões que você já concedeu a sites e aplicativos podem se aplicar a e Você pode gerenciar suas cadeias de sincronização do Brave com sessão iniciada. Suas cadeias de sincronização do Brave são usadas pelo navegador Brave, pela Play Store, pelo Gmail e muito mais. Se você quiser adicionar uma conta para outra pessoa, como um familiar, adicione um novo perfil ao seu . Saiba mais Quando você digita na barra de endereços ou na caixa de pesquisa, o Brave envia o que você digita para o mecanismo de pesquisa padrão para obter melhores sugestões. Isso está desativado em Privado. Quando você digita na barra de endereço ou na caixa de pesquisa, o Brave envia o que você digita para o Google Drive para obter sugestões de itens. Isso está desativado em Privado. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_pt-PT.xtb b/app/resources/chromium_strings_pt-PT.xtb index a7e32710617f..82d57277d092 100644 --- a/app/resources/chromium_strings_pt-PT.xtb +++ b/app/resources/chromium_strings_pt-PT.xtb @@ -414,4 +414,4 @@ As permissões que atribuiu a sites e aplicações podem aplicar-se a esta conta Pode gerir as suas cadeias de sincronização Brave com sessão iniciada. Estas são utilizadas no navegador Brave, na Play Store e no Gmail, entre outros. Caso pretenda adicionar uma conta para outra pessoa, como um familiar, adicione um novo perfil a . Saiba mais Quando introduz alguma coisa na barra de endereços ou na caixa de pesquisa, o Brave envia o que introduziu para o seu motor de busca padrão para ter sugestões melhores. Esta configuração está desativada no modo privado. Quando introduz alguma coisa na barra de endereços ou na caixa de pesquisa, o Brave envia o que introduziu para o Google Drive para ter sugestões de itens. Esta configuração está desativada no modo privado. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ro.xtb b/app/resources/chromium_strings_ro.xtb index 8c828feafaf2..38f2773c25d3 100644 --- a/app/resources/chromium_strings_ro.xtb +++ b/app/resources/chromium_strings_ro.xtb @@ -413,4 +413,4 @@ Permisiunile pe care le-ați acordat deja site-urilor web și aplicațiilor se p Puteți gestiona lanțurile de sincronizare conectate Brave. Acestea se utilizează pentru browser-ul Brave, Play Store, Gmail și altele. Dacă doriți să adăugați un cont pentru o altă persoană, precum un membru al familiei, adăugați un nou profil în . Aflați mai multe Când tastați în bara de adrese sau în caseta de căutare, Brave trimite ceea ce tastați către motorul de căutare implicit pentru a obține sugestii mai bune. Acest lucru este dezactivat în privat. Atunci când tastați în bara de adrese sau în caseta de căutare, Brave trimite ceea ce tastați către Google Drive pentru a obține sugestii de elemente. Acest lucru este dezactivat în privat. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ru.xtb b/app/resources/chromium_strings_ru.xtb index dda3f50f8646..b6cac9039a36 100644 --- a/app/resources/chromium_strings_ru.xtb +++ b/app/resources/chromium_strings_ru.xtb @@ -403,4 +403,4 @@ Вы можете настраивать свой вход в цепи синхронизации Brave, которые используют браузер Brave, Play Store, Gmail и многие другие сайты. Если вы хотите создать аккаунт для кого-то еще, например для домочадца, добавьте новый профиль в свою систему . Подробнее... Когда вы набираете текст в адресной строке или в поле поиска, Brave отправляет его в поисковую систему по умолчанию, чтобы получить лучшие предложения. В режиме «‎Приватный» эта функция отключена. Когда вы набираете текст в адресной строке или в поле поиска, Brave отправляет его на «‎Диск Google» для получения предложений по элементам. В режиме «‎Приватный» эта функция отключена. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_si.xtb b/app/resources/chromium_strings_si.xtb index 78f5139fb8df..81a81bd59e69 100644 --- a/app/resources/chromium_strings_si.xtb +++ b/app/resources/chromium_strings_si.xtb @@ -416,4 +416,4 @@ Brave හට ඔබගේ සැකසුම් ප්‍රතිසාධන {COUNT,plural, =0{මෙම යාවත්කාලීනය යෙදීමට Brave නැවත ආරම්භ කරන ලෙසට පරිපාලකයා ඔබට පවසයි}=1{මෙම යාවත්කාලීනය යෙදීමට Brave නැවත ආරම්භ කරන ලෙසට පරිපාලකයා ඔබට පවසයි. ඔබේ අප්‍රසිද්ධ කවුළුව යළි විවෘත නොවෙයි.}one{මෙම යාවත්කාලීනය යෙදීමට Brave නැවත ආරම්භ කරන ලෙසට පරිපාලකයා ඔබට පවසයි. ඔබේ අප්‍රසිද්ධ කවුළු # යළි විවෘත නොවෙයි.}other{මෙම යාවත්කාලීනය යෙදීමට Brave නැවත ආරම්භ කරන ලෙසට පරිපාලකයා ඔබට පවසයි. ඔබේ අප්‍රසිද්ධ කවුළු # යළි විවෘත නොවෙයි.}} {COUNT,plural, =0{යාවත්කාලීනයක් යෙදීමට ඔබ Brave නැවත ආරම්භ කිරීම පරිපාලකයාට අවශ්‍ය වේ}=1{යාවත්කාලීනයක් යෙදීමට ඔබ Brave නැවත ආරම්භ කිරීම පරිපාලකයාට අවශ්‍ය වේ. ඔබේ අප්‍රසිද්ධ කවුළුව යළි විවෘත නොවෙයි.}one{යාවත්කාලීනයක් යෙදීමට ඔබ Brave නැවත ආරම්භ කිරීම පරිපාලකයාට අවශ්‍ය වේ. ඔබේ අප්‍රසිද්ධ කවුළු # යළි විවෘත නොවෙයි.}other{යාවත්කාලීනයක් යෙදීමට ඔබ Brave නැවත ආරම්භ කිරීම පරිපාලකයාට අවශ්‍ය වේ. ඔබේ අප්‍රසිද්ධ කවුළු # යළි විවෘත නොවෙයි.}} ඔබට ඔබගේ පුරන ලද Brave ගිණුම් කළමනාකරණය කළ හැකිය. ඔබගේ Brave ගිණුම් Brave බ්‍රව්සරය, Play Store, Gmail සහ තවත් දේ සඳහා භාවිත කෙරේ. ඔබට පවුලේ සාමාජිකයකු වැනි, වෙනත් යම් කෙනෙකු සඳහා ගිණුමක් එක් කිරීමට අවශ්‍ය නම්, ඒ වෙනුවට ඔබගේ වෙත නව පුද්ගලයකු එක් කරන්න. තව දැන ගන්න - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sk.xtb b/app/resources/chromium_strings_sk.xtb index c61400a52cc0..6986218613d9 100644 --- a/app/resources/chromium_strings_sk.xtb +++ b/app/resources/chromium_strings_sk.xtb @@ -416,4 +416,4 @@ Na tento účet sa môžu vzťahovať povolenia, ktoré ste už udelili webovým Svoje prihlásené synchronizačné reťazce Brave môžete spravovať. Vaše synchronizačné reťazce Brave sa používajú pre prehliadač Brave, Play Store, Gmail a ďalšie. Ak chcete pridať účet pre niekoho iného, napríklad pre člena rodiny, pridajte do svojho namiesto toho nový profil. Learn more Pri písaní do adresného riadka alebo vyhľadávacieho poľa posiela Brave vložený text vášmu predvolenému vyhľadávaču, čím získate lepšie návrhy. Táto možnosť je v súkromnom režime vypnutá. Pri písaní do adresného riadka alebo vyhľadávacieho poľa posiela Brave vložený text do Google Drive, čím získate návrhy položiek. Táto možnosť je v súkromnom režime vypnutá. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sl.xtb b/app/resources/chromium_strings_sl.xtb index 64149010ced6..42b3581ef73b 100644 --- a/app/resources/chromium_strings_sl.xtb +++ b/app/resources/chromium_strings_sl.xtb @@ -416,4 +416,4 @@ Za ta račun lahko veljajo dovoljenja, ki ste jih že dali spletnim mestom in ap Upravljate lahko prijavljene verige za sinhronizacijo Brave. Vaše verige za sinhronizacijo Brave se uporabljajo za brskalnik Brave, Trgovino Play, Gmail in drugo. Če želite dodati račun za nekoga drugega, na primer družinskega člana, namesto tega dodajte nov profil v svoj . Več o tem Ko v naslovno vrstico ali iskalno polje vtipkate besedilo, Brave vneseno besedilo pošlje vašemu privzetemu iskalniku, da tako dobi boljše predloge. Ta funkcija je v zasebnem načinu izključena. Ko v naslovno vrstico ali iskalno polje vtipkate besedilo, Brave vneseno besedilo pošlje v Google Drive, da tako dobi boljše predloge. Ta funkcija je v zasebnem načinu izključena. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sq.xtb b/app/resources/chromium_strings_sq.xtb index 07c9efb895c5..b8f1b3eaaed9 100644 --- a/app/resources/chromium_strings_sq.xtb +++ b/app/resources/chromium_strings_sq.xtb @@ -415,4 +415,4 @@ Lejet që u ke dhënë sajteve të uebit dhe aplikacioneve mund të zbatohen pë {COUNT,plural, =0{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim}=1{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim Dritarja jote "e fshehtë" nuk do të rihapet.}other{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim # dritaret e tua "të fshehta" nuk do të rihapen.}} {COUNT,plural, =0{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim}=1{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim Dritarja jote "e fshehtë" nuk do të rihapet.}other{Administratori yt kërkon që të hapësh përsëri Brave për të zbatuar këtë përditësim # dritaret e tua "të fshehta" nuk do të rihapen.}} Mund t'i menaxhosh "Llogaritë e Brave" ku je identifikuar. "Llogaritë e tua të Brave" përdoren për shfletuesin Brave, Play Store, Gmail etj. Nëse do të shtosh një llogari për dikë tjetër, si p.sh. anëtar të familjes, shto më mirë një person të ri te yt. Mëso më shumë - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sr-Latn.xtb b/app/resources/chromium_strings_sr-Latn.xtb index 9821b2e12c9a..a8ceef129006 100644 --- a/app/resources/chromium_strings_sr-Latn.xtb +++ b/app/resources/chromium_strings_sr-Latn.xtb @@ -416,4 +416,4 @@ Ovlašćenja koja ste već dali veb-sajtovima i aplikacijama mogu se primeniti n {COUNT,plural, =0{Administrator traži da ponovo pokrenete Brave da biste primenili ovo ažuriranje}=1{Administrator traži da ponovo pokrenete Brave da biste primenili ovo ažuriranje. Prozor bez arhiviranja se neće ponovo otvoriti.}one{Administrator traži da ponovo pokrenete Brave da biste primenili ovo ažuriranje. # prozor bez arhiviranja se neće ponovo otvoriti.}few{Administrator traži da ponovo pokrenete Brave da biste primenili ovo ažuriranje. # prozora bez arhiviranja se neće ponovo otvoriti.}other{Administrator traži da ponovo pokrenete Brave da biste primenili ovo ažuriranje. # prozora bez arhiviranja se neće ponovo otvoriti.}} {COUNT,plural, =0{Administrator zahteva da ponovo pokrenete Brave da biste primenili ažuriranje}=1{Administrator zahteva da ponovo pokrenete Brave da biste primenili ažuriranje. Prozor bez arhiviranja se neće ponovo otvoriti.}one{Administrator zahteva da ponovo pokrenete Brave da biste primenili ažuriranje. # prozor bez arhiviranja se neće ponovo otvoriti.}few{Administrator zahteva da ponovo pokrenete Brave da biste primenili ažuriranje. # prozora bez arhiviranja se neće ponovo otvoriti.}other{Administrator zahteva da ponovo pokrenete Brave da biste primenili ažuriranje. # prozora bez arhiviranja se neće ponovo otvoriti.}} Možete upravljati svojim prijavljenim Brave lancima sinhronizacije. Vaši Brave lanci sinhronizacije koriste se za Brave pretraživač, Play Store, Gmail itd. Ako želite da dodate nalog za nekog drugog, kao što je član porodice, dodajte nov profil na svoj umesto toga. Saznajte više - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sr.xtb b/app/resources/chromium_strings_sr.xtb index 38f36db20375..02c7d6f951ce 100644 --- a/app/resources/chromium_strings_sr.xtb +++ b/app/resources/chromium_strings_sr.xtb @@ -416,4 +416,4 @@ Ovlašćenja koja ste već dali veb-sajtovima i aplikacijama mogu se primeniti n Možete upravljati svojim prijavljenim Brave lancima sinhronizacije. Vaši Brave lanci sinhronizacije koriste se za Brave pretraživač, Play Store, Gmail itd. Ako želite da dodate nalog za nekog drugog, kao što je član porodice, dodajte nov profil na svoj umesto toga. Saznajte više Kada kucate u polje za adresu ili okvir za pretragu, Brave šalje ono što unosite vašem podrazumevanom pretraživaču da bi se dobili bolji predlozi. To se isključuje u delu privatno. Kada kucate u polje za adresu ili okvir za pretragu, Brave šalje ono što unosite na Google Drive da bi se dobili predlozi o artiklu. To se isključuje u delu privatno. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sv.xtb b/app/resources/chromium_strings_sv.xtb index 0c1a23d3c3a1..e85bef0887bc 100644 --- a/app/resources/chromium_strings_sv.xtb +++ b/app/resources/chromium_strings_sv.xtb @@ -416,4 +416,4 @@ Behörigheter du redan har gett till webbplatser och appar kan gälla för det h Du kan hantera dina inloggade Brave-synkroniseringskedjor. Dina Brave-synkroniseringskedjor används för Brave-webbläsaren, Play Store, Gmail och mycket mer. Om du vill lägga till ett konto för någon annan, till exempel en familjemedlem, lägger du till en ny profil i din istället. Läs mer När du skriver i adressfältet eller sökrutan skickas det du skriver till din standardsökmotor för att du ska få bättre förslag. Detta är avstängt i Privat läge. När du skriver i adressfältet eller sökrutan skickas det du skriver till Google Drive för att du ska få förslag på objekt. Detta är avstängt i Privat läge. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_sw.xtb b/app/resources/chromium_strings_sw.xtb index 3b691881c409..c2ac308dd7c3 100644 --- a/app/resources/chromium_strings_sw.xtb +++ b/app/resources/chromium_strings_sw.xtb @@ -416,4 +416,4 @@ Ruhusa ambazo tayari umetoa kwa tovuti na programu zinaweza kutumika katika akau Unaweza kudhibiti minyororo yako ya usawazishaji uliyoingia katika Brave. Minyororo yako ya usawazishaji ya Brave hutumiwa kwa ajili ya kivinjari cha Brave, Play Store, Gmail, na zaidi. Ikiwa unataka kuongeza akaunti ya mtu mwingine, kama vile mwanafamilia, ongeza wasifu mpya kwenye badala yake. Pata maelezo zaidi Unapoandika kwenye upau wa anwani au kisanduku cha utafutaji, Brave hutuma unachoandika kwenye injini yako chaguomsingi ya utafutaji ili kupata mapendekezo bora zaidi. Hili limezimwa katika Faragha. Unapoandika kwenye upau wa anwani au kisanduku cha utafutaji, Brave hutuma unachoandika kwenye Google Drive ili kupata mapendekezo ya kipengee. Hili limezimwa katika Faragha. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ta.xtb b/app/resources/chromium_strings_ta.xtb index e62e5a2d4ef9..923c7dc452df 100644 --- a/app/resources/chromium_strings_ta.xtb +++ b/app/resources/chromium_strings_ta.xtb @@ -414,4 +414,4 @@ {COUNT,plural, =0{இந்தப் புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி பரிந்துரைக்கிறார்}=1{இந்தப் புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி பரிந்துரைக்கிறார். உங்கள் மறைநிலை சாளரம் மீண்டும் திறக்காது.}other{இந்தப் புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி பரிந்துரைக்கிறார். உங்கள் # மறைநிலை சாளரங்கள் மீண்டும் திறக்காது.}} {COUNT,plural, =0{புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி சொல்கிறார்}=1{புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி சொல்கிறார். உங்கள் மறைநிலை சாளரம் மீண்டும் திறக்காது.}other{புதுப்பிப்பைப் பயன்படுத்த Braveமை மீண்டும் தொடங்கும்படி உங்கள் நிர்வாகி சொல்கிறார். உங்கள் # மறைநிலை சாளரங்கள் மீண்டும் திறக்காது.}} நீங்கள் உள்நுழைந்துள்ள Brave கணக்குகளை நிர்வகிக்கலாம். Brave உலாவி, Play Store, Gmail மற்றும் பலவற்றில் உங்கள் Brave கணக்குகள் பயன்படுத்தப்படும். வேறு ஒருவரின் (எ.கா. குடும்ப உறுப்பினர்) கணக்கைச் சேர்க்க விரும்பினால் உங்கள் சாதனத்தில் ஒரு புதிய பயனரைச் சேர்க்கவும். மேலும் அறிக - \ No newline at end of file + diff --git a/app/resources/chromium_strings_te.xtb b/app/resources/chromium_strings_te.xtb index 05826bd06924..fa1a1341985d 100644 --- a/app/resources/chromium_strings_te.xtb +++ b/app/resources/chromium_strings_te.xtb @@ -410,4 +410,4 @@ {COUNT,plural, =0{ఈ అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు}=1{ఈ అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు. మీ అజ్ఞాత విండో మళ్లీ తెరవబడదు.}other{ఈ అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు. మీ # అజ్ఞాత విండోలు మళ్లీ తెరవబడవు.}} {COUNT,plural, =0{అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు}=1{అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు. మీ అజ్ఞాత విండో మళ్లీ తెరవబడదు.}other{అప్‌డేట్‌ను వర్తింపజేయడం కోసం మీరు Braveను పునఃప్రారంభించాలని మీ నిర్వాహకుడు కోరుతున్నారు. మీ # అజ్ఞాత విండోలు మళ్లీ తెరవబడవు.}} మీరు సైన్ ఇన్ చేసిన Brave ఖాతాలను మీరు మేనేజ్ చేయవచ్చు. Brave బ్రౌజర్, Play Store, Gmail, ఇంకా మరిన్నింటి కోసం మీ Brave ఖాతాలు ఉపయోగించబడతాయి. ఫ్యామిలీ మెంబర్ వంటి వారి కోసం మీరు ఖాతాను జోడించాలనుకుంటే, బదులుగా కొత్త వ్యక్తిని మీ కు జోడించండి. మరింత తెలుసుకోండి - \ No newline at end of file + diff --git a/app/resources/chromium_strings_th.xtb b/app/resources/chromium_strings_th.xtb index 3608f0373255..f109fbc69ac2 100644 --- a/app/resources/chromium_strings_th.xtb +++ b/app/resources/chromium_strings_th.xtb @@ -413,4 +413,4 @@ Brave ไม่สามารถกู้คืนการตั้งค่ คุณสามารถจัดการซิงค์เชนของ Brave ที่คุณลงชื่อเข้าใช้ได้ ซึ่งซิงค์เชนของ Brave ของคุณจะใช้สำหรับเบราว์เซอร์ Brave, Play Store, Gmail และอื่นๆ อีกมากมาย หากคุณต้องการเพิ่มบัญชีให้คนอื่น เช่น สมาชิกในครอบครัว ให้เพิ่มโปรไฟล์ใหม่ใน แทนที่ เรียนรู้เพิ่มเติม เมื่อคุณพิมพ์ในแถบที่อยู่หรือช่องค้นหา Brave จะส่งข้อมูลที่คุณพิมพ์ไปยังเครื่องมือค้นหาเริ่มต้นเพื่อรับคำแนะนำที่ดีขึ้น และจะถูกปิดใน Private เมื่อคุณพิมพ์ในแถบที่อยู่หรือช่องค้นหา Brave จะส่งข้อมูลที่คุณพิมพ์ไปยัง Google Drive เพื่อรับคำแนะนำ และจะถูกปิดใน Private - \ No newline at end of file + diff --git a/app/resources/chromium_strings_tr.xtb b/app/resources/chromium_strings_tr.xtb index 89669ed54e5a..612e99771d55 100644 --- a/app/resources/chromium_strings_tr.xtb +++ b/app/resources/chromium_strings_tr.xtb @@ -411,4 +411,4 @@ Web sitelerine ve uygulamalara önceden vermiş olduğunuz izinler bu hesap içi Oturumu açılmış Brave senkronizasyon zincirlerinizi yönetebilirsiniz. Brave senkronizasyon zincirleriniz Brave tarayıcısı, Play Store, Gmail ve daha fazlası için kullanılır. Bir aile üyesi gibi başka biri için bir hesap eklemek istiyorsanız bunun yerine yeni bir profil ekleyin. Daha fazla bilgi Bir adres çubuğuna veya arama kutusuna yazdığınız zaman, Brave daha iyi öneriler almanız için yazdığınız şeyi varsayılan arama motorunuza gönderir. Bu Gizli modda kapalıdır. Bir adres çubuğuna veya arama kutusuna yazdığınız zaman, Brave öğe önerileri almanız için yazdığınız şeyi Google Drive'a gönderir. Bu Gizli modda kapalıdır. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_uk.xtb b/app/resources/chromium_strings_uk.xtb index bfc27dcf7912..9494da89a89f 100644 --- a/app/resources/chromium_strings_uk.xtb +++ b/app/resources/chromium_strings_uk.xtb @@ -414,4 +414,4 @@ Brave не може відновити ваші налаштування.Ви може керувати ланцюжками синхронізації доданих пристроїв Brave. Ваші ланцюжки синхронізації Brave використовуються для браузера Brave, Play Store, Gmail тощо. Якщо ви бажаєте додати акаунт для іншої особи, наприклад члена сім’ї, додайте новий профіль до вашого . Детальніше Коли ви вводите запит в адресний рядок або поле пошуку, Brave надсилає його до пошукової системи за замовчуванням, щоб отримати кращі пропозиції. Цю функцію вимкнено в режимі «‎Приватний». Коли ви вводите запит в адресний рядок або поле пошуку, Brave надсилає його до «Google Диску‎», щоб отримати пропозиції щодо елементів. Цю функцію вимкнено в режимі «‎Приватний». - \ No newline at end of file + diff --git a/app/resources/chromium_strings_ur.xtb b/app/resources/chromium_strings_ur.xtb index c4532f6017f5..6e7486601dde 100644 --- a/app/resources/chromium_strings_ur.xtb +++ b/app/resources/chromium_strings_ur.xtb @@ -415,4 +415,4 @@ Brave آپ کی ترتیبات کو بازیافت کرنے سے قاصر ہے۔ ‏Brave مصنّفین ‏Google Chrome بی ٹا Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_uz.xtb b/app/resources/chromium_strings_uz.xtb index 3baae65e8a15..631e19ab5ec5 100644 --- a/app/resources/chromium_strings_uz.xtb +++ b/app/resources/chromium_strings_uz.xtb @@ -412,4 +412,4 @@ Brave sozlamalaringizni qaytadan tiklay olmadi. Brave mualliflari Google Chrome Beta Google Chrome Dev - \ No newline at end of file + diff --git a/app/resources/chromium_strings_vi.xtb b/app/resources/chromium_strings_vi.xtb index d20aa92a70bf..616a2d2a4bd5 100644 --- a/app/resources/chromium_strings_vi.xtb +++ b/app/resources/chromium_strings_vi.xtb @@ -414,4 +414,4 @@ Các quyền bạn đã cấp cho các trang web và ứng dụng có thể áp Bạn có thể quản lý chuỗi đồng bộ hóa Brave đã đăng nhập của mình. Chuỗi đồng bộ hóa Brave của bạn được sử dụng cho trình duyệt Brave, Cửa hàng Play, Gmail, v.v. Nếu bạn muốn thêm tài khoản cho người khác, chẳng hạn như một thành viên trong gia đình, hãy thêm hồ sơ mới vào . Tìm hiểu thêm Khi bạn nhập vào thanh địa chỉ hoặc hộp tìm kiếm, Brave sẽ gửi nội dung bạn nhập tới công cụ tìm kiếm mặc định của bạn để nhận các đề xuất tốt hơn. Điều này được tắt trong Riêng tư. Khi bạn nhập vào thanh địa chỉ hoặc hộp tìm kiếm, Brave sẽ gửi nội dung bạn nhập tới Google Drive để nhận đề xuất mục. Điều này được tắt trong Riêng tư. - \ No newline at end of file + diff --git a/app/resources/chromium_strings_zh-CN.xtb b/app/resources/chromium_strings_zh-CN.xtb index 731eeb535798..999a629bc4a1 100644 --- a/app/resources/chromium_strings_zh-CN.xtb +++ b/app/resources/chromium_strings_zh-CN.xtb @@ -413,4 +413,4 @@ Brave 无法恢复您的设置。 您可以管理已登录的 Brave 同步链。您的 Brave 同步链用于 Brave 浏览器、应用商店、Gmail 等。如果您想为其他人(例如家庭成员)添加帐户,则请将新的个人资料添加到您的 上。了解详情 当您在地址栏或搜索框中输入时,Brave 会将您输入的内容发送到默认搜索引擎,以获得更好的建议。这是私密的。 当您在地址栏或搜索框中输入时,Brave 会将您输入的内容发送到谷歌 Drive 以获得项目建议。这是私密的。 - \ No newline at end of file + diff --git a/app/resources/chromium_strings_zh-HK.xtb b/app/resources/chromium_strings_zh-HK.xtb index 9b04de09e518..7e0d765bf979 100644 --- a/app/resources/chromium_strings_zh-HK.xtb +++ b/app/resources/chromium_strings_zh-HK.xtb @@ -415,4 +415,4 @@ Brave 無法復原您的設定。 Brave Software Inc Google Chrome 測試版 Google Chrome 開發人員版 - \ No newline at end of file + diff --git a/app/resources/chromium_strings_zh-TW.xtb b/app/resources/chromium_strings_zh-TW.xtb index 4a2aabc17a4e..180c373a086d 100644 --- a/app/resources/chromium_strings_zh-TW.xtb +++ b/app/resources/chromium_strings_zh-TW.xtb @@ -414,4 +414,4 @@ Brave 無法復原你的設定。 您可以管理您已登入的 Brave 同步鏈。您的 Brave 同步鏈用於 Brave 瀏覽器、Play 商店、Gmail 等處。如果您想為其他人(如家庭成員)新增帳戶,請將新的個人檔案新增到您的 深入瞭解 當您在網址列或搜尋方塊輸入內容時,Brave 會將您輸入的內容傳送至您的預設搜尋引擎,以便取得更好的建議。在無痕模式下會停用此功能。 當您在網址列或搜尋方塊輸入內容時,Brave 會將您輸入的內容傳送至 Google 雲端硬碟以取得項目建議。在無痕模式下會停用此功能。 - \ No newline at end of file + diff --git a/app/resources/chromium_strings_zu.xtb b/app/resources/chromium_strings_zu.xtb index 6d3f88d78673..b88a77710e1c 100644 --- a/app/resources/chromium_strings_zu.xtb +++ b/app/resources/chromium_strings_zu.xtb @@ -416,4 +416,4 @@ I-Brave ayikwazi ukubuyisela izilungiselelo zakho. Ababhali be-Brave I-beta ye-Google Chrome I-Google Chrome Dev - \ No newline at end of file + diff --git a/browser/brave_content_browser_client_browsertest.cc b/browser/brave_content_browser_client_browsertest.cc index 54cf9e481a13..58226a3925e8 100644 --- a/browser/brave_content_browser_client_browsertest.cc +++ b/browser/brave_content_browser_client_browsertest.cc @@ -532,14 +532,8 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, MixedContentForOnion) { net::ProxyConfigServiceTor::SetBypassTorProxyConfigForTesting(true); tor::TorNavigationThrottle::SetSkipWaitForTorConnectedForTesting(true); - base::RunLoop loop; - Browser* tor_browser = nullptr; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindLambdaForTesting([&](Browser* browser) { - tor_browser = browser; - loop.Quit(); - })); - loop.Run(); + Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(browser()->profile()); const GURL onion_url = embedded_test_server()->GetURL("test.onion", "/onion.html"); diff --git a/browser/brave_wallet/asset_discovery_manager_unittest.cc b/browser/brave_wallet/asset_discovery_manager_unittest.cc index f3fbe923db7a..5c47e4285d71 100644 --- a/browser/brave_wallet/asset_discovery_manager_unittest.cc +++ b/browser/brave_wallet/asset_discovery_manager_unittest.cc @@ -12,6 +12,7 @@ #include "brave/browser/brave_wallet/json_rpc_service_factory.h" #include "brave/browser/brave_wallet/keyring_service_factory.h" #include "brave/browser/brave_wallet/tx_service_factory.h" +#include "brave/components/brave_wallet/browser/brave_wallet_constants.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_service_delegate.h" #include "brave/components/brave_wallet/browser/brave_wallet_service_observer_base.h" diff --git a/browser/brave_wallet/brave_wallet_service_unittest.cc b/browser/brave_wallet/brave_wallet_service_unittest.cc index a41ccf7f446d..1ce9e17ebd10 100644 --- a/browser/brave_wallet/brave_wallet_service_unittest.cc +++ b/browser/brave_wallet/brave_wallet_service_unittest.cc @@ -20,6 +20,7 @@ #include "brave/browser/brave_wallet/tx_service_factory.h" #include "brave/components/brave_wallet/browser/blockchain_list_parser.h" #include "brave/components/brave_wallet/browser/blockchain_registry.h" +#include "brave/components/brave_wallet/browser/brave_wallet_constants.h" #include "brave/components/brave_wallet/browser/brave_wallet_service_delegate.h" #include "brave/components/brave_wallet/browser/brave_wallet_service_observer_base.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" diff --git a/browser/brave_wallet/ethereum_provider_impl_unittest.cc b/browser/brave_wallet/ethereum_provider_impl_unittest.cc index 8a1b77955315..9c547269aab9 100644 --- a/browser/brave_wallet/ethereum_provider_impl_unittest.cc +++ b/browser/brave_wallet/ethereum_provider_impl_unittest.cc @@ -32,27 +32,20 @@ #include "brave/browser/brave_wallet/keyring_service_factory.h" #include "brave/browser/brave_wallet/tx_service_factory.h" #include "brave/components/brave_wallet/browser/asset_ratio_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_constants.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" -#include "brave/components/brave_wallet/browser/eth_nonce_tracker.h" -#include "brave/components/brave_wallet/browser/eth_pending_tx_tracker.h" #include "brave/components/brave_wallet/browser/eth_tx_manager.h" -#include "brave/components/brave_wallet/browser/hd_keyring.h" #include "brave/components/brave_wallet/browser/json_rpc_service.h" #include "brave/components/brave_wallet/browser/keyring_service.h" -#include "brave/components/brave_wallet/browser/permission_utils.h" -#include "brave/components/brave_wallet/browser/pref_names.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/browser/tx_service.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/hex_utils.h" -#include "brave/components/brave_wallet/common/web3_provider_constants.h" #include "brave/components/permissions/brave_permission_manager.h" -#include "brave/components/permissions/contexts/brave_wallet_permission_context.h" #include "brave/components/version_info/version_info.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/permissions/permission_manager_factory.h" -#include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" @@ -61,9 +54,6 @@ #include "components/grit/brave_components_strings.h" #include "components/permissions/permission_request_manager.h" #include "components/prefs/pref_service.h" -#include "components/sync_preferences/testing_pref_service_syncable.h" -#include "components/user_prefs/user_prefs.h" -#include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_web_contents_factory.h" #include "content/test/test_web_contents.h" diff --git a/browser/brave_wallet/notifications/sources.gni b/browser/brave_wallet/notifications/sources.gni index 3aa64aa8e020..81f274bc6fb1 100644 --- a/browser/brave_wallet/notifications/sources.gni +++ b/browser/brave_wallet/notifications/sources.gni @@ -9,7 +9,6 @@ brave_browser_brave_wallet_deps = brave_browser_brave_wallet_sources = [] if (!is_android) { brave_browser_brave_wallet_sources += [ - "//brave/browser/brave_wallet/notifications/wallet_notification_helper_impl.cc", "//brave/browser/brave_wallet/notifications/wallet_notification_service.cc", "//brave/browser/brave_wallet/notifications/wallet_notification_service.h", "//brave/browser/brave_wallet/notifications/wallet_notification_service_factory.cc", diff --git a/browser/brave_wallet/notifications/wallet_notification_helper_impl.cc b/browser/brave_wallet/notifications/wallet_notification_helper_impl.cc deleted file mode 100644 index 074e33ef27d2..000000000000 --- a/browser/brave_wallet/notifications/wallet_notification_helper_impl.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2022 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/brave_wallet/wallet_notification_helper.h" - -#include "brave/browser/brave_wallet/notifications/wallet_notification_service_factory.h" -#include "brave/components/brave_wallet/browser/tx_service.h" - -namespace brave_wallet { - -void RegisterWalletNotificationService(content::BrowserContext* context, - TxService* tx_service) { - auto* notification_service = - WalletNotificationServiceFactory::GetInstance()->GetServiceForContext( - context); - tx_service->AddObserver(notification_service->GetReceiver()); -} - -} // namespace brave_wallet diff --git a/browser/brave_wallet/notifications/wallet_notification_service.cc b/browser/brave_wallet/notifications/wallet_notification_service.cc index bae793e81ef5..1a28bc5c3b80 100644 --- a/browser/brave_wallet/notifications/wallet_notification_service.cc +++ b/browser/brave_wallet/notifications/wallet_notification_service.cc @@ -9,6 +9,7 @@ #include #include "base/strings/utf_string_conversions.h" +#include "brave/components/brave_wallet/browser/tx_service.h" #include "chrome/browser/notifications/notification_display_service.h" #include "chrome/browser/notifications/notification_display_service_factory.h" #include "chrome/browser/profiles/profile.h" @@ -71,8 +72,11 @@ void PushNotification(content::BrowserContext* context, namespace brave_wallet { WalletNotificationService::WalletNotificationService( + TxService* tx_service, content::BrowserContext* context) - : context_(context) {} + : context_(context) { + tx_service->AddObserver(tx_observer_receiver_.BindNewPipeAndPassRemote()); +} WalletNotificationService::~WalletNotificationService() = default; diff --git a/browser/brave_wallet/notifications/wallet_notification_service.h b/browser/brave_wallet/notifications/wallet_notification_service.h index d92b7024a3aa..c682a55d3d40 100644 --- a/browser/brave_wallet/notifications/wallet_notification_service.h +++ b/browser/brave_wallet/notifications/wallet_notification_service.h @@ -11,7 +11,6 @@ #include "base/memory/raw_ptr.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" namespace content { @@ -19,11 +18,13 @@ class BrowserContext; } // namespace content namespace brave_wallet { +class TxService; class WalletNotificationService : public KeyedService, public mojom::TxServiceObserver { public: - explicit WalletNotificationService(content::BrowserContext* context); + WalletNotificationService(TxService* tx_service, + content::BrowserContext* context); ~WalletNotificationService() override; WalletNotificationService(const WalletNotificationService&) = delete; WalletNotificationService operator=(const WalletNotificationService&) = @@ -35,10 +36,6 @@ class WalletNotificationService : public KeyedService, void OnTransactionStatusChanged(mojom::TransactionInfoPtr tx_info) override; void OnTxServiceReset() override {} - mojo::PendingRemote GetReceiver() { - return tx_observer_receiver_.BindNewPipeAndPassRemote(); - } - private: friend class WalletNotificationServiceUnitTest; diff --git a/browser/brave_wallet/notifications/wallet_notification_service_factory.cc b/browser/brave_wallet/notifications/wallet_notification_service_factory.cc index 6d7c2fb76c3b..1b5762fcc5f9 100644 --- a/browser/brave_wallet/notifications/wallet_notification_service_factory.cc +++ b/browser/brave_wallet/notifications/wallet_notification_service_factory.cc @@ -35,7 +35,8 @@ WalletNotificationServiceFactory::~WalletNotificationServiceFactory() = default; KeyedService* WalletNotificationServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new WalletNotificationService(context); + return new WalletNotificationService( + TxServiceFactory::GetServiceForContext(context), context); } // static diff --git a/browser/brave_wallet/notifications/wallet_notification_service_unittest.cc b/browser/brave_wallet/notifications/wallet_notification_service_unittest.cc index 122f6ade2312..6fc897ebbc77 100644 --- a/browser/brave_wallet/notifications/wallet_notification_service_unittest.cc +++ b/browser/brave_wallet/notifications/wallet_notification_service_unittest.cc @@ -49,8 +49,8 @@ class WalletNotificationServiceUnitTest : public testing::Test { tx_service_ = std::make_unique( json_rpc_service_.get(), nullptr, keyring_service_.get(), prefs(), temp_dir_.GetPath(), base::SequencedTaskRunner::GetCurrentDefault()); - notification_service_ = - std::make_unique(profile()); + notification_service_ = std::make_unique( + tx_service_.get(), profile()); tester_ = std::make_unique(profile()); keyring_service_->CreateWallet(kMnemonicDivideCruise, "brave", base::DoNothing()); diff --git a/browser/brave_wallet/solana_provider_browsertest.cc b/browser/brave_wallet/solana_provider_browsertest.cc index af283d5b89ab..093913ce3f37 100644 --- a/browser/brave_wallet/solana_provider_browsertest.cc +++ b/browser/brave_wallet/solana_provider_browsertest.cc @@ -26,6 +26,7 @@ #include "brave/components/brave_wallet/browser/tx_service.h" #include "brave/components/brave_wallet/common/brave_wallet_constants.h" #include "brave/components/brave_wallet/common/common_utils.h" +#include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/features.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/brave_wallet/renderer/resource_helper.h" diff --git a/browser/brave_wallet/solana_provider_impl_unittest.cc b/browser/brave_wallet/solana_provider_impl_unittest.cc index 3376158bc0d5..ea6764823329 100644 --- a/browser/brave_wallet/solana_provider_impl_unittest.cc +++ b/browser/brave_wallet/solana_provider_impl_unittest.cc @@ -29,6 +29,7 @@ #include "brave/components/brave_wallet/browser/solana_message.h" #include "brave/components/brave_wallet/browser/tx_service.h" #include "brave/components/brave_wallet/common/brave_wallet_constants.h" +#include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/features.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/permissions/brave_permission_manager.h" diff --git a/browser/brave_wallet/solana_provider_renderer_browsertest.cc b/browser/brave_wallet/solana_provider_renderer_browsertest.cc index 0f3b58686d5d..7f17b33a6377 100644 --- a/browser/brave_wallet/solana_provider_renderer_browsertest.cc +++ b/browser/brave_wallet/solana_provider_renderer_browsertest.cc @@ -19,6 +19,7 @@ #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_constants.h" +#include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/features.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/brave_wallet/renderer/resource_helper.h" diff --git a/browser/brave_wallet/tx_service_factory.cc b/browser/brave_wallet/tx_service_factory.cc index 37196f50c79a..cca6af0c0943 100644 --- a/browser/brave_wallet/tx_service_factory.cc +++ b/browser/brave_wallet/tx_service_factory.cc @@ -15,16 +15,11 @@ #include "brave/browser/brave_wallet/brave_wallet_context_utils.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" #include "brave/browser/brave_wallet/keyring_service_factory.h" -#include "brave/components/brave_wallet/browser/brave_wallet_constants.h" #include "brave/components/brave_wallet/browser/tx_service.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/user_prefs/user_prefs.h" -#if !BUILDFLAG(IS_ANDROID) -#include "brave/browser/brave_wallet/wallet_notification_helper.h" -#endif - namespace brave_wallet { // static @@ -148,19 +143,12 @@ TxServiceFactory::~TxServiceFactory() = default; KeyedService* TxServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - auto* tx_service = - new TxService(JsonRpcServiceFactory::GetServiceForContext(context), - BitcoinWalletServiceFactory::GetServiceForContext(context), - KeyringServiceFactory::GetServiceForContext(context), - user_prefs::UserPrefs::Get(context), context->GetPath(), - base::SequencedTaskRunner::GetCurrentDefault()); -#if !BUILDFLAG(IS_ANDROID) - // TODO(apaymyshev): WalletNotificationServiceFactory depends on - // TxServiceFactory and should be responsible for subscribing on TxService. - // Refactor this. - RegisterWalletNotificationService(context, tx_service); -#endif - return tx_service; + return new TxService( + JsonRpcServiceFactory::GetServiceForContext(context), + BitcoinWalletServiceFactory::GetServiceForContext(context), + KeyringServiceFactory::GetServiceForContext(context), + user_prefs::UserPrefs::Get(context), context->GetPath(), + base::SequencedTaskRunner::GetCurrentDefault()); } content::BrowserContext* TxServiceFactory::GetBrowserContextToUse( diff --git a/browser/ipfs/content_browser_client_helper.cc b/browser/ipfs/content_browser_client_helper.cc index 59dd4f2b1dc5..12a99a2e932c 100644 --- a/browser/ipfs/content_browser_client_helper.cc +++ b/browser/ipfs/content_browser_client_helper.cc @@ -120,9 +120,11 @@ bool HandleIPFSURLReverseRewrite(GURL* url, if (ipfs_pos == std::string::npos && ipns_pos == std::string::npos) return false; - auto cid_end = (ipfs_pos == std::string::npos) ? ipns_pos : ipfs_pos; - if (!ipfs::IsValidCIDOrDomain(url->host().substr(0, cid_end))) + if (auto cid_end = (ipfs_pos == std::string::npos) ? ipns_pos : ipfs_pos; + !ipfs::IsValidCIDOrDomain( + ipfs::DecodeSingleLabelForm((url->host().substr(0, cid_end))))) { return false; + } GURL configured_gateway = GetConfiguredBaseGateway( user_prefs::UserPrefs::Get(browser_context), chrome::GetChannel()); diff --git a/browser/ipfs/content_browser_client_helper_unittest.cc b/browser/ipfs/content_browser_client_helper_unittest.cc index d5bb6e362a2c..16aa485139ae 100644 --- a/browser/ipfs/content_browser_client_helper_unittest.cc +++ b/browser/ipfs/content_browser_client_helper_unittest.cc @@ -257,6 +257,12 @@ TEST_F(ContentBrowserClientHelperUnitTest, HandleIPFSURLReverseRewriteLocal) { ASSERT_TRUE(HandleIPFSURLReverseRewrite(&ipns_uri, browser_context())); ASSERT_EQ(ipns_uri.spec(), "ipns://test.com/#ref"); + source = "http://en-wikipedia--on--ipfs-org.ipns.localhost/wiki/Architecture"; + ipns_uri = GURL(source).ReplaceComponents(replacements); + ASSERT_TRUE(HandleIPFSURLReverseRewrite(&ipns_uri, browser_context())); + ASSERT_EQ(ipns_uri.spec(), + "ipns://en-wikipedia--on--ipfs-org/wiki/Architecture"); + source = "http://test.com.ipns.localhost:8000/"; ipns_uri = GURL(source); ASSERT_FALSE(HandleIPFSURLReverseRewrite(&ipns_uri, browser_context())); @@ -318,6 +324,11 @@ TEST_F(ContentBrowserClientHelperUnitTest, HandleIPFSURLReverseRewriteGateway) { ASSERT_FALSE(HandleIPFSURLReverseRewrite(&ipns_uri, browser_context())); ASSERT_EQ(ipns_uri.spec(), source); + source = "http://en-wikipedia--on--ipfs-org.ipns.localhost:48080/wiki/"; + ipns_uri = GURL(source); + ASSERT_FALSE(HandleIPFSURLReverseRewrite(&ipns_uri, browser_context())); + ASSERT_EQ(ipns_uri.spec(), source); + ipns_uri = GURL( "https://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq" ".ipns.localhost:8080/"); diff --git a/browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc b/browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc index 1289b39b5ef7..84c4430a13e5 100644 --- a/browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc +++ b/browser/net/brave_site_hacks_network_delegate_helper_browsertest.cc @@ -386,14 +386,8 @@ IN_PROC_BROWSER_TEST_F(BraveSiteHacksNetworkDelegateBrowserTest, OnionReferrers) { net::ProxyConfigServiceTor::SetBypassTorProxyConfigForTesting(true); tor::TorNavigationThrottle::SetSkipWaitForTorConnectedForTesting(true); - base::RunLoop loop; - Browser* tor_browser = nullptr; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindLambdaForTesting([&](Browser* browser) { - tor_browser = browser; - loop.Quit(); - })); - loop.Run(); + Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(browser()->profile()); // Same-origin navigations { diff --git a/browser/search_engines/search_engine_provider_service_browsertest.cc b/browser/search_engines/search_engine_provider_service_browsertest.cc index bc191fa5fe19..9179a6c99075 100644 --- a/browser/search_engines/search_engine_provider_service_browsertest.cc +++ b/browser/search_engines/search_engine_provider_service_browsertest.cc @@ -62,12 +62,6 @@ testing::AssertionResult VerifyTemplateURLServiceLoad( return testing::AssertionFailure() << "TemplateURLService isn't loaded"; } -// An observer that returns back to test code after a new profile is -// initialized. -void OnProfileCreation(base::RunLoop* run_loop, Browser* browser) { - run_loop->Quit(); -} - TemplateURLData CreateTestSearchEngine() { TemplateURLData result; result.SetShortName(u"test1"); @@ -239,13 +233,14 @@ IN_PROC_BROWSER_TEST_F(SearchEngineProviderServiceTest, incognito_service->GetDefaultSearchProvider()->prepopulate_id()); #if BUILDFLAG(ENABLE_TOR) - base::RunLoop run_loop; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindOnce(&OnProfileCreation, &run_loop)); - run_loop.Run(); - Profile* tor_profile = BrowserList::GetInstance()->GetLastActive()->profile(); + Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(browser()->profile()); + Profile* tor_profile = tor_browser->profile(); EXPECT_TRUE(tor_profile->IsTor()); + // Wait for the search provider to initialize. + base::RunLoop().RunUntilIdle(); + const int default_provider_id = TemplateURLPrepopulateData::PREPOPULATED_ENGINE_ID_BRAVE_TOR; auto* tor_service = TemplateURLServiceFactory::GetForProfile(tor_profile); diff --git a/browser/speedreader/page_distiller.cc b/browser/speedreader/page_distiller.cc index af8026fc0721..59126b24507a 100644 --- a/browser/speedreader/page_distiller.cc +++ b/browser/speedreader/page_distiller.cc @@ -46,6 +46,20 @@ void PageDistiller::GetDistilledText(DistillContentCallback callback) { weak_factory_.GetWeakPtr(), std::move(callback))); } +void PageDistiller::GetTextToSpeak(TextToSpeechContentCallback callback) { + if (state_ != State::kDistilled) { + return std::move(callback).Run(base::Value()); + } + + constexpr const char16_t kGetTextToSpeak[] = uR"js( extractTextToSpeak() )js"; + + web_contents_->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( + kGetTextToSpeak, + base::BindOnce(&PageDistiller::OnGetTextToSpeak, + weak_factory_.GetWeakPtr(), std::move(callback)), + ISOLATED_WORLD_ID_BRAVE_INTERNAL); +} + void PageDistiller::UpdateState(State state) { state_ = state; for (auto& observer : observers_) { @@ -62,22 +76,17 @@ void PageDistiller::StartDistill(DistillContentCallback callback) { return std::move(callback).Run(false, {}); } - if (state_ == State::kDistilled) { - constexpr const char16_t kScript[] = uR"js( extractText() )js"; - web_contents_->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( - kScript, - base::BindOnce(&PageDistiller::OnGetText, weak_factory_.GetWeakPtr(), - std::move(callback)), - ISOLATED_WORLD_ID_BRAVE_INTERNAL); - } else { - constexpr const char16_t kScript[] = - uR"js( document.documentElement.outerHTML )js"; - web_contents_->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( - kScript, - base::BindOnce(&PageDistiller::OnGetOuterHTML, - weak_factory_.GetWeakPtr(), std::move(callback)), - ISOLATED_WORLD_ID_BRAVE_INTERNAL); - } + constexpr const char16_t kGetDocumentSource[] = + uR"js( document.documentElement.outerHTML )js"; + + constexpr const char16_t kGetBodySource[] = + uR"js( document.body.outerHTML )js"; + + web_contents_->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( + (state_ != State::kDistilled) ? kGetDocumentSource : kGetBodySource, + base::BindOnce(&PageDistiller::OnGetOuterHTML, weak_factory_.GetWeakPtr(), + std::move(callback)), + ISOLATED_WORLD_ID_BRAVE_INTERNAL); } void PageDistiller::OnGetOuterHTML(DistillContentCallback callback, @@ -104,14 +113,12 @@ void PageDistiller::OnGetOuterHTML(DistillContentCallback callback, } } -void PageDistiller::OnGetText(DistillContentCallback callback, - base::Value result) { - if (!web_contents_ || !result.is_dict() || - !result.GetDict().FindString("content")) { - return std::move(callback).Run(false, {}); +void PageDistiller::OnGetTextToSpeak(TextToSpeechContentCallback callback, + base::Value result) { + if (!result.is_dict()) { + return std::move(callback).Run(base::Value()); } - std::move(callback).Run(true, - std::move(*result.GetDict().FindString("content"))); + std::move(callback).Run(std::move(result)); } void PageDistiller::OnPageDistilled(DistillContentCallback callback, @@ -147,6 +154,7 @@ void PageDistiller::ExtractText(DistillContentCallback callback, return std::move(callback).Run(false, {}); } + re2::RE2::GlobalReplace(&html_content, "<[^>]*>", " "); std::move(callback).Run(true, html_content); } diff --git a/browser/speedreader/page_distiller.h b/browser/speedreader/page_distiller.h index ed79ab9db407..913343f5ebd2 100644 --- a/browser/speedreader/page_distiller.h +++ b/browser/speedreader/page_distiller.h @@ -41,6 +41,7 @@ class PageDistiller { using DistillContentCallback = base::OnceCallback; + using TextToSpeechContentCallback = base::OnceCallback; State GetState() const; @@ -49,6 +50,7 @@ class PageDistiller { void GetDistilledHTML(DistillContentCallback callback); void GetDistilledText(DistillContentCallback callback); + void GetTextToSpeak(TextToSpeechContentCallback callback); protected: explicit PageDistiller(content::WebContents* web_contents); @@ -60,7 +62,8 @@ class PageDistiller { private: void StartDistill(DistillContentCallback callback); void OnGetOuterHTML(DistillContentCallback callback, base::Value result); - void OnGetText(DistillContentCallback callback, base::Value result); + void OnGetTextToSpeak(TextToSpeechContentCallback callback, + base::Value result); void OnPageDistilled(DistillContentCallback callback, DistillationResult result, std::string original_data, diff --git a/browser/speedreader/speedreader_tab_helper.cc b/browser/speedreader/speedreader_tab_helper.cc index c53437e890c4..042bd6bf0bd9 100644 --- a/browser/speedreader/speedreader_tab_helper.cc +++ b/browser/speedreader/speedreader_tab_helper.cc @@ -26,6 +26,7 @@ #include "brave/components/speedreader/speedreader_rewriter_service.h" #include "brave/components/speedreader/speedreader_service.h" #include "brave/components/speedreader/speedreader_util.h" +#include "brave/components/speedreader/tts_player.h" #include "chrome/common/chrome_isolated_world_ids.h" #include "components/dom_distiller/content/browser/distillable_page_utils.h" #include "components/grit/brave_components_resources.h" @@ -51,6 +52,11 @@ namespace speedreader { std::u16string GetSpeedreaderData( std::initializer_list> resources) { std::u16string result = u"speedreaderData = {"; + + if (kSpeedreaderTTS.Get()) { + result += u"ttsEnabled: true,"; + } + for (const auto& r : resources) { auto text = brave_l10n::GetLocalizedResourceUTF16String(r.second); // Make sure that the text doesn't contain js injection @@ -204,6 +210,17 @@ void SpeedreaderTabHelper::OnShowOriginalPage() { TransitStateTo(DistillStates::ViewOriginal()); } +void SpeedreaderTabHelper::OnTtsPlayPause(int paragraph_index) { + auto& tts_controller = + speedreader::TtsPlayer::GetInstance()->GetControllerFor(web_contents()); + if (tts_controller.IsPlaying() && + tts_controller.IsPlayingRequestedWebContents(paragraph_index)) { + tts_controller.Pause(); + } else { + tts_controller.Play(paragraph_index); + } +} + void SpeedreaderTabHelper::ClearPersistedData() { if (auto* entry = web_contents()->GetController().GetLastCommittedEntry()) { SpeedreaderExtendedInfoHandler::ClearPersistedData(entry); @@ -234,8 +251,10 @@ void SpeedreaderTabHelper::ProcessNavigation( auto* rewriter_service = g_brave_browser_process->speedreader_rewriter_service(); + auto* nav_entry = navigation_handle->GetNavigationEntry(); + const bool url_looks_readable = - rewriter_service && + nav_entry && !nav_entry->IsViewSourceMode() && rewriter_service && rewriter_service->URLLooksReadable(navigation_handle->GetURL()); const bool enabled_for_site = @@ -302,19 +321,22 @@ void SpeedreaderTabHelper::DidStopLoading() { void SpeedreaderTabHelper::DOMContentLoaded( content::RenderFrameHost* render_frame_host) { - if (!render_frame_host->IsInPrimaryMainFrame()) { + if (!render_frame_host->IsInPrimaryMainFrame() || + !DistillStates::IsDistilled(distill_state_)) { return; } + UpdateUI(); - if (!IsPageDistillationAllowed()) { - return; - } else { - UpdateUI(); - } - - static base::NoDestructor kSpeedreaderData(GetSpeedreaderData( - {{"showOriginalLinkText", IDS_READER_MODE_SHOW_ORIGINAL_PAGE_LINK}, - {"minutesText", IDS_READER_MODE_MINUTES_TEXT}})); + static base::NoDestructor kSpeedreaderData( + GetSpeedreaderData({ + {"showOriginalLinkText", IDS_READER_MODE_SHOW_ORIGINAL_PAGE_LINK}, + {"minutesText", IDS_READER_MODE_MINUTES_TEXT}, +#if defined(IDS_READER_MODE_TEXT_TO_SPEECH_PLAY_PAUSE) + { + "playButtonTitle", IDS_READER_MODE_TEXT_TO_SPEECH_PLAY_PAUSE + } +#endif + })); static base::NoDestructor kJsScript(base::UTF8ToUTF16( ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( @@ -448,7 +470,7 @@ void SpeedreaderTabHelper::SetDocumentAttribute(const std::string& attribute, } void SpeedreaderTabHelper::OnGetDocumentSource(bool success, std::string html) { - if (!success) { + if (!success || html.empty()) { // TODO(boocmp): Show error dialog [Distillation failed on this page]. TransitStateTo(DistillStates::DistillReverting( DistillStates::DistillReverting::Reason::kError, false)); @@ -456,7 +478,7 @@ void SpeedreaderTabHelper::OnGetDocumentSource(bool success, std::string html) { return; } - single_show_content_.swap(html); + single_show_content_ = std::move(html); TransitStateTo( DistillStates::Distilling(DistillStates::Distilling::Reason::kManual)); } diff --git a/browser/speedreader/speedreader_tab_helper.h b/browser/speedreader/speedreader_tab_helper.h index b5aa03709170..b1fb7ed23b9c 100644 --- a/browser/speedreader/speedreader_tab_helper.h +++ b/browser/speedreader/speedreader_tab_helper.h @@ -98,6 +98,7 @@ class SpeedreaderTabHelper // mojom::SpeedreaderHost: void OnShowOriginalPage() override; + void OnTtsPlayPause(int index) override; private: friend class content::WebContentsUserData; diff --git a/browser/tor/brave_tor_browsertest.cc b/browser/tor/brave_tor_browsertest.cc index b26c489d9e68..ea86dbeeafc7 100644 --- a/browser/tor/brave_tor_browsertest.cc +++ b/browser/tor/brave_tor_browsertest.cc @@ -174,18 +174,9 @@ class BraveTorTest : public InProcessBrowserTest { } Profile* OpenTorWindow() { - base::RunLoop loop; - Profile* tor_profile = nullptr; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindLambdaForTesting([&](Browser* browser) { - loop.Quit(); - - if (browser) { - tor_profile = browser->profile(); - } - })); - loop.Run(); - return tor_profile; + Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(browser()->profile()); + return tor_browser ? tor_browser->profile() : nullptr; } TorInfo WaitForTorLaunched() { diff --git a/browser/tor/onion_domain_throttle_browsertest.cc b/browser/tor/onion_domain_throttle_browsertest.cc index 6770bdd661b0..67789e567f91 100644 --- a/browser/tor/onion_domain_throttle_browsertest.cc +++ b/browser/tor/onion_domain_throttle_browsertest.cc @@ -77,15 +77,7 @@ class OnionDomainThrottleBrowserTest : public InProcessBrowserTest { } Browser* OpenTorWindow() { - base::RunLoop loop; - Browser* tor_browser = nullptr; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindLambdaForTesting([&](Browser* browser) { - tor_browser = browser; - loop.Quit(); - })); - loop.Run(); - return tor_browser; + return TorProfileManager::SwitchToTorProfile(browser()->profile()); } protected: diff --git a/browser/tor/onion_location_navigation_throttle_browsertest.cc b/browser/tor/onion_location_navigation_throttle_browsertest.cc index 1afd607b0098..b7a292f9d8a5 100644 --- a/browser/tor/onion_location_navigation_throttle_browsertest.cc +++ b/browser/tor/onion_location_navigation_throttle_browsertest.cc @@ -144,15 +144,7 @@ class OnionLocationNavigationThrottleBrowserTest : public InProcessBrowserTest { } Browser* OpenTorWindow() { - base::RunLoop loop; - Browser* tor_browser = nullptr; - TorProfileManager::SwitchToTorProfile( - browser()->profile(), base::BindLambdaForTesting([&](Browser* browser) { - tor_browser = browser; - loop.Quit(); - })); - loop.Run(); - return tor_browser; + return TorProfileManager::SwitchToTorProfile(browser()->profile()); } private: @@ -289,10 +281,14 @@ IN_PROC_BROWSER_TEST_F(OnionLocationNavigationThrottleBrowserTest, nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); GURL url = test_server()->GetURL("/onion"); + content::TestNavigationObserver nav_observer( + browser()->tab_strip_model()->GetActiveWebContents()); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); browser_creation_observer.Wait(); - // We don't close the original tab + // We don't close the original tab but stop loading EXPECT_EQ(browser()->tab_strip_model()->count(), 1); + EXPECT_EQ(nav_observer.last_net_error_code(), net::ERR_BLOCKED_BY_RESPONSE); + content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); tor::OnionLocationTabHelper* helper = @@ -453,3 +449,52 @@ IN_PROC_BROWSER_TEST_F(OnionLocationNavigationThrottleBrowserTest, HTTPHost) { browser_list->get(0)->tab_strip_model()->GetActiveWebContents(); EXPECT_EQ(web_contents->GetVisibleURL(), url); } + +IN_PROC_BROWSER_TEST_F(OnionLocationNavigationThrottleBrowserTest, + RenderInitiatedNavigations) { + browser()->profile()->GetPrefs()->SetBoolean(tor::prefs::kAutoOnionRedirect, + true); + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), GURL("https://brave.com"))); + + const char kScript[] = R"js( + // Spam user. + for (let i = 0; i < 5; i++) { + document.location.href = 'http://spam' + i + '.onion' + } + )js"; + + // Renderer initiated navigations. + ui_test_utils::BrowserChangeObserver browser_creation_observer( + nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + kScript); + browser_creation_observer.Wait(); + + BrowserList* browser_list = BrowserList::GetInstance(); + EXPECT_EQ(2U, browser_list->size()); + EXPECT_TRUE(browser_list->get(1)->profile()->IsTor()); + EXPECT_EQ(1, browser_list->get(1)->tab_strip_model()->count()); + auto* tor_tab = browser_list->get(1)->tab_strip_model()->GetWebContentsAt(0); + EXPECT_EQ(GURL("http://spam4.onion"), tor_tab->GetVisibleURL()); + + // Browser initiated navigation. + content::TestNavigationObserver nav_observer( + browser()->tab_strip_model()->GetActiveWebContents()); + browser()->tab_strip_model()->GetActiveWebContents()->GetController().LoadURL( + GURL("http://user.onion"), content::Referrer(), ui::PAGE_TRANSITION_TYPED, + {}); + nav_observer.Wait(); + + EXPECT_EQ(2U, browser_list->size()); + EXPECT_TRUE(browser_list->get(1)->profile()->IsTor()); + EXPECT_EQ(2, browser_list->get(1)->tab_strip_model()->count()); + EXPECT_EQ(GURL("http://spam4.onion"), browser_list->get(1) + ->tab_strip_model() + ->GetWebContentsAt(0) + ->GetVisibleURL()); + EXPECT_EQ(GURL("http://user.onion"), browser_list->get(1) + ->tab_strip_model() + ->GetWebContentsAt(1) + ->GetVisibleURL()); +} diff --git a/browser/tor/onion_location_navigation_throttle_delegate.cc b/browser/tor/onion_location_navigation_throttle_delegate.cc index 082b38839976..add03ebac735 100644 --- a/browser/tor/onion_location_navigation_throttle_delegate.cc +++ b/browser/tor/onion_location_navigation_throttle_delegate.cc @@ -10,20 +10,76 @@ #include "brave/browser/tor/tor_profile_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_user_data.h" namespace tor { namespace { -void OnTorProfileCreated(GURL onion_location, Browser* browser) { - if (!browser) +class TorNavigationInitiator + : public content::WebContentsUserData { + public: + TorNavigationInitiator(content::WebContents* tor_web_contents, + content::WebContents* initiator_web_contents) + : content::WebContentsUserData(*tor_web_contents), + initiator_web_contents_(initiator_web_contents) { + DCHECK(initiator_web_contents_); + } + + bool IsInitiatedBy(content::WebContents* initiator_web_contents) const { + return initiator_web_contents_ == initiator_web_contents; + } + + private: + friend class WebContentsUserData; + + // Used only for pointer comparasion. + const raw_ptr initiator_web_contents_ = nullptr; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +WEB_CONTENTS_USER_DATA_KEY_IMPL(TorNavigationInitiator); + +void OpenURLInTor(Browser* browser, + const GURL& onion_location, + content::WebContents* initiator) { + if (!browser) { return; - content::OpenURLParams open_tor(onion_location, content::Referrer(), - WindowOpenDisposition::SWITCH_TO_TAB, - ui::PAGE_TRANSITION_TYPED, false); - browser->OpenURL(open_tor); + } + + TorNavigationInitiator* nav_initiator = nullptr; + if (initiator) { + for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { + auto* ni = TorNavigationInitiator::FromWebContents( + browser->tab_strip_model()->GetWebContentsAt(i)); + if (ni && ni->IsInitiatedBy(initiator)) { + nav_initiator = ni; + break; + } + } + } + + if (!nav_initiator) { + // New tab. + content::OpenURLParams open_tor(onion_location, content::Referrer(), + WindowOpenDisposition::SWITCH_TO_TAB, + ui::PAGE_TRANSITION_TYPED, false); + auto* tor_web_contents = browser->OpenURL(open_tor); + if (initiator) { + TorNavigationInitiator::CreateForWebContents(tor_web_contents, initiator); + } else { + tor_web_contents->RemoveUserData(TorNavigationInitiator::UserDataKey()); + } + } else { + // Redirect navigation to an existing tab. + nav_initiator->GetWebContents().GetController().LoadURL( + onion_location, content::Referrer(), ui::PAGE_TRANSITION_TYPED, {}); + nav_initiator->GetWebContents().NotifyNavigationStateChanged( + content::INVALIDATE_TYPE_URL); + } } } // namespace @@ -36,11 +92,16 @@ OnionLocationNavigationThrottleDelegate:: void OnionLocationNavigationThrottleDelegate::OpenInTorWindow( content::WebContents* web_contents, - GURL onion_location) { + const GURL& onion_location, + bool renderer_initiated) { Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); - TorProfileManager::SwitchToTorProfile(profile, - base::BindRepeating(&OnTorProfileCreated, std::move(onion_location))); + Browser* tor_browser = TorProfileManager::SwitchToTorProfile(profile); + if (renderer_initiated) { + OpenURLInTor(tor_browser, onion_location, web_contents); + } else { + OpenURLInTor(tor_browser, onion_location, nullptr); + } } } // namespace tor diff --git a/browser/tor/onion_location_navigation_throttle_delegate.h b/browser/tor/onion_location_navigation_throttle_delegate.h index c6f4c5b5a08d..9a58e41c8307 100644 --- a/browser/tor/onion_location_navigation_throttle_delegate.h +++ b/browser/tor/onion_location_navigation_throttle_delegate.h @@ -23,7 +23,8 @@ class OnionLocationNavigationThrottleDelegate ~OnionLocationNavigationThrottleDelegate() override; void OpenInTorWindow(content::WebContents* web_contents, - GURL onion_location) override; + const GURL& onion_location, + bool renderer_initiated) override; private: OnionLocationNavigationThrottleDelegate( diff --git a/browser/tor/tor_profile_manager.cc b/browser/tor/tor_profile_manager.cc index 5aca0ac4813e..a29059f13f91 100644 --- a/browser/tor/tor_profile_manager.cc +++ b/browser/tor/tor_profile_manager.cc @@ -10,15 +10,16 @@ #include "base/feature_list.h" #include "brave/browser/tor/tor_profile_service_factory.h" -#include "brave/components/brave_shields/browser/brave_shields_util.h" #include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h" #include "brave/components/constants/pref_names.h" #include "brave/components/tor/tor_constants.h" #include "brave/components/tor/tor_profile_service.h" -#include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_window.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -42,17 +43,26 @@ TorProfileManager& TorProfileManager::GetInstance() { } // static -void TorProfileManager::SwitchToTorProfile( - Profile* original_profile, - base::OnceCallback callback) { +Browser* TorProfileManager::SwitchToTorProfile(Profile* original_profile) { Profile* tor_profile = TorProfileManager::GetInstance().GetTorProfile(original_profile); if (!tor_profile) { - return std::move(callback).Run(nullptr); + return nullptr; + } + + // Find an existing Tor Browser, making a new one if no such Browser is + // located. + Browser* browser = chrome::FindTabbedBrowser(tor_profile, false); + if (!browser && Browser::GetCreationStatusForProfile(tor_profile) == + Browser::CreationStatus::kOk) { + browser = Browser::Create(Browser::CreateParams(tor_profile, true)); + chrome::NewTab(browser); + browser->window()->Show(); + } + if (browser) { + browser->window()->Activate(); } - profiles::OpenBrowserWindowForProfile( - std::move(callback), /*always_create=*/false, - /*is_new_profile=*/false, /*unblock_extensions=*/false, tor_profile); + return browser; } // static @@ -82,8 +92,9 @@ Profile* TorProfileManager::GetTorProfile(Profile* profile) { const std::string context_id = tor_profile->UniqueId(); auto it = tor_profiles_.find(context_id); - if (it != tor_profiles_.end()) + if (it != tor_profiles_.end()) { return it->second; + } InitTorProfileUserPrefs(tor_profile); @@ -101,13 +112,15 @@ Profile* TorProfileManager::GetTorProfile(Profile* profile) { } void TorProfileManager::CloseAllTorWindows() { - for (const auto& it : tor_profiles_) + for (const auto& it : tor_profiles_) { CloseTorProfileWindows(it.second); + } } void TorProfileManager::OnBrowserRemoved(Browser* browser) { - if (!browser || !browser->profile()->IsTor()) + if (!browser || !browser->profile()->IsTor()) { return; + } if (!GetTorBrowserCount()) { tor::TorProfileService* service = diff --git a/browser/tor/tor_profile_manager.h b/browser/tor/tor_profile_manager.h index 43a41d044385..a719308b764d 100644 --- a/browser/tor/tor_profile_manager.h +++ b/browser/tor/tor_profile_manager.h @@ -9,17 +9,16 @@ #include #include "base/containers/flat_map.h" -#include "base/functional/callback.h" #include "base/no_destructor.h" -#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_observer.h" #include "chrome/browser/ui/browser_list_observer.h" +class Browser; + class TorProfileManager : public BrowserListObserver, public ProfileObserver { public: static TorProfileManager& GetInstance(); - static void SwitchToTorProfile(Profile* original_profile, - base::OnceCallback callback); + static Browser* SwitchToTorProfile(Profile* original_profile); static void CloseTorProfileWindows(Profile* tor_profile); Profile* GetTorProfile(Profile* original_profile); diff --git a/browser/tor/tor_profile_manager_browsertest.cc b/browser/tor/tor_profile_manager_browsertest.cc index 1c51e4a89022..275618b91ae0 100644 --- a/browser/tor/tor_profile_manager_browsertest.cc +++ b/browser/tor/tor_profile_manager_browsertest.cc @@ -52,27 +52,13 @@ namespace { -// An observer that returns back to test code after a new profile is -// initialized. -void OnUnblockOnProfileCreation(base::RunLoop* run_loop, - TorLauncherFactory* factory, - Browser* browser) { - run_loop->Quit(); - - ASSERT_TRUE(browser); - tor::TorProfileService* service = - TorProfileServiceFactory::GetForContext(browser->profile()); - service->SetTorLauncherFactoryForTest(factory); -} - Profile* SwitchToTorProfile(Profile* parent_profile, TorLauncherFactory* factory, size_t current_profile_num = 1) { - base::RunLoop run_loop; - TorProfileManager::SwitchToTorProfile( - parent_profile, - base::BindOnce(&OnUnblockOnProfileCreation, &run_loop, factory)); - run_loop.Run(); + Browser* tor_browser = TorProfileManager::SwitchToTorProfile(parent_profile); + tor::TorProfileService* service = + TorProfileServiceFactory::GetForContext(tor_browser->profile()); + service->SetTorLauncherFactoryForTest(factory); BrowserList* browser_list = BrowserList::GetInstance(); EXPECT_EQ(current_profile_num + 1, browser_list->size()); diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 6da0657a8561..e3548937be26 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -798,6 +798,8 @@ source_set("ui") { "views/brave_actions/brave_shields_action_view.h", "views/frame/vertical_tab_strip_region_view.cc", "views/frame/vertical_tab_strip_region_view.h", + "views/frame/vertical_tab_strip_root_view.cc", + "views/frame/vertical_tab_strip_root_view.h", "views/frame/vertical_tab_strip_widget_delegate_view.cc", "views/frame/vertical_tab_strip_widget_delegate_view.h", "views/location_bar/brave_location_bar_view.cc", diff --git a/browser/ui/browser_commands.cc b/browser/ui/browser_commands.cc index 09413607269f..da30dc49037d 100644 --- a/browser/ui/browser_commands.cc +++ b/browser/ui/browser_commands.cc @@ -91,7 +91,7 @@ void NewOffTheRecordWindowTor(Browser* browser) { return; } - TorProfileManager::SwitchToTorProfile(browser->profile(), base::DoNothing()); + TorProfileManager::SwitchToTorProfile(browser->profile()); } void NewTorConnectionForSite(Browser* browser) { diff --git a/browser/ui/omnibox/brave_omnibox_client_impl.cc b/browser/ui/omnibox/brave_omnibox_client_impl.cc index bb66dba71cda..122df8634053 100644 --- a/browser/ui/omnibox/brave_omnibox_client_impl.cc +++ b/browser/ui/omnibox/brave_omnibox_client_impl.cc @@ -115,7 +115,9 @@ void BraveOmniboxClientImpl::OnAutocompleteAccept( WeeklyStorage storage(profile_->GetPrefs(), kSearchCountPrefName); storage.AddDelta(1); RecordSearchEventP3A(storage.GetWeeklySum()); - search_engine_tracker_->RecordLocationBarQuery(); + if (search_engine_tracker_ != nullptr) { + search_engine_tracker_->RecordLocationBarQuery(); + } } ChromeOmniboxClient::OnAutocompleteAccept( destination_url, post_content, disposition, transition, match_type, diff --git a/browser/ui/toolbar/brave_vpn_menu_model.cc b/browser/ui/toolbar/brave_vpn_menu_model.cc index ef83b0d933fe..ff5de50d6b8c 100644 --- a/browser/ui/toolbar/brave_vpn_menu_model.cc +++ b/browser/ui/toolbar/brave_vpn_menu_model.cc @@ -31,15 +31,15 @@ BraveVPNMenuModel::~BraveVPNMenuModel() = default; void BraveVPNMenuModel::Build() { AddItemWithStringId(IDC_TOGGLE_BRAVE_VPN, IDS_BRAVE_VPN_MENU); AddSeparator(ui::NORMAL_SEPARATOR); - AddItemWithStringId(IDC_TOGGLE_BRAVE_VPN_TOOLBAR_BUTTON, - IsBraveVPNButtonVisible() - ? IDS_BRAVE_VPN_HIDE_VPN_BUTTON_MENU_ITEM - : IDS_BRAVE_VPN_SHOW_VPN_BUTTON_MENU_ITEM); + if (!IsBraveVPNButtonVisible()) { + AddItemWithStringId(IDC_TOGGLE_BRAVE_VPN_TOOLBAR_BUTTON, + IDS_BRAVE_VPN_SHOW_VPN_BUTTON_MENU_ITEM); + } #if BUILDFLAG(IS_WIN) - AddItemWithStringId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON, - IsTrayIconEnabled() - ? IDS_BRAVE_VPN_HIDE_VPN_TRAY_ICON_MENU_ITEM - : IDS_BRAVE_VPN_SHOW_VPN_TRAY_ICON_MENU_ITEM); + if (!IsTrayIconEnabled()) { + AddItemWithStringId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON, + IDS_BRAVE_VPN_SHOW_VPN_TRAY_ICON_MENU_ITEM); + } #endif // BUILDFLAG(IS_WIN) AddItemWithStringId(IDC_SEND_BRAVE_VPN_FEEDBACK, IDS_BRAVE_VPN_SHOW_FEEDBACK_MENU_ITEM); diff --git a/browser/ui/toolbar/brave_vpn_menu_model_unittest.cc b/browser/ui/toolbar/brave_vpn_menu_model_unittest.cc index f512504e0f74..cd137a7dd081 100644 --- a/browser/ui/toolbar/brave_vpn_menu_model_unittest.cc +++ b/browser/ui/toolbar/brave_vpn_menu_model_unittest.cc @@ -58,12 +58,9 @@ TEST_F(BraveVPNMenuModelUnitTest, TrayIconEnabled) { menu_model.Build(); EXPECT_NE(menu_model.GetItemCount(), 0u); { - auto tray_index = - menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON); - EXPECT_TRUE(tray_index); - EXPECT_EQ( - menu_model.GetLabelAt(tray_index.value()), - l10n_util::GetStringUTF16(IDS_BRAVE_VPN_HIDE_VPN_TRAY_ICON_MENU_ITEM)); + // Don't show toggle menu when tray icon is visible. + EXPECT_FALSE( + menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON)); } // Wireguard protocol disbled in the setting. @@ -73,7 +70,9 @@ TEST_F(BraveVPNMenuModelUnitTest, TrayIconEnabled) { menu_model.Build(); EXPECT_NE(menu_model.GetItemCount(), 0u); { - EXPECT_TRUE(menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON)); + // Still toggle menu is hidden. + EXPECT_FALSE( + menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TRAY_ICON)); } // Cases with Disabled value. @@ -107,12 +106,9 @@ TEST_F(BraveVPNMenuModelUnitTest, ToolbarVPNButton) { menu_model.Build(); EXPECT_NE(menu_model.GetItemCount(), 0u); { - auto toolbar_index = - menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TOOLBAR_BUTTON); - EXPECT_TRUE(toolbar_index); - EXPECT_EQ( - menu_model.GetLabelAt(toolbar_index.value()), - l10n_util::GetStringUTF16(IDS_BRAVE_VPN_HIDE_VPN_BUTTON_MENU_ITEM)); + // Don't show toggle menu when button is visible. + EXPECT_FALSE( + menu_model.GetIndexOfCommandId(IDC_TOGGLE_BRAVE_VPN_TOOLBAR_BUTTON)); } // Cases with Disabled value. diff --git a/browser/ui/views/frame/vertical_tab_strip_region_view.cc b/browser/ui/views/frame/vertical_tab_strip_region_view.cc index 1a933b6da65d..f57b891bac82 100644 --- a/browser/ui/views/frame/vertical_tab_strip_region_view.cc +++ b/browser/ui/views/frame/vertical_tab_strip_region_view.cc @@ -685,9 +685,19 @@ void VerticalTabStripRegionView::OnWidgetDestroying(views::Widget* widget) { widget_observation_.Reset(); } -bool VerticalTabStripRegionView::IsFullscreen() const { - auto* widget = GetWidget(); - return widget && widget->GetTopLevelWidget()->IsFullscreen(); +bool VerticalTabStripRegionView::IsTabFullscreen() const { + auto* exclusive_access_manager = browser_->exclusive_access_manager(); + if (!exclusive_access_manager) { + return false; + } + + auto* fullscreen_controller = + exclusive_access_manager->fullscreen_controller(); + if (!fullscreen_controller) { + return false; + } + + return fullscreen_controller->IsWindowFullscreenForTabOrPending(); } void VerticalTabStripRegionView::SetState(State state) { @@ -1080,7 +1090,7 @@ gfx::Size VerticalTabStripRegionView::GetPreferredSizeForState( return {}; } - if (IsFullscreen()) { + if (IsTabFullscreen()) { return {}; } diff --git a/browser/ui/views/frame/vertical_tab_strip_region_view.h b/browser/ui/views/frame/vertical_tab_strip_region_view.h index 79739c83d114..8240b68cbd45 100644 --- a/browser/ui/views/frame/vertical_tab_strip_region_view.h +++ b/browser/ui/views/frame/vertical_tab_strip_region_view.h @@ -19,7 +19,7 @@ namespace views { class ResizeArea; -} // namespace views +} class BraveNewTabButton; class BrowserView; @@ -116,7 +116,7 @@ class VerticalTabStripRegionView : public views::View, FRIEND_TEST_ALL_PREFIXES(VerticalTabStripBrowserTest, OriginalTabSearchButton); - bool IsFullscreen() const; + bool IsTabFullscreen() const; void SetState(State state); diff --git a/browser/ui/views/frame/vertical_tab_strip_root_view.cc b/browser/ui/views/frame/vertical_tab_strip_root_view.cc new file mode 100644 index 000000000000..80adb9eb83e9 --- /dev/null +++ b/browser/ui/views/frame/vertical_tab_strip_root_view.cc @@ -0,0 +1,71 @@ +/* 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/frame/vertical_tab_strip_root_view.h" + +#include "chrome/browser/ui/views/frame/browser_root_view.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/view_utils.h" + +VerticalTabStripRootView::VerticalTabStripRootView(BrowserView* browser_view, + views::Widget* widget) + : BrowserRootView(browser_view, widget) {} + +VerticalTabStripRootView::~VerticalTabStripRootView() = default; + +bool VerticalTabStripRootView::OnMousePressed(const ui::MouseEvent& event) { +#if defined(USE_AURA) + const bool result = RootView::OnMousePressed(event); + auto* focus_manager = GetFocusManager(); + DCHECK(focus_manager); + + // When vertical tab strip area is clicked, shortcut handling process + // could get broken on Windows. There are 2 paths where shortcut is handled. + // One is BrowserView::AcceleratorPressed(), and the other is + // BrowserView::PreHandleKeyboardEvent(). When web view has focus, the + // first doesn't deal with it and the latter is responsible for the + // shortcuts. when users click the vertical tab strip area with web view + // focused, both path don't handle it. This is because focused view state of + // views/ framework and focused native window state of Aura is out of sync. + // So as a workaround, resets the focused view state so that shortcuts can + // be handled properly. This shouldn't change the actually focused view, and + // is just reset the status. + // https://github.com/brave/brave-browser/issues/28090 + // https://github.com/brave/brave-browser/issues/27812 + if (auto* focused_view = focus_manager->GetFocusedView(); + focused_view && views::IsViewClass(focused_view)) { + focus_manager->ClearFocus(); + focus_manager->RestoreFocusedView(); + } + + return result; +#else + // On Mac, the parent widget doesn't get activated in this case. Then + // shortcut handling could malfunction. So activate it. + // https://github.com/brave/brave-browser/issues/29993 + auto* widget = GetWidget(); + DCHECK(widget); + widget = widget->GetTopLevelWidget(); + widget->Activate(); + + return RootView::OnMousePressed(event); +#endif +} + +bool VerticalTabStripRootView::OnMouseWheel(const ui::MouseWheelEvent& event) { + return views::internal::RootView::OnMouseWheel(event); +} + +void VerticalTabStripRootView::OnMouseExited(const ui::MouseEvent& event) { + views::internal::RootView::OnMouseExited(event); +} + +void VerticalTabStripRootView::PaintChildren( + const views::PaintInfo& paint_info) { + views::internal::RootView::PaintChildren(paint_info); +} + +BEGIN_METADATA(VerticalTabStripRootView, BrowserRootView) +END_METADATA diff --git a/browser/ui/views/frame/vertical_tab_strip_root_view.h b/browser/ui/views/frame/vertical_tab_strip_root_view.h new file mode 100644 index 000000000000..eb2b1b76153b --- /dev/null +++ b/browser/ui/views/frame/vertical_tab_strip_root_view.h @@ -0,0 +1,32 @@ +/* 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_FRAME_VERTICAL_TAB_STRIP_ROOT_VIEW_H_ +#define BRAVE_BROWSER_UI_VIEWS_FRAME_VERTICAL_TAB_STRIP_ROOT_VIEW_H_ + +#include "chrome/browser/ui/views/frame/browser_root_view.h" + +// `VerticalTabStripRootView` extends `BrowserRootView` to support link +// drag-and-drop feature. In order to avoid features other than that, replaces +// mouse event callbacks and bypass the `BrowserRootView`'s implementation. e.g. +// OnMouseWheel() +class VerticalTabStripRootView : public BrowserRootView { + public: + METADATA_HEADER(VerticalTabStripRootView); + + VerticalTabStripRootView(BrowserView* browser_view, views::Widget* widget); + + ~VerticalTabStripRootView() override; + + // BrowserRootView: + bool OnMousePressed(const ui::MouseEvent& event) override; + bool OnMouseWheel(const ui::MouseWheelEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + + protected: + void PaintChildren(const views::PaintInfo& paint_info) override; +}; + +#endif // BRAVE_BROWSER_UI_VIEWS_FRAME_VERTICAL_TAB_STRIP_ROOT_VIEW_H_ diff --git a/browser/ui/views/frame/vertical_tab_strip_root_view_browsertest.cc b/browser/ui/views/frame/vertical_tab_strip_root_view_browsertest.cc new file mode 100644 index 000000000000..b6137d62e7cf --- /dev/null +++ b/browser/ui/views/frame/vertical_tab_strip_root_view_browsertest.cc @@ -0,0 +1,158 @@ +/* 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/browser_commands.h" +#include "brave/browser/ui/views/frame/brave_browser_view.h" +#include "brave/browser/ui/views/frame/vertical_tab_strip_region_view.h" +#include "brave/browser/ui/views/frame/vertical_tab_strip_root_view.h" +#include "brave/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.h" +#include "brave/browser/ui/views/tabs/vertical_tab_utils.h" +#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/test/browser_test.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/drop_target_event.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/compositor/layer_tree_owner.h" + +class VerticalTabStripRootViewBrowserTest : public InProcessBrowserTest { + public: + VerticalTabStripRootViewBrowserTest() = default; + VerticalTabStripRootViewBrowserTest( + const VerticalTabStripRootViewBrowserTest&) = delete; + VerticalTabStripRootViewBrowserTest& operator=( + const VerticalTabStripRootViewBrowserTest&) = delete; + ~VerticalTabStripRootViewBrowserTest() override = default; + + Tab* GetTabAt(int index) { return tab_strip()->tab_at(index); } + + BrowserView* browser_view() { + return BrowserView::GetBrowserViewForBrowser(browser()); + } + + TabStrip* tab_strip() { return browser_view()->tabstrip(); } + + VerticalTabStripRootView* vtab_strip_root_view() { + if (vtab_tab_strip_widget_delegate_view()) { + return static_cast( + vtab_tab_strip_widget_delegate_view()->GetWidget()->GetRootView()); + } + return nullptr; + } + + BrowserNonClientFrameView* browser_non_client_frame_view() { + return browser_view()->frame()->GetFrameView(); + } + + void ToggleVerticalTabStrip() { + brave::ToggleVerticalTabStrip(browser()); + browser_non_client_frame_view()->Layout(); + } + + VerticalTabStripWidgetDelegateView* vtab_tab_strip_widget_delegate_view() { + auto* browser_view = static_cast( + BrowserView::GetBrowserViewForBrowser(browser())); + if (browser_view) { + return browser_view->vertical_tab_strip_widget_delegate_view(); + } + return nullptr; + } +}; + +#if BUILDFLAG(IS_WIN) +// This test is flaky on Windows. +#define MAYBE_DragAfterCurrentTab DISABLED_DragAfterCurrentTab +#else +#define MAYBE_DragAfterCurrentTab DragAfterCurrentTab +#endif + +IN_PROC_BROWSER_TEST_F(VerticalTabStripRootViewBrowserTest, + MAYBE_DragAfterCurrentTab) { + ToggleVerticalTabStrip(); + + ASSERT_TRUE(tabs::utils::ShouldShowVerticalTabs(browser())); + + auto* tab_strip_model = browser()->tab_strip_model(); + EXPECT_EQ(tab_strip_model->count(), 1); + + ui::OSExchangeData data; + GURL url("https://brave.com/"); + data.SetURL(url, std::u16string()); + + Tab* current_tab = GetTabAt(0); + gfx::Point location; + views::View::ConvertPointToWidget(current_tab, &location); + + // To drag after current tab. + location.Offset(0, current_tab->height()); + ui::DropTargetEvent event(data, gfx::PointF(location), gfx::PointF(location), + ui::DragDropTypes::DRAG_COPY); + + VerticalTabStripRootView* root_view = vtab_strip_root_view(); + + EXPECT_NE(root_view, nullptr); + root_view->OnDragUpdated(event); + auto drop_cb = root_view->GetDropCallback(event); + ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; + std::move(drop_cb).Run(event, output_drag_op, + /*drag_image_layer_owner=*/nullptr); + + EXPECT_EQ(output_drag_op, ui::mojom::DragOperation::kCopy); + EXPECT_EQ(tab_strip_model->count(), 2); + EXPECT_TRUE(browser() + ->tab_strip_model() + ->GetWebContentsAt(1) + ->GetURL() + .EqualsIgnoringRef(url)); +} + +#if BUILDFLAG(IS_WIN) +// This test is flaky on Windows. +#define MAYBE_DragOnCurrentTab DISABLED_DragOnCurrentTab +#else +#define MAYBE_DragOnCurrentTab DragOnCurrentTab +#endif +IN_PROC_BROWSER_TEST_F(VerticalTabStripRootViewBrowserTest, + MAYBE_DragOnCurrentTab) { + ToggleVerticalTabStrip(); + + ASSERT_TRUE(tabs::utils::ShouldShowVerticalTabs(browser())); + + auto* tab_strip_model = browser()->tab_strip_model(); + EXPECT_EQ(tab_strip_model->count(), 1); + + ui::OSExchangeData data; + GURL url("https://brave.com/"); + data.SetURL(url, std::u16string()); + + Tab* current_tab = GetTabAt(0); + gfx::Point location; + views::View::ConvertPointToWidget(current_tab, &location); + + // To drag on the same tab. + location.Offset(0, current_tab->height() / 2); + ui::DropTargetEvent event(data, gfx::PointF(location), gfx::PointF(location), + ui::DragDropTypes::DRAG_COPY); + + VerticalTabStripRootView* root_view = vtab_strip_root_view(); + + EXPECT_NE(root_view, nullptr); + root_view->OnDragUpdated(event); + auto drop_cb = root_view->GetDropCallback(event); + ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; + std::move(drop_cb).Run(event, output_drag_op, + /*drag_image_layer_owner=*/nullptr); + + EXPECT_EQ(output_drag_op, ui::mojom::DragOperation::kCopy); + EXPECT_EQ(tab_strip_model->count(), 1); + EXPECT_TRUE(browser() + ->tab_strip_model() + ->GetWebContentsAt(0) + ->GetURL() + .EqualsIgnoringRef(url)); +} diff --git a/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.cc b/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.cc index 2fa7cc6599c1..33ad2f017143 100644 --- a/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.cc +++ b/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.cc @@ -10,10 +10,12 @@ #include "base/check.h" #include "brave/browser/ui/views/frame/brave_browser_view.h" #include "brave/browser/ui/views/frame/vertical_tab_strip_region_view.h" +#include "brave/browser/ui/views/frame/vertical_tab_strip_root_view.h" #include "brave/browser/ui/views/tabs/vertical_tab_utils.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" +#include "chrome/browser/ui/views/frame/browser_root_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/theme_copying_widget.h" #include "chrome/common/pref_names.h" @@ -27,66 +29,19 @@ namespace { -class VerticalTabStripRootView : public views::internal::RootView { - public: - METADATA_HEADER(VerticalTabStripRootView); - - using RootView::RootView; - ~VerticalTabStripRootView() override = default; - - // views::internal::RootView: - bool OnMousePressed(const ui::MouseEvent& event) override { -#if defined(USE_AURA) - const bool result = RootView::OnMousePressed(event); - auto* focus_manager = GetFocusManager(); - DCHECK(focus_manager); - - // When vertical tab strip area is clicked, shortcut handling process - // could get broken on Windows. There are 2 paths where shortcut is handled. - // One is BrowserView::AcceleratorPressed(), and the other is - // BrowserView::PreHandleKeyboardEvent(). When web view has focus, the - // first doesn't deal with it and the latter is responsible for the - // shortcuts. when users click the vertical tab strip area with web view - // focused, both path don't handle it. This is because focused view state of - // views/ framework and focused native window state of Aura is out of sync. - // So as a workaround, resets the focused view state so that shortcuts can - // be handled properly. This shouldn't change the actually focused view, and - // is just reset the status. - // https://github.com/brave/brave-browser/issues/28090 - // https://github.com/brave/brave-browser/issues/27812 - if (auto* focused_view = focus_manager->GetFocusedView(); - focused_view && views::IsViewClass(focused_view)) { - focus_manager->ClearFocus(); - focus_manager->RestoreFocusedView(); - } - - return result; -#else - // On Mac, the parent widget doesn't get activated in this case. Then - // shortcut handling could malfunction. So activate it. - // https://github.com/brave/brave-browser/issues/29993 - auto* widget = GetWidget(); - DCHECK(widget); - widget = widget->GetTopLevelWidget(); - widget->Activate(); - - return RootView::OnMousePressed(event); -#endif - } -}; - -BEGIN_METADATA(VerticalTabStripRootView, views::internal::RootView) -END_METADATA - class VerticalTabStripWidget : public ThemeCopyingWidget { public: - using ThemeCopyingWidget::ThemeCopyingWidget; + VerticalTabStripWidget(BrowserView* browser_view, views::Widget* widget) + : ThemeCopyingWidget(widget), browser_view_(browser_view) {} ~VerticalTabStripWidget() override = default; // ThemeCopyingWidget: views::internal::RootView* CreateRootView() override { - return new VerticalTabStripRootView(this); + return new VerticalTabStripRootView(browser_view_, this); } + + private: + raw_ptr browser_view_; }; } // namespace @@ -108,8 +63,8 @@ VerticalTabStripWidgetDelegateView* VerticalTabStripWidgetDelegateView::Create( // not get focus. params.activatable = views::Widget::InitParams::Activatable::kNo; - auto widget = - std::make_unique(browser_view->GetWidget()); + auto widget = std::make_unique( + browser_view, browser_view->GetWidget()); widget->Init(std::move(params)); #if defined(USE_AURA) widget->GetNativeView()->SetProperty(views::kHostViewKey, host_view); @@ -160,8 +115,9 @@ void VerticalTabStripWidgetDelegateView::AddedToWidget() { void VerticalTabStripWidgetDelegateView::ChildPreferredSizeChanged( views::View* child) { - if (!host_) + if (!host_) { return; + } // Setting minimum size for |host_| so that we can overlay vertical tabs over // the web view. @@ -179,13 +135,15 @@ void VerticalTabStripWidgetDelegateView::OnViewVisibilityChanged( views::View* observed_view, views::View* starting_view) { auto* widget = GetWidget(); - if (!widget || widget->IsVisible() == observed_view->GetVisible()) + if (!widget || widget->IsVisible() == observed_view->GetVisible()) { return; + } - if (observed_view->GetVisible()) + if (observed_view->GetVisible()) { widget->Show(); - else + } else { widget->Hide(); + } } void VerticalTabStripWidgetDelegateView::OnViewBoundsChanged( @@ -243,12 +201,14 @@ void VerticalTabStripWidgetDelegateView::OnWidgetBoundsChanged( } void VerticalTabStripWidgetDelegateView::UpdateWidgetBounds() { - if (!host_) + if (!host_) { return; + } auto* widget = GetWidget(); - if (!widget) + if (!widget) { return; + } // Convert coordinate system based on Browser's widget. gfx::Rect widget_bounds = host_->ConvertRectToWidget(host_->GetLocalBounds()); @@ -274,8 +234,9 @@ void VerticalTabStripWidgetDelegateView::UpdateWidgetBounds() { widget->Show(); } - if (need_to_call_layout) + if (need_to_call_layout) { Layout(); + } #if BUILDFLAG(IS_MAC) UpdateClip(); diff --git a/browser/ui/views/location_bar/onion_location_view.cc b/browser/ui/views/location_bar/onion_location_view.cc index 96de08f9bf3c..5fd5c633c12f 100644 --- a/browser/ui/views/location_bar/onion_location_view.cc +++ b/browser/ui/views/location_bar/onion_location_view.cc @@ -15,6 +15,7 @@ #include "brave/components/l10n/common/localization_util.h" #include "brave/components/tor/onion_location_tab_helper.h" #include "brave/grit/brave_generated_resources.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_window.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -45,15 +46,6 @@ constexpr SkColor kIconColor = SkColorSetRGB(0xf0, 0xf2, 0xff); constexpr SkColor kTextColor = SK_ColorWHITE; constexpr int kIconSize = 12; -void OnTorProfileCreated(GURL onion_location, Browser* browser) { - if (!browser) - return; - content::OpenURLParams open_tor(onion_location, content::Referrer(), - WindowOpenDisposition::SWITCH_TO_TAB, - ui::PAGE_TRANSITION_TYPED, false); - browser->OpenURL(open_tor); -} - // Sets the focus and ink drop highlight path to match the background // along with it's corner radius. class HighlightPathGenerator : public views::HighlightPathGenerator { @@ -129,9 +121,13 @@ class OnionLocationButtonView : public views::LabelButton { } void ButtonPressed() { - TorProfileManager::SwitchToTorProfile( - profile_, - base::BindRepeating(&OnTorProfileCreated, GURL(onion_location_))); + if (Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(profile_)) { + content::OpenURLParams open_tor(onion_location_, content::Referrer(), + WindowOpenDisposition::SWITCH_TO_TAB, + ui::PAGE_TRANSITION_TYPED, false); + tor_browser->OpenURL(open_tor); + } } GURL onion_location_; diff --git a/browser/ui/views/profiles/brave_incognito_menu_view.cc b/browser/ui/views/profiles/brave_incognito_menu_view.cc index fe1da104d6ca..a4fee0b92f71 100644 --- a/browser/ui/views/profiles/brave_incognito_menu_view.cc +++ b/browser/ui/views/profiles/brave_incognito_menu_view.cc @@ -95,8 +95,7 @@ void BraveIncognitoMenuView::AddTorButton() { } void BraveIncognitoMenuView::OnTorProfileButtonClicked() { - TorProfileManager::SwitchToTorProfile(browser()->profile(), - base::DoNothing()); + TorProfileManager::SwitchToTorProfile(browser()->profile()); } std::u16string BraveIncognitoMenuView::GetAccessibleWindowTitle() const { diff --git a/browser/ui/views/tabs/brave_compound_tab_container.cc b/browser/ui/views/tabs/brave_compound_tab_container.cc index 5b6690789508..4dc735227daf 100644 --- a/browser/ui/views/tabs/brave_compound_tab_container.cc +++ b/browser/ui/views/tabs/brave_compound_tab_container.cc @@ -191,8 +191,9 @@ void BraveCompoundTabContainer::TransferTabBetweenContainers( layout_dirty = true; } - if (layout_dirty) + if (layout_dirty) { Layout(); + } } void BraveCompoundTabContainer::Layout() { @@ -299,6 +300,38 @@ int BraveCompoundTabContainer::GetUnpinnedContainerIdealLeadingX() const { return 0; } +BrowserRootView::DropIndex BraveCompoundTabContainer::GetDropIndex( + const ui::DropTargetEvent& event) { + if (!ShouldShowVerticalTabs()) { + return CompoundTabContainer::GetDropIndex(event); + } + + TabContainer* sub_drop_target = GetTabContainerAt(event.location()); + CHECK(sub_drop_target); + CHECK(sub_drop_target->GetDropTarget( + ConvertPointToTarget(this, sub_drop_target, event.location()))); + + // Convert to `sub_drop_target`'s local coordinate space. + const gfx::Point loc_in_sub_target = ConvertPointToTarget( + this, sub_drop_target->GetViewForDrop(), event.location()); + const ui::DropTargetEvent adjusted_event = ui::DropTargetEvent( + event.data(), gfx::PointF(loc_in_sub_target), + gfx::PointF(loc_in_sub_target), event.source_operations()); + + if (sub_drop_target == base::to_address(pinned_tab_container_)) { + // Pinned tab container shares an index and coordinate space, so no + // adjustments needed. + return sub_drop_target->GetDropIndex(adjusted_event); + } else { + // For the unpinned container, we need to transform the output to the + // correct index space. + const BrowserRootView::DropIndex sub_target_index = + sub_drop_target->GetDropIndex(adjusted_event); + return {sub_target_index.value + NumPinnedTabs(), + sub_target_index.drop_before, sub_target_index.drop_in_group}; + } +} + BrowserRootView::DropTarget* BraveCompoundTabContainer::GetDropTarget( gfx::Point loc_in_local_coords) { if (!ShouldShowVerticalTabs()) { @@ -312,7 +345,11 @@ BrowserRootView::DropTarget* BraveCompoundTabContainer::GetDropTarget( return nullptr; } - return GetTabContainerAt(loc_in_local_coords); + if (GetTabContainerAt(loc_in_local_coords)) { + return this; + } + + return nullptr; } void BraveCompoundTabContainer::OnThemeChanged() { diff --git a/browser/ui/views/tabs/brave_compound_tab_container.h b/browser/ui/views/tabs/brave_compound_tab_container.h index 921b46b651de..b23b3633c079 100644 --- a/browser/ui/views/tabs/brave_compound_tab_container.h +++ b/browser/ui/views/tabs/brave_compound_tab_container.h @@ -48,14 +48,18 @@ class BraveCompoundTabContainer : public CompoundTabContainer { gfx::Point point_in_local_coords) const override; gfx::Rect ConvertUnpinnedContainerIdealBoundsToLocal( gfx::Rect ideal_bounds) const override; - BrowserRootView::DropTarget* GetDropTarget( - gfx::Point loc_in_local_coords) override; void OnThemeChanged() override; void PaintChildren(const views::PaintInfo& info) override; void ChildPreferredSizeChanged(views::View* child) override; void SetActiveTab(absl::optional prev_active_index, absl::optional new_active_index) override; + // BrowserRootView::DropTarget + BrowserRootView::DropTarget* GetDropTarget( + gfx::Point loc_in_local_coords) override; + BrowserRootView::DropIndex GetDropIndex( + const ui::DropTargetEvent& event) override; + private: bool ShouldShowVerticalTabs() const; diff --git a/browser/ui/views/tabs/brave_tab_container.cc b/browser/ui/views/tabs/brave_tab_container.cc index 1abe01de79b2..9ad4b399f548 100644 --- a/browser/ui/views/tabs/brave_tab_container.cc +++ b/browser/ui/views/tabs/brave_tab_container.cc @@ -6,10 +6,15 @@ #include "brave/browser/ui/views/tabs/brave_tab_container.h" #include +#include #include #include "base/check_is_test.h" +#include "base/containers/flat_map.h" #include "brave/browser/ui/tabs/brave_tab_prefs.h" +#include "brave/browser/ui/tabs/features.h" +#include "brave/browser/ui/views/frame/brave_browser_view.h" +#include "brave/browser/ui/views/frame/vertical_tab_strip_widget_delegate_view.h" #include "brave/browser/ui/views/tabs/brave_tab_group_header.h" #include "brave/browser/ui/views/tabs/brave_tab_strip.h" #include "brave/browser/ui/views/tabs/vertical_tab_utils.h" @@ -19,8 +24,12 @@ #include "chrome/browser/ui/tabs/tab_style.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/tabs/tab_drag_controller.h" +#include "chrome/grit/theme_resources.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/display/screen.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/skbitmap_operations.h" #include "ui/views/view_utils.h" BraveTabContainer::BraveTabContainer( @@ -35,7 +44,8 @@ BraveTabContainer::BraveTabContainer( tab_slot_controller, scroll_contents_view), drag_context_(static_cast(drag_context)), - tab_style_(TabStyle::Get()) { + tab_style_(TabStyle::Get()), + controller_(controller) { auto* browser = tab_slot_controller_->GetBrowser(); if (!browser) { CHECK_IS_TEST(); @@ -84,8 +94,9 @@ base::OnceClosure BraveTabContainer::LockLayout() { gfx::Size BraveTabContainer::CalculatePreferredSize() const { // Note that we check this before checking currently we're in vertical tab // strip mode. We might be in the middle of changing orientation. - if (layout_locked_) + if (layout_locked_) { return {}; + } if (!tabs::utils::ShouldShowVerticalTabs( tab_slot_controller_->GetBrowser())) { @@ -105,8 +116,9 @@ gfx::Size BraveTabContainer::CalculatePreferredSize() const { // When closing trailing tabs, the last tab's current bottom could be // greater than ideal bounds bottom. Note that closing tabs are not in // tabs_view_model_ so we have to check again here. - for (auto* tab : closing_tabs_) + for (auto* tab : closing_tabs_) { height = std::max(height, tab->bounds().bottom()); + } } const auto slots_bounds = layout_helper_->CalculateIdealBounds( @@ -185,8 +197,9 @@ bool BraveTabContainer::ShouldTabBeVisible(const Tab* tab) const { void BraveTabContainer::StartInsertTabAnimation(int model_index) { // Note that we check this before checking currently we're in vertical tab // strip mode. We might be in the middle of changing orientation. - if (layout_locked_) + if (layout_locked_) { return; + } if (!tabs::utils::ShouldShowVerticalTabs( tab_slot_controller_->GetBrowser())) { @@ -229,8 +242,9 @@ void BraveTabContainer::OnTabCloseAnimationCompleted(Tab* tab) { TabContainerImpl::OnTabCloseAnimationCompleted(tab); // we might have to hide this container entirely - if (!tabs_view_model_.view_size()) + if (!tabs_view_model_.view_size()) { PreferredSizeChanged(); + } } void BraveTabContainer::UpdateLayoutOrientation() { @@ -252,8 +266,9 @@ void BraveTabContainer::OnUnlockLayout() { void BraveTabContainer::CompleteAnimationAndLayout() { // Note that we check this before checking currently we're in vertical tab // strip mode. We might be in the middle of changing orientation. - if (layout_locked_) + if (layout_locked_) { return; + } TabContainerImpl::CompleteAnimationAndLayout(); @@ -293,5 +308,294 @@ void BraveTabContainer::PaintChildren(const views::PaintInfo& paint_info) { } } +BrowserRootView::DropIndex BraveTabContainer::GetDropIndex( + const ui::DropTargetEvent& event) { + if (!tabs::utils::ShouldShowVerticalTabs( + tab_slot_controller_->GetBrowser())) { + return TabContainerImpl::GetDropIndex(event); + } + + // Force animations to stop, otherwise it makes the index calculation tricky. + CompleteAnimationAndLayout(); + + const int x = GetMirroredXInView(event.x()); + const int y = event.y(); + + std::vector views = layout_helper_->GetTabSlotViews(); + + // Loop until we find a tab or group header that intersects |event|'s + // location. + for (TabSlotView* view : views) { + const int max_y = view->y() + view->height(); + const int max_x = view->x() + view->width(); + if (y >= max_y) { + continue; + } + + if (view->GetTabSlotViewType() == TabSlotView::ViewType::kTab) { + Tab* const tab = static_cast(view); + + // Closing tabs should be skipped. + if (tab->closing()) { + continue; + } + + const int model_index = GetModelIndexOf(tab).value(); + + const bool is_tab_pinned = tab->data().pinned; + + // When dropping text or links onto pinned tabs, we need to take the + // x-axis position into consideration. + if (is_tab_pinned && x >= max_x) { + continue; + } + + const bool first_in_group = + tab->group().has_value() && + model_index == controller_->GetFirstTabInGroup(tab->group().value()); + + const int hot_height = tab->height() / 4; + const int hot_width = tab->width() / 4; + + if (is_tab_pinned ? x >= (max_x - hot_width) + : y >= (max_y - hot_height)) { + return {model_index + 1, true /* drop_before */, + false /* drop_in_group */}; + } + + if (is_tab_pinned ? x < tab->x() + hot_width + : y < tab->y() + hot_height) { + return {model_index, true /* drop_before */, first_in_group}; + } + + return {model_index, false /* drop_before */, false /* drop_in_group */}; + } else { + TabGroupHeader* const group_header = static_cast(view); + const int first_tab_index = + controller_->GetFirstTabInGroup(group_header->group().value()) + .value(); + return {first_tab_index, true /* drop_before */, + y >= max_y - group_header->height() / 2 /* drop_in_group */}; + } + } + + // The drop isn't over a tab, add it to the end. + return {GetTabCount(), true, false}; +} + +// BraveTabContainer::DropArrow: +// ---------------------------------------------------------- +BraveTabContainer::DropArrow::DropArrow(const BrowserRootView::DropIndex& index, + Position position, + bool beneath, + views::Widget* context) + : index_(index), position_(position), beneath_(beneath) { + arrow_window_ = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.z_order = ui::ZOrderLevel::kFloatingUIElement; + params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; + params.accept_events = false; + + // All drop images has the same size. + const gfx::ImageSkia* drop_image = + GetDropArrowImage(Position::Horizontal, false); + params.bounds = gfx::Rect(drop_image->width(), drop_image->height()); + + params.context = context->GetNativeWindow(); + arrow_window_->Init(std::move(params)); + arrow_view_ = + arrow_window_->SetContentsView(std::make_unique()); + arrow_view_->SetImage(GetDropArrowImage(position_, beneath_)); + scoped_observation_.Observe(arrow_window_.get()); + + arrow_window_->Show(); +} + +BraveTabContainer::DropArrow::~DropArrow() { + // Close eventually deletes the window, which deletes arrow_view too. + if (arrow_window_) { + arrow_window_->Close(); + } +} + +void BraveTabContainer::DropArrow::SetBeneath(bool beneath) { + if (beneath_ == beneath) { + return; + } + + beneath_ = beneath; + arrow_view_->SetImage(GetDropArrowImage(position_, beneath)); +} + +void BraveTabContainer::DropArrow::SetWindowBounds(const gfx::Rect& bounds) { + arrow_window_->SetBounds(bounds); +} + +void BraveTabContainer::DropArrow::OnWidgetDestroying(views::Widget* widget) { + DCHECK(scoped_observation_.IsObservingSource(arrow_window_.get())); + scoped_observation_.Reset(); + arrow_window_ = nullptr; +} + +void BraveTabContainer::HandleDragUpdate( + const absl::optional& index) { + if (!tabs::utils::ShouldShowVerticalTabs( + tab_slot_controller_->GetBrowser())) { + TabContainerImpl::HandleDragUpdate(index); + return; + } + SetDropArrow(index); +} + +void BraveTabContainer::HandleDragExited() { + if (!tabs::utils::ShouldShowVerticalTabs( + tab_slot_controller_->GetBrowser())) { + TabContainerImpl::HandleDragExited(); + return; + } + SetDropArrow({}); +} + +gfx::Rect BraveTabContainer::GetDropBounds(int drop_index, + bool drop_before, + bool drop_in_group, + bool* is_beneath) { + DCHECK_NE(drop_index, -1); + + // The center is determined along the x-axis if it's pinned, or along the + // y-axis if not. + int center = -1; + + if (GetTabCount() == 0) { + // If the tabstrip is empty, it doesn't matter where the drop arrow goes. + // The tabstrip can only be transiently empty, e.g. during shutdown. + return gfx::Rect(); + } + + Tab* tab = GetTabAtModelIndex(std::min(drop_index, GetTabCount() - 1)); + + const bool is_tab_pinned = tab->data().pinned; + + const bool first_in_group = + drop_index < GetTabCount() && tab->group().has_value() && + GetModelIndexOf(tab) == + controller_->GetFirstTabInGroup(tab->group().value()); + + if (!drop_before || !first_in_group || drop_in_group) { + // Dropping between tabs, or between a group header and the group's first + // tab. + center = is_tab_pinned ? tab->x() : tab->y(); + const int length = is_tab_pinned ? tab->width() : tab->height(); + if (drop_index < GetTabCount()) { + center += drop_before ? -(tabs::kVerticalTabsSpacing / 2) : (length / 2); + } else { + center += length + (tabs::kVerticalTabsSpacing / 2); + } + } else { + // Dropping before a group header. + TabGroupHeader* const header = group_views_[tab->group().value()]->header(); + // Since there is no tab group in pinned tabs, there is no need to consider + // the x-axis. + center = header->y() + tabs::kVerticalTabsSpacing / 2; + } + + // Since all drop indicator images are the same size, we will use the right + // arrow image to determine the height and width. + const gfx::ImageSkia* drop_image = GetDropArrowImage( + BraveTabContainer::DropArrow::Position::Horizontal, false); + + // Determine the screen bounds. + gfx::Point drop_loc(is_tab_pinned ? center - drop_image->width() / 2 : 0, + is_tab_pinned ? tab->y() - drop_image->height() + : center - drop_image->height() / 2); + ConvertPointToScreen(this, &drop_loc); + gfx::Rect drop_bounds(drop_loc.x(), drop_loc.y(), drop_image->width(), + drop_image->height()); + + // If the rect doesn't fit on the monitor, push the arrow to the bottom. + display::Screen* screen = display::Screen::GetScreen(); + display::Display display = screen->GetDisplayMatching(drop_bounds); + *is_beneath = !display.bounds().Contains(drop_bounds); + + if (*is_beneath) { + drop_bounds.Offset( + is_tab_pinned ? 0 : drop_bounds.width() + tab->width(), + is_tab_pinned ? drop_bounds.height() + tab->height() : 0); + } + + return drop_bounds; +} + +gfx::ImageSkia* BraveTabContainer::GetDropArrowImage( + BraveTabContainer::DropArrow::Position pos, + bool beneath) { + using Position = BraveTabContainer::DropArrow::Position; + using RotationAmount = SkBitmapOperations::RotationAmount; + static base::NoDestructor< + base::flat_map, gfx::ImageSkia>> + drop_images([] { + gfx::ImageSkia* top_arrow_image = + ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_TAB_DROP_UP); + + base::flat_map, gfx::ImageSkia> + position_to_images; + + position_to_images.emplace(std::make_pair(Position::Vertical, true), + *top_arrow_image); + position_to_images.emplace( + std::make_pair(Position::Horizontal, false), + gfx::ImageSkiaOperations::CreateRotatedImage( + *top_arrow_image, RotationAmount::ROTATION_90_CW)); + position_to_images.emplace( + std::make_pair(Position::Vertical, false), + gfx::ImageSkiaOperations::CreateRotatedImage( + *top_arrow_image, RotationAmount::ROTATION_180_CW)); + position_to_images.emplace( + std::make_pair(Position::Horizontal, true), + gfx::ImageSkiaOperations::CreateRotatedImage( + *top_arrow_image, RotationAmount::ROTATION_270_CW)); + return position_to_images; + }()); + return &drop_images->find(std::make_pair(pos, beneath))->second; +} + +void BraveTabContainer::SetDropArrow( + const absl::optional& index) { + if (!index) { + controller_->OnDropIndexUpdate(absl::nullopt, false); + drop_arrow_.reset(); + return; + } + + // Let the controller know of the index update. + controller_->OnDropIndexUpdate(index->value, index->drop_before); + + if (drop_arrow_ && (index == drop_arrow_->index())) { + return; + } + + bool is_beneath = false; + gfx::Rect drop_bounds = GetDropBounds(index->value, index->drop_before, + index->drop_in_group, &is_beneath); + + if (!drop_arrow_) { + DropArrow::Position position = DropArrow::Position::Vertical; + if (GetTabCount() > 0) { + Tab* tab = GetTabAtModelIndex(0); + position = tab->data().pinned ? DropArrow::Position::Vertical + : DropArrow::Position::Horizontal; + } + drop_arrow_ = + std::make_unique(*index, position, is_beneath, GetWidget()); + } else { + drop_arrow_->set_index(*index); + drop_arrow_->SetBeneath(is_beneath); + } + + // Reposition the window. + drop_arrow_->SetWindowBounds(drop_bounds); +} + BEGIN_METADATA(BraveTabContainer, TabContainerImpl) END_METADATA diff --git a/browser/ui/views/tabs/brave_tab_container.h b/browser/ui/views/tabs/brave_tab_container.h index eca56a075128..1c4b18e31d98 100644 --- a/browser/ui/views/tabs/brave_tab_container.h +++ b/browser/ui/views/tabs/brave_tab_container.h @@ -6,6 +6,8 @@ #ifndef BRAVE_BROWSER_UI_VIEWS_TABS_BRAVE_TAB_CONTAINER_H_ #define BRAVE_BROWSER_UI_VIEWS_TABS_BRAVE_TAB_CONTAINER_H_ +#include + #include "chrome/browser/ui/views/tabs/tab_container_impl.h" #include "chrome/browser/ui/tabs/tab_style.h" @@ -44,11 +46,68 @@ class BraveTabContainer : public TabContainerImpl { void OnPaintBackground(gfx::Canvas* canvas) override; void PaintChildren(const views::PaintInfo& paint_info) override; + // BrowserRootView::DropTarget + BrowserRootView::DropIndex GetDropIndex( + const ui::DropTargetEvent& event) override; + void HandleDragUpdate( + const absl::optional& index) override; + void HandleDragExited() override; + private: + class DropArrow : public views::WidgetObserver { + public: + enum class Position { Vertical, Horizontal }; + + DropArrow(const BrowserRootView::DropIndex& index, + Position position, + bool beneath, + views::Widget* context); + DropArrow(const DropArrow&) = delete; + DropArrow& operator=(const DropArrow&) = delete; + ~DropArrow() override; + + void set_index(const BrowserRootView::DropIndex& index) { index_ = index; } + BrowserRootView::DropIndex index() const { return index_; } + + void SetBeneath(bool beneath); + bool beneath() const { return beneath_; } + + void SetWindowBounds(const gfx::Rect& bounds); + + // views::WidgetObserver: + void OnWidgetDestroying(views::Widget* widget) override; + + private: + // Index of the tab to drop on. + BrowserRootView::DropIndex index_; + + Position position_ = Position::Vertical; + + bool beneath_ = false; + + // Renders the drop indicator. + raw_ptr arrow_window_ = nullptr; + + raw_ptr arrow_view_ = nullptr; + + base::ScopedObservation + scoped_observation_{this}; + }; + void UpdateLayoutOrientation(); + static gfx::ImageSkia* GetDropArrowImage( + BraveTabContainer::DropArrow::Position pos, + bool beneath); + void OnUnlockLayout(); + void SetDropArrow(const absl::optional& index); + gfx::Rect GetDropBounds(int drop_index, + bool drop_before, + bool drop_in_group, + bool* is_beneath); + base::flat_set closing_tabs_; raw_ptr drag_context_; @@ -56,6 +115,10 @@ class BraveTabContainer : public TabContainerImpl { // A pointer storing the global tab style to be used. const raw_ptr tab_style_; + const raw_ref controller_; + + std::unique_ptr drop_arrow_; + BooleanPrefMember show_vertical_tabs_; BooleanPrefMember vertical_tabs_floating_mode_enabled_; BooleanPrefMember vertical_tabs_collapsed_; diff --git a/browser/ui/views/tabs/vertical_tab_strip_browsertest.cc b/browser/ui/views/tabs/vertical_tab_strip_browsertest.cc index a3493b76b467..a7bad5eaf073 100644 --- a/browser/ui/views/tabs/vertical_tab_strip_browsertest.cc +++ b/browser/ui/views/tabs/vertical_tab_strip_browsertest.cc @@ -391,31 +391,12 @@ IN_PROC_BROWSER_TEST_F(VerticalTabStripBrowserTest, MAYBE_Fullscreen) { observer.Wait(); } - base::RunLoop run_loop; - auto wait_until = base::BindLambdaForTesting( - [&](base::RepeatingCallback predicate) { - if (predicate.Run()) { - return; - } - - base::RepeatingTimer scheduler; - scheduler.Start(FROM_HERE, base::Milliseconds(100), - base::BindLambdaForTesting([&]() { - if (predicate.Run()) { - run_loop.Quit(); - } - })); - run_loop.Run(); - }); - - // Vertical tab strip should be invisible on browser fullscreen. + // Vertical tab strip should be visible on browser fullscreen. ASSERT_TRUE(fullscreen_controller->IsFullscreenForBrowser()); ASSERT_TRUE(browser_view()->IsFullscreen()); - wait_until.Run(base::BindLambdaForTesting([&]() { - return !browser_view() - ->vertical_tab_strip_host_view_->GetPreferredSize() - .width(); - })); + EXPECT_TRUE(browser_view() + ->vertical_tab_strip_host_view_->GetPreferredSize() + .width()); { auto observer = FullscreenNotificationObserver(browser()); @@ -427,6 +408,7 @@ IN_PROC_BROWSER_TEST_F(VerticalTabStripBrowserTest, MAYBE_Fullscreen) { { auto observer = FullscreenNotificationObserver(browser()); + // Vertical tab strip should become invisible on tab fullscreen. fullscreen_controller->EnterFullscreenModeForTab( browser_view() ->browser() @@ -436,8 +418,6 @@ IN_PROC_BROWSER_TEST_F(VerticalTabStripBrowserTest, MAYBE_Fullscreen) { observer.Wait(); } - - // Vertical tab strip should be invisible on tab fullscreen. ASSERT_TRUE(fullscreen_controller->IsTabFullscreen()); if (!browser_view() ->vertical_tab_strip_host_view_->GetPreferredSize() @@ -445,6 +425,28 @@ IN_PROC_BROWSER_TEST_F(VerticalTabStripBrowserTest, MAYBE_Fullscreen) { return; } + base::RunLoop run_loop; + auto wait_until = base::BindLambdaForTesting( + [&](base::RepeatingCallback predicate) { + if (predicate.Run()) { + return; + } + + base::RepeatingTimer scheduler; + scheduler.Start(FROM_HERE, base::Milliseconds(100), + base::BindLambdaForTesting([&]() { + if (predicate.Run()) { + run_loop.Quit(); + } else { + LOG(ERROR) << browser_view() + ->vertical_tab_strip_host_view_ + ->GetPreferredSize() + .width(); + } + })); + run_loop.Run(); + }); + wait_until.Run(base::BindLambdaForTesting([&]() { return !browser_view() ->vertical_tab_strip_host_view_->GetPreferredSize() diff --git a/browser/ui/views/toolbar/wallet_button_notification_source_browsertest.cc b/browser/ui/views/toolbar/wallet_button_notification_source_browsertest.cc index d0449424245a..5ca9b5993ee2 100644 --- a/browser/ui/views/toolbar/wallet_button_notification_source_browsertest.cc +++ b/browser/ui/views/toolbar/wallet_button_notification_source_browsertest.cc @@ -193,8 +193,7 @@ IN_PROC_BROWSER_TEST_F(WalletButtonNotificationSourceTest, "" /* nonce */, "10" /* gas_premium */, "10" /* gas_fee_cap */, "100" /* gas_limit */, "" /* max_fee */, to_account, "11")); tx_service()->AddUnapprovedTransaction( - std::move(tx_data), from_account->account_id.Clone(), absl::nullopt, - absl::nullopt, + std::move(tx_data), from_account->account_id.Clone(), base::BindLambdaForTesting([&](bool success, const std::string& id, const std::string& err_message) { first_tx_meta_id = id; @@ -237,7 +236,7 @@ IN_PROC_BROWSER_TEST_F(WalletButtonNotificationSourceTest, std::vector(), false, absl::nullopt); tx_service()->AddUnapprovedTransaction( brave_wallet::mojom::TxDataUnion::NewEthTxData(std::move(tx_data)), - from_account->account_id.Clone(), absl::nullopt, absl::nullopt, + from_account->account_id.Clone(), base::BindLambdaForTesting([&](bool success, const std::string& id, const std::string& err_message) { second_tx_meta_id = id; @@ -270,7 +269,7 @@ IN_PROC_BROWSER_TEST_F(WalletButtonNotificationSourceTest, tx_service()->AddUnapprovedTransaction( brave_wallet::mojom::TxDataUnion::NewSolanaTxData(std::move(tx_data)), - from_account->account_id.Clone(), absl::nullopt, absl::nullopt, + from_account->account_id.Clone(), base::BindLambdaForTesting([&](bool success, const std::string& id, const std::string& err_message) { third_tx_meta_id = id; @@ -367,8 +366,7 @@ IN_PROC_BROWSER_TEST_F(WalletButtonNotificationSourceTest, "" /* nonce */, "10" /* gas_premium */, "10" /* gas_fee_cap */, "100" /* gas_limit */, "" /* max_fee */, to_account, "11")); tx_service()->AddUnapprovedTransaction( - std::move(tx_data), from_account->account_id.Clone(), absl::nullopt, - absl::nullopt, + std::move(tx_data), from_account->account_id.Clone(), base::BindLambdaForTesting([&](bool success, const std::string& id, const std::string& err_message) { tx_meta_id = id; diff --git a/browser/ui/webui/brave_rewards/tip_panel_ui.cc b/browser/ui/webui/brave_rewards/tip_panel_ui.cc index 8864a55f9bdc..83e57c51865b 100644 --- a/browser/ui/webui/brave_rewards/tip_panel_ui.cc +++ b/browser/ui/webui/brave_rewards/tip_panel_ui.cc @@ -31,6 +31,7 @@ static constexpr webui::LocalizedString kStrings[] = { {"termsOfService", IDS_BRAVE_REWARDS_ONBOARDING_TERMS}, {"sendFormTitle", IDS_REWARDS_TIP_SEND_FORM_TITLE}, {"sendButtonLabel", IDS_REWARDS_TIP_SEND_BUTTON_LABEL}, + {"sendWithButtonLabel", IDS_REWARDS_TIP_SEND_WITH_BUTTON_LABEL}, {"web3ButtonLabel", IDS_REWARDS_TIP_WEB3_BUTTON_LABEL}, {"verifiedTooltipTitle", IDS_REWARDS_TIP_VERIFIED_TOOLTIP_TITLE}, {"verifiedTooltipText", IDS_REWARDS_TIP_VERIFIED_TOOLTIP_TEXT}, diff --git a/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.cc b/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.cc index a0ae9fc4c4b8..05d2ffd143c9 100644 --- a/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.cc +++ b/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.cc @@ -8,6 +8,7 @@ #include #include +#include "base/strings/string_number_conversions.h" #include "brave/browser/speedreader/speedreader_service_factory.h" #include "brave/browser/speedreader/speedreader_tab_helper.h" #include "brave/browser/ui/brave_browser_window.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_isolated_world_ids.h" #include "ui/color/color_provider.h" #if BUILDFLAG(ENABLE_AI_CHAT) @@ -35,14 +37,13 @@ class TtsPlayerDelegate : public speedreader::TtsPlayer::Delegate { void RequestReadingContent( content::WebContents* web_contents, - base::OnceCallback result_cb) - override { + base::OnceCallback result_cb) override { auto* page_distiller = speedreader::SpeedreaderTabHelper::GetPageDistiller(web_contents); if (page_distiller) { - page_distiller->GetDistilledText(std::move(result_cb)); + page_distiller->GetTextToSpeak(std::move(result_cb)); } else { - std::move(result_cb).Run(false, {}); + std::move(result_cb).Run(base::Value()); } } }; @@ -72,6 +73,11 @@ SpeedreaderToolbarDataHandlerImpl::SpeedreaderToolbarDataHandlerImpl( speedreader::TtsPlayer::GetInstance()->set_delegate( std::make_unique()); + + const auto& tts_settings = GetSpeedreaderService()->GetTtsSettings(); + speedreader::TtsPlayer::GetInstance()->SetSpeed( + static_cast(tts_settings.speed) / 100.0); + speedreader::TtsPlayer::GetInstance()->SetVoice(tts_settings.voice); } SpeedreaderToolbarDataHandlerImpl::~SpeedreaderToolbarDataHandlerImpl() = @@ -243,9 +249,24 @@ void SpeedreaderToolbarDataHandlerImpl::OnReadingStop( void SpeedreaderToolbarDataHandlerImpl::OnReadingProgress( content::WebContents* web_contents, - const std::string& element_id, + int paragraph_index, int char_index, - int length) {} + int length) { + if (!web_contents) { + return; + } + + constexpr const char16_t kHighlight[] = uR"js( highlightText($1, $2, $3) )js"; + + const auto script = base::ReplaceStringPlaceholders( + kHighlight, + {base::NumberToString16(paragraph_index), + base::NumberToString16(char_index), base::NumberToString16(length)}, + nullptr); + + web_contents->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( + script, base::DoNothing(), ISOLATED_WORLD_ID_BRAVE_INTERNAL); +} void SpeedreaderToolbarDataHandlerImpl::OnTabStripModelChanged( TabStripModel* tab_strip_model, diff --git a/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.h b/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.h index 941be0907b61..1a95e1b1a5fc 100644 --- a/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.h +++ b/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.h @@ -6,8 +6,6 @@ #ifndef BRAVE_BROWSER_UI_WEBUI_SPEEDREADER_SPEEDREADER_TOOLBAR_DATA_HANDLER_IMPL_H_ #define BRAVE_BROWSER_UI_WEBUI_SPEEDREADER_SPEEDREADER_TOOLBAR_DATA_HANDLER_IMPL_H_ -#include - #include "base/scoped_observation.h" #include "brave/browser/speedreader/speedreader_tab_helper.h" #include "brave/components/speedreader/common/speedreader_toolbar.mojom.h" @@ -87,7 +85,7 @@ class SpeedreaderToolbarDataHandlerImpl void OnReadingStart(content::WebContents* web_contents) override; void OnReadingStop(content::WebContents* web_contents) override; void OnReadingProgress(content::WebContents* web_contents, - const std::string& element_id, + int paragraph_index, int char_index, int length) override; diff --git a/browser/ui/webui/speedreader/speedreader_toolbar_ui.cc b/browser/ui/webui/speedreader/speedreader_toolbar_ui.cc index 853c2f1faeff..25d66a15848f 100644 --- a/browser/ui/webui/speedreader/speedreader_toolbar_ui.cc +++ b/browser/ui/webui/speedreader/speedreader_toolbar_ui.cc @@ -12,6 +12,7 @@ #include "brave/components/constants/webui_url_constants.h" #include "brave/components/l10n/common/localization_util.h" #include "brave/components/speedreader/common/constants.h" +#include "brave/components/speedreader/common/features.h" #include "brave/components/speedreader/resources/panel/grit/brave_speedreader_toolbar_generated_map.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" @@ -52,6 +53,9 @@ SpeedreaderToolbarUI::SpeedreaderToolbarUI(content::WebUI* web_ui, #else source->AddBoolean("aiChatFeatureEnabled", false); #endif + source->AddBoolean("ttsEnabled", + speedreader::features::IsSpeedreaderEnabled() && + speedreader::kSpeedreaderTTS.Get()); } SpeedreaderToolbarUI::~SpeedreaderToolbarUI() = default; diff --git a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc index e0cfad8962f3..c07a35981524 100644 --- a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc @@ -285,12 +285,14 @@ void BraveRenderViewContextMenu::ExecuteCommand(int id, int event_flags) { break; #endif #if BUILDFLAG(ENABLE_TOR) - case IDC_CONTENT_CONTEXT_OPENLINKTOR: - TorProfileManager::SwitchToTorProfile( - GetProfile(), - base::BindRepeating(OnTorProfileCreated, params_.link_url, - HasAlreadyOpenedTorWindow(GetProfile()))); - break; + case IDC_CONTENT_CONTEXT_OPENLINKTOR: { + const bool has_tor_window = HasAlreadyOpenedTorWindow(GetProfile()); + Browser* tor_browser = + TorProfileManager::SwitchToTorProfile(GetProfile()); + if (tor_browser) { + OnTorProfileCreated(params_.link_url, has_tor_window, tor_browser); + } + } break; #endif #if BUILDFLAG(ENABLE_TEXT_RECOGNITION) case IDC_CONTENT_CONTEXT_COPY_TEXT_FROM_IMAGE: diff --git a/chromium_src/chrome/browser/ui/views/web_apps/web_app_views_utils.cc b/chromium_src/chrome/browser/ui/views/web_apps/web_app_views_utils.cc deleted file mode 100644 index cd95a243e56d..000000000000 --- a/chromium_src/chrome/browser/ui/views/web_apps/web_app_views_utils.cc +++ /dev/null @@ -1,22 +0,0 @@ -// 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 "chrome/browser/ui/views/web_apps/web_app_views_utils.h" - -#define CreateOriginLabel CreateOriginLabel_ChromiumImpl -#include "src/chrome/browser/ui/views/web_apps/web_app_views_utils.cc" -#undef CreateOriginLabel - -namespace web_app { - -std::unique_ptr CreateOriginLabel(const url::Origin& origin, - bool is_primary_text) { - const url::Origin updated_origin = url::Origin::CreateFromNormalizedTuple( - origin.scheme() == "chrome" ? "brave" : origin.scheme(), origin.host(), - origin.port()); - return CreateOriginLabel_ChromiumImpl(updated_origin, is_primary_text); -} - -} // namespace web_app diff --git a/chromium_src/chrome/installer/setup/setup_main.cc b/chromium_src/chrome/installer/setup/setup_main.cc index 3b30bc30af3e..e8124163f606 100644 --- a/chromium_src/chrome/installer/setup/setup_main.cc +++ b/chromium_src/chrome/installer/setup/setup_main.cc @@ -3,17 +3,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#define wWinMain wWinMain_ChromiumImpl -#include "src/chrome/installer/setup/setup_main.cc" -#undef wWinMain +#include + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/installer/setup/setup_util.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/util_constants.h" + +namespace { const char kBraveReferralCode[] = "brave-referral-code"; -int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, - wchar_t* command_line, int show_command) { - int return_code = wWinMain_ChromiumImpl(instance, prev_instance, command_line, - show_command); - if (!return_code) { +void SavePromoCode(installer::InstallStatus install_status) { + if (!InstallUtil::GetInstallReturnCode(install_status)) { const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); if (cmd_line.HasSwitch(kBraveReferralCode)) { const std::string referral_code = @@ -30,6 +37,12 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } } } - - return return_code; } + +} // namespace + +#define DoLegacyCleanups \ + SavePromoCode(install_status); \ + DoLegacyCleanups +#include "src/chrome/installer/setup/setup_main.cc" +#undef DoLegacyCleanups diff --git a/chromium_src/components/url_formatter/elide_url.cc b/chromium_src/components/url_formatter/elide_url.cc new file mode 100644 index 000000000000..abaeaa0cb31d --- /dev/null +++ b/chromium_src/components/url_formatter/elide_url.cc @@ -0,0 +1,26 @@ +/* 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 "components/url_formatter/elide_url.h" + +#define FormatOriginForSecurityDisplay \ + FormatOriginForSecurityDisplay_ChromiumImpl + +#include "src/components/url_formatter/elide_url.cc" +#undef FormatOriginForSecurityDisplay + +namespace url_formatter { + +std::u16string FormatOriginForSecurityDisplay( + const url::Origin& origin, + const SchemeDisplay scheme_display) { + const url::Origin updated_origin = url::Origin::CreateFromNormalizedTuple( + origin.scheme() == "chrome" ? "brave" : origin.scheme(), origin.host(), + origin.port()); + return FormatOriginForSecurityDisplay_ChromiumImpl(updated_origin, + scheme_display); +} + +} // namespace url_formatter diff --git a/chromium_src/net/tools/transport_security_state_generator/input_file_parsers.cc b/chromium_src/net/tools/transport_security_state_generator/input_file_parsers.cc index 4d35ba4b166a..969e2d0b896f 100644 --- a/chromium_src/net/tools/transport_security_state_generator/input_file_parsers.cc +++ b/chromium_src/net/tools/transport_security_state_generator/input_file_parsers.cc @@ -541,9 +541,9 @@ bool ParseCertificatesFile(base::StringPiece certs_input, Pinsets* pinsets, base::Time* timestamp) { constexpr base::StringPiece brave_certs = R"brave_certs( -# Last updated: Tue Sep 12 18:47:54 UTC 2023 +# Last updated: Sat Sep 16 02:37:26 UTC 2023 PinsListTimestamp -1694544474 +1694831846 # =====BEGIN BRAVE ROOTS ASC===== #From https://www.amazontrust.com/repository/ diff --git a/components/ai_chat/resources/page/components/conversation_list/index.tsx b/components/ai_chat/resources/page/components/conversation_list/index.tsx index 0ae208831c81..fd3be4d991ef 100644 --- a/components/ai_chat/resources/page/components/conversation_list/index.tsx +++ b/components/ai_chat/resources/page/components/conversation_list/index.tsx @@ -15,7 +15,7 @@ import DataContext from '../../state/context' function ConversationList () { // Scroll the last conversation item in to view when entries are added. const lastConversationEntryElementRef = React.useRef(null) - const { isGenerating, conversationHistory, suggestedQuestions } = React.useContext(DataContext) + const { isGenerating, conversationHistory, suggestedQuestions, shouldDisableUserInput } = React.useContext(DataContext) React.useEffect(() => { if (!conversationHistory.length && !isGenerating) { @@ -77,7 +77,12 @@ function ConversationList () {
{suggestedQuestions.map((question, id) => ( -
- + {hasSeenAgreement && ( + + )}
) -} +}) const LIST_STYLE = { overscrollBehavior: 'contain' } -const getListItemKey = (i: number, data: UserAssetInfoType[]) => getAssetIdKey(data[i].asset) - -export const VirtualizedTokensList = React.memo(({ +export const VirtualizedTokensList = React.memo(function ({ renderToken, userAssetList, estimatedItemSize, getItemSize, - maximumViewableTokens -}: VirtualizedTokensListProps) => { + maximumViewableTokens, + getItemKey +}: VirtualizedTokensListProps) { // computed // last item shown as 50% visible to indicate that scrolling is possible here const maxTokens = @@ -87,7 +83,7 @@ export const VirtualizedTokensList = React.memo(({ // methods const renderListChild = React.useCallback( - (itemProps: ListChildComponentProps) => ( + (itemProps: ListChildComponentProps) => ( diff --git a/components/brave_wallet_ui/components/desktop/views/portfolio/portfolio-asset.tsx b/components/brave_wallet_ui/components/desktop/views/portfolio/portfolio-asset.tsx index e8ad7c960aa1..bc62845a6bd4 100644 --- a/components/brave_wallet_ui/components/desktop/views/portfolio/portfolio-asset.tsx +++ b/components/brave_wallet_ui/components/desktop/views/portfolio/portfolio-asset.tsx @@ -31,6 +31,7 @@ import { } from '../../../../utils/asset-utils' import { getLocale } from '../../../../../common/locale' import { makeNetworkAsset } from '../../../../options/asset-options' +import { makeDepositFundsRoute } from '../../../../utils/routes-utils' // actions import { WalletPageActions } from '../../../../page/actions' @@ -412,9 +413,7 @@ export const PortfolioAsset = (props: Props) => { }, [selectedAssetFromParams?.symbol]) const onSelectDeposit = React.useCallback(() => { - history.push( - `${WalletRoutes.DepositFundsPageStart}/${selectedAssetFromParams?.symbol}` - ) + history.push(makeDepositFundsRoute(selectedAssetFromParams?.symbol)) }, [selectedAssetFromParams?.symbol]) React.useEffect(() => { diff --git a/components/brave_wallet_ui/components/desktop/wallet-menus/asset-item-menu.tsx b/components/brave_wallet_ui/components/desktop/wallet-menus/asset-item-menu.tsx index 3074b21d64d1..784eba043ef6 100644 --- a/components/brave_wallet_ui/components/desktop/wallet-menus/asset-item-menu.tsx +++ b/components/brave_wallet_ui/components/desktop/wallet-menus/asset-item-menu.tsx @@ -26,6 +26,7 @@ import { // Utils import { getLocale } from '../../../../common/locale' import Amount from '../../../utils/amount' +import { makeDepositFundsRoute } from '../../../utils/routes-utils' // Components import { @@ -129,9 +130,7 @@ export const AssetItemMenu = (props: Props) => { }, []) const onClickDeposit = React.useCallback(() => { - history.push( - WalletRoutes.DepositFundsPage.replace(':tokenId?', asset.symbol) - ) + history.push(makeDepositFundsRoute(asset.symbol)) }, [asset.symbol]) const onClickSell = React.useCallback(() => { diff --git a/components/brave_wallet_ui/components/desktop/wallet-nav/wallet-nav-button/wallet-nav-button.tsx b/components/brave_wallet_ui/components/desktop/wallet-nav/wallet-nav-button/wallet-nav-button.tsx index 5e8ab00883dd..f1765f73fb4b 100644 --- a/components/brave_wallet_ui/components/desktop/wallet-nav/wallet-nav-button/wallet-nav-button.tsx +++ b/components/brave_wallet_ui/components/desktop/wallet-nav/wallet-nav-button/wallet-nav-button.tsx @@ -22,6 +22,7 @@ import { export interface Props { option: NavOption + onClick?: (() => void) | (() => Promise) } export const WalletNavButton = (props: Props) => { @@ -33,8 +34,9 @@ export const WalletNavButton = (props: Props) => { // Methods const onClick = React.useCallback(() => { - history.push(option.route) - }, [option.route]) + props.onClick?.() + history.push(props.option.route) + }, [props]) return ( { - // Selectors + // redux + const dispatch = useDispatch() const isPanel = useSafeUISelector(UISelectors.isPanel) return ( - - +
- {PanelNavOptions.map((option) => + {PanelNavOptions.map((option) => ( - )} + ))}
- {NavOptions.map((option) => + {NavOptions.map((option) => ( - )} + ))}
- {BuySendSwapDepositOptions.map((option) => - - )} + {BuySendSwapDepositOptions.map((option) => ( + { + if ( + option.route === WalletRoutes.FundWalletPageStart || + option.route === WalletRoutes.DepositFundsPageStart + ) { + dispatch(WalletActions.selectOnRampAssetId(undefined)) + } + }} + /> + ))}
-
) } diff --git a/components/brave_wallet_ui/components/extension/confirm-transaction-panel/confirm-bitcoin-transaction-panel.tsx b/components/brave_wallet_ui/components/extension/confirm-transaction-panel/confirm-bitcoin-transaction-panel.tsx index af48c7b8dea6..f572a27dd855 100644 --- a/components/brave_wallet_ui/components/extension/confirm-transaction-panel/confirm-bitcoin-transaction-panel.tsx +++ b/components/brave_wallet_ui/components/extension/confirm-transaction-panel/confirm-bitcoin-transaction-panel.tsx @@ -5,9 +5,6 @@ import * as React from 'react' -// types -import { BraveWallet } from '../../../constants/types' - // Utils import Amount from '../../../utils/amount' import { WalletSelectors } from '../../../common/selectors' @@ -47,15 +44,7 @@ import { AccountCircleWrapper, ArrowIcon, FromToRow, - GroupBox, - GroupBoxColumn, - GroupBoxTitle, - GroupBoxText, - GroupEnumeration, - SmallLoadIcon } from './style' -import { StatusBubble } from '../../shared/style' -import { getTransactionStatusString } from '../../../utils/tx-utils' type confirmPanelTabs = 'transaction' | 'details' @@ -74,8 +63,6 @@ export const ConfirmBitcoinTransactionPanel = () => { transactionDetails, transactionsNetwork, transactionTitle, - groupTransactions, - selectedPendingTransactionGroupIndex, selectedPendingTransaction, onConfirm, onReject, @@ -164,34 +151,6 @@ export const ConfirmBitcoinTransactionPanel = () => { } - {(groupTransactions.length > 0 && - selectedPendingTransactionGroupIndex >= 0 && - selectedPendingTransaction) && - - - - Transaction group - - { - groupTransactions.map((txn, idx) => - - - [{idx + 1}/{groupTransactions.length}] - - - - - {getTransactionStatusString(txn.txStatus)} - - {[BraveWallet.TransactionStatus.Approved, BraveWallet.TransactionStatus.Submitted] - .includes(txn.txStatus) && } - - ) - } - - - } - { transactionsNetwork, transactionTitle, isSolanaDappTransaction, - groupTransactions, - selectedPendingTransactionGroupIndex, selectedPendingTransaction, onConfirm, onReject, @@ -200,34 +188,6 @@ export const ConfirmSolanaTransactionPanel = () => { } - {(groupTransactions.length > 0 && - selectedPendingTransactionGroupIndex >= 0 && - selectedPendingTransaction) && - - - - Transaction group - - { - groupTransactions.map((txn, idx) => - - - [{idx + 1}/{groupTransactions.length}] - - - - - {getTransactionStatusString(txn.txStatus)} - - {[BraveWallet.TransactionStatus.Approved, BraveWallet.TransactionStatus.Submitted] - .includes(txn.txStatus) && } - - ) - } - - - } - p.theme.color.divider01}; - box-sizing: border-box; - border-radius: 4px; - width: 255px; - min-height: 82px; - padding: 4px 14px; - overflow-y: scroll; - overflow-x: hidden; - position: relative; - margin-top: 10px; - background: ${p => p.theme.color.infoBackground}; -` - -export const GroupBoxColumn = styled.div` - display: flex; - align-items: flex-start; - justify-content: flex-start; - width: 100%; - flex-direction: column; -` - -export const GroupBoxTitle = styled.span` - font-family: Poppins; - font-size: 12px; - font-weight: 600; - line-height: 18px; - letter-spacing: 0.01em; - color: ${(p) => p.theme.color.text02}; - word-break: break-all; -` - -export const GroupBoxText = styled.div<{ dark: boolean }>` - font-family: Poppins; - font-size: 11px; - font-weight: ${(p) => p.dark ? 600 : 400}; - line-height: 18px; - letter-spacing: 0.01em; - color: ${(p) => p.dark ? p.theme.color.text02 : p.theme.color.text03}; - flex: 1; - display: flex; - align-items: center; - justify-content: flex-start; - flex-direction: row; -` - -export const GroupEnumeration = styled.code` - padding-right: 5px; -` - -export const SmallLoadIcon = styled(LoaderIcon)` - color: ${p => p.theme.color.interactive08}; - height: 16px; - width: 16px; - opacity: .4; - padding-left: 5px; -` - export const ContractButton = styled(WalletButton)` display: flex; align-items: center; diff --git a/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx b/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx index 41bd84e74f7e..96931c531221 100644 --- a/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx +++ b/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx @@ -25,81 +25,96 @@ import { getNetworkLogo } from '../../../options/asset-options' // Hooks import { useNetworkOrb } from '../../../common/hooks/use-orb' +type SimpleNetwork = Pick< + BraveWallet.NetworkInfo, + 'iconUrls' | 'chainId' | 'symbol' | 'chainName' +> + interface Props { - network?: Pick< - BraveWallet.NetworkInfo, - 'iconUrls' | 'chainId' | 'symbol' | 'chainName' - > + network?: SimpleNetwork marginRight?: number size?: 'huge' | 'big' | 'small' | 'tiny' | 'extra-small' } const isStorybook = isComponentInStorybook() -export const CreateNetworkIcon = ({ - network, - marginRight, - size -}: Props) => { - // computed - const networkImageURL = stripERC20TokenImageURL(network?.iconUrls[0]) - const isRemoteURL = isRemoteImageURL(networkImageURL) - const isDataURL = network?.iconUrls[0]?.startsWith( - 'chrome://erc-token-images/' - ) - - const networkLogo = network - ? getNetworkLogo(network.chainId, network.symbol) - : '' - - const isValidIcon = - isStorybook || - (network && - (isRemoteURL || isDataURL - ? isValidIconExtension(new URL(network?.iconUrls[0]).pathname) - : false)) - - const needsPlaceholder = - networkLogo === '' && (networkImageURL === '' || !isValidIcon) - - const orb = useNetworkOrb(network) +export const CreateNetworkIcon = ({ network, marginRight, size }: Props) => { + // exit early if no network + if (!network) { + return ( + + ) + } - const remoteImage = isRemoteURL - ? `chrome://image?${networkImageURL}` - : '' + // computed + const networkLogo = getNetworkLogo(network.chainId, network.symbol) + const isTestnet = SupportedTestNetworks.includes(network.chainId) - // render - if (needsPlaceholder) { + // simple render + if (networkLogo) { return ( - + ) } + // complex compute + render + const networkIcon = network.iconUrls[0] + const isSandboxUrl = networkIcon?.startsWith('chrome://erc-token-images/') + const networkImageURL = isSandboxUrl + ? stripERC20TokenImageURL(networkIcon) + : networkIcon + + const isRemoteURL = isRemoteImageURL(networkImageURL) + + // needs placeholder + if ( + !networkImageURL || + !isStorybook || + (isRemoteURL || isSandboxUrl + ? !isValidIconExtension(new URL(networkIcon).pathname) + : true) + ) { + return ( + + ) + } + return ( ) } export default CreateNetworkIcon + +function NetworkPlaceholderIcon({ + marginRight, + network +}: { + marginRight: number | undefined + network?: SimpleNetwork +}) { + // custom hooks + const orb = useNetworkOrb(network) + + // render + return ( + + + + ) +} diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index 6a1deaceaa00..690c36001af9 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -395,7 +395,6 @@ export interface SolanaSerializedTransactionParams { accountId: BraveWallet.AccountId txType: BraveWallet.TransactionType sendOptions?: BraveWallet.SolanaSendTransactionOptions - groupId?: string } export interface SendEthTransactionParams extends BaseEthTransactionParams { @@ -648,11 +647,12 @@ export enum WalletRoutes { // fund wallet page FundWalletPageStart = '/crypto/fund-wallet', - FundWalletPage = '/crypto/fund-wallet/token/:currencyCode?/:buyAmount?', + FundWalletPage = '/crypto/fund-wallet/:currencyCode?/:buyAmount?', FundWalletPurchaseOptionsPage = '/crypto/fund-wallet/purchase/' + ':currencyCode/:buyAmount', DepositFundsPageStart = '/crypto/deposit-funds', - DepositFundsPage = '/crypto/deposit-funds/:tokenId?', + DepositFundsPage = '/crypto/deposit-funds', + DepositFundsAccountPage = '/crypto/deposit-funds/account', // market Market = '/crypto/market', diff --git a/components/brave_wallet_ui/page/container.tsx b/components/brave_wallet_ui/page/container.tsx index 1d0df6668fb3..3f64c3822916 100644 --- a/components/brave_wallet_ui/page/container.tsx +++ b/components/brave_wallet_ui/page/container.tsx @@ -9,7 +9,6 @@ import { Redirect, Route, Switch, useHistory, useLocation } from 'react-router-d // utils import { getWalletLocationTitle } from '../utils/string-utils' -import { getLocale } from '../../common/locale' // actions import * as WalletPageActions from './actions/wallet_page_actions' @@ -96,7 +95,6 @@ export const Container = () => { // state const [sessionRoute, setSessionRoute] = React.useState(undefined) const [inputValue, setInputValue] = React.useState('') - const [showDepositAddress, setShowDepositAddress] = React.useState(false) // methods const onToggleShowRestore = React.useCallback(() => { @@ -151,17 +149,6 @@ export const Container = () => { dispatch(WalletPageActions.openWalletSettings()) }, []) - const handleDepositScreenBack = React.useCallback(() => { - if (!showDepositAddress && history.length) { - return history.goBack() - } - - if (showDepositAddress) { - // go back to asset selection - setShowDepositAddress(false) - } - }, [showDepositAddress, history]) - // computed const walletNotYetCreated = (!isWalletCreated || setupStillInProgress) @@ -202,8 +189,8 @@ export const Container = () => { if ( walletLocation === WalletRoutes.Swap || walletLocation === WalletRoutes.SendPageStart || - walletLocation.includes(WalletRoutes.DepositFundsPage) || - walletLocation.includes(WalletRoutes.FundWalletPage) || + walletLocation.includes(WalletRoutes.DepositFundsPageStart) || + walletLocation.includes(WalletRoutes.FundWalletPageStart) || walletLocation.includes(WalletRoutes.LocalIpfsNode) || walletLocation.includes(WalletRoutes.InspectNfts) || walletLocation.includes(WalletRoutes.PortfolioAssets) || @@ -315,23 +302,8 @@ export const Container = () => { } {!isWalletLocked && - - - } - > - - + + } diff --git a/components/brave_wallet_ui/page/screens/fund-wallet/android/deposit-funds.tsx b/components/brave_wallet_ui/page/screens/fund-wallet/android/deposit-funds.tsx index 0558d455c359..ec92e3f50c14 100644 --- a/components/brave_wallet_ui/page/screens/fund-wallet/android/deposit-funds.tsx +++ b/components/brave_wallet_ui/page/screens/fund-wallet/android/deposit-funds.tsx @@ -18,7 +18,6 @@ import 'emptykit.css' // Utils import { loadTimeData } from '../../../../../common/loadTimeData' import * as Lib from '../../../../common/async/lib' -import { getLocale } from '../../../../../common/locale' // actions import * as WalletActions from '../../../../common/actions/wallet_actions' @@ -32,48 +31,17 @@ import { LibContext } from '../../../../common/context/lib.context' import { ApiProxyContext } from '../../../../common/context/api-proxy.context' -import { WalletPageWrapper } - from '../../../../components/desktop/wallet-page-wrapper/wallet-page-wrapper' -import { PageTitleHeader } - from '../../../../components/desktop/card-headers/page-title-header' - import { setIconBasePath } from '@brave/leo/react/icon' setIconBasePath('chrome://resources/brave-icons') export function AndroidDepositApp() { - const [showDepositAddress, setShowDepositAddress] = React.useState(false) - - const handleDepositScreenBack = React.useCallback(() => { - if (showDepositAddress) { - // go back to asset selection - setShowDepositAddress(false) - } - }, [showDepositAddress]) - return ( - - } - > - - + diff --git a/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.stories.tsx b/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.stories.tsx index 32080310a597..25c5637d367d 100644 --- a/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.stories.tsx +++ b/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.stories.tsx @@ -10,10 +10,7 @@ import { DepositFundsScreen } from './deposit-funds' export const _DepositFundsScreen = () => { return - {}} - /> + } diff --git a/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.tsx b/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.tsx index aacbea776a79..c0d50bb629bb 100644 --- a/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.tsx +++ b/components/brave_wallet_ui/page/screens/fund-wallet/deposit-funds.tsx @@ -4,25 +4,23 @@ // you can obtain one at https://mozilla.org/MPL/2.0/. import * as React from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' import { skipToken } from '@reduxjs/toolkit/query/react' -import { useParams } from 'react-router' +import { Redirect, Route, Switch, useHistory } from 'react-router' // utils import { getLocale } from '../../../../common/locale' -import { generateQRCode } from '../../../utils/qr-code-utils' import { makeNetworkAsset } from '../../../options/asset-options' -import { - getBatTokensFromList, - getAssetIdKey -} from '../../../utils/asset-utils' +import { getBatTokensFromList, getAssetIdKey } from '../../../utils/asset-utils' import { WalletActions } from '../../../common/slices/wallet.slice' +import { WalletSelectors } from '../../../common/selectors' +import { makeDepositFundsRoute } from '../../../utils/routes-utils' // types import { BraveWallet, - UserAssetInfoType, - WalletState + NetworkFilterType, + WalletRoutes } from '../../../constants/types' // options @@ -32,14 +30,28 @@ import { AllNetworksOption } from '../../../options/network-filter-options' import { useCopyToClipboard } from '../../../common/hooks/use-copy-to-clipboard' import { useGetMainnetsQuery, - useGetNetworkQuery + useGetNetworkQuery, + useGetQrCodeImageQuery } from '../../../common/slices/api.slice' import { - useGetCombinedTokensListQuery + useGetCombinedTokensListQuery // } from '../../../common/slices/api.slice.extra' +import { + useSafeWalletSelector, + useUnsafeWalletSelector +} from '../../../common/hooks/use-safe-selector' +import { useScrollIntoView } from '../../../common/hooks/use-scroll-into-view' +import { useDebouncedCallback } from '../swap/hooks/useDebouncedCallback' // style -import { Column, CopyButton, HorizontalSpace, LoadingIcon, Row, VerticalSpace } from '../../../components/shared/style' +import { + Column, + CopyButton, + HorizontalSpace, + LoadingIcon, + Row, + VerticalSpace +} from '../../../components/shared/style' import { Description, NextButtonRow, @@ -53,9 +65,16 @@ import { SearchWrapper, SelectAssetWrapper } from './fund-wallet.style' +import { + LoadingRing // +} from '../../../components/extension/add-suggested-token-panel/style' +import { + FilterTokenRow // +} from '../../../components/desktop/views/portfolio/style' // components import { + RenderTokenFunc, VirtualizedTokensList } from '../../../components/desktop/views/portfolio/components/token-lists/virtualized-tokens-list' import SearchBar from '../../../components/shared/search-bar/index' @@ -66,59 +85,143 @@ import { CopiedToClipboardConfirmation } from '../../../components/desktop/copie import { NavButton } from '../../../components/extension/buttons/nav-button/index' import CreateAccountTab from '../../../components/buy-send-swap/create-account/index' import SelectHeader from '../../../components/buy-send-swap/select-header/index' -import { - FilterTokenRow // -} from '../../../components/desktop/views/portfolio/style' import { NetworkFilterSelector // } from '../../../components/desktop/network-filter-selector' +import { + WalletPageWrapper // +} from '../../../components/desktop/wallet-page-wrapper/wallet-page-wrapper' +import { + PageTitleHeader // +} from '../../../components/desktop/card-headers/page-title-header' const itemSize = 82 -function getItemSize (index: number): number { +function getItemSize(index: number): number { return itemSize } -interface Props { - showDepositAddress: boolean - onShowDepositAddress: (showDepositAddress: boolean) => void -} - -export const DepositFundsScreen = (props: Props) => { - const { showDepositAddress, onShowDepositAddress } = props +const getItemKey = (i: number, data: BraveWallet.BlockchainToken[]) => + getAssetIdKey(data[i]) +export const DepositFundsScreen = () => { // routing - const { tokenId } = useParams<{ tokenId?: string }>() + const history = useHistory() // redux const dispatch = useDispatch() - const accounts = useSelector(({ wallet }: { wallet: WalletState }) => wallet.accounts) - const selectedNetworkFilter = useSelector(({ wallet }: { wallet: WalletState }) => wallet.selectedNetworkFilter) + + // clear selected asset on page mount + React.useEffect(() => { + dispatch(WalletActions.selectOnRampAssetId(undefined)) + }, []) + + // render + return ( + + + { + dispatch(WalletActions.selectOnRampAssetId(undefined)) + history.goBack() + }} + /> + } + > + + + + + + + } + > + + + + + ) +} + +function AssetSelection() { + // routing + const history = useHistory() + const params = new URLSearchParams(history.location.search) + const searchParam = params.get('search') + const chainIdParam = params.get('chainId') + const coinTypeParam = params.get('coinType') // custom hooks - const { copyToClipboard, isCopied, resetCopyState } = useCopyToClipboard() + const scrollIntoView = useScrollIntoView() + + // redux + const dispatch = useDispatch() + const selectedDepositAssetId = useSafeWalletSelector( + WalletSelectors.selectedOnRampAssetId + ) + + // refs + const listItemRefs = React.useRef | null>(null) + + const getRefsMap = React.useCallback( + function () { + if (!listItemRefs.current) { + // Initialize the Map on first usage. + listItemRefs.current = new Map() + } + return listItemRefs.current + }, + [listItemRefs] + ) // state - const [showAccountSearch, setShowAccountSearch] = React.useState(false) - const [accountSearchText, setAccountSearchText] = React.useState('') - const [qrCode, setQRCode] = React.useState('') - const [selectedAsset, setSelectedAsset] = React.useState< - BraveWallet.BlockchainToken | undefined - >(undefined) - const [selectedAccount, setSelectedAccount] = - React.useState() - const [searchValue, setSearchValue] = React.useState(tokenId ?? '') + const [searchValue, setSearchValue] = React.useState( + searchParam ?? '' + ) + const [selectedNetworkFilter, setSelectedNetworkFilter] = + React.useState( + chainIdParam && coinTypeParam !== null + ? { + chainId: chainIdParam, + coin: Number(coinTypeParam) + } + : AllNetworksOption + ) // queries + const { data: selectedNetworkFromFilter = AllNetworksOption } = + useGetNetworkQuery( + !selectedNetworkFilter || + selectedNetworkFilter.chainId === AllNetworksOption.chainId + ? skipToken + : selectedNetworkFilter + ) const { data: combinedTokensList } = useGetCombinedTokensListQuery() - const { data: mainnetsList = [] } = useGetMainnetsQuery() - const { data: selectedAssetNetwork } = useGetNetworkQuery( - selectedAsset ?? skipToken + const selectedAsset = combinedTokensList.find( + (token) => getAssetIdKey(token) === selectedDepositAssetId ) - // memos - const isNextStepEnabled = React.useMemo(() => !!selectedAsset, [selectedAsset]) + const { data: mainnetsList = [] } = useGetMainnetsQuery() + + // computed + const isNextStepEnabled = !!selectedAsset + // memos const mainnetNetworkAssetsList = React.useMemo(() => { return (mainnetsList || []).map(makeNetworkAsset) }, [mainnetsList]) @@ -158,63 +261,223 @@ export const DepositFundsScreen = (props: Props) => { ] }, [mainnetNetworkAssetsList, combinedTokensList, nftCollectionAssets]) - const assetsForFilteredNetwork: UserAssetInfoType[] = React.useMemo(() => { - const assets = selectedNetworkFilter.chainId === AllNetworksOption.chainId - ? fullAssetsList - : fullAssetsList.filter(({ chainId }) => selectedNetworkFilter.chainId === chainId) + const assetsForFilteredNetwork = React.useMemo(() => { + const assets = + selectedNetworkFilter.chainId === AllNetworksOption.chainId + ? fullAssetsList + : fullAssetsList.filter( + ({ chainId }) => selectedNetworkFilter.chainId === chainId + ) - return assets.map(asset => ({ asset, assetBalance: '1' })) + return assets }, [selectedNetworkFilter.chainId, fullAssetsList]) - const accountsForSelectedAssetNetwork = React.useMemo(() => { - return selectedAssetNetwork - ? accounts.filter(a => a.accountId.coin === selectedAssetNetwork.coin) + const assetListSearchResults = React.useMemo(() => { + if (searchValue === '') { + return assetsForFilteredNetwork + } + return assetsForFilteredNetwork.filter((asset) => { + const searchValueLower = searchValue.toLowerCase() + return ( + asset.name.toLowerCase().startsWith(searchValueLower) || + asset.symbol.toLowerCase().startsWith(searchValueLower) + ) + }) + }, [searchValue, assetsForFilteredNetwork]) + + // methods + // This filters a list of assets when the user types in search bar + const onSearchValueChange = React.useCallback( + (event: React.ChangeEvent) => { + setSearchValue(event.target.value) + }, + [] + ) + + const nextStep = React.useCallback(() => { + const searchValueLower = searchValue.toLowerCase() + + // save latest form values in router history + history.replace( + makeDepositFundsRoute( + // save latest search-box value (if it matches selection name or symbol) + searchValue && + (selectedAsset?.name.toLowerCase().startsWith(searchValueLower) || + selectedAsset?.symbol.toLowerCase().startsWith(searchValueLower)) + ? searchValue + : undefined, + // saving network filter (if it matches selection) + selectedAsset?.chainId === selectedNetworkFilter.chainId + ? selectedNetworkFilter.chainId || AllNetworksOption.chainId + : AllNetworksOption.chainId, + selectedAsset?.coin === selectedNetworkFilter.coin + ? selectedNetworkFilter.coin.toString() || + AllNetworksOption.coin.toString() + : AllNetworksOption.coin.toString() + ) + ) + + history.push(WalletRoutes.DepositFundsAccountPage) + }, [history, selectedNetworkFilter, searchValue, selectedAsset]) + + const renderToken = React.useCallback< + RenderTokenFunc + >( + ({ item: asset }) => { + const assetId = getAssetIdKey(asset) + return ( + { + const refs = getRefsMap() + if (node) { + refs.set(assetId, node) + } else { + refs.delete(assetId) + } + }} + key={assetId} + token={asset} + onClick={() => dispatch(WalletActions.selectOnRampAssetId(assetId))} + /> + ) + }, + [dispatch, getRefsMap] + ) + + // effects + React.useEffect(() => { + // scroll selected item into view + if (selectedDepositAssetId) { + const ref = getRefsMap().get(selectedDepositAssetId) + if (ref) { + scrollIntoView(ref, true) + } + } + }, [selectedDepositAssetId, getRefsMap, scrollIntoView]) + + // render + return ( + <> + + + + + + + + + {fullAssetsList.length ? ( + + ) : ( + + + + )} + + + + + + + + + ) +} + +function DepositAccount() { + // routing + const history = useHistory() + + // redux + const dispatch = useDispatch() + const accounts = useUnsafeWalletSelector(WalletSelectors.accounts) + const selectedDepositAssetId = useSafeWalletSelector( + WalletSelectors.selectedOnRampAssetId + ) + + // queries + const { data: combinedTokensList } = useGetCombinedTokensListQuery() + const selectedAsset = combinedTokensList.find( + (token) => getAssetIdKey(token) === selectedDepositAssetId + ) + const { data: selectedAssetNetwork } = useGetNetworkQuery( + selectedAsset ?? skipToken + ) + const accountsForSelectedAssetCoinType = React.useMemo(() => { + return selectedAsset + ? accounts.filter((a) => a.accountId.coin === selectedAsset.coin) : [] }, [selectedAssetNetwork, accounts]) - const needsAccount: boolean = React.useMemo(() => { - return !!selectedAsset && accountsForSelectedAssetNetwork.length < 1 - }, [selectedAsset, accountsForSelectedAssetNetwork.length]) + // search + const [showAccountSearch, setShowAccountSearch] = + React.useState(false) + const [accountSearchText, setAccountSearchText] = React.useState('') + + // selected account + const [selectedAccount, setSelectedAccount] = React.useState< + BraveWallet.AccountInfo | undefined + >(accountsForSelectedAssetCoinType[0]) + const { data: qrCode, isLoading: isLoadingQrCode } = useGetQrCodeImageQuery( + selectedAccount?.accountId.address || skipToken + ) + + // custom hooks + const { copyToClipboard, isCopied, resetCopyState } = useCopyToClipboard() + + // memos & computed + const needsAccount = + !!selectedAsset && accountsForSelectedAssetCoinType.length < 1 const accountListSearchResults = React.useMemo(() => { if (accountSearchText === '') { - return accountsForSelectedAssetNetwork + return accountsForSelectedAssetCoinType } - return accountsForSelectedAssetNetwork.filter((item) => { + return accountsForSelectedAssetCoinType.filter((item) => { return item.name.toLowerCase().startsWith(accountSearchText.toLowerCase()) }) - }, [accountSearchText, accountsForSelectedAssetNetwork]) - - const assetListSearchResults = React.useMemo(() => { - if (searchValue === '') { - return assetsForFilteredNetwork - } - return assetsForFilteredNetwork.filter((item) => { - const searchValueLower = searchValue.toLowerCase() - return ( - item.asset.name.toLowerCase().startsWith(searchValueLower) || - item.asset.symbol.toLowerCase().startsWith(searchValueLower) - ) - }) - }, [ - searchValue, - assetsForFilteredNetwork - ]) + }, [accountSearchText, accountsForSelectedAssetCoinType]) const depositTitleText: string = React.useMemo(() => { - const isNativeAsset = ( + const isNativeAsset = selectedAsset?.coin === BraveWallet.CoinType.ETH && !selectedAsset?.isErc20 && !selectedAsset?.isErc721 - ) const isFil = selectedAsset?.coin === BraveWallet.CoinType.FIL const isSolOrSpl = selectedAsset?.coin === BraveWallet.CoinType.SOL const isErc = selectedAsset?.isErc20 || selectedAsset?.isErc721 // EVM native network (gas) assets & Filecoin if (isNativeAsset || isFil) { - return getLocale('braveWalletDepositX').replace('$1', selectedAsset.symbol) + return getLocale('braveWalletDepositX').replace( + '$1', + selectedAsset.symbol + ) } // ERC-based tokens @@ -231,17 +494,20 @@ export const DepositFundsScreen = (props: Props) => { }, [selectedAsset]) // methods - const openAccountSearch = React.useCallback(() => setShowAccountSearch(true), []) - const closeAccountSearch = React.useCallback(() => setShowAccountSearch(false), []) - const onSearchTextChanged = React.useCallback((e: React.ChangeEvent) => setAccountSearchText(e.target.value), []) - - // This filters a list of assets when the user types in search bar - const onSearchValueChange = React.useCallback( - (event: React.ChangeEvent) => { - setSearchValue(event.target.value) - }, + const openAccountSearch = React.useCallback( + () => setShowAccountSearch(true), + [] + ) + const closeAccountSearch = React.useCallback( + () => setShowAccountSearch(false), [] ) + const _onSearchTextChanged = React.useCallback( + (e: React.ChangeEvent) => + setAccountSearchText(e.target.value), + [] + ) + const onSearchTextChanged = useDebouncedCallback(_onSearchTextChanged, 250) const onSelectAccountFromSearch = React.useCallback( (account: BraveWallet.AccountInfo) => { @@ -252,237 +518,109 @@ export const DepositFundsScreen = (props: Props) => { [closeAccountSearch, resetCopyState] ) - const nextStep = React.useCallback(() => { - if (!isNextStepEnabled || !selectedAssetNetwork) { - return - } - onShowDepositAddress(true) - }, [isNextStepEnabled, selectedAssetNetwork, onShowDepositAddress]) - - const goBackToSelectAssets = React.useCallback(() => { - onShowDepositAddress(false) - resetCopyState() - setSelectedAsset(undefined) - }, [onShowDepositAddress, resetCopyState]) - const copyAddressToClipboard = React.useCallback(() => { copyToClipboard(selectedAccount?.address || '') }, [copyToClipboard, selectedAccount?.address]) - const onCopyKeyPress = React.useCallback(({ key }: React.KeyboardEvent) => { - // Invoke for space or enter, just like a regular input or button - if ([' ', 'Enter'].includes(key)) { - copyAddressToClipboard() - } - }, [copyAddressToClipboard]) - - // effects - React.useEffect(() => { - let subscribed = true - - // fetch selected Account QR Code - selectedAccount?.address && generateQRCode(selectedAccount.address).then(qr => { - if (subscribed) { - setQRCode(qr) + const onCopyKeyPress = React.useCallback( + ({ key }: React.KeyboardEvent) => { + // Invoke for space or enter, just like a regular input or button + if ([' ', 'Enter'].includes(key)) { + copyAddressToClipboard() } - }) - - // cleanup - return () => { - subscribed = false - } - }, [selectedAccount?.address]) - - - // sync default selected account with selected asset - React.useEffect(() => { - if ( - selectedAsset && - selectedAssetNetwork && - // asset is selected & account is available - accountsForSelectedAssetNetwork.length && - // needs to change accounts to one with correct network - selectedAccount?.accountId?.coin !== selectedAsset.coin - ) { - setSelectedAccount(accountsForSelectedAssetNetwork[0]) - } - }, [ - selectedAsset, - selectedAssetNetwork, - accountsForSelectedAssetNetwork, - selectedAccount?.accountId?.coin - ]) - - React.useEffect(() => { - if (!showDepositAddress) { - if (isCopied) { - resetCopyState() - } - - if (showAccountSearch) { - closeAccountSearch() - } - } - }, [showDepositAddress, showAccountSearch, isCopied, closeAccountSearch, resetCopyState]) - - React.useEffect(() => { - // reset search field on list update - if (fullAssetsList && !tokenId) { - setSearchValue('') - } - }, [fullAssetsList, tokenId]) + }, + [copyAddressToClipboard] + ) // render + if (!selectedDepositAssetId) { + return + } + + /* Creates wallet Account if needed for deposit */ + if (needsAccount && selectedAssetNetwork) { + return ( + { + resetCopyState() + dispatch(WalletActions.selectOnRampAssetId(undefined)) + history.push(WalletRoutes.DepositFundsPage) + }} + /> + ) + } + + if (showAccountSearch) { + return ( + + + + + + + + ) + } + return ( - <> - {/* Asset Selection */} - {!showDepositAddress && ( - <> - - - - - - - - - {fullAssetsList.length ? ( - ( - - dispatch( - WalletActions.selectOnRampAssetId(getAssetIdKey(asset)) - ) - } - /> - )} - /> - ) : ( - - - + + + {depositTitleText} + + {selectedAssetNetwork && ( + + {getLocale('braveWalletDepositOnlySendOnXNetwork').replace( + '$1', + selectedAssetNetwork.chainName )} - - - - - - - - - )} - - {/* Creates wallet Account if needed for deposit */} - {needsAccount && showDepositAddress && selectedAssetNetwork && ( - + )} + + + + + - )} - - {/* Address display & Account selection/search */} - {!needsAccount && showDepositAddress && ( - <> - {!showAccountSearch && ( - - - {depositTitleText} - - {selectedAssetNetwork && ( - - {getLocale('braveWalletDepositOnlySendOnXNetwork').replace( - '$1', - selectedAssetNetwork.chainName - )} - - )} - - - - - - - - - - - - - - Address: - - - {selectedAccount?.address} - - - - {isCopied && } - - - )} - - {showAccountSearch && ( - - - - - - - - )} - - )} - + + + + + {isLoadingQrCode ? : } + + + + Address: + + + {selectedAccount?.address} + + + + {isCopied && } + + ) } diff --git a/components/brave_wallet_ui/page/screens/fund-wallet/fund-wallet.tsx b/components/brave_wallet_ui/page/screens/fund-wallet/fund-wallet.tsx index 05c32cd983c6..8502a56547a5 100644 --- a/components/brave_wallet_ui/page/screens/fund-wallet/fund-wallet.tsx +++ b/components/brave_wallet_ui/page/screens/fund-wallet/fund-wallet.tsx @@ -101,11 +101,22 @@ function getItemSize(index: number): number { return itemSize } +const getItemKey = (i: number, data: BraveWallet.BlockchainToken[]) => + getAssetIdKey(data[i]) + interface Props { isAndroid?: boolean } export const FundWalletScreen = ({ isAndroid }: Props) => { + // redux + const dispatch = useDispatch() + + // clear selected asset on page mount + React.useEffect(() => { + dispatch(WalletActions.selectOnRampAssetId(undefined)) + }, []) + // render return ( @@ -113,10 +124,9 @@ export const FundWalletScreen = ({ isAndroid }: Props) => { - + - ) } @@ -186,9 +196,21 @@ function AssetSelection({ isAndroid }: Props) { const allBuyAssetOptions = options?.allAssetOptions || [] // refs - const listItemRefs = React.useRef< - Record | undefined> - >({}) + const listItemRefs = React.useRef | null>(null) + + const getRefsMap = React.useCallback( + function () { + if (!listItemRefs.current) { + // Initialize the Map on first usage. + listItemRefs.current = new Map() + } + return listItemRefs.current + }, + [listItemRefs] + ) // custom hooks const scrollIntoView = useScrollIntoView() @@ -202,22 +224,29 @@ function AssetSelection({ isAndroid }: Props) { [] ) - const renderToken: RenderTokenFunc = React.useCallback( - ({ item: { asset } }) => { - const assetId = getAssetIdKey(asset) - const ref = React.createRef() - listItemRefs.current[assetId] = ref - return ( - dispatch(WalletActions.selectOnRampAssetId(assetId))} - /> - )}, - [selectedCurrency, listItemRefs] - ) + const renderToken: RenderTokenFunc = + React.useCallback( + ({ item: asset }) => { + const assetId = getAssetIdKey(asset) + return ( + { + const refs = getRefsMap() + if (node) { + refs.set(assetId, node) + } else { + refs.delete(assetId) + } + }} + selectedCurrency={selectedCurrency} + key={assetId} + token={asset} + onClick={() => dispatch(WalletActions.selectOnRampAssetId(assetId))} + /> + ) + }, + [selectedCurrency, getRefsMap, dispatch] + ) // memos & computed const assetsForFilteredNetwork = React.useMemo(() => { @@ -232,18 +261,18 @@ function AssetSelection({ isAndroid }: Props) { ({ chainId }) => selectedNetworkFilter.chainId === chainId ) - return assets.map((asset) => ({ asset, assetBalance: '1' })) + return assets }, [selectedNetworkFilter.chainId, allBuyAssetOptions]) const assetListSearchResults = React.useMemo(() => { if (searchValue === '') { return assetsForFilteredNetwork } - return assetsForFilteredNetwork.filter((item) => { + return assetsForFilteredNetwork.filter((asset) => { const searchValueLower = searchValue.toLowerCase() return ( - item.asset.name.toLowerCase().startsWith(searchValueLower) || - item.asset.symbol.toLowerCase().startsWith(searchValueLower) + asset.name.toLowerCase().startsWith(searchValueLower) || + asset.symbol.toLowerCase().startsWith(searchValueLower) ) }) }, [searchValue, assetsForFilteredNetwork]) @@ -252,6 +281,7 @@ function AssetSelection({ isAndroid }: Props) { () => allBuyAssetOptions?.length ? ( { // scroll selected item into view if (selectedOnRampAssetId) { - const ref = listItemRefs.current[selectedOnRampAssetId] - if (ref?.current) { - scrollIntoView(ref.current, true) + const ref = getRefsMap().get(selectedOnRampAssetId) + if (ref) { + scrollIntoView(ref, true) } } - }, [selectedOnRampAssetId, listItemRefs, scrollIntoView]) + }, [selectedOnRampAssetId, getRefsMap, scrollIntoView]) // render if (showFiatSelection) { diff --git a/components/brave_wallet_ui/page/screens/swap/components/swap/swap-container/swap-container.style.ts b/components/brave_wallet_ui/page/screens/swap/components/swap/swap-container/swap-container.style.ts index 15f17614d057..ab40bf50ce22 100644 --- a/components/brave_wallet_ui/page/screens/swap/components/swap/swap-container/swap-container.style.ts +++ b/components/brave_wallet_ui/page/screens/swap/components/swap/swap-container/swap-container.style.ts @@ -16,7 +16,7 @@ export const Wrapper = styled(StyledDiv)` left: 0; right: 0; bottom: 0; - overflow-y: scroll; + overflow-y: auto; position: absolute; background-color: ${p => p.theme.color.background01}; @media (prefers-color-scheme: dark) { diff --git a/components/brave_wallet_ui/page/screens/swap/hooks/useDebouncedCallback.ts b/components/brave_wallet_ui/page/screens/swap/hooks/useDebouncedCallback.ts index 36d276407021..0b5b92777569 100644 --- a/components/brave_wallet_ui/page/screens/swap/hooks/useDebouncedCallback.ts +++ b/components/brave_wallet_ui/page/screens/swap/hooks/useDebouncedCallback.ts @@ -5,8 +5,8 @@ import { useEffect, useRef, useCallback } from 'react' -export function useDebouncedCallback ( - callback: (...args: A) => Promise, +export function useDebouncedCallback( + callback: ((...args: A) => Promise) | ((...args: A) => void), wait: number ) { // Track args & timeout handle between calls diff --git a/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts b/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts index 3c3fdbdcc3e1..c59acd1fa53d 100644 --- a/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts +++ b/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts @@ -56,7 +56,6 @@ export const mockTransactionInfo: SerializableTransactionInfo = { submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '0x0d8775f648430679a709e98d2b0cb6250d2887ef' } @@ -104,7 +103,6 @@ export const mockSolanaTransactionInfo: SerializableTransactionInfo = { submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: undefined } @@ -114,7 +112,6 @@ export const mockFilSendTransaction: FileCoinTransactionInfo = { createdTime: { microseconds: BigInt(new Date().getUTCMilliseconds()) }, fromAddress: mockFilecoinAccount.address, fromAccountId: mockFilecoinAccount.accountId, - groupId: undefined, id: 'fil-send-tx', originInfo: undefined, submittedTime: { microseconds: BigInt(new Date().getUTCMilliseconds()) }, diff --git a/components/brave_wallet_ui/stories/wallet-extension-panels.tsx b/components/brave_wallet_ui/stories/wallet-extension-panels.tsx index ac944aada234..fe8e360cbccc 100644 --- a/components/brave_wallet_ui/stories/wallet-extension-panels.tsx +++ b/components/brave_wallet_ui/stories/wallet-extension-panels.tsx @@ -149,7 +149,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: (Date.now() * 1000) - 1000 * 60 * 5 }, confirmedTime: { microseconds: (Date.now() * 1000) - 1000 * 60 * 5 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' }, { @@ -186,7 +185,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' }, { @@ -223,7 +221,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' }, { @@ -260,7 +257,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' }, { @@ -297,7 +293,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' } ], @@ -336,7 +331,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' }, { @@ -373,7 +367,6 @@ const transactionDummyData: SerializableTransactionInfo[][] = [ submittedTime: { microseconds: 0 }, confirmedTime: { microseconds: 0 }, originInfo: mockOriginInfo, - groupId: undefined, effectiveRecipient: '' } ] diff --git a/components/brave_wallet_ui/stories/wrappers/wallet-page-story-wrapper.tsx b/components/brave_wallet_ui/stories/wrappers/wallet-page-story-wrapper.tsx index a81a69551b48..9f8a8257a49d 100644 --- a/components/brave_wallet_ui/stories/wrappers/wallet-page-story-wrapper.tsx +++ b/components/brave_wallet_ui/stories/wrappers/wallet-page-story-wrapper.tsx @@ -36,6 +36,7 @@ export interface WalletPageStoryProps { accountTabStateOverride?: Partial uiStateOverride?: Partial apiOverrides?: WalletApiDataOverrides + initialRoute?: WalletRoutes } const mockedProxy = getMockedAPIProxy() @@ -47,6 +48,7 @@ export const WalletPageStory: React.FC { // redux const store = React.useMemo(() => { @@ -72,7 +74,9 @@ export const WalletPageStory: React.FC + diff --git a/components/brave_wallet_ui/utils/routes-utils.ts b/components/brave_wallet_ui/utils/routes-utils.ts index 47539ddcbf5e..00495a2a3585 100644 --- a/components/brave_wallet_ui/utils/routes-utils.ts +++ b/components/brave_wallet_ui/utils/routes-utils.ts @@ -66,3 +66,26 @@ export const makeFundWalletPurchaseOptionsRoute = ( currencyCode ).replace(':buyAmount', buyAmount) } + +export const makeDepositFundsRoute = ( + searchText?: string, + chainId?: string, + coinType?: string +) => { + const params = new URLSearchParams() + if (searchText) { + params?.append('search', searchText) + } + if (chainId) { + params?.append('chainId', chainId) + } + if (coinType) { + params?.append('coinType', coinType) + } + + const paramsString = params ? params.toString() : undefined + + return `${WalletRoutes.DepositFundsPage}${ + paramsString ? `?${paramsString}` : '' + }` +} diff --git a/components/ipfs/ipfs_service.cc b/components/ipfs/ipfs_service.cc index 413640ab9ae0..035d49bb445f 100644 --- a/components/ipfs/ipfs_service.cc +++ b/components/ipfs/ipfs_service.cc @@ -9,11 +9,9 @@ #include #include "base/files/file_util.h" -#include "base/json/json_reader.h" #include "base/memory/raw_ref.h" #include "base/rand_util.h" #include "base/strings/strcat.h" -#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/task/thread_pool.h" #include "brave/base/process/process_launcher.h" @@ -31,14 +29,10 @@ #include "components/grit/brave_components_strings.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" -#include "components/user_prefs/user_prefs.h" #include "net/base/url_util.h" #include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_status_code.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" -#include "services/network/public/mojom/url_response_head.mojom.h" #include "url/gurl.h" #if BUILDFLAG(ENABLE_IPFS_LOCAL_NODE) @@ -48,7 +42,6 @@ #include "brave/components/ipfs/keys/ipns_keys_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/service_process_host.h" -#include "content/public/browser/storage_partition.h" #endif namespace { @@ -100,6 +93,11 @@ base::flat_map GetHeaders(const GURL& url) { {net::HttpRequestHeaders::kOrigin, url::Origin::Create(url).Serialize()}}; } +absl::optional ConvertPlainStringToJsonArray( + const std::string& json) { + return base::StrCat({"[\"", json, "\"]"}); +} + } // namespace namespace ipfs { @@ -125,10 +123,12 @@ IpfsService::IpfsService( file_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), - ipfs_p3a_(this, prefs), - weak_factory_(this) { + ipfs_p3a_(this, prefs) { DCHECK(!user_data_dir.empty()); + api_request_helper_ = std::make_unique( + GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory); + // Return early since g_brave_browser_process and ipfs_client_updater are not // available in unit tests. if (ipfs_client_updater_) { @@ -144,7 +144,7 @@ IpfsService::IpfsService( ipfs_dns_resolver_subscription_ = ipfs_dns_resolver_->AddObserver(base::BindRepeating( - &IpfsService::OnDnsConfigChanged, base::Unretained(this))); + &IpfsService::OnDnsConfigChanged, weak_factory_.GetWeakPtr())); } IpfsService::~IpfsService() { @@ -231,9 +231,9 @@ void IpfsService::LaunchIfNotRunning(const base::FilePath& executable_path) { .Pass()); ipfs_service_.set_disconnect_handler( - base::BindOnce(&IpfsService::OnIpfsCrashed, base::Unretained(this))); + base::BindOnce(&IpfsService::OnIpfsCrashed, weak_factory_.GetWeakPtr())); ipfs_service_->SetCrashHandler(base::BindOnce( - &IpfsService::OnIpfsDaemonCrashed, base::Unretained(this))); + &IpfsService::OnIpfsDaemonCrashed, weak_factory_.GetWeakPtr())); auto config = mojom::IpfsConfig::New( executable_path, GetConfigFilePath(), GetDataPath(), @@ -242,7 +242,7 @@ void IpfsService::LaunchIfNotRunning(const base::FilePath& executable_path) { ipfs_service_->Launch( std::move(config), - base::BindOnce(&IpfsService::OnIpfsLaunched, base::Unretained(this))); + base::BindOnce(&IpfsService::OnIpfsLaunched, weak_factory_.GetWeakPtr())); #endif } @@ -250,7 +250,7 @@ void IpfsService::RestartDaemon() { if (!IsDaemonLaunched()) return; auto launch_callback = - base::BindOnce(&IpfsService::LaunchDaemon, base::Unretained(this)); + base::BindOnce(&IpfsService::LaunchDaemon, weak_factory_.GetWeakPtr()); ShutdownDaemon(base::BindOnce( [](base::OnceCallback launch_callback, const bool success) { @@ -428,16 +428,10 @@ void IpfsService::AddPin(const std::vector& cids, } gurl = net::AppendQueryParameter(gurl, "recursive", recursive ? "true" : "false"); - - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnPinAddResult, base::Unretained(this), - cids.size(), recursive, iter, std::move(callback)), + base::BindOnce(&IpfsService::OnPinAddResult, weak_factory_.GetWeakPtr(), + cids.size(), recursive, std::move(callback)), GetHeaders(gurl), api_request_helper::APIRequestOptions{.timeout = base::Minutes(2)}); } @@ -454,15 +448,10 @@ void IpfsService::RemovePin(const std::vector& cids, gurl = net::AppendQueryParameter(gurl, kArgQueryParam, cid); } - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnPinRemoveResult, base::Unretained(this), - iter, std::move(callback)), + base::BindOnce(&IpfsService::OnPinRemoveResult, + weak_factory_.GetWeakPtr(), std::move(callback)), GetHeaders(gurl)); } @@ -550,14 +539,10 @@ void IpfsService::GetPins(const absl::optional>& cids, gurl = net::AppendQueryParameter(gurl, "type", type); gurl = net::AppendQueryParameter(gurl, "quiet", quiet ? "true" : "false"); - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnGetPinsResult, base::Unretained(this), - iter, std::move(callback)), + base::BindOnce(&IpfsService::OnGetPinsResult, weak_factory_.GetWeakPtr(), + std::move(callback)), GetHeaders(gurl)); } @@ -697,15 +682,10 @@ void IpfsService::GetConnectedPeers(GetConnectedPeersCallback callback, return; } auto gurl = server_endpoint_.Resolve(kSwarmPeersPath); - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnGetConnectedPeers, base::Unretained(this), - iter, std::move(callback), + base::BindOnce(&IpfsService::OnGetConnectedPeers, + weak_factory_.GetWeakPtr(), std::move(callback), retries.value_or(kPeersDefaultRetries)), GetHeaders(gurl)); } @@ -719,12 +699,10 @@ base::TimeDelta IpfsService::CalculatePeersRetryTime() { } void IpfsService::OnGetConnectedPeers( - APIRequestList::iterator iter, GetConnectedPeersCallback callback, int retry_number, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); bool success = response.Is2XXResponseCode(); last_peers_retry_value_for_test_ = retry_number; @@ -762,26 +740,18 @@ void IpfsService::GetAddressesConfig(GetAddressesConfigCallback callback) { GURL gurl = net::AppendQueryParameter(server_endpoint_.Resolve(kConfigPath), kArgQueryParam, kAddressesField); - - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnGetAddressesConfig, base::Unretained(this), - iter, std::move(callback)), + base::BindOnce(&IpfsService::OnGetAddressesConfig, + weak_factory_.GetWeakPtr(), std::move(callback)), GetHeaders(gurl)); } void IpfsService::OnGetAddressesConfig( - APIRequestList::iterator iter, GetAddressesConfigCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); bool success = response.Is2XXResponseCode(); - requests_list_.erase(iter); ipfs::AddressesConfig addresses_config; if (!success) { @@ -935,23 +905,16 @@ void IpfsService::GetRepoStats(GetRepoStatsCallback callback) { net::AppendQueryParameter(server_endpoint_.Resolve(ipfs::kRepoStatsPath), ipfs::kRepoStatsHumanReadableParamName, ipfs::kRepoStatsHumanReadableParamValue); - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnRepoStats, base::Unretained(this), iter, + base::BindOnce(&IpfsService::OnRepoStats, weak_factory_.GetWeakPtr(), std::move(callback)), GetHeaders(gurl)); } -void IpfsService::OnRepoStats(APIRequestList::iterator iter, - GetRepoStatsCallback callback, +void IpfsService::OnRepoStats(GetRepoStatsCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); bool success = response.Is2XXResponseCode(); @@ -975,23 +938,16 @@ void IpfsService::GetNodeInfo(GetNodeInfoCallback callback) { GURL gurl = server_endpoint_.Resolve(ipfs::kNodeInfoPath); - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnNodeInfo, base::Unretained(this), iter, + base::BindOnce(&IpfsService::OnNodeInfo, weak_factory_.GetWeakPtr(), std::move(callback)), GetHeaders(gurl)); } -void IpfsService::OnNodeInfo(APIRequestList::iterator iter, - GetNodeInfoCallback callback, +void IpfsService::OnNodeInfo(GetNodeInfoCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); bool success = response.Is2XXResponseCode(); @@ -1015,24 +971,17 @@ void IpfsService::RunGarbageCollection(GarbageCollectionCallback callback) { GURL gurl = server_endpoint_.Resolve(ipfs::kGarbageCollectionPath); - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request( + api_request_helper_->Request( "POST", gurl, std::string(), std::string(), - base::BindOnce(&IpfsService::OnGarbageCollection, base::Unretained(this), - iter, std::move(callback)), + base::BindOnce(&IpfsService::OnGarbageCollection, + weak_factory_.GetWeakPtr(), std::move(callback)), GetHeaders(gurl)); } void IpfsService::OnGarbageCollection( - APIRequestList::iterator iter, GarbageCollectionCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); bool success = response.Is2XXResponseCode(); if (!success) { @@ -1048,21 +997,14 @@ void IpfsService::OnGarbageCollection( } void IpfsService::PreWarmShareableLink(const GURL& url) { - auto url_loader = std::make_unique( - GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); - - auto iter = - requests_list_.insert(requests_list_.begin(), std::move(url_loader)); - iter->get()->Request("HEAD", url, std::string(), std::string(), - base::BindOnce(&IpfsService::OnPreWarmComplete, - base::Unretained(this), iter), - GetHeaders(url)); + api_request_helper_->Request("HEAD", url, std::string(), std::string(), + base::BindOnce(&IpfsService::OnPreWarmComplete, + weak_factory_.GetWeakPtr()), + GetHeaders(url)); } void IpfsService::OnPreWarmComplete( - APIRequestList::iterator iter, - api_request_helper::APIRequestResult response) { - requests_list_.erase(iter); + [[maybe_unused]] api_request_helper::APIRequestResult response) { if (prewarm_callback_for_testing_) std::move(prewarm_callback_for_testing_).Run(); } @@ -1082,11 +1024,9 @@ void IpfsService::OnPreWarmComplete( // } //} void IpfsService::OnGetPinsResult( - APIRequestList::iterator iter, GetPinsCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to get pins, response_code = " << response_code; @@ -1108,11 +1048,9 @@ void IpfsService::OnGetPinsResult( void IpfsService::OnPinAddResult( size_t cids_count_in_request, bool recursive, - APIRequestList::iterator iter, AddPinCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to add pin, response_code = " << response_code; @@ -1140,11 +1078,9 @@ void IpfsService::OnPinAddResult( } void IpfsService::OnPinRemoveResult( - APIRequestList::iterator iter, RemovePinCallback callback, api_request_helper::APIRequestResult response) { int response_code = response.response_code(); - requests_list_.erase(iter); if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to remove pin, response_code = " << response_code; @@ -1169,39 +1105,34 @@ void IpfsService::ValidateGateway(const GURL& url, BoolCallback callback) { std::string path = "/ipfs/"; path += kGatewayValidationCID; replacements.SetPathStr(path); - GURL validationUrl = url.ReplaceComponents(replacements); - auto url_loader = CreateURLLoader(validationUrl, "GET"); - auto iter = url_loaders_.insert(url_loaders_.begin(), std::move(url_loader)); - iter->get()->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_.get(), + GURL validation_url = url.ReplaceComponents(replacements); + + auto conversion_callback = base::BindOnce(&ConvertPlainStringToJsonArray); + api_request_helper_->Request( + "GET", validation_url, "", "", base::BindOnce(&IpfsService::OnGatewayValidationComplete, - base::Unretained(this), iter, std::move(callback), url)); + weak_factory_.GetWeakPtr(), std::move(callback), url), + {}, {}, std::move(conversion_callback)); } void IpfsService::OnGatewayValidationComplete( - SimpleURLLoaderList::iterator iter, BoolCallback callback, const GURL& initial_url, - std::unique_ptr response_body) { - auto* url_loader = iter->get(); - auto final_url = url_loader->GetFinalURL(); - - int error_code = url_loader->NetError(); - int response_code = -1; - if (url_loader->ResponseInfo() && url_loader->ResponseInfo()->headers) - response_code = url_loader->ResponseInfo()->headers->response_code(); - url_loaders_.erase(iter); + api_request_helper::APIRequestResult response) const { + int response_code = response.response_code(); - bool success = (error_code == net::OK && response_code == net::HTTP_OK); + bool success = response.Is2XXResponseCode(); if (!success) { - VLOG(1) << "Fail to validate gateway, error_code = " << error_code - << " response_code = " << response_code; + VLOG(1) << "Fail to validate gateway, response_code = " << response_code; } + std::string error; if (success) { - std::string valid_host = base::StringPrintf( + const auto final_url = response.final_url(); + const std::string valid_host = base::StringPrintf( "%s.ipfs.%s", kGatewayValidationCID, initial_url.host().c_str()); - success = (*response_body == kGatewayValidationResult) && + success = (response.body() == + ConvertPlainStringToJsonArray(kGatewayValidationResult)) && (initial_url.host() != final_url.host()) && (initial_url.scheme() == final_url.scheme()) && (final_url.host() == valid_host); diff --git a/components/ipfs/ipfs_service.h b/components/ipfs/ipfs_service.h index bf325737f78f..4649809b8a1a 100644 --- a/components/ipfs/ipfs_service.h +++ b/components/ipfs/ipfs_service.h @@ -49,7 +49,6 @@ class SequencedTaskRunner; namespace network { class SharedURLLoaderFactory; -class SimpleURLLoader; } // namespace network class PrefRegistrySimple; @@ -191,10 +190,6 @@ class IpfsService : public KeyedService, void OnConfigLoaded(GetConfigCallback, const std::pair&); private: - using APIRequestList = - std::list>; - using SimpleURLLoaderList = - std::list>; FRIEND_TEST_ALL_PREFIXES(IpfsServiceBrowserTest, UpdaterRegistrationSuccessLaunch); FRIEND_TEST_ALL_PREFIXES(IpfsServiceBrowserTest, @@ -221,16 +216,13 @@ class IpfsService : public KeyedService, NodeCallback callback); // Local pins - void OnGetPinsResult(APIRequestList::iterator iter, - GetPinsCallback callback, + void OnGetPinsResult(GetPinsCallback callback, api_request_helper::APIRequestResult response); void OnPinAddResult(size_t cids_count_in_request, bool recursive, - APIRequestList::iterator iter, AddPinCallback callback, api_request_helper::APIRequestResult response); - void OnPinRemoveResult(APIRequestList::iterator iter, - RemovePinCallback callback, + void OnPinRemoveResult(RemovePinCallback callback, api_request_helper::APIRequestResult response); void OnRemovePinCli(BoolCallback callback, std::set cids, @@ -238,29 +230,23 @@ class IpfsService : public KeyedService, #endif base::TimeDelta CalculatePeersRetryTime(); - void OnGatewayValidationComplete(SimpleURLLoaderList::iterator iter, - BoolCallback callback, - const GURL& initial_url, - std::unique_ptr response_body); + void OnGatewayValidationComplete( + BoolCallback callback, + const GURL& initial_url, + api_request_helper::APIRequestResult response) const; - void OnGetConnectedPeers(APIRequestList::iterator iter, - GetConnectedPeersCallback, + void OnGetConnectedPeers(GetConnectedPeersCallback, int retries, api_request_helper::APIRequestResult response); - void OnGetAddressesConfig(APIRequestList::iterator iter, - GetAddressesConfigCallback callback, + void OnGetAddressesConfig(GetAddressesConfigCallback callback, api_request_helper::APIRequestResult response); - void OnRepoStats(APIRequestList::iterator iter, - GetRepoStatsCallback callback, + void OnRepoStats(GetRepoStatsCallback callback, api_request_helper::APIRequestResult response); - void OnNodeInfo(APIRequestList::iterator iter, - GetNodeInfoCallback callback, + void OnNodeInfo(GetNodeInfoCallback callback, api_request_helper::APIRequestResult response); - void OnGarbageCollection(APIRequestList::iterator iter, - GarbageCollectionCallback callback, + void OnGarbageCollection(GarbageCollectionCallback callback, api_request_helper::APIRequestResult responsey); - void OnPreWarmComplete(APIRequestList::iterator iter, - api_request_helper::APIRequestResult response); + void OnPreWarmComplete(api_request_helper::APIRequestResult response); std::string GetStorageSize(); void OnDnsConfigChanged(absl::optional dns_server); @@ -275,8 +261,7 @@ class IpfsService : public KeyedService, const raw_ptr prefs_ = nullptr; scoped_refptr url_loader_factory_; - APIRequestList requests_list_; - SimpleURLLoaderList url_loaders_; + std::unique_ptr api_request_helper_; BlobContextGetterFactoryPtr blob_context_getter_factory_; base::queue pending_launch_callbacks_; @@ -303,7 +288,7 @@ class IpfsService : public KeyedService, #endif scoped_refptr file_task_runner_; IpfsP3A ipfs_p3a_; - base::WeakPtrFactory weak_factory_; + base::WeakPtrFactory weak_factory_{this}; }; } // namespace ipfs diff --git a/components/p3a/metric_names.h b/components/p3a/metric_names.h index c65ad8cf4c18..ef50f3b957d9 100644 --- a/components/p3a/metric_names.h +++ b/components/p3a/metric_names.h @@ -205,6 +205,7 @@ constexpr inline auto kCollectedSlowHistograms = "Brave.Sync.EnabledTypes", "Brave.Sync.SyncedObjectsCount", "Brave.Today.UsageMonthly", + "Brave.Toolbar.ForwardNavigationAction", "Brave.Wallet.UsageMonthly" }); diff --git a/components/resources/rewards_strings.grdp b/components/resources/rewards_strings.grdp index 9b64cd7566b8..df574248407e 100644 --- a/components/resources/rewards_strings.grdp +++ b/components/resources/rewards_strings.grdp @@ -445,6 +445,9 @@ Send + + Send with $1 + Use Web3 Wallet diff --git a/components/sidebar/constants.h b/components/sidebar/constants.h index 6df1fb8b3507..bde581a26b0d 100644 --- a/components/sidebar/constants.h +++ b/components/sidebar/constants.h @@ -13,7 +13,7 @@ constexpr char kSidebarItemTypeKey[] = "type"; constexpr char kSidebarItemBuiltInItemTypeKey[] = "built_in_item_type"; constexpr char kSidebarItemTitleKey[] = "title"; constexpr char kSidebarItemOpenInPanelKey[] = "open_in_panel"; -constexpr int kDefaultSidePanelWidth = 480; +constexpr int kDefaultSidePanelWidth = 320; // list is provided from chrome layer. constexpr char kBraveTalkURL[] = "https://talk.brave.com/widget"; diff --git a/components/skus/browser/rs/lib/src/sdk/credentials/mod.rs b/components/skus/browser/rs/lib/src/sdk/credentials/mod.rs index 2f945a7448b8..84cb5052be4c 100644 --- a/components/skus/browser/rs/lib/src/sdk/credentials/mod.rs +++ b/components/skus/browser/rs/lib/src/sdk/credentials/mod.rs @@ -2,7 +2,7 @@ mod fetch; mod present; use chrono::Utc; -use tracing::instrument; +use tracing::{error, instrument}; use crate::errors::{InternalError, SkusError}; use crate::models::*; @@ -49,9 +49,10 @@ where if let Some(expires_at) = expires_at { // attempt to refresh credentials if we're within 5 days of expiry if Utc::now().naive_utc() > (expires_at - chrono::Duration::days(5)) { + error!("Within 5 days of expiry; refreshing order credentials."); let refreshed = self.refresh_order_credentials(order_id).await; if refreshed.is_err() { - continue; + error!("Error refreshing order credentials."); } } } @@ -70,6 +71,8 @@ where active, })); } + + error!("No matches found for credential summary."); } CredentialType::SingleUse => { let wrapped_creds = self.client.get_single_use_item_creds(&item.id).await?; @@ -101,23 +104,24 @@ where if let Some(expires_at) = expires_at { // attempt to refresh credentials if we're within 5 days of expiry if Utc::now().naive_utc() > (expires_at - chrono::Duration::days(5)) { + error!("Within 5 days of expiry; refreshing order credentials."); let refreshed = self.refresh_order_credentials(order_id).await; if refreshed.is_err() { - continue; + error!("Error refreshing order credentials."); } } } - let active = matches!( - self.matching_time_limited_credential(&item.id).await, - Ok(Some(_)) - ); - - return Ok(Some(CredentialSummary { - order, - remaining_credential_count: 1, - expires_at, - active, - })); + + if let Ok(Some(_)) = self.matching_time_limited_credential(&item.id).await { + return Ok(Some(CredentialSummary { + order, + remaining_credential_count: 1, + expires_at, + active: true, + })); + } + + error!("No matches found for credential summary."); } }; } // for diff --git a/components/skus/browser/skus_service_unittest.cc b/components/skus/browser/skus_service_unittest.cc index c584011efb08..08f410115dca 100644 --- a/components/skus/browser/skus_service_unittest.cc +++ b/components/skus/browser/skus_service_unittest.cc @@ -29,194 +29,172 @@ const char kTestVpnOrders[] = R"( { "items": { - "424bc657-633f-4fcc-bd8e-92a51c8e4971": + "93e2e06b-bb69-47e9-8dff-270b53938157": { "creds": [ + "pvGUZncSMLz5v4eW5oJVe9NEYpE09HDryFTBDjDE3XrLpwZh2Xwi/l3tU6UBdeGHNZw0KEFluZQPRZt0PRiTPIH0A8NnXy52Al1gQF9D5fmZ4Do1awJM2NWrdCh6GlUP", + "FXg607b9IPPe6k65y1A76g7qV6+wMNZAlwvMarZ+fAbIGv4wJb/sneWcHmN9rvDJ7wyeupGPj08po6ymIln9ESX8ODU/9Ng0zhBiG0o4mGYj5uwT6QVDSocBekwmOdIG", + "PvtiOx8Nt300OFozXLZqcJAxTzuq+wxOiAKi44r0x33aoCZcOmJ7qZrWUGfECB4Ueq4XP9F8tarNaZqd8MbxUWQxVIiwR1FoffZqVV03uoXfCIgD+DOAtNg52oW1pusF" + ], + "item_id": "93e2e06b-bb69-47e9-8dff-270b53938157", + "state": "ActiveCredentials", + "type": "time-limited-v2", + "unblinded_creds": + [ + { + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "nfjj7YWTOJ3Ct7kAB2eyBzdhxOg1RKItWOgJdMCkj33ksrTE2FMvGjI12gu2UdgGJP1d2QTzHKh7k/aIIaUV+F4vjG/FpaWS0VShkPk2I8ODI2aNgcEUDHC0zeRIpjkg" + }, + { + "spent": false, + "unblinded_cred": "c6UZLQYdkgUK0pqvyvawr1sDqGrJ/d67hWl3J69+f0qlTTreNNjrYZyw+IzXSHimTgYrzF7gRc5sG2nv+d8Nrqxaf7P4f/yPL5f7XnaM6C2BVxS+P7Maz1+Ibkk2mbwA" + } + ], + "valid_from": "2022-06-19T19:31:40", + "valid_to": "{year}-06-20T19:31:40" + }, { - "expires_at": "2022-05-13T00:00:00", - "issued_at": "2022-05-11T00:00:00", - "item_id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", - "token": "q7gunpfaAVvnoP6uvnLaZHLivyky1VmF4NqryK3Hx+dq67LNtA3KLx8251Pc5tLH" + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "Lw06d7LyqIAhjKr7HynJ2+8vGJNBknzYkhsAHBV592q650mzswoUa1ob6s6ALH3mFCgAhELFPrDM2BAue003okp0aMSgDtZOVSYm1i1HYyEBeCms8dqsEJ0PZom+Kd8W" + }, + { + "spent": false, + "unblinded_cred": "UuDemArRSL/WW1tLIePymNWGVPDYrj0dDzKqBrHkIvWuGImfJW/7mpQa9VwU4Ac1J/bnIPsuS8lnXogfLfcfxIwtYK6KSj42zCu7s4E4xQuwKi1wlprliKRVv6SnwZlX" + } + ], + "valid_from": "2022-06-20T19:31:40", + "valid_to": "{year}-06-21T19:31:40" }, { - "expires_at": "2022-05-13T00:00:00", - "issued_at": "2022-05-11T00:00:00", - "item_id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", - "token": "8N35H12HrUElmWl9owqKOxg8/rHrtCPSuOHpjU4gv4xNcZUMrjnStqWo2NgwIhpZ" + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "48XvG94GrosHjnU38gsfF7maMwFOkPmUjxRBo/VU3tzUkUdue0LEZQIgeKlO2MKujKToDAn5GWP9RAl5sKiLpX62pTXLpS7fQ41CdyREBU9Jdc2hf0eRTdJsbdm6mL9Z" + }, + { + "spent": false, + "unblinded_cred": "hSHfygeq++tl3SgkhygbjyvNTWdnMjJlt51To6KOb19SlgJ5kUMZEvsw6H1/e0MV+KyFBeJTd24ED6kzbac2ugDi8aXnBoucVyeJa3XBtSvqcAJhRu8VABv6IfxW81AT" + } + ], + "valid_from": "2022-06-21T19:31:40", + "valid_to": "{year}-06-22T19:31:40" } - ], - "item_id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", - "type": "time-limited" + ] }, - "463b9cca-8609-4255-a29e-0f2ac475af3b": + "424bc657-633f-4fcc-bd8e-92a51c8e4971": { "creds": + [ + "pvGUZncSMLz5v4eW5oJVe9NEYpE09HDryFTBDjDE3XrLpwZh2Xwi/l3tU6UBdeGHNZw0KEFluZQPRZt0PRiTPIH0A8NnXy52Al1gQF9D5fmZ4Do1awJM2NWrdCh6GlUP", + "FXg607b9IPPe6k65y1A76g7qV6+wMNZAlwvMarZ+fAbIGv4wJb/sneWcHmN9rvDJ7wyeupGPj08po6ymIln9ESX8ODU/9Ng0zhBiG0o4mGYj5uwT6QVDSocBekwmOdIG", + "u3aByl/KnY/yuVPhWWDodB0w7uhmS0RW0V3n8WHkn0JlBTcCgBp0HIzLxqgdzKWOEFrIL7nLYul/qjLbf2HBKj08n1JkDpzLLy2NmizBrP13pzMeZ8PBED3ArU9jfvoB" + ], + "item_id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", + "state": "ActiveCredentials", + "type": "time-limited-v2", + "unblinded_creds": [ { - "expires_at": "2021-07-19T00:00:00", - "issued_at": "2021-07-18T00:00:00", - "item_id": "463b9cca-8609-4255-a29e-0f2ac475af3b", - "token": "8N35H12HrUElmWl9owqKOxg8/rHrtCPSuOHpjU4gv4xNcZUMrjnStqWo2NgwIhpZ" + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "nfjj7YWTOJ3Ct7kAB2eyBzdhxOg1RKItWOgJdMCkj33ksrTE2FMvGjI12gu2UdgGJP1d2QTzHKh7k/aIIaUV+F4vjG/FpaWS0VShkPk2I8ODI2aNgcEUDHC0zeRIpjkg" + }, + { + "spent": false, + "unblinded_cred": "c6UZLQYdkgUK0pqvyvawr1sDqGrJ/d67hWl3J69+f0qlTTreNNjrYZyw+IzXSHimTgYrzF7gRc5sG2nv+d8Nrqxaf7P4f/yPL5f7XnaM6C2BVxS+P7Maz1+Ibkk2mbwA" + } + ], + "valid_from": "2022-06-19T19:31:40", + "valid_to": "2022-06-20T19:31:40" }, { - "expires_at": "2022-06-14T00:00:00", - "issued_at": "2022-06-13T00:00:00", - "item_id": "463b9cca-8609-4255-a29e-0f2ac475af3b", - "token": "q7gunpfaAVvnoP6uvnLaZHLivyky1VmF4NqryK3Hx+dq67LNtA3KLx8251Pc5tLH" + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "Lw06d7LyqIAhjKr7HynJ2+8vGJNBknzYkhsAHBV592q650mzswoUa1ob6s6ALH3mFCgAhELFPrDM2BAue003okp0aMSgDtZOVSYm1i1HYyEBeCms8dqsEJ0PZom+Kd8W" + }, + { + "spent": false, + "unblinded_cred": "UuDemArRSL/WW1tLIePymNWGVPDYrj0dDzKqBrHkIvWuGImfJW/7mpQa9VwU4Ac1J/bnIPsuS8lnXogfLfcfxIwtYK6KSj42zCu7s4E4xQuwKi1wlprliKRVv6SnwZlX" + } + ], + "valid_from": "2022-06-20T19:31:40", + "valid_to": "2022-06-21T19:31:40" }, { - "expires_at": "2021-07-19T00:00:00", - "issued_at": "2021-07-18T00:00:00", - "item_id": "463b9cca-8609-4255-a29e-0f2ac475af3b", - "token": "8N35H12HrUElmWl9owqKOxg8/rHrtCPSuOHpjU4gv4xNcZUMrjnStqWo2NgwIhpZ" + "issuer_id": "8dc09cb0-a69b-4695-8288-7bf716615385", + "unblinded_creds": + [ + { + "spent": false, + "unblinded_cred": "48XvG94GrosHjnU38gsfF7maMwFOkPmUjxRBo/VU3tzUkUdue0LEZQIgeKlO2MKujKToDAn5GWP9RAl5sKiLpX62pTXLpS7fQ41CdyREBU9Jdc2hf0eRTdJsbdm6mL9Z" + }, + { + "spent": false, + "unblinded_cred": "hSHfygeq++tl3SgkhygbjyvNTWdnMjJlt51To6KOb19SlgJ5kUMZEvsw6H1/e0MV+KyFBeJTd24ED6kzbac2ugDi8aXnBoucVyeJa3XBtSvqcAJhRu8VABv6IfxW81AT" + } + ], + "valid_from": "2022-06-21T19:31:40", + "valid_to": "2022-06-22T19:31:40" } - ], - "item_id": "463b9cca-8609-4255-a29e-0f2ac475af3b", - "type": "time-limited" + ] } } }, "orders": { - "33a8231a-7c69-47bd-a061-2045b9b1b890": - { - "created_at": "2022-06-13T13:05:17.144570", - "currency": "USD", - "expires_at": "2022-06-14T14:36:02.579641", - "id": "33a8231a-7c69-47bd-a061-2045b9b1b890", - "items": - [ - { - "created_at": "2022-06-13T14:35:28.313786", - "credential_type": "time-limited", - "currency": "USD", - "description": "Brave VPN", - "id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", - "location": "{domain}", - "order_id": "33a8231a-7c69-47bd-a061-2045b9b1b890", - "price": 9.99, - "quantity": 1, - "sku": "brave-vpn-premium", - "subtotal": 9.99, - "updated_at": "2022-06-13T14:35:28.313786" - }, - { - "created_at": "2022-06-13T13:05:17.144570", - "credential_type": "time-limited", - "currency": "USD", - "description": "Brave VPN", - "id": "55555555-633f-4fcc-bd8e-92a51c8e4971", - "location": "{domain}", - "order_id": "33a8231a-7c69-47bd-a061-2045b9b1b890", - "price": 9.99, - "quantity": 1, - "sku": "brave-vpn-premium", - "subtotal": 9.99, - "updated_at": "2022-06-13T13:05:17.144570" - } - ], - "last_paid_at": "2022-06-13T13:06:49.466083", - "location": "{domain}", - "merchant_id": "brave.com", - "metadata": - { - "num_intervals": null, - "num_per_interval": null, - "payment_processor": null, - "stripe_checkout_session_id": null - }, - "status": "paid", - "total_price": 9.99, - "updated_at": "2022-06-13T13:06:49.465232" - }, - "7df66bcb-921e-424b-ad53-37885948fb34": - { - "created_at": "2022-06-13T14:35:28.313786", - "currency": "USD", - "expires_at": "{year}-06-14T14:36:02.579641", - "id": "7df66bcb-921e-424b-ad53-37885948fb34", - "items": - [ - { - "created_at": "2022-06-13T14:35:28.313786", - "credential_type": "time-limited", - "currency": "USD", - "description": "Brave VPN", - "id": "463b9cca-8609-4255-a29e-0f2ac475af3", - "location": "{domain}", - "order_id": "7df66bcb-921e-424b-ad53-37885948fb34", - "price": 9.99, - "quantity": 1, - "sku": "brave-vpn-premium", - "subtotal": 9.99, - "updated_at": "2022-06-13T14:35:28.313786" - }, - { - "created_at": "2022-06-13T14:35:28.313786", - "credential_type": "time-limited", - "currency": "USD", - "description": "Brave VPN", - "id": "00000000-633f-4fcc-bd8e-92a51c8e4971", - "location": "{domain}", - "order_id": "7df66bcb-921e-424b-ad53-37885948fb34", - "price": 9.99, - "quantity": 1, - "sku": "brave-vpn-premium", - "subtotal": 9.99, - "updated_at": "2022-06-13T14:35:28.313786" - } - ], - "last_paid_at": "2022-06-13T14:36:02.579656", - "location": "{domain}", - "merchant_id": "brave.com", - "metadata": - { - "num_intervals": null, - "num_per_interval": null, - "payment_processor": null, - "stripe_checkout_session_id": null - }, - "status": "paid", - "total_price": 9.99, - "updated_at": "2022-06-13T14:36:02.577786" - }, - "2ba8231a-7c69-47bd-a061-2045b9b1b890": + "ed5a53c1-9555-4b9c-81df-485521ab8161": { - "created_at": "2022-06-13T13:05:17.144570", + "created_at": "2023-02-16T22:48:02.804478", "currency": "USD", - "expires_at": "{year}-06-13T13:06:49.466071", - "id": "2ba8231a-7c69-47bd-a061-2045b9b1b890", + "expires_at": "{year}-09-16T23:56:52.839338", + "id": "ed5a53c1-9555-4b9c-81df-485521ab8161", "items": [ { - "created_at": "2022-06-13T13:05:17.144570", - "credential_type": "time-limited", + "created_at": "2023-02-16T22:48:02.804478", + "credential_type": "time-limited-v2", "currency": "USD", - "description": "Brave VPN", - "id": "424bc657-633f-4fcc-bd8e-92a51c8e4971", + "description": "brave-vpn-premium", + "id": "93e2e06b-bb69-47e9-8dff-270b53938157", "location": "{domain}", - "order_id": "2ba8231a-7c69-47bd-a061-2045b9b1b890", + "order_id": "ed5a53c1-9555-4b9c-81df-485521ab8161", "price": 9.99, "quantity": 1, "sku": "brave-vpn-premium", "subtotal": 9.99, - "updated_at": "2022-06-13T13:05:17.144570" + "updated_at": "2023-02-16T22:48:02.804478" } ], - "last_paid_at": "2022-06-13T13:06:49.466083", + "last_paid_at": "2023-08-16T23:56:52.839338", "location": "{domain}", "merchant_id": "brave.com", "metadata": { - "num_intervals": null, - "num_per_interval": null, - "payment_processor": null, - "stripe_checkout_session_id": null + "num_intervals": 33, + "num_per_interval": 2, + "payment_processor": "stripe", + "stripe_checkout_session_id": "cs_live_b1l4e7azojxIWro3UYp3Bx8dO1CMb9IRbAC1x6qaKAtsMH9KPO77quKGoM" }, "status": "paid", "total_price": 9.99, - "updated_at": "2022-06-13T13:06:49.465232" + "updated_at": "2023-08-16T23:56:52.837510" } }, "promotions": null, @@ -309,7 +287,7 @@ TEST_F(SkusServiceTestUnitTest, CredentialSummarySuccess) { auto* order = credentials_json->GetDict().Find("order"); EXPECT_TRUE(order); EXPECT_EQ(*order, GetExpectedCreds(testing_payload, - "7df66bcb-921e-424b-ad53-37885948fb34")); + "ed5a53c1-9555-4b9c-81df-485521ab8161")); } TEST_F(SkusServiceTestUnitTest, CredentialSummaryFailed) { @@ -321,7 +299,7 @@ TEST_F(SkusServiceTestUnitTest, CredentialSummaryFailed) { auto* orders = payload_value->GetDict().FindDict("orders"); EXPECT_TRUE(orders); // Remove unexpired creds - orders->Remove("7df66bcb-921e-424b-ad53-37885948fb34"); + orders->Remove("ed5a53c1-9555-4b9c-81df-485521ab8161"); std::string json; base::JSONWriter::WriteWithOptions( payload_value.value(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); diff --git a/components/speedreader/common/features.cc b/components/speedreader/common/features.cc index 288598b875e0..1ba5ca98db23 100644 --- a/components/speedreader/common/features.cc +++ b/components/speedreader/common/features.cc @@ -18,4 +18,7 @@ BASE_FEATURE(kSpeedreaderFeature, const base::FeatureParam kSpeedreaderMinOutLengthParam{ &kSpeedreaderFeature, "min_out_length", 1000}; +const base::FeatureParam kSpeedreaderTTS{&kSpeedreaderFeature, "tts", + false}; + } // namespace speedreader diff --git a/components/speedreader/common/features.h b/components/speedreader/common/features.h index c7b82e100c36..1e846ce9c365 100644 --- a/components/speedreader/common/features.h +++ b/components/speedreader/common/features.h @@ -12,6 +12,7 @@ namespace speedreader { BASE_DECLARE_FEATURE(kSpeedreaderFeature); extern const base::FeatureParam kSpeedreaderMinOutLengthParam; +extern const base ::FeatureParam kSpeedreaderTTS; } // namespace speedreader #endif // BRAVE_COMPONENTS_SPEEDREADER_COMMON_FEATURES_H_ diff --git a/components/speedreader/common/speedreader.mojom b/components/speedreader/common/speedreader.mojom index 221122645719..64df9a0aa510 100644 --- a/components/speedreader/common/speedreader.mojom +++ b/components/speedreader/common/speedreader.mojom @@ -8,4 +8,7 @@ module speedreader.mojom; interface SpeedreaderHost { // The browser handler for clicking on the "Show original page" link. OnShowOriginalPage(); + + // The browser handler for clicking on the "Play/Pause" button. + OnTtsPlayPause(int32 paragraph_index); }; diff --git a/components/speedreader/renderer/speedreader_js_handler.cc b/components/speedreader/renderer/speedreader_js_handler.cc index 6bfde1338e1c..84e7722f4dcf 100644 --- a/components/speedreader/renderer/speedreader_js_handler.cc +++ b/components/speedreader/renderer/speedreader_js_handler.cc @@ -55,13 +55,15 @@ void SpeedreaderJSHandler::Install( v8::Local speedreader_value = global->Get(context, gin::StringToV8(isolate, kSpeedreader)) .ToLocalChecked(); - if (!speedreader_value->IsUndefined()) + if (!speedreader_value->IsUndefined()) { return; + } gin::Handle handler = gin::CreateHandle(isolate, new SpeedreaderJSHandler(std::move(owner))); - if (handler.IsEmpty()) + if (handler.IsEmpty()) { return; + } v8::PropertyDescriptor desc(handler.ToV8(), false); desc.set_configurable(false); @@ -75,13 +77,15 @@ void SpeedreaderJSHandler::Install( gin::ObjectTemplateBuilder SpeedreaderJSHandler::GetObjectTemplateBuilder( v8::Isolate* isolate) { return gin::Wrappable::GetObjectTemplateBuilder(isolate) - .SetMethod("showOriginalPage", &SpeedreaderJSHandler::ShowOriginalPage); + .SetMethod("showOriginalPage", &SpeedreaderJSHandler::ShowOriginalPage) + .SetMethod("ttsPlayPause", &SpeedreaderJSHandler::TtsPlayPause); } void SpeedreaderJSHandler::ShowOriginalPage(v8::Isolate* isolate) { DCHECK(isolate); - if (!owner_) + if (!owner_) { return; + } mojo::AssociatedRemote speedreader_host; owner_->render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( @@ -92,4 +96,20 @@ void SpeedreaderJSHandler::ShowOriginalPage(v8::Isolate* isolate) { } } +void SpeedreaderJSHandler::TtsPlayPause(v8::Isolate* isolate, + int paragraph_index) { + DCHECK(isolate); + if (!owner_) { + return; + } + + mojo::AssociatedRemote speedreader_host; + owner_->render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( + &speedreader_host); + + if (speedreader_host.is_bound()) { + speedreader_host->OnTtsPlayPause(paragraph_index); + } +} + } // namespace speedreader diff --git a/components/speedreader/renderer/speedreader_js_handler.h b/components/speedreader/renderer/speedreader_js_handler.h index adb190bfaeeb..c2d78ea3137b 100644 --- a/components/speedreader/renderer/speedreader_js_handler.h +++ b/components/speedreader/renderer/speedreader_js_handler.h @@ -36,6 +36,8 @@ class SpeedreaderJSHandler final : public gin::Wrappable { // A function to be called from JS void ShowOriginalPage(v8::Isolate* isolate); + void TtsPlayPause(v8::Isolate* isolate, int index); + base::WeakPtr owner_; }; diff --git a/components/speedreader/resources/panel/components/lists/index.tsx b/components/speedreader/resources/panel/components/lists/index.tsx index c1c3f3d5245f..183d27cb4693 100644 --- a/components/speedreader/resources/panel/components/lists/index.tsx +++ b/components/speedreader/resources/panel/components/lists/index.tsx @@ -36,7 +36,7 @@ const mainButtonsOptions = [ id: 'tts', type: MainButtonType.TextToSpeech, iconName: 'headphones', - hidden: true, // TODO(boocmp): Enable in future PR. + hidden: !loadTimeData.getBoolean('ttsEnabled'), title: getLocale('braveReaderModeTextToSpeech') }, { diff --git a/components/speedreader/resources/panel/components/theme-control/style.ts b/components/speedreader/resources/panel/components/theme-control/style.ts index d18277ebd62d..644c4086e2d9 100644 --- a/components/speedreader/resources/panel/components/theme-control/style.ts +++ b/components/speedreader/resources/panel/components/theme-control/style.ts @@ -56,6 +56,18 @@ export const Box = styled.div` align-self: center; justify-self: center; color: #5F5CF1; + position: relative; + + &:before { + content: ''; + position: absolute; + width: 8px; + height: 8px; + left: 4px; + top: 4px; + border-radius: 100px; + background-color: white; + } } .is-light { background-color: #FFFFFF; } diff --git a/components/speedreader/resources/panel/components/tts-control/index.tsx b/components/speedreader/resources/panel/components/tts-control/index.tsx index 9389cb9b9ab9..38d653b9aa0e 100644 --- a/components/speedreader/resources/panel/components/tts-control/index.tsx +++ b/components/speedreader/resources/panel/components/tts-control/index.tsx @@ -20,15 +20,22 @@ interface TtsControlProps { function TtsControl(props: TtsControlProps) { const [voices, setVoices] = React.useState(speechSynthesis.getVoices()) - speechSynthesis.onvoiceschanged = () => { - setVoices(speechSynthesis.getVoices()) - } - const [playbackState, setPlaybackState] = React.useState(PlaybackState.kStopped) - getToolbarAPI().dataHandler.getPlaybackState().then(res => setPlaybackState(res.playbackState)) - getToolbarAPI().eventsRouter.setPlaybackState.addListener((state: PlaybackState) => { - setPlaybackState(state) - }) + + React.useEffect(() => { + const updateVoices = () => { + setVoices(speechSynthesis.getVoices().filter((v) => { + return navigator.languages.find((l) => { return v.lang.startsWith(l) }) + })) + } + speechSynthesis.onvoiceschanged = updateVoices + window.onlanguagechange = updateVoices + + getToolbarAPI().dataHandler.getPlaybackState().then(res => setPlaybackState(res.playbackState)) + getToolbarAPI().eventsRouter.setPlaybackState.addListener((state: PlaybackState) => { + setPlaybackState(state) + }) + }, []) return ( diff --git a/components/speedreader/resources/speedreader-desktop.css b/components/speedreader/resources/speedreader-desktop.css index 5dd8e3305c70..8520ed96a811 100644 --- a/components/speedreader/resources/speedreader-desktop.css +++ b/components/speedreader/resources/speedreader-desktop.css @@ -548,6 +548,7 @@ iframe { html, html[data-theme='light'] { + position: relative !important; scrollbar-gutter: stable; background-color: var(--background-color); @@ -644,4 +645,79 @@ html[data-font-family='dyslexic'] { html[data-content-style='text-only'] img { display: none !important; +} + +.tts-highlighted, +.tts-highlighted * { + position: relative; +} + +@keyframes tts-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +.tts-highlighted::after { + animation: tts-fade-in 0.75s; + + content: ''; + background: linear-gradient(90deg, rgba(168, 168, 168, 0.5), rgba(128, 128, 128, 0.1)); + mix-blend-mode: luminosity; + + background-size: 100%; + border-radius: 10px; + + position: absolute; + + left: -1.5rem; + right: -1.5rem; + top: -0.5rem; + bottom: -0.5rem; + + pointer-events: none; +} + +[tts-paragraph-index] { + position: relative; +} + +[tts-paragraph-index]:hover>.tts-paragraph-player { + opacity: 1; +} + +.tts-paragraph-player { + opacity: 0; + position: absolute; + + left: -4rem; + width: 4rem; + display: flex; + flex-direction: column; + flex-wrap: wrap; + overflow: hidden; + height: max(2rem, 100%); + flex: none; + gap: 1rem; +} + +.tts-paragraph-player-button { + -webkit-mask-position: left; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 2rem; + + position: relative; + display: inline-block; + background-color: var(--summary-text-color); + cursor: pointer; + width: 4rem; + height: 2rem; +} + +.tts-play-icon { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='none'%3E%3Cpath fill='%23687485' fill-rule='evenodd' d='M7.105 5.62a.2.2 0 0 0-.305.17v12.42a.2.2 0 0 0 .305.17l10.092-6.21a.2.2 0 0 0 0-.34L7.105 5.62ZM5.2 5.79c0-1.409 1.544-2.271 2.743-1.533l10.092 6.21a1.8 1.8 0 0 1 0 3.066l-10.092 6.21C6.744 20.481 5.2 19.62 5.2 18.21V5.79Z' clip-rule='evenodd'/%3E%3C/svg%3E"); } \ No newline at end of file diff --git a/components/speedreader/resources/speedreader-desktop.js b/components/speedreader/resources/speedreader-desktop.js index 953e4a9b18d9..1bbc62694b79 100644 --- a/components/speedreader/resources/speedreader-desktop.js +++ b/components/speedreader/resources/speedreader-desktop.js @@ -9,6 +9,14 @@ const readTimeDivId = 'da24e4ef-db57-4b9f-9fa5-548924fc9c32' const metaDataDivId = '3bafd2b4-a87d-4471-8134-7a9cca092000' const contentDivId = '7c08a417-bf02-4241-a55e-ad5b8dc88f69' +const defaultSpeedreaderData = { + showOriginalLinkText: 'View original', + playButtonTitle: 'Play/Pause', + averageWordsPerMinute: 265, + minutesText: 'min. read', + ttsEnabled: false, +} + const $ = (id) => { return document.getElementById(id) } @@ -41,18 +49,103 @@ const calculateReadtime = () => { readTimeDiv.innerText = minutes + ' ' + speedreaderData.minutesText } -const defaultSpeedreaderData = { - showOriginalLinkText: 'View original', - averageWordsPerMinute: 265, - minutesText: 'min. read', +const getTextContent = (element) => { + if (!element) { + return null + } + const text = element.innerText.replace(/\n|\r +/g, ' ').trim() + if (text.length > 0) { + return text + } + return null } -const extractText = () => { +const initTextToSpeak = () => { + if (navigator.userAgentData.mobile || !speedreaderData.ttsEnabled) { + return + } + + const textTags = ['P', 'DIV', 'MAIN', 'ARTICLE', 'H1', 'H2', 'H3', 'H4', 'H5', 'STRONG', 'BLOCKQUOTE'] + + const extractParagraphs = (node) => { + let paragraphs = [] + if (!node) { + return paragraphs + } + for (const child of node.children) { + if (textTags.indexOf(child.tagName) >= 0) { + const childParagraphs = extractParagraphs(child) + if (childParagraphs.length == 0) { + paragraphs.push(child) + } else { + paragraphs = paragraphs.concat(childParagraphs) + } + } + } + return paragraphs + } + + let textToSpeak = 0 + + const makeParagraph = (elem) => { + if (!elem) { + return false + } + const text = getTextContent(elem) + if (text) { + elem.setAttribute('tts-paragraph-index', textToSpeak++) + return true + } + return false + } + + const createPlayer = (p) => { + const player = document.createElement('span') + player.classList.add('tts-paragraph-player') + const playButton = document.createElement('span') + playButton.classList.add('tts-paragraph-player-button', 'tts-play-icon') + playButton.title = speedreaderData.playButtonTitle + playButton.onclick = (ev) => { + window.speedreader.ttsPlayPause(parseInt(p.getAttribute('tts-paragraph-index'))) + } + player.insertAdjacentElement('afterbegin', playButton) + p.insertAdjacentElement('afterbegin', player) + } + + makeParagraph($(metaDataDivId)?.querySelector('.title')) + + extractParagraphs($(contentDivId)).forEach((p) => { + if (makeParagraph(p)) { + createPlayer(p) + } + }) +} + +const extractTextToSpeak = () => { + const paragraphs = Array.from(document.querySelectorAll('[tts-paragraph-index]')) + .map((p) => { + return getTextContent(p) + }) + return { title: document.title, author: $(metaDataDivId)?.querySelector('.author')?.textContent, desciption: $(metaDataDivId)?.querySelector('.subhead')?.textContent, - content: $(contentDivId)?.innerText.replace(/\n|\r +/g, ' ') + paragraphs: paragraphs + } +} + +const highlightText = (ttsParagraphIndex, charIndex, length) => { + document.querySelectorAll('.tts-highlighted').forEach((e) => { + if (e.getAttribute('tts-paragraph-index') != ttsParagraphIndex) { + e.classList.remove('tts-highlighted') + } + }) + + const paragraph = document.querySelector( + '[tts-paragraph-index="' + ttsParagraphIndex + '"]') + if (paragraph) { + paragraph.classList.add('tts-highlighted') } } @@ -62,6 +155,7 @@ const main = () => { initShowOriginalLink() calculateReadtime() + initTextToSpeak() } (() => { main() })() diff --git a/components/speedreader/tts_player.cc b/components/speedreader/tts_player.cc index dc42cacc90ce..1011d14289cb 100644 --- a/components/speedreader/tts_player.cc +++ b/components/speedreader/tts_player.cc @@ -8,10 +8,15 @@ #include #include +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/tts_controller.h" #include "content/public/browser/tts_utterance.h" #include "content/public/browser/web_contents.h" +namespace { +constexpr const char kParagraphsKey[] = "paragraphs"; +} + namespace speedreader { TtsPlayer::TtsPlayer() = default; @@ -76,21 +81,30 @@ bool TtsPlayer::Controller::IsPlaying() const { return tts->IsSpeaking(); } -bool TtsPlayer::Controller::IsPlayingRequestedWebContents() const { +bool TtsPlayer::Controller::IsPlayingRequestedWebContents( + absl::optional paragraph_index) const { + if (paragraph_index.has_value() && paragraph_index != paragraph_index_) { + return false; + } return playing_web_contents_ == request_web_contents_; } -void TtsPlayer::Controller::Play() { +void TtsPlayer::Controller::Play(absl::optional paragraph_index) { DCHECK(request_web_contents_); if (IsPlayingRequestedWebContents()) { Observe(playing_web_contents_); + if (paragraph_index.has_value() && paragraph_index != paragraph_index_) { + paragraph_index_ = paragraph_index.value(); + reading_start_position_ = 0; + reading_position_ = 0; + } Resume(true); } else { Stop(); TtsPlayer::GetInstance()->delegate_->RequestReadingContent( request_web_contents_, base::BindOnce(&Controller::OnContentReady, base::Unretained(this), - request_web_contents_)); + request_web_contents_, std::move(paragraph_index))); } } @@ -98,7 +112,7 @@ void TtsPlayer::Controller::Pause() { if (IsPlayingRequestedWebContents()) { auto* tts = content::TtsController::GetInstance(); reading_start_position_ = - std::min(static_cast(reading_content_.size()), + std::min(static_cast(GetParagraphToRead().size()), reading_start_position_ + reading_position_); reading_position_ = 0; tts->Stop(); @@ -115,29 +129,46 @@ void TtsPlayer::Controller::Resume() { void TtsPlayer::Controller::Stop() { auto* tts = content::TtsController::GetInstance(); tts->Stop(); + + paragraph_index_ = -1; reading_position_ = 0; reading_start_position_ = 0; + for (auto& o : owner_->observers_) { + o.OnReadingProgress(playing_web_contents_, paragraph_index_, 0, 0); + } playing_web_contents_ = nullptr; Observe(nullptr); } void TtsPlayer::Controller::Forward() { - reading_start_position_ = - std::min(static_cast(reading_content_.size()), - reading_start_position_ + reading_position_ + 32); + if (!HasNextParagraph()) { + return; + } + ++paragraph_index_; + reading_start_position_ = 0; reading_position_ = 0; if (IsPlaying()) { Resume(true); + } else { + for (auto& o : owner_->observers_) { + o.OnReadingProgress(request_web_contents_, paragraph_index_, 0, 0); + } } } void TtsPlayer::Controller::Rewind() { - reading_start_position_ = - std::max(0, reading_start_position_ + reading_position_ - 32); + if (paragraph_index_ > 0) { + --paragraph_index_; + } + reading_start_position_ = 0; reading_position_ = 0; if (IsPlaying()) { Resume(true); + } else { + for (auto& o : owner_->observers_) { + o.OnReadingProgress(request_web_contents_, paragraph_index_, 0, 0); + } } } @@ -151,7 +182,7 @@ void TtsPlayer::Controller::Resume(bool recreate_utterance) { reading_start_position_ += reading_position_; reading_position_ = 0; - utterance->SetText(reading_content_.substr(reading_start_position_)); + utterance->SetText(GetParagraphToRead().substr(reading_start_position_)); utterance->SetShouldClearQueue(true); utterance->SetEventDelegate(this); utterance->SetVoiceName(current_voice_); @@ -162,8 +193,38 @@ void TtsPlayer::Controller::Resume(bool recreate_utterance) { } } +bool TtsPlayer::Controller::HasNextParagraph() { + if (!reading_content_.is_dict()) { + return false; + } + const auto* content = reading_content_.GetDict().FindList(kParagraphsKey); + if (!content) { + return false; + } + return paragraph_index_ + 1 < static_cast(content->size()); +} + +const std::string& TtsPlayer::Controller::GetParagraphToRead() { + if (!reading_content_.is_dict()) { + return base::EmptyString(); + } + const auto* content = reading_content_.GetDict().FindList(kParagraphsKey); + if (!content) { + return base::EmptyString(); + } + if (0 <= paragraph_index_ && + paragraph_index_ < static_cast(content->size())) { + return (*content)[paragraph_index_].GetString(); + } + return base::EmptyString(); +} + void TtsPlayer::Controller::DidStartNavigation( content::NavigationHandle* handle) { + if (!handle->IsInPrimaryMainFrame() || + handle->GetReloadType() == content::ReloadType::NONE) { + return; + } Stop(); } @@ -180,21 +241,32 @@ void TtsPlayer::Controller::OnTtsEvent(content::TtsUtterance* utterance, case content::TtsEventType::TTS_EVENT_WORD: reading_position_ = char_index; for (auto& o : owner_->observers_) { - o.OnReadingProgress(playing_web_contents_, "content", char_index, + o.OnReadingProgress(playing_web_contents_, paragraph_index_, char_index, length); } break; - case content::TtsEventType::TTS_EVENT_PAUSE: case content::TtsEventType::TTS_EVENT_ERROR: case content::TtsEventType::TTS_EVENT_INTERRUPTED: case content::TtsEventType::TTS_EVENT_CANCELLED: - case content::TtsEventType::TTS_EVENT_END: + case content::TtsEventType::TTS_EVENT_PAUSE: for (auto& o : owner_->observers_) { o.OnReadingStop(playing_web_contents_); } - if (event_type == content::TtsEventType::TTS_EVENT_END) { - reading_position_ = 0; - reading_start_position_ = 0; + break; + case content::TtsEventType::TTS_EVENT_END: + reading_position_ = 0; + reading_start_position_ = 0; + + if (HasNextParagraph()) { + ++paragraph_index_; + Resume(true); + } else { + paragraph_index_ = -1; + for (auto& o : owner_->observers_) { + o.OnReadingProgress(playing_web_contents_, paragraph_index_, + char_index, length); + o.OnReadingStop(playing_web_contents_); + } } break; case content::TtsEventType::TTS_EVENT_RESUME: @@ -210,15 +282,16 @@ void TtsPlayer::Controller::OnTtsEvent(content::TtsUtterance* utterance, } void TtsPlayer::Controller::OnContentReady(content::WebContents* web_contents, - bool success, - std::string content) { - if (!success || web_contents != request_web_contents_) { + absl::optional paragraph_index, + base::Value content) { + if (!content.is_dict() || web_contents != request_web_contents_) { return; } playing_web_contents_ = web_contents; Observe(playing_web_contents_); + paragraph_index_ = paragraph_index.value_or(0); reading_content_ = std::move(content); reading_position_ = 0; reading_start_position_ = 0; diff --git a/components/speedreader/tts_player.h b/components/speedreader/tts_player.h index b2795a9ed1aa..d72acabf7dcd 100644 --- a/components/speedreader/tts_player.h +++ b/components/speedreader/tts_player.h @@ -14,8 +14,10 @@ #include "base/memory/raw_ptr.h" #include "base/memory/singleton.h" #include "base/observer_list.h" +#include "base/values.h" #include "content/public/browser/tts_utterance.h" #include "content/public/browser/web_contents_observer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class WebContents; @@ -34,8 +36,7 @@ class TtsPlayer { virtual void RequestReadingContent( content::WebContents* web_contents, - base::OnceCallback - result_cb) = 0; + base::OnceCallback result_cb) = 0; }; class Observer : public base::CheckedObserver { @@ -43,7 +44,7 @@ class TtsPlayer { virtual void OnReadingStart(content::WebContents* web_contents) {} virtual void OnReadingStop(content::WebContents* web_contents) {} virtual void OnReadingProgress(content::WebContents* web_contents, - const std::string& element_id, + int tts_order, int char_index, int length) {} @@ -58,9 +59,10 @@ class TtsPlayer { public content::UtteranceEventDelegate { public: bool IsPlaying() const; - bool IsPlayingRequestedWebContents() const; + bool IsPlayingRequestedWebContents( + absl::optional paragraph_index = absl::nullopt) const; - void Play(); + void Play(absl::optional paragraph_index = absl::nullopt); void Pause(); void Resume(); void Stop(); @@ -77,6 +79,9 @@ class TtsPlayer { void Resume(bool recreate_utterance); + bool HasNextParagraph(); + const std::string& GetParagraphToRead(); + // content::WebContentsObserver: void DidStartNavigation(content::NavigationHandle* handle) override; void WebContentsDestroyed() override; @@ -89,17 +94,18 @@ class TtsPlayer { const std::string& error_message) override; void OnContentReady(content::WebContents* web_contents, - bool success, - std::string content); + absl::optional paragraph_index, + base::Value content); raw_ptr owner_ = nullptr; raw_ptr playing_web_contents_ = nullptr; raw_ptr request_web_contents_ = nullptr; + int paragraph_index_ = -1; int reading_start_position_ = 0; int reading_position_ = 0; - std::string reading_content_; + base::Value reading_content_; double current_speed_ = 1.0; std::string current_voice_; diff --git a/components/tor/onion_location_navigation_throttle.cc b/components/tor/onion_location_navigation_throttle.cc index 16fd2cf28e4e..f980df108305 100644 --- a/components/tor/onion_location_navigation_throttle.cc +++ b/components/tor/onion_location_navigation_throttle.cc @@ -16,6 +16,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "net/base/url_util.h" #include "net/http/http_response_headers.h" @@ -28,10 +29,12 @@ bool GetOnionLocation(const net::HttpResponseHeaders* headers, DCHECK(onion_location); onion_location->clear(); - std::string name = "onion-location"; + constexpr const char kHeaderName[] = "onion-location"; - if (!headers || !headers->EnumerateHeader(nullptr, name, onion_location)) + if (!headers || + !headers->EnumerateHeader(nullptr, kHeaderName, onion_location)) { return false; + } return true; } @@ -86,7 +89,9 @@ OnionLocationNavigationThrottle::WillProcessResponse() { } // If user prefers opening it automatically if (pref_service_->GetBoolean(prefs::kAutoOnionRedirect)) { - delegate_->OpenInTorWindow(navigation_handle()->GetWebContents(), url); + delegate_->OpenInTorWindow(navigation_handle()->GetWebContents(), url, + false); + return content::NavigationThrottle::BLOCK_RESPONSE; } else { OnionLocationTabHelper::SetOnionLocation( navigation_handle()->GetWebContents(), url); @@ -106,8 +111,8 @@ OnionLocationNavigationThrottle::WillStartRequest() { GURL url = navigation_handle()->GetURL(); if (url.SchemeIsHTTPOrHTTPS() && net::IsOnion(url)) { if (pref_service_->GetBoolean(prefs::kAutoOnionRedirect)) { - delegate_->OpenInTorWindow(navigation_handle()->GetWebContents(), - std::move(url)); + delegate_->OpenInTorWindow(navigation_handle()->GetWebContents(), url, + navigation_handle()->IsRendererInitiated()); } else { OnionLocationTabHelper::SetOnionLocation( navigation_handle()->GetWebContents(), url); diff --git a/components/tor/onion_location_navigation_throttle.h b/components/tor/onion_location_navigation_throttle.h index c1ece75e9fdd..2e39c658c4b3 100644 --- a/components/tor/onion_location_navigation_throttle.h +++ b/components/tor/onion_location_navigation_throttle.h @@ -26,7 +26,8 @@ class OnionLocationNavigationThrottle : public content::NavigationThrottle { public: virtual ~Delegate() = default; virtual void OpenInTorWindow(content::WebContents* context, - GURL onion_location) = 0; + const GURL& onion_location, + bool renderer_initiated) = 0; }; static std::unique_ptr MaybeCreateThrottleFor(content::NavigationHandle* navigation_handle, diff --git a/ios/browser/api/brave_wallet/brave_wallet_solana_utils.mm b/ios/browser/api/brave_wallet/brave_wallet_solana_utils.mm index 7bfd53af5aba..67ec0ca165ba 100644 --- a/ios/browser/api/brave_wallet/brave_wallet_solana_utils.mm +++ b/ios/browser/api/brave_wallet/brave_wallet_solana_utils.mm @@ -8,6 +8,7 @@ #include #include #include "base/strings/sys_string_conversions.h" +#include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/solana_utils.h" @implementation NSData (Base58) diff --git a/package-lock.json b/package-lock.json index 11f17dd2ead2..0d66a8d84eb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "brave-core", - "version": "1.60.22", + "version": "1.60.37", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "brave-core", - "version": "1.60.22", + "version": "1.60.37", "license": "MPL-2.0", "dependencies": { "@brave/brave-ui": "0.40.4", diff --git a/package.json b/package.json index 4181c30df866..a75c822b2bcc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "brave-core", - "version": "1.60.22", + "version": "1.60.37", "description": "Brave Core is a set of changes, APIs and scripts used for customizing Chromium to make Brave.", "main": "index.js", "scripts": { @@ -267,7 +267,7 @@ "projects": { "chrome": { "dir": "src", - "tag": "117.0.5938.62", + "tag": "117.0.5938.88", "repository": { "url": "https://github.com/brave/chromium" } diff --git a/patches/chrome-VERSION.patch b/patches/chrome-VERSION.patch index a5bf9c0c00f3..4ae05943b2d5 100644 --- a/patches/chrome-VERSION.patch +++ b/patches/chrome-VERSION.patch @@ -1,12 +1,12 @@ diff --git a/chrome/VERSION b/chrome/VERSION -index 4fa29de75bcf550773e826499c620a7600a9e990..27af5c71667a12a33e2b3984cb96c0de02a093fb 100644 +index 174a9a8ce8bb1c2c42461414b91b87b785ad9dc1..250924a95791a903f78c2fd7e04f71bb77473b35 100644 --- a/chrome/VERSION +++ b/chrome/VERSION @@ -1,4 +1,4 @@ MAJOR=117 -MINOR=0 -BUILD=5938 --PATCH=62 +-PATCH=88 +MINOR=1 +BUILD=60 -+PATCH=22 ++PATCH=37 diff --git a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch index a259ea136bf3..0f3e95359412 100644 --- a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch +++ b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc -index 9e9372e1b3b7fb80c7cc218a817dc9eedcd52ef5..1ec1d9d958d35bb512115a9e1b5e5f7bcd336c1c 100644 +index b3e367b9ea823627814922f39d5d14ced31413b3..6a771e3d5a51a4d83925699ef1fdb8b51f9ddbcc 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc -@@ -2136,6 +2136,7 @@ void RenderViewContextMenu::AppendSearchProvider() { +@@ -2137,6 +2137,7 @@ void RenderViewContextMenu::AppendSearchProvider() { selection_navigation_url_ = match.destination_url; if (!selection_navigation_url_.is_valid()) return; diff --git a/test/BUILD.gn b/test/BUILD.gn index f07cc1ecad54..83d90cae8060 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1084,6 +1084,7 @@ test("brave_browser_tests") { "//brave/browser/ui/views/brave_shields/cookie_list_opt_in_browsertest.cc", "//brave/browser/ui/views/frame/brave_non_client_hit_test_helper_browsertest.cc", "//brave/browser/ui/views/frame/brave_tabs_search_button_browsertest.cc", + "//brave/browser/ui/views/frame/vertical_tab_strip_root_view_browsertest.cc", "//brave/browser/ui/views/omnibox/brave_omnibox_view_views_browsertest.cc", "//brave/browser/ui/views/omnibox/omnibox_autocomplete_browsertest.cc", "//brave/browser/ui/views/profiles/brave_profile_menu_view_browsertest.cc", diff --git a/third_party/rust/Cargo.lock b/third_party/rust/Cargo.lock index 10f1a864bb3f..8fe756318048 100644 --- a/third_party/rust/Cargo.lock +++ b/third_party/rust/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "adblock" -version = "0.8.0" +version = "0.8.1" dependencies = [ "base64", "bitflags", diff --git a/third_party/rust/adblock/v0_8/README.chromium b/third_party/rust/adblock/v0_8/README.chromium index 73e30e2160aa..0eca9fb5306d 100644 --- a/third_party/rust/adblock/v0_8/README.chromium +++ b/third_party/rust/adblock/v0_8/README.chromium @@ -1,7 +1,7 @@ Name: adblock URL: https://crates.io/crates/adblock Description: Native Rust module for Adblock Plus syntax (e.g. EasyList, EasyPrivacy) filter parsing and matching. -Version: 0.8.0 +Version: 0.8.1 Security Critical: no License: Mozilla Public License 2.0 -Revision: cb0dd04c193cf301403d7596bee326f4a0a1658b +Revision: bc39fa8a52bc96db18e8c14de73ed63d883a7b09 diff --git a/third_party/rust/adblock/v0_8/crate/.cargo_vcs_info.json b/third_party/rust/adblock/v0_8/crate/.cargo_vcs_info.json index caa9f4aa8557..021833609e52 100644 --- a/third_party/rust/adblock/v0_8/crate/.cargo_vcs_info.json +++ b/third_party/rust/adblock/v0_8/crate/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "cb0dd04c193cf301403d7596bee326f4a0a1658b" + "sha1": "bc39fa8a52bc96db18e8c14de73ed63d883a7b09" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/third_party/rust/adblock/v0_8/crate/Cargo.lock b/third_party/rust/adblock/v0_8/crate/Cargo.lock index 67000c8cb25f..ae63b8c94c87 100644 --- a/third_party/rust/adblock/v0_8/crate/Cargo.lock +++ b/third_party/rust/adblock/v0_8/crate/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "adblock" -version = "0.8.0" +version = "0.8.1" dependencies = [ "addr", "base64", diff --git a/third_party/rust/adblock/v0_8/crate/Cargo.toml b/third_party/rust/adblock/v0_8/crate/Cargo.toml index 8a94a144446a..b51e864eeed3 100644 --- a/third_party/rust/adblock/v0_8/crate/Cargo.toml +++ b/third_party/rust/adblock/v0_8/crate/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "adblock" -version = "0.8.0" +version = "0.8.1" authors = [ "Andrius Aucinas ", "Anton Lazarev ", diff --git a/third_party/rust/adblock/v0_8/crate/Cargo.toml.orig b/third_party/rust/adblock/v0_8/crate/Cargo.toml.orig index d2edd45e4307..f2432f9892c3 100644 --- a/third_party/rust/adblock/v0_8/crate/Cargo.toml.orig +++ b/third_party/rust/adblock/v0_8/crate/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "adblock" -version = "0.8.0" +version = "0.8.1" authors = ["Andrius Aucinas ", "Anton Lazarev "] edition = "2021" diff --git a/third_party/rust/adblock/v0_8/crate/src/blocker.rs b/third_party/rust/adblock/v0_8/crate/src/blocker.rs index 338eeacb2235..e69c058310dd 100644 --- a/third_party/rust/adblock/v0_8/crate/src/blocker.rs +++ b/third_party/rust/adblock/v0_8/crate/src/blocker.rs @@ -51,15 +51,18 @@ pub struct BlockerResult { /// modified at all, the new version will be here. This should be used /// as long as the request is not blocked. pub rewritten_url: Option, - /// Exception is `Some` when the blocker matched on an exception rule. + /// Contains a string representation of any matched exception rule. /// Effectively this means that there was a match, but the request should - /// not be blocked. It is a non-empty string if the blocker was initialized - /// from a list of rules with debugging enabled, otherwise the original - /// string representation is discarded to reduce memory use. + /// not be blocked. + /// + /// If debugging was _not_ enabled (see [`crate::FilterSet::new`]), this + /// will only contain a constant `"NetworkFilter"` placeholder string. pub exception: Option, - /// Filter--similarly to exception--includes the string representation of - /// the rule when there is a match and debugging is enabled. Otherwise, on - /// a match, it is `Some`. + /// When `matched` is true, this contains a string representation of the + /// matched blocking rule. + /// + /// If debugging was _not_ enabled (see [`crate::FilterSet::new`]), this + /// will only contain a constant `"NetworkFilter"` placeholder string. pub filter: Option, } @@ -2119,6 +2122,19 @@ fn test_removeparam_same_tokens() { } } +#[cfg(test)] +mod placeholder_string_tests { + /// If this changes, be sure to update the documentation for [`BlockerResult`] as well. + #[test] + fn test_constant_placeholder_string() { + let mut filter_set = crate::lists::FilterSet::new(false); + filter_set.add_filter("||example.com^", Default::default()).unwrap(); + let engine = crate::Engine::from_filter_set(filter_set, true); + let block = engine.check_network_request(&crate::request::Request::new("https://example.com", "https://example.com", "document").unwrap()); + assert_eq!(block.filter, Some("NetworkFilter".to_string())); + } +} + #[cfg(test)] mod legacy_rule_parsing_tests { use crate::test_utils::rules_from_lists; diff --git a/third_party/rust/adblock/v0_8/crate/src/resources/resource_storage.rs b/third_party/rust/adblock/v0_8/crate/src/resources/resource_storage.rs index 128a13e14a11..4d2f9f515b18 100644 --- a/third_party/rust/adblock/v0_8/crate/src/resources/resource_storage.rs +++ b/third_party/rust/adblock/v0_8/crate/src/resources/resource_storage.rs @@ -215,7 +215,7 @@ fn template_argument_regex(i: usize) -> Regex { fn patch_template_scriptlet(mut template: String, args: &[impl AsRef]) -> String { // `regex` treats `$` as a special character. Instead, `$$` is interpreted as a literal `$` // character. - args.iter().enumerate().for_each(|(i, arg)| { + args.iter().take(TEMPLATE_ARGUMENT_RE.len()).enumerate().for_each(|(i, arg)| { template = TEMPLATE_ARGUMENT_RE[i] .replace(&template, arg.as_ref().replace('$', "$$")) .to_string(); @@ -559,6 +559,30 @@ mod scriptlet_storage_tests { ); } + /// Currently, only 9 template arguments are supported - but reaching that limit should not + /// cause a panic. + #[test] + fn patch_argslist_many_args() { + let resources = ResourceStorage::from_resources([ + Resource { + name: "abort-current-script.js".into(), + aliases: vec!["acs.js".into()], + kind: ResourceType::Mime(MimeType::ApplicationJavascript), + content: base64::encode("{{1}} {{2}} {{3}} {{4}} {{5}} {{6}} {{7}} {{8}} {{9}} {{10}} {{11}} {{12}}"), + dependencies: vec![], + permission: Default::default(), + }, + ]); + + let args = parse_scriptlet_args("acs, this, probably, is, going, to, break, brave, and, crash, it, instead, of, ignoring, it"); + assert_eq!(args, vec!["acs", "this", "probably", "is", "going", "to", "break", "brave", "and", "crash", "it", "instead", "of", "ignoring", "it"]); + + assert_eq!( + resources.get_scriptlet_resource("acs, this, probably, is, going, to, break, brave, and, crash, it, instead, of, ignoring, it", Default::default()), + Ok("this probably is going to break brave and crash {{10}} {{11}} {{12}}".to_string()), + ); + } + #[test] fn permissions() { const PERM0: PermissionMask = PermissionMask::from_bits(0b00000001); diff --git a/third_party/rust/third_party.toml b/third_party/rust/third_party.toml index c5ff17ce95db..738be4eb4017 100644 --- a/third_party/rust/third_party.toml +++ b/third_party/rust/third_party.toml @@ -228,7 +228,7 @@ if (is_mac) { ''' [dependencies.adblock] -version = "0.8.0" +version = "0.8.1" default-features = false features = ["full-regex-handling", "regex-debug-info", "css-validation"] gn-variables-lib = '''