From 2429a784bc91bc097f898051681c9cfcf4563a87 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Tue, 3 Sep 2024 16:15:45 +0100 Subject: [PATCH 01/22] remove MissingTranslation attribute --- app/src/main/res/values/strings.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 45d0513748fb..1a5d058dab7b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -804,10 +804,9 @@ Skip - - Show on App Launch - Last Opened Tab - New Tab Page - Specific Page + Show on App Launch + Last Opened Tab + New Tab Page + Specific Page \ No newline at end of file From 356e7a221f8b81366de07b44bc06061db55491f6 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 12:01:25 -0400 Subject: [PATCH 02/22] Translate strings to values-et --- app/src/main/res/values-et/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 02787d4afe39..fa73ae6d9bfe 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -804,4 +804,10 @@ Proovi seda Jäta vahele + + Kuva rakenduse käivitamisel + Viimati avatud vahekaart + Uue vahekaardi leht + Konkreetne lehekülg + \ No newline at end of file From b2db903d7d77ed0ba4e994ccb365494729546538 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 12:16:23 -0400 Subject: [PATCH 03/22] Translate strings to values-hu --- app/src/main/res/values-hu/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 9356d23c557b..c7b2b23aef47 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -804,4 +804,10 @@ Kipróbálom Kihagyás + + Megjelenítés az alkalmazás indításakor + Utoljára megnyitott lap + „Új lap” oldal + Speciális oldal + \ No newline at end of file From bdd9eebd48cc449f2bdc23802adfcfccdd4310f7 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 12:31:23 -0400 Subject: [PATCH 04/22] Translate strings to values-ru --- app/src/main/res/values-ru/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 14a438cd1928..207b193025f6 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -808,4 +808,10 @@ Попробовать Пропустить + + Показывать при запуске приложения + Последняя открытая вкладка + Страница новой вкладки + Конкретная страница + \ No newline at end of file From 1cfd6149f6c6a80c058b1f7c7e277254c05f82a7 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 12:46:23 -0400 Subject: [PATCH 05/22] Translate strings to values-fi Translate strings to values-fr --- app/src/main/res/values-fi/strings.xml | 6 ++++++ app/src/main/res/values-fr/strings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 9f5156b7101f..ae44778928ca 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -804,4 +804,10 @@ Kokeile sitä Ohita + + Näytä sovelluksen käynnistyksen yhteydessä + Viimeksi avattu -välilehti + Uusi välilehti -sivu + Tietty sivu + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a1dda1311df5..b8cb6bc0d1bb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -804,4 +804,10 @@ Essayez Ignorer + + Afficher au lancement de l\'application + Dernier onglet ouvert + Nouvelle page d\'onglet + Page spécifique + \ No newline at end of file From 67d42e5e3b930dbdea0f3c2bc619d23d0544577d Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 13:46:20 -0400 Subject: [PATCH 06/22] Translate strings to values-tr --- app/src/main/res/values-tr/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0d1db20540bc..c1a3740130ac 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -804,4 +804,10 @@ Deneyin Atla + + Uygulama Başlatıldığında Göster + Son Açılan Sekme + Yeni Sekme Sayfası + Belirli Bir Sayfa + \ No newline at end of file From 3c5deb0c784bd16ea885dad22fc33b6e85a7aa1c Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Tue, 3 Sep 2024 14:31:25 -0400 Subject: [PATCH 07/22] Translate strings to values-de --- app/src/main/res/values-de/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 894a32e87eaa..ac28ea5c267e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -804,4 +804,10 @@ Ausprobieren Überspringen + + Beim App-Start anzeigen + Zuletzt geöffneter Tab + Neue Tab-Seite + Bestimmte Seite + \ No newline at end of file From 4c0d9f521f933beb04f396e616ab4fddad41eb1b Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 01:01:24 -0400 Subject: [PATCH 08/22] Translate strings to values-lv --- app/src/main/res/values-lv/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index aa511c0b9385..cd42761a5e8d 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -806,4 +806,10 @@ Izmēģini Izlaist + + Rādīt lietotnes palaišanas laikā + Pēdējā atvērtā cilne + Jaunas cilnes lapa + Konkrēta lapa + \ No newline at end of file From beee7215e484e579f71545737c1e1a02d290d464 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 02:31:22 -0400 Subject: [PATCH 09/22] Translate strings to values-da Translate strings to values-cs --- app/src/main/res/values-cs/strings.xml | 6 ++++++ app/src/main/res/values-da/strings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 422bb50038d8..24b582c733e9 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -808,4 +808,10 @@ Vyzkoušejte ho Přeskočit + + Zobrazit při spuštění aplikace + Naposledy otevřená karta + Stránka Nová karta + Konkrétní stránka + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index a3bf45069a0b..02c3749e9530 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -804,4 +804,10 @@ Prøv det Spring over + + Vis ved app-start + Sidst åbnede fane + Ny faneside + Specifik side + \ No newline at end of file From 158c60560f70ea890a1bc1887820be824dbf05a4 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 02:46:23 -0400 Subject: [PATCH 10/22] Translate strings to values-lt --- app/src/main/res/values-lt/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index aee51daa759d..8b5434b9a8d6 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -808,4 +808,10 @@ Išbandykite Praleisti + + Rodyti paleidus programą + Paskutinį kartą atidarytas skirtukas + Naujas skirtuko puslapis + Konkretus puslapis + \ No newline at end of file From 31ac498a97bd2ebe58250d6672d872893e7671fe Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 03:46:18 -0400 Subject: [PATCH 11/22] Translate strings to values-sl --- app/src/main/res/values-sl/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index a556e128a75b..bcf62b479c58 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -808,4 +808,10 @@ Preizkusite Preskoči + + Pokaži ob zagonu aplikacije + Zadnji odprt zavihek + Stran z novim zavihkom + Določena stran + \ No newline at end of file From e3672584f5695f4274f925bb071485bcb01a6b64 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 04:01:24 -0400 Subject: [PATCH 12/22] Translate strings to values-nl Translate strings to values-sv --- app/src/main/res/values-nl/strings.xml | 6 ++++++ app/src/main/res/values-sv/strings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 58ab7c7d4620..eea341068676 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -804,4 +804,10 @@ Probeer het zelf Overslaan + + Weergeven bij het starten van de app + Laatst geopende tabblad + Nieuwe tabbladpagina + Specifieke pagina + \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index ced34339ff33..6d8761e31799 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -804,4 +804,10 @@ Prova Hoppa över + + Visa vid app-start + Senast öppnade flik + Ny fliksida + Specifik sida + \ No newline at end of file From d4bda2a67b135b1228a80926f7735f16b7905a33 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 04:46:30 -0400 Subject: [PATCH 13/22] Translate strings to values-pt --- app/src/main/res/values-pt/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 1d97c164e0fe..5bdf25135ddb 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -804,4 +804,10 @@ Experimenta-o Ignorar + + Mostrar ao abrir a aplicação + Último separador aberto + Nova página de separador + Página específica + \ No newline at end of file From 11990c7ab7c77d4f69284decc785c944e2069ff2 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 05:16:27 -0400 Subject: [PATCH 14/22] Translate strings to values-bg --- app/src/main/res/values-bg/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 8161436a27c5..3215e11c4bc5 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -804,4 +804,10 @@ Изпробвайте го Пропускане + + Показване при стартиране на приложението + Последно отворен раздел + Страница с нов раздел + Конкретна страница + \ No newline at end of file From 551d9a84a4b1d7b0502722ec91f989c72783ea28 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 05:46:21 -0400 Subject: [PATCH 15/22] Translate strings to values-es Translate strings to values-sk --- app/src/main/res/values-es/strings.xml | 6 ++++++ app/src/main/res/values-sk/strings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 3304f5f9d577..22e34bf6cab9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -804,4 +804,10 @@ Pruébalo Omitir + + Mostrar al abrir la aplicación + Última pestaña abierta + Página de nueva pestaña + Página específica + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 42487000ef4e..3b71d98185d2 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -808,4 +808,10 @@ Vyskúšajte to Preskočiť + + Zobraziť pri spustení aplikácie + Naposledy otvorená karta + Stránka na novej karte + Špecifická stránka + \ No newline at end of file From e69417a655924c767acea1301b81a1e69204fa9c Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 06:31:23 -0400 Subject: [PATCH 16/22] Translate strings to values-nb --- app/src/main/res/values-nb/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 98ad6c994096..128c20170500 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -804,4 +804,10 @@ Prøv det Hopp over + + Vis ved lansering av appen + Sist åpnet fane + Ny faneside + Spesifikk side + \ No newline at end of file From 9ad595c42e6bd95baf8547ed0ae8dfbe9da20aaa Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 10:01:25 -0400 Subject: [PATCH 17/22] Translate strings to values-pl --- app/src/main/res/values-pl/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 96ae2a15ab5e..f0c390e31d70 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -808,4 +808,10 @@ Wypróbuj Pomiń + + Pokaż przy uruchomieniu aplikacji + Ostatnio otwarta karta + Strona nowej karty + Określona strona + \ No newline at end of file From 76e0247f3e1f77d64267a7b8f29fa1d8fa28a471 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Wed, 4 Sep 2024 11:31:31 -0400 Subject: [PATCH 18/22] Translate strings to values-ro --- app/src/main/res/values-ro/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index ba2788d7b2bb..c718da5738da 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -806,4 +806,10 @@ Încearcă-l Ignorare + + Afișează la lansarea aplicației + Ultima filă deschisă + Filă nouă + Pagină specifică + \ No newline at end of file From 409f691d071b84e1fc928615708a415d93489742 Mon Sep 17 00:00:00 2001 From: Marcos Holgado Date: Thu, 5 Sep 2024 06:33:30 -0400 Subject: [PATCH 19/22] Translate strings to values-hr Translate strings to values-el Translate strings to values-it --- app/src/main/res/values-el/strings.xml | 6 ++++++ app/src/main/res/values-hr/strings.xml | 6 ++++++ app/src/main/res/values-it/strings.xml | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 5fded24fe51f..92923fab3108 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -804,4 +804,10 @@ Δοκιμάστε το Παράλειψη + + Εμφάνιση στην Εκκίνηση εφαρμογής + Τελευταία καρτέλα που άνοιξε + Σελίδα νέας καρτέλας + Συγκεκριμένη σελίδα + \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 581fb976678c..76ca339af5a5 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -808,4 +808,10 @@ Isprobaj ga Preskoči + + Prikaži pri pokretanju aplikacije + Posljednja otvorena kartica + Nova stranica kartice + Specifična stranica + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index f174a40d6662..4ee6851a4abe 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -804,4 +804,10 @@ Provalo Salta + + Mostra all\'avvio dell\'app + Ultima scheda aperta + Pagina Nuova scheda + Pagina specifica + \ No newline at end of file From b40783d4aef4da80f7c062fc99da4fa161bff577 Mon Sep 17 00:00:00 2001 From: Dax The Translator Date: Wed, 11 Sep 2024 04:01:39 -0400 Subject: [PATCH 20/22] Translate strings to values-de Translate strings to values-es Translate strings to values-ro Translate strings to values-tr Translate strings to values-sk Translate strings to values-ru Translate strings to values-et Translate strings to values-it Translate strings to values-pl Translate strings to values-bg Translate strings to values-lv Translate strings to values-fi Translate strings to values-sl Translate strings to values-nl Translate strings to values-hr Translate strings to values-hu Translate strings to values-nb Translate strings to values-sv Translate strings to values-da Translate strings to values-el Translate strings to values-fr Translate strings to values-lt Translate strings to values-pt Translate strings to values-cs --- app/src/main/res/values-bg/strings.xml | 4 ++-- app/src/main/res/values-cs/strings.xml | 4 ++-- app/src/main/res/values-da/strings.xml | 4 ++-- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-el/strings.xml | 4 ++-- app/src/main/res/values-es/strings.xml | 4 ++-- app/src/main/res/values-et/strings.xml | 4 ++-- app/src/main/res/values-fi/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-hr/strings.xml | 4 ++-- app/src/main/res/values-hu/strings.xml | 4 ++-- app/src/main/res/values-it/strings.xml | 4 ++-- app/src/main/res/values-lt/strings.xml | 4 ++-- app/src/main/res/values-lv/strings.xml | 4 ++-- app/src/main/res/values-nb/strings.xml | 4 ++-- app/src/main/res/values-nl/strings.xml | 4 ++-- app/src/main/res/values-pl/strings.xml | 4 ++-- app/src/main/res/values-pt/strings.xml | 4 ++-- app/src/main/res/values-ro/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 4 ++-- app/src/main/res/values-sk/strings.xml | 4 ++-- app/src/main/res/values-sl/strings.xml | 4 ++-- app/src/main/res/values-sv/strings.xml | 4 ++-- app/src/main/res/values-tr/strings.xml | 4 ++-- 24 files changed, 48 insertions(+), 48 deletions(-) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 3215e11c4bc5..8a36559d7dca 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Лого на DuckDuckGo Постижима поверителност Да diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 24b582c733e9..1be7f11ae073 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Ochrana soukromí, zjednodušená Ano diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 02c3749e9530..007e67fa7d28 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Fortrolighed, helt enkelt Ja diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ac28ea5c267e..e57d5e9bff10 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-Logo Privatsphäre – leicht gemacht Ja diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 92923fab3108..57ee864fee63 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Λογότυπο DuckDuckGo Η ιδιωτικότητα απλοποιημένη Ναι diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 22e34bf6cab9..bf5178e28f06 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotipo de DuckDuckGo La privacidad, simplificada diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index fa73ae6d9bfe..07ec66660473 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logo Privaatsus, lihtsustatud Jah diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index ae44778928ca..28da5e57f419 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Itsestään selvää tietosuojaa Kyllä diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b8cb6bc0d1bb..e7675aa5ae0d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Votre confidentialité, simplifiée Oui diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 76ca339af5a5..a99c533789ea 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotip DuckDuckGo Zaštita privatnosti na jednostavniji način Da diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index c7b2b23aef47..c9eec83bed37 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logó Adatvédelem, leegyszerűsítve Igen diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4ee6851a4abe..88d1a4147848 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo La privacy, semplificata diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 8b5434b9a8d6..6f5851d76e26 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + „DuckDuckGo“ + „DuckDuckGo“ „DuckDuckGo“ logotipas Privatumas, paprasčiau Taip diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index cd42761a5e8d..fd241c737d0c 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logotips Privātums – vienkāršots diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 128c20170500..4ab1dae3a173 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Personvern gjort enkelt Ja diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index eea341068676..5b402e54b055 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Privacy, vereenvoudigd Ja diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index f0c390e31d70..72a5e7aba09c 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Prywatność — jeszcze prostsza Tak diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 5bdf25135ddb..a367bf5ef6b6 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logótipo do DuckDuckGo Privacidade, simplificada Sim diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index c718da5738da..623e4c1463af 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logoul DuckDuckGo Despre confidențialitate, pe scurt Da diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 207b193025f6..b7a09d342799 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Логотип DuckDuckGo Максимум конфиденциальности, минимум усилий Да diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 3b71d98185d2..691ac94a20f9 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Súkromie, zjednodušene Áno diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index bcf62b479c58..97533f89518a 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotip DuckDuckGo Zasebnost, poenostavljeno Da diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 6d8761e31799..54c7e0ed7b8f 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGos logotyp Personlig integritet, förenklad Ja diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c1a3740130ac..b559ce04b361 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logosu Gizlilik, basitleştirildi Evet From 059fcd17fa4d5f76b93ec106d9b1ebe6a0449779 Mon Sep 17 00:00:00 2001 From: Dax The Translator Date: Thu, 19 Sep 2024 11:01:35 -0400 Subject: [PATCH 21/22] Translate strings to values-de Translate strings to values-es Translate strings to values-ro Translate strings to values-tr Translate strings to values-sk Translate strings to values-ru Translate strings to values-et Translate strings to values-it Translate strings to values-pl Translate strings to values-bg Translate strings to values-lv Translate strings to values-fi Translate strings to values-sl Translate strings to values-nl Translate strings to values-hr Translate strings to values-hu Translate strings to values-nb Translate strings to values-sv Translate strings to values-da Translate strings to values-el Translate strings to values-fr Translate strings to values-lt Translate strings to values-pt Translate strings to values-cs --- app/src/main/res/values-bg/strings.xml | 4 ++-- app/src/main/res/values-cs/strings.xml | 4 ++-- app/src/main/res/values-da/strings.xml | 4 ++-- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-el/strings.xml | 4 ++-- app/src/main/res/values-es/strings.xml | 4 ++-- app/src/main/res/values-et/strings.xml | 4 ++-- app/src/main/res/values-fi/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-hr/strings.xml | 4 ++-- app/src/main/res/values-hu/strings.xml | 4 ++-- app/src/main/res/values-it/strings.xml | 4 ++-- app/src/main/res/values-lt/strings.xml | 4 ++-- app/src/main/res/values-lv/strings.xml | 4 ++-- app/src/main/res/values-nb/strings.xml | 4 ++-- app/src/main/res/values-nl/strings.xml | 4 ++-- app/src/main/res/values-pl/strings.xml | 4 ++-- app/src/main/res/values-pt/strings.xml | 4 ++-- app/src/main/res/values-ro/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 4 ++-- app/src/main/res/values-sk/strings.xml | 4 ++-- app/src/main/res/values-sl/strings.xml | 4 ++-- app/src/main/res/values-sv/strings.xml | 4 ++-- app/src/main/res/values-tr/strings.xml | 4 ++-- 24 files changed, 48 insertions(+), 48 deletions(-) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 8a36559d7dca..3215e11c4bc5 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Лого на DuckDuckGo Постижима поверителност Да diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 1be7f11ae073..24b582c733e9 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Ochrana soukromí, zjednodušená Ano diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 007e67fa7d28..02c3749e9530 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Fortrolighed, helt enkelt Ja diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index e57d5e9bff10..ac28ea5c267e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-Logo Privatsphäre – leicht gemacht Ja diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 57ee864fee63..92923fab3108 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Λογότυπο DuckDuckGo Η ιδιωτικότητα απλοποιημένη Ναι diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bf5178e28f06..22e34bf6cab9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotipo de DuckDuckGo La privacidad, simplificada diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 07ec66660473..fa73ae6d9bfe 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logo Privaatsus, lihtsustatud Jah diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 28da5e57f419..ae44778928ca 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Itsestään selvää tietosuojaa Kyllä diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e7675aa5ae0d..b8cb6bc0d1bb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Votre confidentialité, simplifiée Oui diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index a99c533789ea..76ca339af5a5 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotip DuckDuckGo Zaštita privatnosti na jednostavniji način Da diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index c9eec83bed37..c7b2b23aef47 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logó Adatvédelem, leegyszerűsítve Igen diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 88d1a4147848..4ee6851a4abe 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo La privacy, semplificata diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 6f5851d76e26..8b5434b9a8d6 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -17,8 +17,8 @@ - „DuckDuckGo“ - „DuckDuckGo“ + DuckDuckGo + DuckDuckGo „DuckDuckGo“ logotipas Privatumas, paprasčiau Taip diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index fd241c737d0c..cd42761a5e8d 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logotips Privātums – vienkāršots diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 4ab1dae3a173..128c20170500 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo-logo Personvern gjort enkelt Ja diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 5b402e54b055..eea341068676 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Privacy, vereenvoudigd Ja diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 72a5e7aba09c..f0c390e31d70 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Prywatność — jeszcze prostsza Tak diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index a367bf5ef6b6..5bdf25135ddb 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logótipo do DuckDuckGo Privacidade, simplificada Sim diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 623e4c1463af..c718da5738da 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logoul DuckDuckGo Despre confidențialitate, pe scurt Da diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b7a09d342799..207b193025f6 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Логотип DuckDuckGo Максимум конфиденциальности, минимум усилий Да diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 691ac94a20f9..3b71d98185d2 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logo DuckDuckGo Súkromie, zjednodušene Áno diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 97533f89518a..bcf62b479c58 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo Logotip DuckDuckGo Zasebnost, poenostavljeno Da diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 54c7e0ed7b8f..6d8761e31799 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGos logotyp Personlig integritet, förenklad Ja diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index b559ce04b361..c1a3740130ac 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -17,8 +17,8 @@ - DuckDuckGo - DuckDuckGo + DuckDuckGo + DuckDuckGo DuckDuckGo logosu Gizlilik, basitleştirildi Evet From 94fb762afc2f7f059901b38e85892d2d60956ac2 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Fri, 20 Sep 2024 18:24:33 +0200 Subject: [PATCH 22/22] Show on App Launch: Open launch option when set (#4995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1207908166761516/1208167186867417/f ### Description Adds functionality to open the show on app launch option based on what has been set. If there is no specialised launch happening then we check the show on app launch setting: 1. If LastOpenedTab is set, we do nothing as this is current behaviour 2. If NewTabPage is set then we open a new tab 3. If SpecificPage is set we compare the url to the current selected tab, if it's not the same we open a new tab otherwise we do nothing Also as part of this PR, we add validation to the URL: 1. It is blank will set it as a default to duckduckgo.com 2. If it has no scheme will add http (in case the website does not currently support https) 3. Otherwise return the url what was passed in ### Steps to test this PR _Last Opened Tab_ - [x] Set "Show on App Launch" to **Last Opened Tab** - [x] Exit Settings - [x] Remember your current tab and tab count - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is the same as when you closed - [x] Ensure the tab count has not increased _New Tab Page_ - [x] Set "Show on App Launch" to **New Tab Page** - [x] Exit Settings - [x] Remember your current tab and tab count. If this is the **New Tab Page** then please open a website e.g. “bbc.com" - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is now the **New Tab Page** - [x] Ensure the tab count **has** increased by one - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is still the **New Tab Page** - [x] Ensure the tab count has **not** increased by one _Specific Page_ - [x] Set "Show on App Launch" to **Specific Page** - [x] Check the default URL is “https://duckduckgo.com/” - [x] Exit Settings - [x] Remember your current tab (it should not be “https://duckduckgo.com/”) and tab count - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is now **https://duckduckgo.com/** - [x] Ensure the tab count **has** increased by one (if your tab was on the new tab page before you force closed it would not increase) - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is still **https://duckduckgo.com/** - [ ] Ensure the tab count has **not** increased by one _Specific Page Lowercasing_ - [x] Set "Show on App Launch" to **Specific Page** - [x] Change the default URL to “BBC.com” - [x] Press back - [x] Check that under the "Show on App Launch” setting the url is “http://bbc.com” _Specific Page Updated_ - [x] Set "Show on App Launch" to **Specific Page** - [x] Change the default URL to a different url e.g. “cnn.com" - [x] Exit Settings - [x] Remember your current tab (it should **not** be the same url you entered earlier) and tab count - [x] Force close the app via recents - [x] Open the app - [x] Check the tab is now the url you set e.g. **cnn.com** - [x] Ensure the tab count **has** increased by one _Specific Page Not a URL_ - [x] Set "Show on App Launch" to **Specific Page** - [x] Change the default URL to a url that is invalid e.g. “example" - [x] Press back - [x] Check that under the "Show on App Launch” setting the url is “http://example” - [x] Remember your current tab (it should **not** be the same url you entered earlier) and tab count - [x] Force close the app via recents - [x] Open the app - [x] Check the tab has attempted to load "http://example" - [x] Ensure the tab count **has** increased by one _Specific Page Different Scheme_ - [x] Set "Show on App Launch" to **Specific Page** - [x] Change the default URL to a url with a different scheme e.g. “ftp://file.com" - [x] Press back - [x] Check that under the "Show on App Launch” setting the url is still “ftp://file.com” ### UI changes N/A ### Demo https://github.com/user-attachments/assets/6296bd2e-d083-46fd-a738-787e8bf2b6ee --- .../duckduckgo/app/browser/BrowserActivity.kt | 2 + .../app/browser/BrowserViewModel.kt | 22 +++ .../GeneralSettingsViewModel.kt | 2 + .../ShowOnAppLaunchStateReporterPlugin.kt | 53 ++++++++ .../ShowOnAppLaunchUrlConverterImpl.kt | 45 +++++++ .../ShowOnAppLaunchViewModel.kt | 12 +- .../showonapplaunch/UrlConverter.kt | 22 +++ .../model/ShowOnAppLaunchOption.kt | 16 +++ .../store/ShowOnAppLaunchDataStoreModule.kt | 5 + .../store/ShowOnAppLaunchOptionDataStore.kt | 15 ++- .../com/duckduckgo/app/pixels/AppPixelName.kt | 4 + .../app/tabs/model/TabDataRepository.kt | 3 + .../app/browser/BrowserViewModelTest.kt | 95 +++++++++---- .../GeneralSettingsViewModelTest.kt | 8 ++ .../ShowOnAppLaunchStateReporterPluginTest.kt | 70 ++++++++++ .../ShowOnAppLaunchUrlConverterImplTest.kt | 125 ++++++++++++++++++ .../ShowOnAppLaunchViewModelTest.kt | 120 +++++++++++++++++ .../FakeShowOnAppLaunchOptionDataStore.kt | 6 +- .../ShowOnAppLaunchPrefsDataStoreTest.kt | 115 ++++++++++++++++ .../java/com/duckduckgo/fakes/FakePixel.kt | 60 +++++++++ .../app/tabs/model/TabRepository.kt | 2 + .../duckduckgo/app/statistics/pixels/Pixel.kt | 1 + 22 files changed, 767 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPlugin.kt create mode 100644 app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImpl.kt create mode 100644 app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/UrlConverter.kt create mode 100644 app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPluginTest.kt create mode 100644 app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImplTest.kt create mode 100644 app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModelTest.kt create mode 100644 app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchPrefsDataStoreTest.kt create mode 100644 app/src/test/java/com/duckduckgo/fakes/FakePixel.kt diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index aa8fd23901fc..fd85ef28f075 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -364,6 +364,8 @@ open class BrowserActivity : DuckDuckGoActivity() { return } } + + viewModel.handleShowOnAppLaunchOption() } private fun configureObservers() { diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index b9359b5f3586..7452b7b362f6 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -20,11 +20,16 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.duckduckgo.anvil.annotations.ContributesRemoteFeature import com.duckduckgo.anvil.annotations.ContributesViewModel import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter import com.duckduckgo.app.fire.DataClearer +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.LastOpenedTab +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore import com.duckduckgo.app.global.ApplicationClearDataState import com.duckduckgo.app.global.rating.AppEnjoymentPromptEmitter import com.duckduckgo.app.global.rating.AppEnjoymentPromptOptions @@ -55,6 +60,7 @@ import com.duckduckgo.feature.toggles.api.Toggle import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import timber.log.Timber @@ -69,6 +75,7 @@ class BrowserViewModel @Inject constructor( private val dispatchers: DispatcherProvider, private val pixel: Pixel, private val skipUrlConversionOnNewTabFeature: SkipUrlConversionOnNewTabFeature, + private val showOnAppLaunchOptionDataStore: ShowOnAppLaunchOptionDataStore, ) : ViewModel(), CoroutineScope { @@ -284,6 +291,21 @@ class BrowserViewModel @Inject constructor( fun onBookmarksActivityResult(url: String) { command.value = Command.OpenSavedSite(url) } + + fun handleShowOnAppLaunchOption() { + viewModelScope.launch { + when (val option = showOnAppLaunchOptionDataStore.optionFlow.first()) { + LastOpenedTab -> Unit + NewTabPage -> onNewTabRequested() + is SpecificPage -> { + val liveSelectedTabUrl = tabRepository.getSelectedTab()?.url + if (liveSelectedTabUrl != option.url) { + onOpenInNewTabRequested(option.url) + } + } + } + } + } } /** diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModel.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModel.kt index f737e87867e7..487bbd5ac77b 100644 --- a/app/src/main/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModel.kt @@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope import com.duckduckgo.anvil.annotations.ContributesViewModel import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.pixels.AppPixelName import com.duckduckgo.app.pixels.AppPixelName.AUTOCOMPLETE_GENERAL_SETTINGS_TOGGLED_OFF import com.duckduckgo.app.pixels.AppPixelName.AUTOCOMPLETE_GENERAL_SETTINGS_TOGGLED_ON import com.duckduckgo.app.pixels.AppPixelName.AUTOCOMPLETE_RECENT_SITES_GENERAL_SETTINGS_TOGGLED_OFF @@ -143,6 +144,7 @@ class GeneralSettingsViewModel @Inject constructor( fun onShowOnAppLaunchButtonClick() { sendCommand(Command.LaunchShowOnAppLaunchScreen) + pixel.fire(AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_PRESSED) } private fun observeShowOnAppLaunchOption() { diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPlugin.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPlugin.kt new file mode 100644 index 000000000000..2bfcbbac34f7 --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPlugin.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.statistics.api.BrowserFeatureStateReporterPlugin +import com.duckduckgo.app.statistics.pixels.Pixel.PixelParameter +import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.di.scopes.AppScope +import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import javax.inject.Inject +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking + +interface ShowOnAppLaunchReporterPlugin + +@ContributesMultibinding( + scope = AppScope::class, + boundType = BrowserFeatureStateReporterPlugin::class, +) +@ContributesBinding(scope = AppScope::class, boundType = ShowOnAppLaunchReporterPlugin::class) +class ShowOnAppLaunchStateReporterPlugin +@Inject +constructor( + private val dispatcherProvider: DispatcherProvider, + private val showOnAppLaunchOptionDataStore: ShowOnAppLaunchOptionDataStore, +) : ShowOnAppLaunchReporterPlugin, BrowserFeatureStateReporterPlugin { + + override fun featureStateParams(): Map { + val option = + runBlocking(dispatcherProvider.io()) { + showOnAppLaunchOptionDataStore.optionFlow.first() + } + val dailyPixelValue = ShowOnAppLaunchOption.getDailyPixelValue(option) + return mapOf(PixelParameter.LAUNCH_SCREEN to dailyPixelValue) + } +} diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImpl.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImpl.kt new file mode 100644 index 000000000000..15f4c86f42c2 --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImpl.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +import android.net.Uri +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore + +class ShowOnAppLaunchUrlConverterImpl : UrlConverter { + + override fun convertUrl(url: String?): String { + if (url.isNullOrBlank()) return ShowOnAppLaunchOptionDataStore.DEFAULT_SPECIFIC_PAGE_URL + + val uri = Uri.parse(url.trim()) + + val convertedUri = if (uri.scheme == null) { + Uri.Builder().scheme("http").authority(uri.path?.lowercase()) + } else { + uri.buildUpon() + .scheme(uri.scheme?.lowercase()) + .authority(uri.authority?.lowercase()) + } + .apply { + query(uri.query) + fragment(uri.fragment) + } + .build() + .toString() + + return Uri.decode(convertedUri) + } +} diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModel.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModel.kt index 7b1a3d6aac09..965d3cdc3dcc 100644 --- a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModel.kt @@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope import com.duckduckgo.anvil.annotations.ContributesViewModel import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.ActivityScope import javax.inject.Inject @@ -37,6 +38,8 @@ import timber.log.Timber class ShowOnAppLaunchViewModel @Inject constructor( private val dispatcherProvider: DispatcherProvider, private val showOnAppLaunchOptionDataStore: ShowOnAppLaunchOptionDataStore, + private val urlConverter: UrlConverter, + private val pixel: Pixel, ) : ViewModel() { data class ViewState( @@ -64,6 +67,7 @@ class ShowOnAppLaunchViewModel @Inject constructor( fun onShowOnAppLaunchOptionChanged(option: ShowOnAppLaunchOption) { Timber.i("User changed show on app launch option to $option") viewModelScope.launch(dispatcherProvider.io()) { + firePixel(option) showOnAppLaunchOptionDataStore.setShowOnAppLaunchOption(option) } } @@ -71,7 +75,13 @@ class ShowOnAppLaunchViewModel @Inject constructor( fun setSpecificPageUrl(url: String) { Timber.i("Setting specific page url to $url") viewModelScope.launch(dispatcherProvider.io()) { - showOnAppLaunchOptionDataStore.setSpecificPageUrl(url) + val convertedUrl = urlConverter.convertUrl(url) + showOnAppLaunchOptionDataStore.setSpecificPageUrl(convertedUrl) } } + + private fun firePixel(option: ShowOnAppLaunchOption) { + val pixelName = ShowOnAppLaunchOption.getPixelName(option) + pixel.fire(pixelName) + } } diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/UrlConverter.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/UrlConverter.kt new file mode 100644 index 000000000000..87703ab36a73 --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/UrlConverter.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +interface UrlConverter { + + fun convertUrl(url: String?): String +} diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/model/ShowOnAppLaunchOption.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/model/ShowOnAppLaunchOption.kt index fdc384e94a02..806794a2df61 100644 --- a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/model/ShowOnAppLaunchOption.kt +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/model/ShowOnAppLaunchOption.kt @@ -16,6 +16,10 @@ package com.duckduckgo.app.generalsettings.showonapplaunch.model +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_LAST_OPENED_TAB_SELECTED +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_NEW_TAB_PAGE_SELECTED +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_SPECIFIC_PAGE_SELECTED + sealed class ShowOnAppLaunchOption(val id: Int) { data object LastOpenedTab : ShowOnAppLaunchOption(1) @@ -30,5 +34,17 @@ sealed class ShowOnAppLaunchOption(val id: Int) { 3 -> SpecificPage("") else -> throw IllegalArgumentException("Unknown id: $id") } + + fun getPixelName(option: ShowOnAppLaunchOption) = when (option) { + LastOpenedTab -> SETTINGS_GENERAL_APP_LAUNCH_LAST_OPENED_TAB_SELECTED + NewTabPage -> SETTINGS_GENERAL_APP_LAUNCH_NEW_TAB_PAGE_SELECTED + is SpecificPage -> SETTINGS_GENERAL_APP_LAUNCH_SPECIFIC_PAGE_SELECTED + } + + fun getDailyPixelValue(option: ShowOnAppLaunchOption) = when (option) { + LastOpenedTab -> "last_opened_tab" + NewTabPage -> "new_tab_page" + is SpecificPage -> "specific_page" + } } } diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchDataStoreModule.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchDataStoreModule.kt index 6ad3493c006a..291efa1fe04a 100644 --- a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchDataStoreModule.kt +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchDataStoreModule.kt @@ -20,6 +20,8 @@ import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore +import com.duckduckgo.app.generalsettings.showonapplaunch.ShowOnAppLaunchUrlConverterImpl +import com.duckduckgo.app.generalsettings.showonapplaunch.UrlConverter import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesTo import dagger.Module @@ -37,6 +39,9 @@ object ShowOnAppLaunchDataStoreModule { @Provides @ShowOnAppLaunch fun showOnAppLaunchDataStore(context: Context): DataStore = context.showOnAppLaunchDataStore + + @Provides + fun showOnAppLaunchUrlConverter(): UrlConverter = ShowOnAppLaunchUrlConverterImpl() } @Qualifier diff --git a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchOptionDataStore.kt b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchOptionDataStore.kt index 25fae184a2b7..298800165e4e 100644 --- a/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchOptionDataStore.kt +++ b/app/src/main/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchOptionDataStore.kt @@ -17,6 +17,7 @@ package com.duckduckgo.app.generalsettings.showonapplaunch.store import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.MutablePreferences import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey @@ -25,6 +26,7 @@ import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchO import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.LastOpenedTab import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore.Companion.DEFAULT_SPECIFIC_PAGE_URL import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesBinding import javax.inject.Inject @@ -37,6 +39,10 @@ interface ShowOnAppLaunchOptionDataStore { suspend fun setShowOnAppLaunchOption(showOnAppLaunchOption: ShowOnAppLaunchOption) suspend fun setSpecificPageUrl(url: String) + + companion object { + const val DEFAULT_SPECIFIC_PAGE_URL = "https://duckduckgo.com/" + } } @ContributesBinding(AppScope::class) @@ -67,19 +73,22 @@ class ShowOnAppLaunchOptionPrefsDataStore @Inject constructor( preferences[intPreferencesKey(KEY_SHOW_ON_APP_LAUNCH_OPTION)] = showOnAppLaunchOption.id if (showOnAppLaunchOption is SpecificPage) { - preferences[stringPreferencesKey(KEY_SHOW_ON_APP_LAUNCH_SPECIFIC_PAGE_URL)] + preferences.setShowOnAppLaunch(showOnAppLaunchOption.url) } } } override suspend fun setSpecificPageUrl(url: String) { store.edit { preferences -> - preferences[stringPreferencesKey(KEY_SHOW_ON_APP_LAUNCH_SPECIFIC_PAGE_URL)] = url + preferences.setShowOnAppLaunch(url) } } + private fun MutablePreferences.setShowOnAppLaunch(url: String) { + set(stringPreferencesKey(KEY_SHOW_ON_APP_LAUNCH_SPECIFIC_PAGE_URL), url) + } + companion object { - private const val DEFAULT_SPECIFIC_PAGE_URL = "duckduckgo.com" private const val KEY_SHOW_ON_APP_LAUNCH_OPTION = "SHOW_ON_APP_LAUNCH_OPTION" private const val KEY_SHOW_ON_APP_LAUNCH_SPECIFIC_PAGE_URL = "SHOW_ON_APP_LAUNCH_SPECIFIC_PAGE_URL" } diff --git a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt index d43daef4b3d5..09fa7f3e333c 100644 --- a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt +++ b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt @@ -139,6 +139,10 @@ enum class AppPixelName(override val pixelName: String) : Pixel.PixelName { SETTINGS_PRIVATE_SEARCH_MORE_SEARCH_SETTINGS_PRESSED("ms_private_search_more_search_settings_pressed"), SETTINGS_COOKIE_POPUP_PROTECTION_PRESSED("ms_cookie_popup_protection_setting_pressed"), SETTINGS_FIRE_BUTTON_PRESSED("ms_fire_button_setting_pressed"), + SETTINGS_GENERAL_APP_LAUNCH_PRESSED("m_settings_general_app_launch_pressed"), + SETTINGS_GENERAL_APP_LAUNCH_LAST_OPENED_TAB_SELECTED("m_settings_general_app_launch_last_opened_tab_selected"), + SETTINGS_GENERAL_APP_LAUNCH_NEW_TAB_PAGE_SELECTED("m_settings_general_app_launch_new_tab_page_selected"), + SETTINGS_GENERAL_APP_LAUNCH_SPECIFIC_PAGE_SELECTED("m_settings_general_app_launch_specific_page_selected"), SURVEY_CTA_SHOWN(pixelName = "mus_cs"), SURVEY_CTA_DISMISSED(pixelName = "mus_cd"), diff --git a/app/src/main/java/com/duckduckgo/app/tabs/model/TabDataRepository.kt b/app/src/main/java/com/duckduckgo/app/tabs/model/TabDataRepository.kt index 70f08a2dff60..f34550357e0f 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/model/TabDataRepository.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/model/TabDataRepository.kt @@ -298,6 +298,9 @@ class TabDataRepository @Inject constructor( siteData.clear() } + override suspend fun getSelectedTab(): TabEntity? = + withContext(dispatchers.io()) { tabsDao.selectedTab() } + override suspend fun select(tabId: String) { databaseExecutor().scheduleDirect { val selection = TabSelectionEntity(tabId = tabId) diff --git a/app/src/test/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt index f660ae9b8b3c..836fb0c1c20f 100644 --- a/app/src/test/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt +++ b/app/src/test/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt @@ -23,6 +23,8 @@ import com.duckduckgo.app.browser.BrowserViewModel.Command import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter import com.duckduckgo.app.fire.DataClearer +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore import com.duckduckgo.app.global.rating.AppEnjoymentPromptEmitter import com.duckduckgo.app.global.rating.AppEnjoymentPromptOptions import com.duckduckgo.app.global.rating.AppEnjoymentUserEventRecorder @@ -35,6 +37,7 @@ import com.duckduckgo.app.tabs.model.TabRepository import com.duckduckgo.common.test.CoroutineTestRule import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory import com.duckduckgo.feature.toggles.api.Toggle.State +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertEquals @@ -52,34 +55,27 @@ class BrowserViewModelTest { @Suppress("unused") var instantTaskExecutorRule = InstantTaskExecutorRule() - @get:Rule - var coroutinesTestRule = CoroutineTestRule() + @get:Rule var coroutinesTestRule = CoroutineTestRule() - @Mock - private lateinit var mockCommandObserver: Observer + @Mock private lateinit var mockCommandObserver: Observer private val commandCaptor = argumentCaptor() - @Mock - private lateinit var mockTabRepository: TabRepository + @Mock private lateinit var mockTabRepository: TabRepository + + @Mock private lateinit var mockOmnibarEntryConverter: OmnibarEntryConverter - @Mock - private lateinit var mockOmnibarEntryConverter: OmnibarEntryConverter + @Mock private lateinit var mockAutomaticDataClearer: DataClearer - @Mock - private lateinit var mockAutomaticDataClearer: DataClearer + @Mock private lateinit var mockAppEnjoymentUserEventRecorder: AppEnjoymentUserEventRecorder - @Mock - private lateinit var mockAppEnjoymentUserEventRecorder: AppEnjoymentUserEventRecorder + @Mock private lateinit var mockAppEnjoymentPromptEmitter: AppEnjoymentPromptEmitter - @Mock - private lateinit var mockAppEnjoymentPromptEmitter: AppEnjoymentPromptEmitter + @Mock private lateinit var mockPixel: Pixel - @Mock - private lateinit var mockPixel: Pixel + @Mock private lateinit var mockDefaultBrowserDetector: DefaultBrowserDetector - @Mock - private lateinit var mockDefaultBrowserDetector: DefaultBrowserDetector + @Mock private lateinit var showOnAppLaunchOptionDataStore: ShowOnAppLaunchOptionDataStore private lateinit var testee: BrowserViewModel @@ -93,17 +89,7 @@ class BrowserViewModelTest { configureSkipUrlConversionInNewTabState(enabled = true) - testee = BrowserViewModel( - tabRepository = mockTabRepository, - queryUrlConverter = mockOmnibarEntryConverter, - dataClearer = mockAutomaticDataClearer, - appEnjoymentPromptEmitter = mockAppEnjoymentPromptEmitter, - appEnjoymentUserEventRecorder = mockAppEnjoymentUserEventRecorder, - defaultBrowserDetector = mockDefaultBrowserDetector, - dispatchers = coroutinesTestRule.testDispatcherProvider, - pixel = mockPixel, - skipUrlConversionOnNewTabFeature = skipUrlConversionOnNewTabFeature, - ) + initTestee() testee.command.observeForever(mockCommandObserver) @@ -267,6 +253,57 @@ class BrowserViewModelTest { verify(mockOmnibarEntryConverter).convertQueryToUrl("query") } + @Test + fun whenAppOpenAndLastOpenedTabSetThenNoTabsAdded() = runTest { + whenever(showOnAppLaunchOptionDataStore.optionFlow) + .thenReturn(flowOf(ShowOnAppLaunchOption.LastOpenedTab)) + + testee.handleShowOnAppLaunchOption() + + verify(mockTabRepository, never()).add(url = any(), skipHome = any()) + verify(mockTabRepository, never()).addFromSourceTab(url = any(), skipHome = any(), sourceTabId = any()) + verify(mockTabRepository, never()).addDefaultTab() + } + + @Test + fun whenAppOpenAndNewTabPageSetThenNewTabAdded() = runTest { + whenever(showOnAppLaunchOptionDataStore.optionFlow) + .thenReturn(flowOf(ShowOnAppLaunchOption.NewTabPage)) + + testee.handleShowOnAppLaunchOption() + + verify(mockTabRepository, atMost(1)).add() + verify(mockTabRepository, never()).addFromSourceTab(url = any(), skipHome = any(), sourceTabId = any()) + verify(mockTabRepository, never()).addDefaultTab() + } + + @Test + fun whenAppOpenAndSpecificPageSetThenNewTabAddedWithUrl() = runTest { + whenever(showOnAppLaunchOptionDataStore.optionFlow) + .thenReturn(flowOf(ShowOnAppLaunchOption.SpecificPage("example.com"))) + + testee.handleShowOnAppLaunchOption() + + verify(mockTabRepository, atMost(1)).add(url = "example.com", skipHome = false) + verify(mockTabRepository, never()).addFromSourceTab(url = any(), skipHome = any(), sourceTabId = any()) + verify(mockTabRepository, never()).addDefaultTab() + } + + private fun initTestee() { + testee = BrowserViewModel( + tabRepository = mockTabRepository, + queryUrlConverter = mockOmnibarEntryConverter, + dataClearer = mockAutomaticDataClearer, + appEnjoymentPromptEmitter = mockAppEnjoymentPromptEmitter, + appEnjoymentUserEventRecorder = mockAppEnjoymentUserEventRecorder, + defaultBrowserDetector = mockDefaultBrowserDetector, + dispatchers = coroutinesTestRule.testDispatcherProvider, + pixel = mockPixel, + skipUrlConversionOnNewTabFeature = skipUrlConversionOnNewTabFeature, + showOnAppLaunchOptionDataStore = showOnAppLaunchOptionDataStore, + ) + } + private fun configureSkipUrlConversionInNewTabState(enabled: Boolean) { skipUrlConversionOnNewTabFeature.self().setEnabled(State(enable = enabled)) } diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModelTest.kt index a592ce39533a..8058465395bb 100644 --- a/app/src/test/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModelTest.kt +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/GeneralSettingsViewModelTest.kt @@ -24,6 +24,7 @@ import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchO import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage import com.duckduckgo.app.generalsettings.showonapplaunch.store.FakeShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_PRESSED import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.common.test.CoroutineTestRule import com.duckduckgo.history.api.NavigationHistory @@ -230,6 +231,13 @@ internal class GeneralSettingsViewModelTest { } } + @Test + fun whenShowOnAppLaunchClickedThenPixelFiredEmitted() = runTest { + testee.onShowOnAppLaunchButtonClick() + + verify(mockPixel).fire(SETTINGS_GENERAL_APP_LAUNCH_PRESSED) + } + private fun defaultViewState() = GeneralSettingsViewModel.ViewState( autoCompleteSuggestionsEnabled = true, autoCompleteRecentlyVisitedSitesSuggestionsUserEnabled = true, diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPluginTest.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPluginTest.kt new file mode 100644 index 000000000000..07c10d5e99a3 --- /dev/null +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchStateReporterPluginTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption +import com.duckduckgo.app.generalsettings.showonapplaunch.store.FakeShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.statistics.pixels.Pixel.PixelParameter +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.common.utils.DispatcherProvider +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ShowOnAppLaunchReporterPluginTest { + + @get:Rule val coroutineTestRule = CoroutineTestRule() + + private val dispatcherProvider: DispatcherProvider = coroutineTestRule.testDispatcherProvider + private lateinit var testee: ShowOnAppLaunchStateReporterPlugin + private lateinit var fakeDataStore: ShowOnAppLaunchOptionDataStore + + @Before + fun setup() { + fakeDataStore = FakeShowOnAppLaunchOptionDataStore(ShowOnAppLaunchOption.LastOpenedTab) + + testee = ShowOnAppLaunchStateReporterPlugin(dispatcherProvider, fakeDataStore) + } + + @Test + fun whenOptionIsSetToLastOpenedPageThenShouldReturnDailyPixelValue() = runTest { + fakeDataStore.setShowOnAppLaunchOption(ShowOnAppLaunchOption.LastOpenedTab) + val result = testee.featureStateParams() + assertEquals("last_opened_tab", result[PixelParameter.LAUNCH_SCREEN]) + } + + @Test + fun whenOptionIsSetToNewTabPageThenShouldReturnDailyPixelValue() = runTest { + fakeDataStore.setShowOnAppLaunchOption(ShowOnAppLaunchOption.NewTabPage) + val result = testee.featureStateParams() + assertEquals("new_tab_page", result[PixelParameter.LAUNCH_SCREEN]) + } + + @Test + fun whenOptionIsSetToSpecificPageThenShouldReturnDailyPixelValue() = runTest { + val specificPage = ShowOnAppLaunchOption.SpecificPage("example.com") + fakeDataStore.setShowOnAppLaunchOption(specificPage) + val result = testee.featureStateParams() + assertEquals("specific_page", result[PixelParameter.LAUNCH_SCREEN]) + } +} diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImplTest.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImplTest.kt new file mode 100644 index 000000000000..ed3109a79593 --- /dev/null +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchUrlConverterImplTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.duckduckgo.app.generalsettings.showonapplaunch.store.ShowOnAppLaunchOptionDataStore.Companion.DEFAULT_SPECIFIC_PAGE_URL +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ShowOnAppLaunchUrlConverterImplTest { + + private val urlConverter = ShowOnAppLaunchUrlConverterImpl() + + @Test + fun whenUrlIsNullThenShouldReturnDefaultUrl() { + val result = urlConverter.convertUrl(null) + assertEquals(DEFAULT_SPECIFIC_PAGE_URL, result) + } + + @Test + fun whenUrlIsEmptyThenShouldReturnDefaultUrl() { + val result = urlConverter.convertUrl("") + assertEquals(DEFAULT_SPECIFIC_PAGE_URL, result) + } + + @Test + fun whenUrlIsBlankThenShouldReturnDefaultUrl() { + val result = urlConverter.convertUrl(" ") + assertEquals(DEFAULT_SPECIFIC_PAGE_URL, result) + } + + @Test + fun whenUrlHasNoSchemeThenHttpSchemeIsAdded() { + val result = urlConverter.convertUrl("www.example.com") + assertEquals("http://www.example.com", result) + } + + @Test + fun whenUrlHasNoSchemeAndSubdomainThenHttpSchemeIsAdded() { + val result = urlConverter.convertUrl("example.com") + assertEquals("http://example.com", result) + } + + @Test + fun whenUrlHasASchemeThenShouldReturnTheSameUrl() { + val result = urlConverter.convertUrl("https://www.example.com") + assertEquals("https://www.example.com", result) + } + + @Test + fun whenUrlHasDifferentSchemeThenShouldReturnTheSameUrl() { + val result = urlConverter.convertUrl("ftp://www.example.com") + assertEquals("ftp://www.example.com", result) + } + + @Test + fun whenUrlHasSpecialCharactersThenShouldReturnTheSameUrl() { + val result = urlConverter.convertUrl("https://www.example.com/path?query=param&another=param") + assertEquals("https://www.example.com/path?query=param&another=param", result) + } + + @Test + fun whenUrlHasPortThenShouldReturnTheSameUrl() { + val result = urlConverter.convertUrl("https://www.example.com:8080") + assertEquals("https://www.example.com:8080", result) + } + + @Test + fun whenUrlHasPathAndQueryParametersThenShouldReturnTheSameUrl() { + val result = urlConverter.convertUrl("https://www.example.com/path/to/resource?query=param") + assertEquals("https://www.example.com/path/to/resource?query=param", result) + } + + @Test + fun whenUrlHasUppercaseProtocolThenShouldLowercaseProtocol() { + val result = urlConverter.convertUrl("HTTPS://www.example.com") + assertEquals("https://www.example.com", result) + } + + @Test + fun whenUrlHasUppercaseSubdomainThenShouldLowercaseSubdomain() { + val result = urlConverter.convertUrl("https://WWW.example.com") + assertEquals("https://www.example.com", result) + } + + @Test + fun whenUrlHasUppercaseDomainThenShouldLowercaseDomain() { + val result = urlConverter.convertUrl("https://www.EXAMPLE.com") + assertEquals("https://www.example.com", result) + } + + @Test + fun whenUrlHasUppercaseTopLevelDomainThenShouldLowercaseTopLevelDomain() { + val result = urlConverter.convertUrl("https://www.example.COM") + assertEquals("https://www.example.com", result) + } + + @Test + fun whenUrlHasMixedCaseThenOnlyProtocolSubdomainDomainAndTldAreLowercased() { + val result = urlConverter.convertUrl("HTTPS://WWW.EXAMPLE.COM/Path?Query=Param#Fragment") + assertEquals("https://www.example.com/Path?Query=Param#Fragment", result) + } + + @Test + fun whenUrlIsNotAValidUrlReturnsInvalidUrlWithHttpScheme() { + val result = urlConverter.convertUrl("example") + assertEquals("http://example", result) + } +} diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModelTest.kt new file mode 100644 index 000000000000..dc8a0af55ac0 --- /dev/null +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/ShowOnAppLaunchViewModelTest.kt @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch + +import app.cash.turbine.test +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.LastOpenedTab +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage +import com.duckduckgo.app.generalsettings.showonapplaunch.store.FakeShowOnAppLaunchOptionDataStore +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_LAST_OPENED_TAB_SELECTED +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_NEW_TAB_PAGE_SELECTED +import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_APP_LAUNCH_SPECIFIC_PAGE_SELECTED +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.fakes.FakePixel +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class ShowOnAppLaunchViewModelTest { + + @get:Rule + val coroutineTestRule = CoroutineTestRule() + + private lateinit var testee: ShowOnAppLaunchViewModel + private lateinit var fakeDataStore: FakeShowOnAppLaunchOptionDataStore + private lateinit var fakePixel: FakePixel + private val dispatcherProvider: DispatcherProvider = coroutineTestRule.testDispatcherProvider + + @Before + fun setup() { + fakeDataStore = FakeShowOnAppLaunchOptionDataStore(LastOpenedTab) + fakePixel = FakePixel() + testee = ShowOnAppLaunchViewModel(dispatcherProvider, fakeDataStore, FakeUrlConverter(), fakePixel) + } + + @Test + fun whenViewModelInitializedThenInitialStateIsCorrect() = runTest { + testee.viewState.test { + val initialState = awaitItem() + assertEquals(LastOpenedTab, initialState.selectedOption) + assertEquals("https://duckduckgo.com", initialState.specificPageUrl) + } + } + + @Test + fun whenShowOnAppLaunchOptionChangedThenStateIsUpdated() = runTest { + testee.onShowOnAppLaunchOptionChanged(NewTabPage) + testee.viewState.test { + val updatedState = awaitItem() + assertEquals(NewTabPage, updatedState.selectedOption) + } + } + + @Test + fun whenSpecificPageUrlSetThenStateIsUpdated() = runTest { + val newUrl = "https://example.com" + + testee.setSpecificPageUrl(newUrl) + testee.viewState.test { + val updatedState = awaitItem() + assertEquals(newUrl, updatedState.specificPageUrl) + } + } + + @Test + fun whenMultipleOptionsChangedThenStateIsUpdatedCorrectly() = runTest { + testee.onShowOnAppLaunchOptionChanged(NewTabPage) + testee.onShowOnAppLaunchOptionChanged(LastOpenedTab) + testee.viewState.test { + val updatedState = awaitItem() + assertEquals(LastOpenedTab, updatedState.selectedOption) + } + } + + @Test + fun whenOptionChangedToLastOpenedPageThenLastOpenedPageIsFired() = runTest { + testee.onShowOnAppLaunchOptionChanged(NewTabPage) + testee.onShowOnAppLaunchOptionChanged(LastOpenedTab) + assertEquals(2, fakePixel.firedPixels.size) + assertEquals(SETTINGS_GENERAL_APP_LAUNCH_LAST_OPENED_TAB_SELECTED.pixelName, fakePixel.firedPixels.last()) + } + + @Test + fun whenOptionChangedToNewTabPageThenNewTabPagePixelIsFired() = runTest { + testee.onShowOnAppLaunchOptionChanged(NewTabPage) + assertEquals(1, fakePixel.firedPixels.size) + assertEquals(SETTINGS_GENERAL_APP_LAUNCH_NEW_TAB_PAGE_SELECTED.pixelName, fakePixel.firedPixels[0]) + } + + @Test + fun whenOptionChangedToSpecificPageThenSpecificPixelIsFired() = runTest { + testee.onShowOnAppLaunchOptionChanged(SpecificPage("https://example.com")) + assertEquals(1, fakePixel.firedPixels.size) + assertEquals(SETTINGS_GENERAL_APP_LAUNCH_SPECIFIC_PAGE_SELECTED.pixelName, fakePixel.firedPixels[0]) + } + + private class FakeUrlConverter : UrlConverter { + + override fun convertUrl(url: String?): String { + return url ?: "https://duckduckgo.com" + } + } +} diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/FakeShowOnAppLaunchOptionDataStore.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/FakeShowOnAppLaunchOptionDataStore.kt index 51261a3d6e70..d96d1c396cba 100644 --- a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/FakeShowOnAppLaunchOptionDataStore.kt +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/FakeShowOnAppLaunchOptionDataStore.kt @@ -22,11 +22,11 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.filterNotNull -class FakeShowOnAppLaunchOptionDataStore : ShowOnAppLaunchOptionDataStore { +class FakeShowOnAppLaunchOptionDataStore(defaultOption: ShowOnAppLaunchOption? = null) : ShowOnAppLaunchOptionDataStore { - private var currentOptionStateFlow = MutableStateFlow(null) + private var currentOptionStateFlow = MutableStateFlow(defaultOption) - private var currentSpecificPageUrl = MutableStateFlow("duckduckgo.com") + private var currentSpecificPageUrl = MutableStateFlow("https://duckduckgo.com") override val optionFlow: Flow = currentOptionStateFlow.asStateFlow().filterNotNull() diff --git a/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchPrefsDataStoreTest.kt b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchPrefsDataStoreTest.kt new file mode 100644 index 000000000000..dcb1c8dec27a --- /dev/null +++ b/app/src/test/java/com/duckduckgo/app/generalsettings/showonapplaunch/store/ShowOnAppLaunchPrefsDataStoreTest.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.generalsettings.showonapplaunch.store + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStoreFile +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import app.cash.turbine.test +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.LastOpenedTab +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage +import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage +import com.duckduckgo.common.test.CoroutineTestRule +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ShowOnAppLaunchPrefsDataStoreTest { + + @get:Rule val coroutineRule = CoroutineTestRule() + + private val context: Context + get() = ApplicationProvider.getApplicationContext() + + private val dataStoreFile = context.preferencesDataStoreFile("show_on_app_launch") + + private val testDataStore: DataStore = + PreferenceDataStoreFactory.create( + scope = coroutineRule.testScope, + produceFile = { dataStoreFile }, + ) + + private val testee: ShowOnAppLaunchOptionDataStore = + ShowOnAppLaunchOptionPrefsDataStore(testDataStore) + + @After + fun after() { + dataStoreFile.delete() + } + + @Test + fun whenOptionIsNullThenShouldReturnLastOpenedPage() = runTest { + assertEquals(LastOpenedTab, testee.optionFlow.first()) + } + + @Test + fun whenOptionIsSetToLastOpenedPageThenShouldReturnLastOpenedPage() = runTest { + testee.setShowOnAppLaunchOption(LastOpenedTab) + assertEquals(LastOpenedTab, testee.optionFlow.first()) + } + + @Test + fun whenOptionIsSetToNewTabPageThenShouldReturnNewTabPage() = runTest { + testee.setShowOnAppLaunchOption(NewTabPage) + assertEquals(NewTabPage, testee.optionFlow.first()) + } + + @Test + fun whenOptionIsSetToSpecificPageThenShouldReturnSpecificPage() = runTest { + val specificPage = SpecificPage("example.com") + + testee.setShowOnAppLaunchOption(specificPage) + assertEquals(specificPage, testee.optionFlow.first()) + } + + @Test + fun whenSpecificPageIsNullThenShouldReturnDefaultUrl() = runTest { + assertEquals("https://duckduckgo.com/", testee.specificPageUrlFlow.first()) + } + + @Test + fun whenSpecificPageUrlIsSetThenShouldReturnSpecificPageUrl() = runTest { + testee.setSpecificPageUrl("example.com") + assertEquals("example.com", testee.specificPageUrlFlow.first()) + } + + @Test + fun whenOptionIsChangedThenNewOptionEmitted() = runTest { + testee.optionFlow.test { + val defaultOption = awaitItem() + + assertEquals(LastOpenedTab, defaultOption) + + testee.setShowOnAppLaunchOption(NewTabPage) + + assertEquals(NewTabPage, awaitItem()) + + testee.setShowOnAppLaunchOption(SpecificPage("example.com")) + + assertEquals(SpecificPage("example.com"), awaitItem()) + } + } +} diff --git a/app/src/test/java/com/duckduckgo/fakes/FakePixel.kt b/app/src/test/java/com/duckduckgo/fakes/FakePixel.kt new file mode 100644 index 000000000000..ca4bbb7ec52d --- /dev/null +++ b/app/src/test/java/com/duckduckgo/fakes/FakePixel.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.fakes + +import com.duckduckgo.app.statistics.pixels.Pixel +import com.duckduckgo.app.statistics.pixels.Pixel.PixelName +import com.duckduckgo.app.statistics.pixels.Pixel.PixelType + +internal class FakePixel : Pixel { + + val firedPixels = mutableListOf() + + override fun fire( + pixel: PixelName, + parameters: Map, + encodedParameters: Map, + type: PixelType, + ) { + firedPixels.add(pixel.pixelName) + } + + override fun fire( + pixelName: String, + parameters: Map, + encodedParameters: Map, + type: PixelType, + ) { + firedPixels.add(pixelName) + } + + override fun enqueueFire( + pixel: PixelName, + parameters: Map, + encodedParameters: Map, + ) { + firedPixels.add(pixel.pixelName) + } + + override fun enqueueFire( + pixelName: String, + parameters: Map, + encodedParameters: Map, + ) { + firedPixels.add(pixelName) + } +} diff --git a/browser-api/src/main/java/com/duckduckgo/app/tabs/model/TabRepository.kt b/browser-api/src/main/java/com/duckduckgo/app/tabs/model/TabRepository.kt index a96eb9f44eb5..d9adb1780081 100644 --- a/browser-api/src/main/java/com/duckduckgo/app/tabs/model/TabRepository.kt +++ b/browser-api/src/main/java/com/duckduckgo/app/tabs/model/TabRepository.kt @@ -93,6 +93,8 @@ interface TabRepository { suspend fun deleteAll() + suspend fun getSelectedTab(): TabEntity? + suspend fun select(tabId: String) fun updateTabPreviewImage( diff --git a/statistics/statistics-api/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt b/statistics/statistics-api/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt index c0fb603e92a4..f7776e936252 100644 --- a/statistics/statistics-api/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt +++ b/statistics/statistics-api/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt @@ -60,6 +60,7 @@ interface Pixel { // Loading Bar Experiment const val LOADING_BAR_EXPERIMENT = "loading_bar_exp" + const val LAUNCH_SCREEN = "launch_screen" } object PixelValues {