From 2ac0d1f13a808a377fd9b8ebaa4e416d0059809c Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 2 Jul 2024 09:31:34 +0200 Subject: [PATCH 01/22] add NP icon for Android Studio's NewUI --- .idea/icon.svg | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .idea/icon.svg diff --git a/.idea/icon.svg b/.idea/icon.svg new file mode 100644 index 00000000000..51fdf95dee0 --- /dev/null +++ b/.idea/icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + From 9f766ebf781b770b6e1b37da084e6193698cee4c Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 11 Jul 2024 09:30:22 +0200 Subject: [PATCH 02/22] Fix NPE in MediaSessionPlayerUi while destroying player --- .../newpipe/player/mediasession/MediaSessionPlayerUi.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java index 737ebc5dd04..c673e688c47 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java @@ -38,7 +38,9 @@ public class MediaSessionPlayerUi extends PlayerUi implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "MediaSessUi"; + @Nullable private MediaSessionCompat mediaSession; + @Nullable private MediaSessionConnector sessionConnector; private final String ignoreHardwareMediaButtonsKey; @@ -198,6 +200,11 @@ private void updateMediaSessionActions() { return; } + if (sessionConnector == null) { + // sessionConnector will be null after destroyPlayer is called + return; + } + // only use the fourth and fifth actions (the settings page also shows only the last 2 on // Android 13+) final List newNotificationActions = IntStream.of(3, 4) From 0e0cee1bcecc0414a25b88ff0b153273c6a9d546 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 11 Jul 2024 23:27:26 +0200 Subject: [PATCH 03/22] Update NewPipeExtractor to v0.24.1 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 28a20819511..eebf9135f9a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -198,7 +198,7 @@ dependencies { // name and the commit hash with the commit hash of the (pushed) commit you want to test // This works thanks to JitPack: https://jitpack.io/ implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751' - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.0' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.1' implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0' /** Checkstyle **/ From acc5be92ac0fcf1899ac265575b01349f4768d82 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 11 Jul 2024 23:39:53 +0200 Subject: [PATCH 04/22] Add changelogs for hotfix release v0.27.1 (998) --- fastlane/metadata/android/ar/changelogs/998.txt | 1 + fastlane/metadata/android/az/changelogs/998.txt | 1 + fastlane/metadata/android/cs/changelogs/998.txt | 1 + fastlane/metadata/android/de/changelogs/998.txt | 1 + fastlane/metadata/android/en-US/changelogs/998.txt | 4 ++++ fastlane/metadata/android/es/changelogs/998.txt | 1 + fastlane/metadata/android/fa/changelogs/998.txt | 1 + fastlane/metadata/android/fr/changelogs/998.txt | 1 + fastlane/metadata/android/he/changelogs/998.txt | 1 + fastlane/metadata/android/hi/changelogs/998.txt | 1 + fastlane/metadata/android/id/changelogs/998.txt | 1 + fastlane/metadata/android/it/changelogs/998.txt | 4 ++++ fastlane/metadata/android/ka/changelogs/998.txt | 1 + fastlane/metadata/android/nl/changelogs/998.txt | 1 + fastlane/metadata/android/pa/changelogs/998.txt | 1 + fastlane/metadata/android/pt-BR/changelogs/998.txt | 1 + fastlane/metadata/android/pt-PT/changelogs/998.txt | 1 + fastlane/metadata/android/pt/changelogs/998.txt | 1 + fastlane/metadata/android/ru/changelogs/998.txt | 1 + fastlane/metadata/android/sv/changelogs/998.txt | 1 + fastlane/metadata/android/tr/changelogs/998.txt | 1 + fastlane/metadata/android/uk/changelogs/998.txt | 1 + fastlane/metadata/android/vi/changelogs/998.txt | 1 + fastlane/metadata/android/zh-Hans/changelogs/998.txt | 1 + fastlane/metadata/android/zh-Hant/changelogs/998.txt | 1 + fastlane/metadata/android/zh_Hant_HK/changelogs/998.txt | 1 + 26 files changed, 32 insertions(+) create mode 100644 fastlane/metadata/android/ar/changelogs/998.txt create mode 100644 fastlane/metadata/android/az/changelogs/998.txt create mode 100644 fastlane/metadata/android/cs/changelogs/998.txt create mode 100644 fastlane/metadata/android/de/changelogs/998.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/998.txt create mode 100644 fastlane/metadata/android/es/changelogs/998.txt create mode 100644 fastlane/metadata/android/fa/changelogs/998.txt create mode 100644 fastlane/metadata/android/fr/changelogs/998.txt create mode 100644 fastlane/metadata/android/he/changelogs/998.txt create mode 100644 fastlane/metadata/android/hi/changelogs/998.txt create mode 100644 fastlane/metadata/android/id/changelogs/998.txt create mode 100644 fastlane/metadata/android/it/changelogs/998.txt create mode 100644 fastlane/metadata/android/ka/changelogs/998.txt create mode 100644 fastlane/metadata/android/nl/changelogs/998.txt create mode 100644 fastlane/metadata/android/pa/changelogs/998.txt create mode 100644 fastlane/metadata/android/pt-BR/changelogs/998.txt create mode 100644 fastlane/metadata/android/pt-PT/changelogs/998.txt create mode 100644 fastlane/metadata/android/pt/changelogs/998.txt create mode 100644 fastlane/metadata/android/ru/changelogs/998.txt create mode 100644 fastlane/metadata/android/sv/changelogs/998.txt create mode 100644 fastlane/metadata/android/tr/changelogs/998.txt create mode 100644 fastlane/metadata/android/uk/changelogs/998.txt create mode 100644 fastlane/metadata/android/vi/changelogs/998.txt create mode 100644 fastlane/metadata/android/zh-Hans/changelogs/998.txt create mode 100644 fastlane/metadata/android/zh-Hant/changelogs/998.txt create mode 100644 fastlane/metadata/android/zh_Hant_HK/changelogs/998.txt diff --git a/fastlane/metadata/android/ar/changelogs/998.txt b/fastlane/metadata/android/ar/changelogs/998.txt new file mode 100644 index 00000000000..562f169445a --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/998.txt @@ -0,0 +1 @@ +تم إصلاح YouTube الذي لا يقوم بتشغيل أي دفق diff --git a/fastlane/metadata/android/az/changelogs/998.txt b/fastlane/metadata/android/az/changelogs/998.txt new file mode 100644 index 00000000000..16a2e101364 --- /dev/null +++ b/fastlane/metadata/android/az/changelogs/998.txt @@ -0,0 +1 @@ +YouTube-un heç bir yayım oynatmaması düzəldildi diff --git a/fastlane/metadata/android/cs/changelogs/998.txt b/fastlane/metadata/android/cs/changelogs/998.txt new file mode 100644 index 00000000000..7035a111220 --- /dev/null +++ b/fastlane/metadata/android/cs/changelogs/998.txt @@ -0,0 +1 @@ +Opraveno nepřehrávání jakéhokoli streamu ve službě YouTube diff --git a/fastlane/metadata/android/de/changelogs/998.txt b/fastlane/metadata/android/de/changelogs/998.txt new file mode 100644 index 00000000000..43623578f6a --- /dev/null +++ b/fastlane/metadata/android/de/changelogs/998.txt @@ -0,0 +1 @@ +Behoben, dass YouTube keinen Stream abspielte diff --git a/fastlane/metadata/android/en-US/changelogs/998.txt b/fastlane/metadata/android/en-US/changelogs/998.txt new file mode 100644 index 00000000000..468df020430 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/998.txt @@ -0,0 +1,4 @@ +Fixed YouTube not playing any stream because of HTTP 403 errors. + +Occasional HTTP 403 errors in the middle of a YouTube video are not fixed yet. +That issue will be addressed in another hotfix release as soon as possible. diff --git a/fastlane/metadata/android/es/changelogs/998.txt b/fastlane/metadata/android/es/changelogs/998.txt new file mode 100644 index 00000000000..80b4efa553d --- /dev/null +++ b/fastlane/metadata/android/es/changelogs/998.txt @@ -0,0 +1 @@ +Arreglo en YouTube no reproduciendo flujos diff --git a/fastlane/metadata/android/fa/changelogs/998.txt b/fastlane/metadata/android/fa/changelogs/998.txt new file mode 100644 index 00000000000..ba5413d49f8 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/998.txt @@ -0,0 +1 @@ +مشکل عدم نمایش پخش‌زنده برطرف شد diff --git a/fastlane/metadata/android/fr/changelogs/998.txt b/fastlane/metadata/android/fr/changelogs/998.txt new file mode 100644 index 00000000000..3ad3bf2798b --- /dev/null +++ b/fastlane/metadata/android/fr/changelogs/998.txt @@ -0,0 +1 @@ +Correction de YouTube qui ne lisait aucun média diff --git a/fastlane/metadata/android/he/changelogs/998.txt b/fastlane/metadata/android/he/changelogs/998.txt new file mode 100644 index 00000000000..50731171e10 --- /dev/null +++ b/fastlane/metadata/android/he/changelogs/998.txt @@ -0,0 +1 @@ +תוקנה התקלה ש־YouTube לא מנגן אף תזרים diff --git a/fastlane/metadata/android/hi/changelogs/998.txt b/fastlane/metadata/android/hi/changelogs/998.txt new file mode 100644 index 00000000000..071ab64e338 --- /dev/null +++ b/fastlane/metadata/android/hi/changelogs/998.txt @@ -0,0 +1 @@ +फिक्स्ड YouTube कोई स्ट्रीम नहीं चला रहा है diff --git a/fastlane/metadata/android/id/changelogs/998.txt b/fastlane/metadata/android/id/changelogs/998.txt new file mode 100644 index 00000000000..d3fea84ab5e --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/998.txt @@ -0,0 +1 @@ +Memperbaiki YouTube yang tidak memutar streaming apa pun diff --git a/fastlane/metadata/android/it/changelogs/998.txt b/fastlane/metadata/android/it/changelogs/998.txt new file mode 100644 index 00000000000..73fc6f2d862 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/998.txt @@ -0,0 +1,4 @@ +Corretto problema di riproduzione di YouTube causato da errori HTTP 403. + +Gli errori HTTP 403 saltuari nel mezzo di un video di YouTube non sono ancora stati sistemati. +Questo problema sarà affrontato in un altra release hotfix non appena possibile. diff --git a/fastlane/metadata/android/ka/changelogs/998.txt b/fastlane/metadata/android/ka/changelogs/998.txt new file mode 100644 index 00000000000..d20512f1710 --- /dev/null +++ b/fastlane/metadata/android/ka/changelogs/998.txt @@ -0,0 +1 @@ +გაასწორა YouTube არ უკრავს არცერთ ნაკადს diff --git a/fastlane/metadata/android/nl/changelogs/998.txt b/fastlane/metadata/android/nl/changelogs/998.txt new file mode 100644 index 00000000000..9bd8adf8693 --- /dev/null +++ b/fastlane/metadata/android/nl/changelogs/998.txt @@ -0,0 +1 @@ +YouTube speelt geen stream af opgelost diff --git a/fastlane/metadata/android/pa/changelogs/998.txt b/fastlane/metadata/android/pa/changelogs/998.txt new file mode 100644 index 00000000000..fe62a1330fe --- /dev/null +++ b/fastlane/metadata/android/pa/changelogs/998.txt @@ -0,0 +1 @@ +ਸਥਿਰ YouTube ਕੋਈ ਸਟ੍ਰੀਮ ਨਹੀਂ ਚਲਾ ਰਿਹਾ diff --git a/fastlane/metadata/android/pt-BR/changelogs/998.txt b/fastlane/metadata/android/pt-BR/changelogs/998.txt new file mode 100644 index 00000000000..59fc6a5cdb0 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/998.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir qualquer transmissão diff --git a/fastlane/metadata/android/pt-PT/changelogs/998.txt b/fastlane/metadata/android/pt-PT/changelogs/998.txt new file mode 100644 index 00000000000..93519d64d7a --- /dev/null +++ b/fastlane/metadata/android/pt-PT/changelogs/998.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir nenhuma transmissão diff --git a/fastlane/metadata/android/pt/changelogs/998.txt b/fastlane/metadata/android/pt/changelogs/998.txt new file mode 100644 index 00000000000..93519d64d7a --- /dev/null +++ b/fastlane/metadata/android/pt/changelogs/998.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir nenhuma transmissão diff --git a/fastlane/metadata/android/ru/changelogs/998.txt b/fastlane/metadata/android/ru/changelogs/998.txt new file mode 100644 index 00000000000..d3978869d59 --- /dev/null +++ b/fastlane/metadata/android/ru/changelogs/998.txt @@ -0,0 +1 @@ +Исправлено: YouTube не воспроизводил никакие потоки diff --git a/fastlane/metadata/android/sv/changelogs/998.txt b/fastlane/metadata/android/sv/changelogs/998.txt new file mode 100644 index 00000000000..35f298dbff8 --- /dev/null +++ b/fastlane/metadata/android/sv/changelogs/998.txt @@ -0,0 +1 @@ +Åtgärdat att YouTube inte spelar någon stream diff --git a/fastlane/metadata/android/tr/changelogs/998.txt b/fastlane/metadata/android/tr/changelogs/998.txt new file mode 100644 index 00000000000..e5979c68d6a --- /dev/null +++ b/fastlane/metadata/android/tr/changelogs/998.txt @@ -0,0 +1 @@ +YouTube'un herhangi bir akışı oynatmaması düzeltildi diff --git a/fastlane/metadata/android/uk/changelogs/998.txt b/fastlane/metadata/android/uk/changelogs/998.txt new file mode 100644 index 00000000000..905287c7494 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/998.txt @@ -0,0 +1 @@ +Виправлено проблему невідтворюваності трансляцій diff --git a/fastlane/metadata/android/vi/changelogs/998.txt b/fastlane/metadata/android/vi/changelogs/998.txt new file mode 100644 index 00000000000..d2086b62c1f --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/998.txt @@ -0,0 +1 @@ +Đã sửa lỗi YouTube không phát bất kỳ luồng nào diff --git a/fastlane/metadata/android/zh-Hans/changelogs/998.txt b/fastlane/metadata/android/zh-Hans/changelogs/998.txt new file mode 100644 index 00000000000..8a5424c9e02 --- /dev/null +++ b/fastlane/metadata/android/zh-Hans/changelogs/998.txt @@ -0,0 +1 @@ +修复YouTube无法播放任何视频 diff --git a/fastlane/metadata/android/zh-Hant/changelogs/998.txt b/fastlane/metadata/android/zh-Hant/changelogs/998.txt new file mode 100644 index 00000000000..4e8bf65377d --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/changelogs/998.txt @@ -0,0 +1 @@ +修正 YouTube 無法播放任何串流 diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/998.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/998.txt new file mode 100644 index 00000000000..9a4721551a1 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/998.txt @@ -0,0 +1 @@ +修正咗 YouTube 乜嘢實況串流都播唔到嘅問題 From 0f64158469d42a37df5c8ef200f7963cafabe361 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 11 Jul 2024 23:41:53 +0200 Subject: [PATCH 05/22] Hotfix release v0.27.1 (998) --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index eebf9135f9a..397a7301e90 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,8 +20,8 @@ android { resValue "string", "app_name", "NewPipe" minSdk 21 targetSdk 33 - versionCode 997 - versionName "0.27.0" + versionCode 998 + versionName "0.27.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From ad6b676c81ad0beca27a287bb2d0b5f8b41f8f20 Mon Sep 17 00:00:00 2001 From: #27 <68751594+tag27@users.noreply.github.com> Date: Sat, 13 Jul 2024 14:32:24 -0300 Subject: [PATCH 06/22] Update README.pt_BR.md (#11275) --- doc/README.pt_BR.md | 126 +++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/doc/README.pt_BR.md b/doc/README.pt_BR.md index 01fa718ad99..59ff65db3df 100644 --- a/doc/README.pt_BR.md +++ b/doc/README.pt_BR.md @@ -1,3 +1,6 @@ +

Nós estamos planejando reescrever grandes pedaços do código base, para gerar um novo, moderno e estável NewPipe!

+

Por favor, não abra solicitações de pull para novos recursos por enquanto, apenas correções de bugs serão aceitas.

+

NewPipe

@@ -13,16 +16,16 @@


-

ScreenshotsDescriçãoCaracterísticasAtualizaçõesContribuiçãoDoarLicença

+

ScreenshotsServiços SuportadosDescriçãoRecursosInstalação e atualizaçõesContribuiçõesDoarLicença

SiteBlogFAQPress


-*Read this document in other languages: [Deutsch](README.de.md), [English](../README.md), [Español](README.es.md), [Français](README.fr.md), [हिन्दी](README.hi.md), [Italiano](README.it.md), [한국어](README.ko.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [ਪੰਜਾਬੀ ](README.pa.md), [日本語](README.ja.md), [Română](README.ro.md), [Soomaali](README.so.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md), [অসমীয়া](README.asm.md), [うちなーぐち](README.ryu.md), [Српски](README.sr.md)* +*Leia esse documento em outras línguas: [Deutsch](README.de.md), [English](../README.md), [Español](README.es.md), [Français](README.fr.md), [हिन्दी](README.hi.md), [Italiano](README.it.md), [한국어](README.ko.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [ਪੰਜਾਬੀ ](README.pa.md), [日本語](README.ja.md), [Română](README.ro.md), [Soomaali](README.so.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md), [অসমীয়া](README.asm.md), [うちなーぐち](README.ryu.md), [Српски](README.sr.md)* > [!warning] -> ESTA É UMA VERSÃO BETA, PORTANTO, VOCÊ PODE ENCONTRAR BUGS. ENCONTROU ALGUM, ABRA UM ISSUE ATRAVÉS DO NOSSO REPOSITÓRIO GITHUB. +> ESTA É UMA VERSÃO BETA, PORTANTO, VOCÊ PODE ENCONTRAR BUGS. ENCONTROU ALGUM, ABRA UM ISSUE ATRAVÉS DO NOSSO REPOSITÓRIO GITHUB PREENCHENDO O MODELO. > -> COLOCAR NEWPIPE OU QUALQUER FORK DELE NA GOOGLE PLAY STORE VIOLA SEUS TERMOS E CONDIÇÕES. +> COLOCAR NEWPIPE, OU QUALQUER FORK DELE, NA GOOGLE PLAY STORE VIOLA SEUS TERMOS E CONDIÇÕES. ## Screenshots @@ -39,83 +42,84 @@ [](../fastlane/metadata/android/en-US/images/tenInchScreenshots/09.png) [](../fastlane/metadata/android/en-US/images/tenInchScreenshots/10.png) -## Descrição +### Serviços Suportados -O NewPipe não usa nenhuma biblioteca de framework do Google, nem a API do YouTube. Os sites são apenas analisados para obter informações necessárias, para que este aplicativo possa ser usado em dispositivos sem os serviços do Google instalados. Além disso, você não precisa de uma conta no YouTube para usar o NewPipe, que é um software livre com copyleft. - -### Características - -* Procurar vídeos -* Exibir informações gerais sobre vídeos -* Assista aos vídeos do YouTube -* Ouça vídeos do YouTube -* Modo popup (player flutuante) -* Selecione o player para assistir streaming -* Baixar vídeos -* Baixar somente áudio -* Abrir vídeo no Kodi -* Mostrar vídeos próximos/relacionados -* Pesquise no YouTube em um idioma específico -* Assistir/Bloquear material restrito -* Exibir informações gerais sobre canais -* Pesquisar canais -* Assista a vídeos de um canal -* Suporte Orbot/Tor (ainda não diretamente) -* Suporte 1080p/2K/4K -* Ver histórico -* Inscreva-se nos canais -* Procurar histórico -* Porcurar/Assistir playlists -* Assistir playlists em fila -* Vídeos em fila -* Playlists Local -* Legenda -* Suporte a live -* Mostrar comentários +Atualmente, os serviços suportados são: -### Serviços Suportados +* YouTube ([site](https://www.youtube.com/)) e YouTube Music ([site](https://music.youtube.com/)) ([wiki](https://en.wikipedia.org/wiki/YouTube)) +* PeerTube ([site](https://joinpeertube.org/)) e todas suas instâncias (abra o site para saber o que isso significa!) ([wiki](https://en.wikipedia.org/wiki/PeerTube)) +* Bandcamp ([site](https://bandcamp.com/)) ([wiki](https://en.wikipedia.org/wiki/Bandcamp)) +* SoundCloud ([site](https://soundcloud.com/)) ([wiki](https://en.wikipedia.org/wiki/SoundCloud)) +* media.ccc.de ([site](https://media.ccc.de/)) ([wiki](https://en.wikipedia.org/wiki/Chaos_Computer_Club)) -O NewPipe suporta vários serviços. Nosso [documentação](https://teamnewpipe.github.io/documentation/) fornecer mais informações sobre como um novo serviço pode ser adicionado ao aplicativo e ao extrator. Por favor, entre em contato conosco se você pretende adicionar um novo. Atualmente, os serviços suportados são: +Como você pode ver, o NewPipe suporta múltiplos serviços de vídeo e áudio. Embora tenha começado com o YouTube, outras pessoas adicionaram mais serviços ao longo dos anos, tornando o NewPipe cada vez mais versátil! -* YouTube -* SoundCloud \[beta\] -* media.ccc.de \[beta\] -* PeerTube instances \[beta\] -* Bandcamp \[beta\] +Parcialmente devido as circustâncias e a sua popularidade, o YouTube tem o melhor suporte em relação a esses serviços. Se você usa ou é familarizado com qualquer um desses serviços, por favor ajude-nos a melhorar o suporte para eles! Estamos procurando mantenedores para o SoundCloud e o PeerTube. -## Atualizações -Quando uma alteração no código NewPipe (devido à adição de recursos ou fixação de bugs), eventualmente ocorrerá uma versão. Estes estão no formato x.xx.x . A fim de obter esta nova versão, você pode: - 1. Construa um APK de depuração você mesmo. Esta é a maneira mais rápida de obter novos recursos em seu dispositivo, mas é muito mais complicado, por isso recomendamos usar um dos outros métodos. - 2. Adicione nosso repo personalizado ao F-Droid e instale-o a partir daí assim que publicarmos um lançamento. As instruções estão aqui.: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/ - 3. Baixe o APK do [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) e instalá-lo assim que publicarmos um lançamento. - 4. Atualização via F-droid. Este é o método mais lento para obter atualizações, pois o F-Droid deve reconhecer alterações, construir o próprio APK, assiná-lo e, em seguida, enviar a atualização para os usuários. +Se você pretende adicionar um novo serviço, por favor entre em contato conosco primeiro! Nossa [documentação](https://teamnewpipe.github.io/documentation/) traz mais informações em como um novo serviço pode ser adicionado ao aplicativo e no [NewPipe Extractor](https://github.com/TeamNewPipe/NewPipeExtractor). -Recomendamos o método 2 para a maioria dos usuários. Os APKs instalados usando o método 2 ou 3 são compatíveis entre si, mas não com aqueles instalados usando o método 4. Isso se deve à mesma chave de assinatura (nossa) sendo usada para 2 e 3, mas uma chave de assinatura diferente (F-Droid's) está sendo usada para 4. Construir um APK depuração usando o método 1 exclui totalmente uma chave. Assinar chaves ajudam a garantir que um usuário não seja enganado para instalar uma atualização maliciosa em um aplicativo. +## Descrição + +NewPipe funciona buscando os dados necessários da API oficial (ex. PeerTube) ou do serviço que você está usando. Se a API oficial é restrita (ex. YouTube) para nossos propósitos, ou é proprietária, o aplicativo analisa o site ou usa uma API interna. Isso significa que não é preciso ter uma conta de qualquer serviço para usar o NewPipe. + +Também, desde que somos um software livre e de código aberto, nem o aplicativo e nem o Extractor usa qualquer biblioteca ou framework proprietário, como o Google Play Services. Isso significa que você pode usar o NewPipe em dispositivos ou ROMs customizadas em que não tem os aplicativos do Google instalados. + +### Recursos + +* Assistir vídeos em resoluções de até 4K +* Escutar o áudio em segundo plano, carregando apenas o fluxo de áudio para salvar dados +* Modo popup (player flutuante, aka Picture-in-Picture) +* Assista a transmissões ao vivo +* Mostrar/esconder legendas/closed captions +* Buscar vídeos e áudios (no YouTube, você pode especificar o conteúdo da linguagem também) +* Enfileirar vídeos (e opcionalmente salvar eles como playlists locais) +* Mostrar/esconder informações gerais sobre os vídeos (como descrições e tags) +* Mostrar/esconder vídeos próximos/relacionados +* Mostrar/esconder comentários +* Buscar vídeos, áudios, canais, playlists e álbuns +* Navegar vídeos e áudios dentro de um canal +* Inscrever-se a canais (sim, mesmo se não estiver logado a qualquer conta!) +* Receba notificações sobre novos vídeos de canais em que você está inscrito +* Crie e edite grupos de canais (para facilitar a navegação e o gerenciamento) +* Navege feeds de vídeo gerados a partir dos seus grupos de canais +* Veja e pesquise seu histórico de vídeos +* Pesquise e assista playlists (Eles são playlists remotas, o que significa que eles serão obtidos do serviço que você está navegando) +* Crie e edite playlists locais (Eles são criados e salvos no aplicativo, e não são relacionados com nenhum serviço) +* Baixe vídeos/áudios/legendas (closed captions) +* Abra no Kodi +* Assista/Bloqueie material restrito + +## Instalação e atualizações +Você pode instalar NewPipe com um dos seguintes métodos: + 1. Adicione nosso repo personalizado ao F-Droid e instale-o a partir daí. As instruções estão aqui: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/ + 2. Baixe o APK aqui no [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) e instalá-lo assim que publicarmos um lançamento. + 3. Atualização via F-droid. Este é o método mais lento para obter atualizações, pois o F-Droid deve reconhecer alterações, construir o próprio APK, assiná-lo e, em seguida, enviar a atualização para os usuários. + 4. Construa um APK de depuração você mesmo. Esta é a maneira mais rápida de obter novos recursos em seu dispositivo, mas é muito mais complicado, por isso recomendamos usar um dos outros métodos. + 5. Se você estiver interessado em um recurso específico ou uma correção de bug fornecido em uma solicitação de Pull nesse repositório, pode instalar o APK a partir de lá. Leia a descrição da solicitação para instruções. A grande vantagem dos APKs específicos de S.P é que eles são instalados lado a lado com o aplicativo oficial, então você não precisa se preocupar em perder seus dados ou estragar alguma coisa. + +Recomendamos o método 1 para a maioria dos usuários. Os APKs instalados usando o método 1 ou 2 são compatíveis entre si (o que significa que se você instalou o NewPipe usando o método 1 ou 2, você também pode atualizar o NewPipe usando o outro), mas não com aqueles instalados usando o método 3. Isso se deve à mesma chave de assinatura (nossa) sendo usada para 1 e 2, mas uma chave de assinatura diferente (F-Droid's) está sendo usada para 3. Construir um APK depuração usando o método 4 exclui totalmente uma chave. Assinar chaves ajudam a garantir que um usuário não seja enganado para instalar uma atualização maliciosa em um aplicativo. Ao usar o método 5, cada APK é assinado com uma chave aleatória diferente fornecida pelo GitHub Actions, portanto você não pode nem mesmo atualizá-lo. Você terá que fazer backup e restaurar os dados do aplicativo sempre que desejar usar um novo APK. Enquanto isso, se você quiser trocar de fontes por algum motivo (por exemplo, a funcionalidade principal do NewPipe foi quebrada e o F-Droid ainda não tem a atualização), recomendamos seguir este procedimento: -1. Faça backup de seus dados através de Configurações > Conteúdo > Exportar Base de Dados para que você mantenha seu histórico, inscrições e playlists +1. Faça backup de seus dados através de Configurações > Backup e Restauração > Exportar Base de Dados para que você mantenha seu histórico, inscrições e playlists 2. Desinstale o NewPipe 3. Baixe o APK da nova fonte e instale-o -4. Importe os dados da etapa 1 via Configurações > Conteúdo > Inportar Banco de Dados - -## Contribuição -Se você tem ideias, traduções, alterações de design, limpeza de códigos ou mudanças reais de código, a ajuda é sempre bem-vinda. -Quanto mais for feito, melhor fica! +4. Importe os dados da etapa 1 via Configurações > Backup e Restauração > Importar Base de Dados -Se você quiser se envolver, verifique nossa [notas de contribuição](../.github/CONTRIBUTING.md). +## Contribuições +Se você tem ideias, traduções, alterações de design, limpeza de códigos ou mudanças reais de código, a ajuda é sempre bem-vinda. O aplicativo fica cada vez melhor a cada contribuição, não importa quão grande ou pequena! Se você quiser se envolver, verifique nossas [notas de contribuição](.github/CONTRIBUTING.md). -Translation status +Estado da tradução ## Doar -Se você gosta de NewPipe, ficaríamos felizes com uma doação. Você pode enviar bitcoin ou doar via Bountysource ou Liberapay. Para obter mais informações sobre como doar para a NewPipe, visite nosso [site](https://newpipe.net/donate). +Se você gosta do NewPipe, pode enivar uma doação. Nós preferimos Liberapay, pois é de código aberto e sem fins lucrativos. Para mais informações sobre como doar para o NewPipe, visite nosso [site](https://newpipe.net/donate). - - + +
LiberapayVisit NewPipe at liberapay.comDonate via LiberapayVisite NewPipe em liberapay.comDoar via Liberapay
From 0e8303f13ae9905e20be9471c8b2cf48a2e04758 Mon Sep 17 00:00:00 2001 From: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:21:21 +0000 Subject: [PATCH 07/22] Update Matrix room link, and prioritise it (#11350) * Update Matrix room link, and prioritise it * Update Matrix room link in CONTRIBUTING.md * Prioritise Matrix in contribution doc too --- .github/CONTRIBUTING.md | 6 +++--- .github/ISSUE_TEMPLATE/config.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 70c81c7b152..647cfbabb48 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -79,6 +79,6 @@ The [ktlint](https://github.com/pinterest/ktlint) plugin does the same job as ch ## Communication -* The #newpipe channel on Libera Chat (`ircs://irc.libera.chat:6697/newpipe`) has the core team and other developers in it. [Click here for webchat](https://web.libera.chat/#newpipe)! -* You can also use a Matrix account to join the NewPipe channel at [#newpipe:libera.chat](https://matrix.to/#/#newpipe:libera.chat). Some convenient clients, available both for phone and desktop, are listed at that link. -* You can post your suggestions, changes, ideas etc. on either GitHub or IRC. +* You can use a Matrix account to join the NewPipe channel at [#newpipe:matrix.newpipe-ev.de](https://matrix.to/#/#newpipe:matrix.newpipe-ev.de). Some convenient clients, available both for phone and desktop, are listed at that link. +* Alternatively, the #newpipe channel on Libera Chat (`ircs://irc.libera.chat:6697/newpipe`) can also be joined, as it is bridged to the Matrix room. [Click here for webchat](https://web.libera.chat/#newpipe)! +* You can post your suggestions, changes, ideas etc. on either GitHub or Matrix (including via IRC). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4721637bf6e..49ab78c7d6a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,9 @@ contact_links: - name: ❓ Question url: https://github.com/TeamNewPipe/NewPipe/discussions/new?category=questions about: Ask about anything NewPipe-related + - name: 💬 Matrix + url: https://matrix.to/#/#newpipe:matrix.newpipe-ev.de + about: Chat with us via Matrix for quick Q/A - name: 💬 IRC url: https://web.libera.chat/#newpipe about: Chat with us via IRC for quick Q/A - - name: 💬 Matrix - url: https://matrix.to/#/#newpipe:libera.chat - about: Chat with us via Matrix for quick Q/A From 947ac2826a3e118b932a9e781e0ec752a5882e9b Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 25 Jul 2024 18:37:05 +0200 Subject: [PATCH 08/22] Update NewPipeExtractor to v0.24.2 --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/error/ReCaptchaActivity.java | 9 +++------ .../newpipe/settings/DownloadSettingsFragment.java | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 397a7301e90..142a0dba60d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -198,7 +198,7 @@ dependencies { // name and the commit hash with the commit hash of the (pushed) commit you want to test // This works thanks to JitPack: https://jitpack.io/ implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751' - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.1' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.2' implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0' /** Checkstyle **/ diff --git a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java index 3c14cfe4cac..42ef261a15d 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java @@ -27,8 +27,6 @@ import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.util.ThemeHelper; -import java.io.UnsupportedEncodingException; - /* * Created by beneth on 06.12.16. * @@ -190,11 +188,10 @@ private void handleCookiesFromUrl(@Nullable final String url) { String abuseCookie = url.substring(abuseStart + 13, abuseEnd); abuseCookie = Utils.decodeUrlUtf8(abuseCookie); handleCookies(abuseCookie); - } catch (UnsupportedEncodingException | StringIndexOutOfBoundsException e) { + } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { if (MainActivity.DEBUG) { - e.printStackTrace(); - Log.d(TAG, "handleCookiesFromUrl: invalid google abuse starting at " - + abuseStart + " and ending at " + abuseEnd + " for url " + url); + Log.e(TAG, "handleCookiesFromUrl: invalid google abuse starting at " + + abuseStart + " and ending at " + abuseEnd + " for url " + url, e); } } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java index 472db6afe6f..76163b30aaa 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java @@ -30,7 +30,6 @@ import java.io.File; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URI; public class DownloadSettingsFragment extends BasePreferenceFragment { @@ -125,7 +124,7 @@ private void showPathInSummary(final String prefKey, @StringRes final int defaul try { rawUri = decodeUrlUtf8(rawUri); - } catch (final UnsupportedEncodingException e) { + } catch (final IllegalArgumentException e) { // nothing to do } From 56b62413117f3d7ca8a46dc7c326b35f16e512b4 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 25 Jul 2024 18:43:03 +0200 Subject: [PATCH 09/22] Hotfix release v0.27.2 (999) --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 142a0dba60d..5706f1c4bda 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,8 +20,8 @@ android { resValue "string", "app_name", "NewPipe" minSdk 21 targetSdk 33 - versionCode 998 - versionName "0.27.1" + versionCode 999 + versionName "0.27.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 03a6b5c7b9ab1236d42ad2ee7fe953309ee210fd Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 11 Jul 2024 23:39:53 +0200 Subject: [PATCH 10/22] Add changelogs for hotfix release v0.27.2 (999) --- fastlane/metadata/android/ar/changelogs/999.txt | 1 + fastlane/metadata/android/az/changelogs/999.txt | 1 + fastlane/metadata/android/cs/changelogs/999.txt | 1 + fastlane/metadata/android/de/changelogs/999.txt | 1 + fastlane/metadata/android/en-US/changelogs/999.txt | 12 ++++++++++++ fastlane/metadata/android/es/changelogs/999.txt | 1 + fastlane/metadata/android/fa/changelogs/999.txt | 1 + fastlane/metadata/android/fr/changelogs/999.txt | 1 + fastlane/metadata/android/he/changelogs/999.txt | 1 + fastlane/metadata/android/hi/changelogs/999.txt | 1 + fastlane/metadata/android/id/changelogs/999.txt | 1 + fastlane/metadata/android/it/changelogs/999.txt | 12 ++++++++++++ fastlane/metadata/android/ka/changelogs/999.txt | 1 + fastlane/metadata/android/nl/changelogs/999.txt | 1 + fastlane/metadata/android/pa/changelogs/999.txt | 1 + fastlane/metadata/android/pt-BR/changelogs/999.txt | 1 + fastlane/metadata/android/pt-PT/changelogs/999.txt | 1 + fastlane/metadata/android/pt/changelogs/999.txt | 1 + fastlane/metadata/android/ru/changelogs/999.txt | 1 + fastlane/metadata/android/sv/changelogs/999.txt | 1 + fastlane/metadata/android/tr/changelogs/999.txt | 1 + fastlane/metadata/android/uk/changelogs/999.txt | 1 + fastlane/metadata/android/vi/changelogs/999.txt | 1 + fastlane/metadata/android/zh-Hans/changelogs/999.txt | 1 + fastlane/metadata/android/zh-Hant/changelogs/999.txt | 1 + .../metadata/android/zh_Hant_HK/changelogs/999.txt | 1 + 26 files changed, 48 insertions(+) create mode 100644 fastlane/metadata/android/ar/changelogs/999.txt create mode 100644 fastlane/metadata/android/az/changelogs/999.txt create mode 100644 fastlane/metadata/android/cs/changelogs/999.txt create mode 100644 fastlane/metadata/android/de/changelogs/999.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/999.txt create mode 100644 fastlane/metadata/android/es/changelogs/999.txt create mode 100644 fastlane/metadata/android/fa/changelogs/999.txt create mode 100644 fastlane/metadata/android/fr/changelogs/999.txt create mode 100644 fastlane/metadata/android/he/changelogs/999.txt create mode 100644 fastlane/metadata/android/hi/changelogs/999.txt create mode 100644 fastlane/metadata/android/id/changelogs/999.txt create mode 100644 fastlane/metadata/android/it/changelogs/999.txt create mode 100644 fastlane/metadata/android/ka/changelogs/999.txt create mode 100644 fastlane/metadata/android/nl/changelogs/999.txt create mode 100644 fastlane/metadata/android/pa/changelogs/999.txt create mode 100644 fastlane/metadata/android/pt-BR/changelogs/999.txt create mode 100644 fastlane/metadata/android/pt-PT/changelogs/999.txt create mode 100644 fastlane/metadata/android/pt/changelogs/999.txt create mode 100644 fastlane/metadata/android/ru/changelogs/999.txt create mode 100644 fastlane/metadata/android/sv/changelogs/999.txt create mode 100644 fastlane/metadata/android/tr/changelogs/999.txt create mode 100644 fastlane/metadata/android/uk/changelogs/999.txt create mode 100644 fastlane/metadata/android/vi/changelogs/999.txt create mode 100644 fastlane/metadata/android/zh-Hans/changelogs/999.txt create mode 100644 fastlane/metadata/android/zh-Hant/changelogs/999.txt create mode 100644 fastlane/metadata/android/zh_Hant_HK/changelogs/999.txt diff --git a/fastlane/metadata/android/ar/changelogs/999.txt b/fastlane/metadata/android/ar/changelogs/999.txt new file mode 100644 index 00000000000..562f169445a --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/999.txt @@ -0,0 +1 @@ +تم إصلاح YouTube الذي لا يقوم بتشغيل أي دفق diff --git a/fastlane/metadata/android/az/changelogs/999.txt b/fastlane/metadata/android/az/changelogs/999.txt new file mode 100644 index 00000000000..16a2e101364 --- /dev/null +++ b/fastlane/metadata/android/az/changelogs/999.txt @@ -0,0 +1 @@ +YouTube-un heç bir yayım oynatmaması düzəldildi diff --git a/fastlane/metadata/android/cs/changelogs/999.txt b/fastlane/metadata/android/cs/changelogs/999.txt new file mode 100644 index 00000000000..7035a111220 --- /dev/null +++ b/fastlane/metadata/android/cs/changelogs/999.txt @@ -0,0 +1 @@ +Opraveno nepřehrávání jakéhokoli streamu ve službě YouTube diff --git a/fastlane/metadata/android/de/changelogs/999.txt b/fastlane/metadata/android/de/changelogs/999.txt new file mode 100644 index 00000000000..43623578f6a --- /dev/null +++ b/fastlane/metadata/android/de/changelogs/999.txt @@ -0,0 +1 @@ +Behoben, dass YouTube keinen Stream abspielte diff --git a/fastlane/metadata/android/en-US/changelogs/999.txt b/fastlane/metadata/android/en-US/changelogs/999.txt new file mode 100644 index 00000000000..c089ed197ef --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/999.txt @@ -0,0 +1,12 @@ +This hotfix release fixes HTTP 403 errors in the middle of YouTube videos. + +New +• [SoundCloud] Add support for on.soundcloud.com URLs + +Improved +• [Bandcamp] Show additional info in radio kiosk + +Fixed +• [YouTube] Fix occasional HTTP 403 errors at the beginning or in the middle of videos +• [YouTube] Extract avatar and banner from more channel header types +• [Bandcamp] Fix various bugs and always use HTTPS diff --git a/fastlane/metadata/android/es/changelogs/999.txt b/fastlane/metadata/android/es/changelogs/999.txt new file mode 100644 index 00000000000..80b4efa553d --- /dev/null +++ b/fastlane/metadata/android/es/changelogs/999.txt @@ -0,0 +1 @@ +Arreglo en YouTube no reproduciendo flujos diff --git a/fastlane/metadata/android/fa/changelogs/999.txt b/fastlane/metadata/android/fa/changelogs/999.txt new file mode 100644 index 00000000000..ba5413d49f8 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/999.txt @@ -0,0 +1 @@ +مشکل عدم نمایش پخش‌زنده برطرف شد diff --git a/fastlane/metadata/android/fr/changelogs/999.txt b/fastlane/metadata/android/fr/changelogs/999.txt new file mode 100644 index 00000000000..3ad3bf2798b --- /dev/null +++ b/fastlane/metadata/android/fr/changelogs/999.txt @@ -0,0 +1 @@ +Correction de YouTube qui ne lisait aucun média diff --git a/fastlane/metadata/android/he/changelogs/999.txt b/fastlane/metadata/android/he/changelogs/999.txt new file mode 100644 index 00000000000..50731171e10 --- /dev/null +++ b/fastlane/metadata/android/he/changelogs/999.txt @@ -0,0 +1 @@ +תוקנה התקלה ש־YouTube לא מנגן אף תזרים diff --git a/fastlane/metadata/android/hi/changelogs/999.txt b/fastlane/metadata/android/hi/changelogs/999.txt new file mode 100644 index 00000000000..071ab64e338 --- /dev/null +++ b/fastlane/metadata/android/hi/changelogs/999.txt @@ -0,0 +1 @@ +फिक्स्ड YouTube कोई स्ट्रीम नहीं चला रहा है diff --git a/fastlane/metadata/android/id/changelogs/999.txt b/fastlane/metadata/android/id/changelogs/999.txt new file mode 100644 index 00000000000..d3fea84ab5e --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/999.txt @@ -0,0 +1 @@ +Memperbaiki YouTube yang tidak memutar streaming apa pun diff --git a/fastlane/metadata/android/it/changelogs/999.txt b/fastlane/metadata/android/it/changelogs/999.txt new file mode 100644 index 00000000000..c2652da28ee --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/999.txt @@ -0,0 +1,12 @@ +Questo aggiornamento hotfix risolve gli errori HTTP 403 nel mezzo dei video di YouTube. + +Novità +• [SoundCloud] Aggiunto il supporto per gli URL on.soundcloud.com + +Migliorie +• [Bandcamp] Mostra informazioni aggiuntive nel chiosco della radio + +Correzioni +• [YouTube] Corretti errori HTTP 403 occasionali all'inizio o nel mezzo dei video +• [YouTube] Estrazione avatar e banner da più tipi di canali +• [Bandcamp] Risolti vari bug e forzato l'uso di HTTPS diff --git a/fastlane/metadata/android/ka/changelogs/999.txt b/fastlane/metadata/android/ka/changelogs/999.txt new file mode 100644 index 00000000000..d20512f1710 --- /dev/null +++ b/fastlane/metadata/android/ka/changelogs/999.txt @@ -0,0 +1 @@ +გაასწორა YouTube არ უკრავს არცერთ ნაკადს diff --git a/fastlane/metadata/android/nl/changelogs/999.txt b/fastlane/metadata/android/nl/changelogs/999.txt new file mode 100644 index 00000000000..9bd8adf8693 --- /dev/null +++ b/fastlane/metadata/android/nl/changelogs/999.txt @@ -0,0 +1 @@ +YouTube speelt geen stream af opgelost diff --git a/fastlane/metadata/android/pa/changelogs/999.txt b/fastlane/metadata/android/pa/changelogs/999.txt new file mode 100644 index 00000000000..fe62a1330fe --- /dev/null +++ b/fastlane/metadata/android/pa/changelogs/999.txt @@ -0,0 +1 @@ +ਸਥਿਰ YouTube ਕੋਈ ਸਟ੍ਰੀਮ ਨਹੀਂ ਚਲਾ ਰਿਹਾ diff --git a/fastlane/metadata/android/pt-BR/changelogs/999.txt b/fastlane/metadata/android/pt-BR/changelogs/999.txt new file mode 100644 index 00000000000..59fc6a5cdb0 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/999.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir qualquer transmissão diff --git a/fastlane/metadata/android/pt-PT/changelogs/999.txt b/fastlane/metadata/android/pt-PT/changelogs/999.txt new file mode 100644 index 00000000000..93519d64d7a --- /dev/null +++ b/fastlane/metadata/android/pt-PT/changelogs/999.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir nenhuma transmissão diff --git a/fastlane/metadata/android/pt/changelogs/999.txt b/fastlane/metadata/android/pt/changelogs/999.txt new file mode 100644 index 00000000000..93519d64d7a --- /dev/null +++ b/fastlane/metadata/android/pt/changelogs/999.txt @@ -0,0 +1 @@ +Corrigido YouTube não reproduzir nenhuma transmissão diff --git a/fastlane/metadata/android/ru/changelogs/999.txt b/fastlane/metadata/android/ru/changelogs/999.txt new file mode 100644 index 00000000000..d3978869d59 --- /dev/null +++ b/fastlane/metadata/android/ru/changelogs/999.txt @@ -0,0 +1 @@ +Исправлено: YouTube не воспроизводил никакие потоки diff --git a/fastlane/metadata/android/sv/changelogs/999.txt b/fastlane/metadata/android/sv/changelogs/999.txt new file mode 100644 index 00000000000..35f298dbff8 --- /dev/null +++ b/fastlane/metadata/android/sv/changelogs/999.txt @@ -0,0 +1 @@ +Åtgärdat att YouTube inte spelar någon stream diff --git a/fastlane/metadata/android/tr/changelogs/999.txt b/fastlane/metadata/android/tr/changelogs/999.txt new file mode 100644 index 00000000000..e5979c68d6a --- /dev/null +++ b/fastlane/metadata/android/tr/changelogs/999.txt @@ -0,0 +1 @@ +YouTube'un herhangi bir akışı oynatmaması düzeltildi diff --git a/fastlane/metadata/android/uk/changelogs/999.txt b/fastlane/metadata/android/uk/changelogs/999.txt new file mode 100644 index 00000000000..905287c7494 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/999.txt @@ -0,0 +1 @@ +Виправлено проблему невідтворюваності трансляцій diff --git a/fastlane/metadata/android/vi/changelogs/999.txt b/fastlane/metadata/android/vi/changelogs/999.txt new file mode 100644 index 00000000000..d2086b62c1f --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/999.txt @@ -0,0 +1 @@ +Đã sửa lỗi YouTube không phát bất kỳ luồng nào diff --git a/fastlane/metadata/android/zh-Hans/changelogs/999.txt b/fastlane/metadata/android/zh-Hans/changelogs/999.txt new file mode 100644 index 00000000000..8a5424c9e02 --- /dev/null +++ b/fastlane/metadata/android/zh-Hans/changelogs/999.txt @@ -0,0 +1 @@ +修复YouTube无法播放任何视频 diff --git a/fastlane/metadata/android/zh-Hant/changelogs/999.txt b/fastlane/metadata/android/zh-Hant/changelogs/999.txt new file mode 100644 index 00000000000..4e8bf65377d --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/changelogs/999.txt @@ -0,0 +1 @@ +修正 YouTube 無法播放任何串流 diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/999.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/999.txt new file mode 100644 index 00000000000..9a4721551a1 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/999.txt @@ -0,0 +1 @@ +修正咗 YouTube 乜嘢實況串流都播唔到嘅問題 From dbcb721dc21429c25aa164afb98dc3b91e19672b Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 25 Jul 2024 20:56:16 +0200 Subject: [PATCH 11/22] Don't warn about rhino class in proguard Likely related to https://github.com/mozilla/rhino/commit/01a7b20655602f7e2df59af744b47b77f678b6cf but I am not completely sure. I tested the app and it works well, so I think that org.mozilla.javascript.JavaToJSONConverters is not used really. This is the full list of errors: Missing class java.beans.BeanDescriptor (referenced from: java.lang.Object org.mozilla.javascript.JavaToJSONConverters.lambda$static$4(java.lang.Object)) Missing class java.beans.BeanInfo (referenced from: java.lang.Object org.mozilla.javascript.JavaToJSONConverters.lambda$static$4(java.lang.Object)) Missing class java.beans.IntrospectionException (referenced from: java.lang.Object org.mozilla.javascript.JavaToJSONConverters.lambda$static$4(java.lang.Object)) Missing class java.beans.Introspector (referenced from: java.lang.Object org.mozilla.javascript.JavaToJSONConverters.lambda$static$4(java.lang.Object)) Missing class java.beans.PropertyDescriptor (referenced from: java.lang.Object org.mozilla.javascript.JavaToJSONConverters.lambda$static$4(java.lang.Object)) --- app/build.gradle | 3 +++ app/proguard-rules.pro | 1 + 2 files changed, 4 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 5706f1c4bda..35cb8509ec7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,6 +56,9 @@ android { resValue "string", "app_name", "NewPipe " + System.getProperty('packageSuffix') archivesBaseName = 'NewPipe_' + System.getProperty('packageSuffix') } + applicationIdSuffix ".whatever" + resValue "string", "app_name", "NewPipe whatever" + archivesBaseName = 'NewPipe_whatever' minifyEnabled true shrinkResources false // disabled to fix F-Droid's reproducible build proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index d21f33e1f11..435c4e29b71 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -7,6 +7,7 @@ -keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; } -keep class org.mozilla.javascript.** { *; } -keep class org.mozilla.classfile.ClassFileWriter +-dontwarn org.mozilla.javascript.JavaToJSONConverters -dontwarn org.mozilla.javascript.tools.** ## Rules for ExoPlayer From d442b458361b002ab90d9608db223203601ee2cc Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 25 Jul 2024 20:58:29 +0200 Subject: [PATCH 12/22] Remove code committed accidentally --- app/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 35cb8509ec7..5706f1c4bda 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,9 +56,6 @@ android { resValue "string", "app_name", "NewPipe " + System.getProperty('packageSuffix') archivesBaseName = 'NewPipe_' + System.getProperty('packageSuffix') } - applicationIdSuffix ".whatever" - resValue "string", "app_name", "NewPipe whatever" - archivesBaseName = 'NewPipe_whatever' minifyEnabled true shrinkResources false // disabled to fix F-Droid's reproducible build proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' From d2cc37ae946b20dc85f7efd7867ba435e4fb9008 Mon Sep 17 00:00:00 2001 From: brais Date: Mon, 5 Aug 2024 00:27:18 +0200 Subject: [PATCH 13/22] Added daggerhilt for better dependency injection for Compose Viewmodels --- app/build.gradle | 17 ++++++++++++++++- app/src/main/java/org/schabi/newpipe/App.java | 2 ++ build.gradle | 6 ++++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4652cf6e5ba..ec3493828a0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,6 +9,7 @@ plugins { id "kotlin-parcelize" id "checkstyle" id "org.sonarqube" version "4.0.0.2929" + id "dagger.hilt.android.plugin" } android { @@ -122,6 +123,8 @@ ext { googleAutoServiceVersion = '1.1.1' groupieVersion = '2.10.1' markwonVersion = '4.6.2' + hiltVersion = '1.2.0' + daggerVersion = '2.51.1' leakCanaryVersion = '2.12' stethoVersion = '1.6.0' @@ -203,7 +206,7 @@ dependencies { // name and the commit hash with the commit hash of the (pushed) commit you want to test // This works thanks to JitPack: https://jitpack.io/ implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751' - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.0' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.2' implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0' /** Checkstyle **/ @@ -295,6 +298,14 @@ dependencies { implementation 'androidx.activity:activity-compose' implementation 'androidx.compose.ui:ui-tooling-preview' + // hilt + implementation("androidx.hilt:hilt-navigation-compose:${hiltVersion}") + kapt("androidx.hilt:hilt-compiler:${hiltVersion}") + + // dagger + implementation("com.google.dagger:hilt-android:${daggerVersion}") + kapt("com.google.dagger:hilt-android-compiler:${daggerVersion}") + /** Debugging **/ // Memory leak detection debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}" @@ -315,6 +326,10 @@ dependencies { androidTestImplementation "androidx.test:runner:1.5.2" androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}" androidTestImplementation "org.assertj:assertj-core:3.24.2" + + // dagger + testImplementation("com.google.dagger:hilt-android-testing${daggerVersion}") + androidTestImplementation("com.google.dagger:hilt-android-testing${daggerVersion}") } static String getGitWorkingBranch() { diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index d92425d200e..35be89489a7 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Objects; +import dagger.hilt.android.HiltAndroidApp; import io.reactivex.rxjava3.exceptions.CompositeException; import io.reactivex.rxjava3.exceptions.MissingBackpressureException; import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException; @@ -57,6 +58,7 @@ * along with NewPipe. If not, see . */ +@HiltAndroidApp public class App extends Application { public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID; private static final String TAG = App.class.toString(); diff --git a/build.gradle b/build.gradle index 6d19a6f8a84..35c1b25da38 100644 --- a/build.gradle +++ b/build.gradle @@ -2,14 +2,15 @@ buildscript { ext.kotlin_version = '1.9.10' + ext.dagger_version ='2.51.1' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.0' + classpath 'com.android.tools.build:gradle:8.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - + classpath("com.google.dagger:hilt-android-gradle-plugin:$dagger_version") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -19,6 +20,7 @@ allprojects { repositories { google() mavenCentral() + gradlePluginPortal() maven { url "https://jitpack.io" } maven { url "https://repo.clojars.org" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d022615ff6d..efe1dac97da 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From e1169dcc1f5e5468b73bfadc01f67f28700bdd5d Mon Sep 17 00:00:00 2001 From: brais Date: Mon, 5 Aug 2024 00:34:35 +0200 Subject: [PATCH 14/22] fixed inversed colors of surface for light theme --- app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt b/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt index b61906ebed6..28b3e65c437 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt @@ -20,8 +20,8 @@ val md_theme_light_onError = Color(0xFFFFFFFF) val md_theme_light_onErrorContainer = Color(0xFF410002) val md_theme_light_background = Color(0xFFEEEEEE) val md_theme_light_onBackground = Color(0xFF1B1B1B) -val md_theme_light_surface = Color(0xFFE53835) -val md_theme_light_onSurface = Color(0xFFFFFFFF) +val md_theme_light_surface = Color(0xFFFFFFFF) +val md_theme_light_onSurface = Color(0xFFE53835) val md_theme_light_surfaceVariant = Color(0xFFF5DDDB) val md_theme_light_onSurfaceVariant = Color(0xFF534341) val md_theme_light_outline = Color(0xFF857371) From 91af8b0b98a551e37709e191a448536669767322 Mon Sep 17 00:00:00 2001 From: brais Date: Mon, 5 Aug 2024 00:42:01 +0200 Subject: [PATCH 15/22] Added the new compose screen with its components and events --- .../java/org/schabi/newpipe/MainActivity.java | 3 + .../IrreversiblePreference.kt | 86 ++++++++ .../switch_preference/SwitchPreference.kt | 74 +++++++ .../history_cache/HistoryCacheEvent.kt | 12 ++ .../HistoryCacheSettingsScreen.kt | 102 +++++++++ .../history_cache/HistoryCacheUiState.kt | 12 ++ .../components/CachePreferences.kt | 204 ++++++++++++++++++ .../components/HistoryPreferences.kt | 116 ++++++++++ 8 files changed, 609 insertions(+) create mode 100644 app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 17569412572..a74d30c74de 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -98,6 +98,9 @@ import java.util.List; import java.util.Objects; +import dagger.hilt.android.AndroidEntryPoint; + +@AndroidEntryPoint public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @SuppressWarnings("ConstantConditions") diff --git a/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt b/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt new file mode 100644 index 00000000000..b66e4eb5fc6 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt @@ -0,0 +1,86 @@ +package org.schabi.newpipe.settings.components.irreversible_preference + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.tooling.preview.Preview +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraSmall +import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium + +@Composable +fun IrreversiblePreferenceComponent( + title: String, + summary: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, +) { + Row( + modifier = Modifier + .clickable { + if (enabled) { + onClick() + } + } + .then(modifier), + verticalAlignment = Alignment.CenterVertically, + ) { + val alpha by remember { + derivedStateOf { + if (enabled) 1f else 0.38f + } + } + Column( + modifier = Modifier.padding(SpacingMedium) + ) { + Text( + text = title, + modifier = Modifier.alpha(alpha), + ) + Spacer(modifier = Modifier.padding(SpacingExtraSmall)) + Text( + text = summary, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.alpha(alpha * 0.6f), + ) + } + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) +@Composable +private fun IrreversiblePreferenceComponentPreview() { + val title = "Wipe cached metadata" + val summary = "Remove all cached webpage data" + AppTheme { + Column { + + IrreversiblePreferenceComponent( + title = title, + summary = summary, + onClick = {}, + modifier = Modifier.fillMaxWidth() + ) + IrreversiblePreferenceComponent( + title = title, + summary = summary, + onClick = {}, + modifier = Modifier.fillMaxWidth(), + enabled = false + ) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt b/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt new file mode 100644 index 00000000000..29015badfae --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt @@ -0,0 +1,74 @@ +package org.schabi.newpipe.settings.components.switch_preference + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.tooling.preview.Preview +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraSmall +import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium + +@Composable +fun SwitchPreferenceComponent( + title: String, + summary: String, + isChecked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier, + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Center, + modifier = Modifier.padding(SpacingMedium) + ) { + Text(text = title) + Spacer(modifier = Modifier.padding(SpacingExtraSmall)) + Text( + text = summary, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.alpha(0.6f) + ) + } + + Switch( + checked = isChecked, + onCheckedChange = onCheckedChange, + modifier = Modifier.padding(SpacingMedium) + ) + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) +@Composable +private fun SwitchPreferenceComponentPreview() { + val title = "Watch history" + val subtitle = "Keep track of watched videos" + var isChecked = false + AppTheme { + SwitchPreferenceComponent( + title = title, + summary = subtitle, + isChecked = isChecked, + onCheckedChange = { + isChecked = it + }, + modifier = Modifier.fillMaxWidth() + ) + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt new file mode 100644 index 00000000000..f899803fa38 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt @@ -0,0 +1,12 @@ +package org.schabi.newpipe.settings.presentation.history_cache + +sealed class HistoryCacheEvent { + data class OnUpdateBooleanPreference(val key: String, val isEnabled: Boolean) : + HistoryCacheEvent() + + data class OnClickWipeCachedMetadata(val key: String) : HistoryCacheEvent() + data class OnClickClearWatchHistory(val key: String) : HistoryCacheEvent() + data class OnClickDeletePlaybackPositions(val key: String) : HistoryCacheEvent() + data class OnClickClearSearchHistory(val key: String) : HistoryCacheEvent() + data class OnClickReCaptchaCookies(val key: String) : HistoryCacheEvent() +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt new file mode 100644 index 00000000000..9fc87fbec2f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt @@ -0,0 +1,102 @@ +package org.schabi.newpipe.settings.presentation.history_cache + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import kotlinx.coroutines.launch +import org.schabi.newpipe.settings.presentation.history_cache.components.CachePreferencesComponent +import org.schabi.newpipe.settings.presentation.history_cache.components.HistoryPreferencesComponent +import org.schabi.newpipe.ui.theme.AppTheme + +@Composable +fun HistoryCacheScreen( + modifier: Modifier = Modifier, + viewModel: HistoryCacheSettingsViewModel = hiltViewModel(), +) { + val state by viewModel.state.collectAsState() + HistoryCacheComponent( + state = state, + onEvent = viewModel::onEvent, + modifier = modifier + ) +} + +@Composable +fun HistoryCacheComponent( + state: HistoryCacheUiState, + onEvent: (HistoryCacheEvent) -> Unit, + modifier: Modifier = Modifier, +) { + val snackBarHostState = remember { SnackbarHostState() } + Scaffold( + modifier = modifier, + snackbarHost = { + SnackbarHost(snackBarHostState) + } + ) { padding -> + val scrollState = rememberScrollState() + Column( + modifier = Modifier + .padding(padding) + .verticalScroll(scrollState), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + HistoryPreferencesComponent( + state = state.switchPreferencesUiState, + onEvent = onEvent, + modifier = Modifier.fillMaxWidth() + ) + val coroutineScope = rememberCoroutineScope() + CachePreferencesComponent( + onEvent = onEvent, + onShowSnackbar = { + coroutineScope.launch { + snackBarHostState.showSnackbar(it) + } + }, + modifier = Modifier.fillMaxWidth() + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun HistoryCacheComponentPreview() { + val state by remember { + mutableStateOf( + HistoryCacheUiState() + ) + } + AppTheme( + useDarkTheme = false + ) { + Surface { + HistoryCacheComponent( + state = state, + onEvent = { + }, + modifier = Modifier.fillMaxSize() + ) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt new file mode 100644 index 00000000000..1d346244eeb --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt @@ -0,0 +1,12 @@ +package org.schabi.newpipe.settings.presentation.history_cache + +data class HistoryCacheUiState( + val switchPreferencesUiState: SwitchPreferencesUiState = SwitchPreferencesUiState() +) + +data class SwitchPreferencesUiState( + val watchHistoryEnabled: Boolean = false, + val resumePlaybackEnabled: Boolean = false, + val positionsInListsEnabled: Boolean = false, + val searchHistoryEnabled: Boolean = false, +) diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt new file mode 100644 index 00000000000..6657b78272a --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt @@ -0,0 +1,204 @@ +package org.schabi.newpipe.settings.presentation.history_cache.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import org.schabi.newpipe.R +import org.schabi.newpipe.settings.components.irreversible_preference.IrreversiblePreferenceComponent +import org.schabi.newpipe.settings.presentation.history_cache.HistoryCacheEvent +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium + +@Composable +fun CachePreferencesComponent( + onEvent: (HistoryCacheEvent) -> Unit, + onShowSnackbar: (String) -> Unit, + modifier: Modifier = Modifier, +) { + val preferences = rememberPreferences() + var dialogTitle by remember { mutableStateOf("") } + var dialogOnClick by remember { mutableStateOf({}) } + var isDialogVisible by remember { mutableStateOf(false) } + + Column( + modifier = modifier, + ) { + Text( + stringResource(id = R.string.settings_category_clear_data_title), + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(SpacingMedium) + ) + preferences.forEach { + val elementDialogTitle = it.dialogTitle?.let { dialogTitle -> + stringResource(dialogTitle) + } + val elementSnackBarText = stringResource(it.snackBarText) + val key = stringResource(id = it.keyId) + val onClick = { + if (elementDialogTitle != null) { + dialogTitle = elementDialogTitle + isDialogVisible = true + dialogOnClick = { + onEvent(it.event(key)) + isDialogVisible = false + onShowSnackbar(elementSnackBarText) + } + } else { + onEvent(it.event(key)) + onShowSnackbar(elementSnackBarText) + } + } + IrreversiblePreferenceComponent( + title = stringResource(id = it.title), + summary = stringResource(it.summary), + onClick = onClick, + modifier = Modifier.fillMaxWidth() + ) + } + + CacheAlertDialog( + isDialogVisible = isDialogVisible, + dialogTitle = dialogTitle, + onClickCancel = { isDialogVisible = false }, + onClick = dialogOnClick + ) + } +} + +@Composable +private fun rememberPreferences(): List { + val preferences by remember { + mutableStateOf( + listOf( + IrreversiblePreferenceUiState( + title = R.string.metadata_cache_wipe_title, + summary = R.string.metadata_cache_wipe_summary, + dialogTitle = null, + snackBarText = R.string.metadata_cache_wipe_complete_notice, + event = { HistoryCacheEvent.OnClickWipeCachedMetadata(it) }, + keyId = R.string.metadata_cache_wipe_key, + ), + IrreversiblePreferenceUiState( + title = R.string.clear_views_history_title, + summary = R.string.clear_views_history_summary, + dialogTitle = R.string.delete_view_history_alert, + snackBarText = R.string.watch_history_deleted, + event = { HistoryCacheEvent.OnClickClearWatchHistory(it) }, + keyId = R.string.clear_views_history_key, + ), + IrreversiblePreferenceUiState( + title = R.string.clear_playback_states_title, + summary = R.string.clear_playback_states_summary, + dialogTitle = R.string.delete_playback_states_alert, + snackBarText = R.string.watch_history_states_deleted, + event = { HistoryCacheEvent.OnClickDeletePlaybackPositions(it) }, + keyId = R.string.clear_playback_states_key, + ), + IrreversiblePreferenceUiState( + title = R.string.clear_search_history_title, + summary = R.string.clear_search_history_summary, + dialogTitle = R.string.delete_search_history_alert, + snackBarText = R.string.search_history_deleted, + event = { HistoryCacheEvent.OnClickClearSearchHistory(it) }, + keyId = R.string.clear_search_history_key, + ), + IrreversiblePreferenceUiState( + title = R.string.clear_cookie_title, + summary = R.string.clear_cookie_summary, + dialogTitle = null, + snackBarText = R.string.recaptcha_cookies_cleared, + event = { HistoryCacheEvent.OnClickReCaptchaCookies(it) }, + keyId = R.string.recaptcha_cookies_key, + ) + ) + ) + } + return preferences +} + +private data class IrreversiblePreferenceUiState( + val title: Int, + val summary: Int, + val dialogTitle: Int?, + val snackBarText: Int, + val enabled: Boolean = true, + val event: (String) -> HistoryCacheEvent, + val keyId: Int, +) + +@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) +@Composable +private fun CachePreferencesComponentPreview() { + AppTheme { + Scaffold { padding -> + CachePreferencesComponent( + onEvent = {}, + onShowSnackbar = {}, + modifier = Modifier + .fillMaxWidth() + .padding(padding) + ) + } + } +} + +@Composable +private fun CacheAlertDialog( + isDialogVisible: Boolean, + dialogTitle: String, + onClickCancel: () -> Unit, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + if (isDialogVisible) { + AlertDialog( + onDismissRequest = onClickCancel, + confirmButton = { + TextButton(onClick = onClick) { + Text(text = "Delete") + } + }, + dismissButton = { + TextButton(onClick = onClickCancel) { + Text(text = "Cancel") + } + }, + title = { + Text(text = dialogTitle) + }, + text = { + Text(text = "This is an irreversible action") + }, + modifier = modifier + ) + } +} + +@Preview(backgroundColor = 0xFFFFFFFF) +@Composable +private fun CacheAlertDialogPreview() { + AppTheme { + Scaffold { padding -> + CacheAlertDialog( + isDialogVisible = true, + dialogTitle = "Delete view history", + onClickCancel = {}, + onClick = {}, + modifier = Modifier.padding(padding) + ) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt new file mode 100644 index 00000000000..f929e387ab7 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt @@ -0,0 +1,116 @@ +package org.schabi.newpipe.settings.presentation.history_cache.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import org.schabi.newpipe.R +import org.schabi.newpipe.settings.components.switch_preference.SwitchPreferenceComponent +import org.schabi.newpipe.settings.presentation.history_cache.HistoryCacheEvent +import org.schabi.newpipe.settings.presentation.history_cache.SwitchPreferencesUiState +import org.schabi.newpipe.ui.theme.AppTheme + +@Composable +fun HistoryPreferencesComponent( + state: SwitchPreferencesUiState, + onEvent: (HistoryCacheEvent) -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier, + ) { + val preferences = rememberSwitchPreferencesUiState(state) + preferences.forEach { preference -> + val key = stringResource(preference.keyId) + SwitchPreferenceComponent( + title = stringResource(id = preference.titleId), + summary = stringResource(id = preference.summaryId), + isChecked = preference.isEnabled, + onCheckedChange = { + onEvent(HistoryCacheEvent.OnUpdateBooleanPreference(key, it)) + }, + modifier = Modifier.fillMaxWidth() + ) + } + } +} + +@Composable +private fun rememberSwitchPreferencesUiState( + state: SwitchPreferencesUiState, +): List { + val preferences by remember { + mutableStateOf( + listOf( + SwitchPreferencesIdState( + titleId = R.string.enable_watch_history_title, + summaryId = R.string.enable_watch_history_summary, + isEnabled = state.watchHistoryEnabled, + keyId = R.string.enable_watch_history_key + ), + SwitchPreferencesIdState( + titleId = R.string.enable_playback_resume_title, + summaryId = R.string.enable_playback_resume_summary, + isEnabled = state.resumePlaybackEnabled, + keyId = R.string.enable_playback_resume_key + ), + SwitchPreferencesIdState( + titleId = R.string.enable_playback_state_lists_title, + summaryId = R.string.enable_playback_state_lists_summary, + isEnabled = state.positionsInListsEnabled, + keyId = R.string.enable_playback_state_lists_key + ), + SwitchPreferencesIdState( + titleId = R.string.enable_search_history_title, + summaryId = R.string.enable_search_history_summary, + isEnabled = state.searchHistoryEnabled, + keyId = R.string.enable_search_history_key + ) + ) + ) + } + return preferences +} + +private data class SwitchPreferencesIdState( + val titleId: Int, + val summaryId: Int, + val isEnabled: Boolean, + val keyId: Int, +) + +@Preview(showBackground = true) +@Composable +private fun SwitchPreferencesComponentPreview() { + var state by remember { + mutableStateOf( + SwitchPreferencesUiState() + ) + } + AppTheme( + useDarkTheme = false + ) { + Scaffold { padding -> + HistoryPreferencesComponent( + state = state, + onEvent = { + // Mock behaviour to preview + state = state.copy( + watchHistoryEnabled = !state.watchHistoryEnabled + ) + }, + modifier = Modifier + .fillMaxWidth() + .padding(padding) + ) + } + } +} From 38c823a042ee3ca880b15d79095087a89d66f627 Mon Sep 17 00:00:00 2001 From: TwoAi Date: Sat, 10 Aug 2024 15:42:35 -0400 Subject: [PATCH 16/22] Remove outdated returnActivity test code returnActivity was removed in 463dd8e --- .../schabi/newpipe/error/ErrorActivity.java | 22 ------------ .../newpipe/error/ErrorActivityTest.java | 35 ------------------- 2 files changed, 57 deletions(-) delete mode 100644 app/src/test/java/org/schabi/newpipe/error/ErrorActivityTest.java diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 831a8cc4bba..2f607b4876a 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -2,7 +2,6 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -13,7 +12,6 @@ import android.view.MenuInflater; import android.view.MenuItem; -import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; @@ -22,7 +20,6 @@ import com.grack.nanojson.JsonWriter; import org.schabi.newpipe.BuildConfig; -import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.ActivityErrorBinding; import org.schabi.newpipe.util.Localization; @@ -187,25 +184,6 @@ private String formErrorText(final String[] el) { .collect(Collectors.joining(separator + "\n", separator + "\n", separator)); } - /** - * Get the checked activity. - * - * @param returnActivity the activity to return to - * @return the casted return activity or null - */ - @Nullable - static Class getReturnActivity(final Class returnActivity) { - Class checkedReturnActivity = null; - if (returnActivity != null) { - if (Activity.class.isAssignableFrom(returnActivity)) { - checkedReturnActivity = returnActivity.asSubclass(Activity.class); - } else { - checkedReturnActivity = MainActivity.class; - } - } - return checkedReturnActivity; - } - private void buildInfo(final ErrorInfo info) { String text = ""; diff --git a/app/src/test/java/org/schabi/newpipe/error/ErrorActivityTest.java b/app/src/test/java/org/schabi/newpipe/error/ErrorActivityTest.java deleted file mode 100644 index f77c7b2681c..00000000000 --- a/app/src/test/java/org/schabi/newpipe/error/ErrorActivityTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.schabi.newpipe.error; - -import android.app.Activity; - -import org.junit.Test; -import org.schabi.newpipe.MainActivity; -import org.schabi.newpipe.RouterActivity; -import org.schabi.newpipe.fragments.detail.VideoDetailFragment; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Unit tests for {@link ErrorActivity}. - */ -public class ErrorActivityTest { - @Test - public void getReturnActivity() { - Class returnActivity; - returnActivity = ErrorActivity.getReturnActivity(MainActivity.class); - assertEquals(MainActivity.class, returnActivity); - - returnActivity = ErrorActivity.getReturnActivity(RouterActivity.class); - assertEquals(RouterActivity.class, returnActivity); - - returnActivity = ErrorActivity.getReturnActivity(null); - assertNull(returnActivity); - - returnActivity = ErrorActivity.getReturnActivity(Integer.class); - assertEquals(MainActivity.class, returnActivity); - - returnActivity = ErrorActivity.getReturnActivity(VideoDetailFragment.class); - assertEquals(MainActivity.class, returnActivity); - } -} From 7a498d8b723713e73ad8ea23605885036994c3f5 Mon Sep 17 00:00:00 2001 From: brais Date: Sun, 11 Aug 2024 18:31:51 +0200 Subject: [PATCH 17/22] changed a bit the components to make the screen stable for compose --- .../switch_preference/SwitchPreference.kt | 1 - .../history_cache/HistoryCacheEvent.kt | 12 -- .../HistoryCacheSettingsScreen.kt | 60 ++++-- .../HistoryCacheSettingsViewModel.kt | 189 ++++++++++++++++ ...UiState.kt => SwitchPreferencesUiState.kt} | 6 +- .../components/CachePreferences.kt | 203 +++++++----------- .../components/HistoryPreferences.kt | 98 ++++----- .../history_cache/events/HistoryCacheEvent.kt | 10 + .../events/HistoryCacheUiEvent.kt | 9 + 9 files changed, 375 insertions(+), 213 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt rename app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/{HistoryCacheUiState.kt => SwitchPreferencesUiState.kt} (70%) create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheEvent.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheUiEvent.kt diff --git a/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt b/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt index 29015badfae..61a64e8633d 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/components/switch_preference/SwitchPreference.kt @@ -31,7 +31,6 @@ fun SwitchPreferenceComponent( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Column( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Center, diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt deleted file mode 100644 index f899803fa38..00000000000 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheEvent.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.schabi.newpipe.settings.presentation.history_cache - -sealed class HistoryCacheEvent { - data class OnUpdateBooleanPreference(val key: String, val isEnabled: Boolean) : - HistoryCacheEvent() - - data class OnClickWipeCachedMetadata(val key: String) : HistoryCacheEvent() - data class OnClickClearWatchHistory(val key: String) : HistoryCacheEvent() - data class OnClickDeletePlaybackPositions(val key: String) : HistoryCacheEvent() - data class OnClickClearSearchHistory(val key: String) : HistoryCacheEvent() - data class OnClickReCaptchaCookies(val key: String) : HistoryCacheEvent() -} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt index 9fc87fbec2f..f512a3d652b 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt @@ -7,45 +7,75 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel -import kotlinx.coroutines.launch +import org.schabi.newpipe.R import org.schabi.newpipe.settings.presentation.history_cache.components.CachePreferencesComponent import org.schabi.newpipe.settings.presentation.history_cache.components.HistoryPreferencesComponent +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowClearWatchHistorySnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeletePlaybackSnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeleteSearchHistorySnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowReCaptchaCookiesSnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar import org.schabi.newpipe.ui.theme.AppTheme @Composable -fun HistoryCacheScreen( +fun HistoryCacheSettingsScreen( modifier: Modifier = Modifier, viewModel: HistoryCacheSettingsViewModel = hiltViewModel(), ) { + val snackBarHostState = remember { SnackbarHostState() } + val playBackPositionsDeleted = stringResource(R.string.watch_history_states_deleted) + val watchHistoryDeleted = stringResource(R.string.watch_history_deleted) + val wipeCachedMetadataSnackbar = stringResource(R.string.metadata_cache_wipe_complete_notice) + val deleteSearchHistory = stringResource(R.string.search_history_deleted) + val clearReCaptchaCookiesSnackbar = stringResource(R.string.recaptcha_cookies_cleared) + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collect { event -> + val message = when (event) { + is ShowDeletePlaybackSnackbar -> playBackPositionsDeleted + is ShowClearWatchHistorySnackbar -> watchHistoryDeleted + is ShowWipeCachedMetadataSnackbar -> wipeCachedMetadataSnackbar + is ShowDeleteSearchHistorySnackbar -> deleteSearchHistory + is ShowReCaptchaCookiesSnackbar -> clearReCaptchaCookiesSnackbar + } + + snackBarHostState.showSnackbar(message) + } + } + val state by viewModel.state.collectAsState() HistoryCacheComponent( state = state, onEvent = viewModel::onEvent, + snackBarHostState = snackBarHostState, modifier = modifier ) } @Composable fun HistoryCacheComponent( - state: HistoryCacheUiState, + state: SwitchPreferencesUiState, onEvent: (HistoryCacheEvent) -> Unit, + snackBarHostState: SnackbarHostState, modifier: Modifier = Modifier, ) { - val snackBarHostState = remember { SnackbarHostState() } Scaffold( modifier = modifier, snackbarHost = { @@ -61,18 +91,15 @@ fun HistoryCacheComponent( verticalArrangement = Arrangement.Center, ) { HistoryPreferencesComponent( - state = state.switchPreferencesUiState, - onEvent = onEvent, - modifier = Modifier.fillMaxWidth() + state = state, + onEvent = { key, value -> + onEvent(HistoryCacheEvent.OnUpdateBooleanPreference(key, value)) + }, + modifier = Modifier.fillMaxWidth(), ) - val coroutineScope = rememberCoroutineScope() + HorizontalDivider(Modifier.fillMaxWidth()) CachePreferencesComponent( - onEvent = onEvent, - onShowSnackbar = { - coroutineScope.launch { - snackBarHostState.showSnackbar(it) - } - }, + onEvent = { onEvent(it) }, modifier = Modifier.fillMaxWidth() ) } @@ -84,7 +111,7 @@ fun HistoryCacheComponent( private fun HistoryCacheComponentPreview() { val state by remember { mutableStateOf( - HistoryCacheUiState() + SwitchPreferencesUiState() ) } AppTheme( @@ -95,6 +122,7 @@ private fun HistoryCacheComponentPreview() { state = state, onEvent = { }, + snackBarHostState = SnackbarHostState(), modifier = Modifier.fillMaxSize() ) } diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt new file mode 100644 index 00000000000..94f056ed338 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt @@ -0,0 +1,189 @@ +package org.schabi.newpipe.settings.presentation.history_cache + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.schabi.newpipe.DownloaderImpl +import org.schabi.newpipe.R +import org.schabi.newpipe.error.ErrorInfo +import org.schabi.newpipe.error.ReCaptchaActivity +import org.schabi.newpipe.error.UserAction +import org.schabi.newpipe.error.usecases.OpenErrorActivity +import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteSearchHistory +import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteStreamStateHistory +import org.schabi.newpipe.settings.domain.usecases.DeleteWatchHistory +import org.schabi.newpipe.settings.domain.usecases.get_preference.GetPreference +import org.schabi.newpipe.settings.domain.usecases.update_boolean_preference.UpdatePreference +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickClearSearchHistory +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickClearWatchHistory +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickDeletePlaybackPositions +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickReCaptchaCookies +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickWipeCachedMetadata +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnUpdateBooleanPreference +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowClearWatchHistorySnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeletePlaybackSnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeleteSearchHistorySnackbar +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar +import org.schabi.newpipe.util.InfoCache +import javax.inject.Inject + +@HiltViewModel +class HistoryCacheSettingsViewModel @Inject constructor( + private val updateBooleanPreference: UpdatePreference, + private val updateStringPreference: UpdatePreference, + private val getBooleanPreference: GetPreference, + private val deleteWatchHistory: DeleteWatchHistory, + private val deleteCompleteStreamStateHistory: DeleteCompleteStreamStateHistory, + private val deleteCompleteSearchHistory: DeleteCompleteSearchHistory, + private val openErrorActivity: OpenErrorActivity, +) : ViewModel() { + private val _state = MutableStateFlow(SwitchPreferencesUiState()) + val state: StateFlow = _state.asStateFlow() + + private val _eventFlow = MutableSharedFlow() + val eventFlow = _eventFlow.asSharedFlow() + + init { + viewModelScope.launch { + getBooleanPreference(R.string.enable_watch_history_key, true).collect { preference -> + _state.update { oldState -> + oldState.copy( + watchHistoryEnabled = preference + ) + } + } + } + + viewModelScope.launch { + getBooleanPreference(R.string.enable_playback_resume_key, true).collect { preference -> + _state.update { oldState -> + oldState.copy( + resumePlaybackEnabled = preference + ) + } + } + } + + viewModelScope.launch { + getBooleanPreference( + R.string.enable_playback_state_lists_key, + true + ).collect { preference -> + _state.update { oldState -> + oldState.copy( + positionsInListsEnabled = preference + ) + } + } + } + viewModelScope.launch { + getBooleanPreference(R.string.enable_search_history_key, true).collect { preference -> + _state.update { oldState -> + oldState.copy( + searchHistoryEnabled = preference + ) + } + } + } + } + + fun onEvent(event: HistoryCacheEvent) { + when (event) { + is OnUpdateBooleanPreference -> { + viewModelScope.launch { + updateBooleanPreference(event.key, event.isEnabled) + } + } + + is OnClickWipeCachedMetadata -> { + InfoCache.getInstance().clearCache() + viewModelScope.launch { + _eventFlow.emit(ShowWipeCachedMetadataSnackbar) + } + } + + is OnClickClearWatchHistory -> { + viewModelScope.launch { + deleteWatchHistory( + onDeletePlaybackStates = { + viewModelScope.launch { + _eventFlow.emit(ShowDeletePlaybackSnackbar) + } + }, + onDeleteWholeStreamHistory = { + viewModelScope.launch { + _eventFlow.emit(ShowClearWatchHistorySnackbar) + } + }, + onRemoveOrphanedRecords = { + // TODO: ask why original did nothing + } + ) + } + } + + is OnClickDeletePlaybackPositions -> { + viewModelScope.launch { + deleteCompleteStreamStateHistory( + Dispatchers.IO, + onError = { error -> + openErrorActivity( + ErrorInfo( + error, + UserAction.DELETE_FROM_HISTORY, + "Delete playback states" + ) + ) + }, + onSuccess = { + viewModelScope.launch { + _eventFlow.emit(ShowDeletePlaybackSnackbar) + } + } + ) + } + } + + is OnClickClearSearchHistory -> { + viewModelScope.launch { + deleteCompleteSearchHistory( + dispatcher = Dispatchers.IO, + onError = { error -> + openErrorActivity( + ErrorInfo( + error, + UserAction.DELETE_FROM_HISTORY, + "Delete search history" + ) + ) + }, + onSuccess = { + viewModelScope.launch { + _eventFlow.emit(ShowDeleteSearchHistorySnackbar) + } + } + ) + } + } + + is OnClickReCaptchaCookies -> { + viewModelScope.launch { + updateStringPreference(event.key, "") + DownloaderImpl.getInstance() + .setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, "") + _eventFlow.emit(HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar) + } + } + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt similarity index 70% rename from app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt rename to app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt index 1d346244eeb..77de7a45552 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheUiState.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt @@ -1,9 +1,7 @@ package org.schabi.newpipe.settings.presentation.history_cache -data class HistoryCacheUiState( - val switchPreferencesUiState: SwitchPreferencesUiState = SwitchPreferencesUiState() -) - +import androidx.compose.runtime.Stable +@Stable data class SwitchPreferencesUiState( val watchHistoryEnabled: Boolean = false, val resumePlaybackEnabled: Boolean = false, diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt index 6657b78272a..6f967085411 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt @@ -18,21 +18,32 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import org.schabi.newpipe.R import org.schabi.newpipe.settings.components.irreversible_preference.IrreversiblePreferenceComponent -import org.schabi.newpipe.settings.presentation.history_cache.HistoryCacheEvent +import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent import org.schabi.newpipe.ui.theme.AppTheme import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium @Composable fun CachePreferencesComponent( onEvent: (HistoryCacheEvent) -> Unit, - onShowSnackbar: (String) -> Unit, modifier: Modifier = Modifier, ) { - val preferences = rememberPreferences() var dialogTitle by remember { mutableStateOf("") } var dialogOnClick by remember { mutableStateOf({}) } var isDialogVisible by remember { mutableStateOf(false) } + val deleteViewHistory = stringResource(id = R.string.delete_view_history_alert) + val deletePlayBacks = stringResource(id = R.string.delete_playback_states_alert) + val deleteSearchHistory = stringResource(id = R.string.delete_search_history_alert) + + val onOpenDialog: (String, HistoryCacheEvent) -> Unit = { title, eventType -> + dialogTitle = title + isDialogVisible = true + dialogOnClick = { + onEvent(eventType) + isDialogVisible = false + } + } + Column( modifier = modifier, ) { @@ -41,104 +52,61 @@ fun CachePreferencesComponent( style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(SpacingMedium) ) - preferences.forEach { - val elementDialogTitle = it.dialogTitle?.let { dialogTitle -> - stringResource(dialogTitle) - } - val elementSnackBarText = stringResource(it.snackBarText) - val key = stringResource(id = it.keyId) - val onClick = { - if (elementDialogTitle != null) { - dialogTitle = elementDialogTitle - isDialogVisible = true - dialogOnClick = { - onEvent(it.event(key)) - isDialogVisible = false - onShowSnackbar(elementSnackBarText) - } - } else { - onEvent(it.event(key)) - onShowSnackbar(elementSnackBarText) - } - } - IrreversiblePreferenceComponent( - title = stringResource(id = it.title), - summary = stringResource(it.summary), - onClick = onClick, - modifier = Modifier.fillMaxWidth() - ) - } - - CacheAlertDialog( - isDialogVisible = isDialogVisible, - dialogTitle = dialogTitle, - onClickCancel = { isDialogVisible = false }, - onClick = dialogOnClick + IrreversiblePreferenceComponent( + title = stringResource(id = R.string.metadata_cache_wipe_title), + summary = stringResource(id = R.string.metadata_cache_wipe_summary), + onClick = { onEvent(HistoryCacheEvent.OnClickWipeCachedMetadata(R.string.metadata_cache_wipe_key)) }, + modifier = Modifier.fillMaxWidth() ) - } -} - -@Composable -private fun rememberPreferences(): List { - val preferences by remember { - mutableStateOf( - listOf( - IrreversiblePreferenceUiState( - title = R.string.metadata_cache_wipe_title, - summary = R.string.metadata_cache_wipe_summary, - dialogTitle = null, - snackBarText = R.string.metadata_cache_wipe_complete_notice, - event = { HistoryCacheEvent.OnClickWipeCachedMetadata(it) }, - keyId = R.string.metadata_cache_wipe_key, - ), - IrreversiblePreferenceUiState( - title = R.string.clear_views_history_title, - summary = R.string.clear_views_history_summary, - dialogTitle = R.string.delete_view_history_alert, - snackBarText = R.string.watch_history_deleted, - event = { HistoryCacheEvent.OnClickClearWatchHistory(it) }, - keyId = R.string.clear_views_history_key, - ), - IrreversiblePreferenceUiState( - title = R.string.clear_playback_states_title, - summary = R.string.clear_playback_states_summary, - dialogTitle = R.string.delete_playback_states_alert, - snackBarText = R.string.watch_history_states_deleted, - event = { HistoryCacheEvent.OnClickDeletePlaybackPositions(it) }, - keyId = R.string.clear_playback_states_key, - ), - IrreversiblePreferenceUiState( - title = R.string.clear_search_history_title, - summary = R.string.clear_search_history_summary, - dialogTitle = R.string.delete_search_history_alert, - snackBarText = R.string.search_history_deleted, - event = { HistoryCacheEvent.OnClickClearSearchHistory(it) }, - keyId = R.string.clear_search_history_key, - ), - IrreversiblePreferenceUiState( - title = R.string.clear_cookie_title, - summary = R.string.clear_cookie_summary, - dialogTitle = null, - snackBarText = R.string.recaptcha_cookies_cleared, - event = { HistoryCacheEvent.OnClickReCaptchaCookies(it) }, - keyId = R.string.recaptcha_cookies_key, + IrreversiblePreferenceComponent( + title = stringResource(id = R.string.clear_views_history_title), + summary = stringResource(id = R.string.clear_views_history_summary), + onClick = { + onOpenDialog( + deleteViewHistory, + HistoryCacheEvent.OnClickClearWatchHistory(R.string.clear_views_history_key) ) - ) + }, + modifier = Modifier.fillMaxWidth() + ) + IrreversiblePreferenceComponent( + title = stringResource(id = R.string.clear_playback_states_title), + summary = stringResource(id = R.string.clear_playback_states_summary), + onClick = { + onOpenDialog( + deletePlayBacks, + HistoryCacheEvent.OnClickDeletePlaybackPositions(R.string.clear_playback_states_key) + ) + }, + modifier = Modifier.fillMaxWidth() + ) + IrreversiblePreferenceComponent( + title = stringResource(id = R.string.clear_search_history_title), + summary = stringResource(id = R.string.clear_search_history_summary), + onClick = { + onOpenDialog( + deleteSearchHistory, + HistoryCacheEvent.OnClickClearSearchHistory(R.string.clear_search_history_key) + ) + }, + modifier = Modifier.fillMaxWidth() + ) + IrreversiblePreferenceComponent( + title = stringResource(id = R.string.clear_cookie_title), + summary = stringResource(id = R.string.clear_cookie_summary), + onClick = { onEvent(HistoryCacheEvent.OnClickReCaptchaCookies(R.string.recaptcha_cookies_key)) }, + modifier = Modifier.fillMaxWidth() ) + if (isDialogVisible) { + CacheAlertDialog( + dialogTitle = dialogTitle, + onClickCancel = { isDialogVisible = false }, + onClick = dialogOnClick + ) + } } - return preferences } -private data class IrreversiblePreferenceUiState( - val title: Int, - val summary: Int, - val dialogTitle: Int?, - val snackBarText: Int, - val enabled: Boolean = true, - val event: (String) -> HistoryCacheEvent, - val keyId: Int, -) - @Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) @Composable private fun CachePreferencesComponentPreview() { @@ -146,7 +114,6 @@ private fun CachePreferencesComponentPreview() { Scaffold { padding -> CachePreferencesComponent( onEvent = {}, - onShowSnackbar = {}, modifier = Modifier .fillMaxWidth() .padding(padding) @@ -157,34 +124,31 @@ private fun CachePreferencesComponentPreview() { @Composable private fun CacheAlertDialog( - isDialogVisible: Boolean, dialogTitle: String, onClickCancel: () -> Unit, onClick: () -> Unit, modifier: Modifier = Modifier, ) { - if (isDialogVisible) { - AlertDialog( - onDismissRequest = onClickCancel, - confirmButton = { - TextButton(onClick = onClick) { - Text(text = "Delete") - } - }, - dismissButton = { - TextButton(onClick = onClickCancel) { - Text(text = "Cancel") - } - }, - title = { - Text(text = dialogTitle) - }, - text = { - Text(text = "This is an irreversible action") - }, - modifier = modifier - ) - } + AlertDialog( + onDismissRequest = onClickCancel, + confirmButton = { + TextButton(onClick = onClick) { + Text(text = "Delete") + } + }, + dismissButton = { + TextButton(onClick = onClickCancel) { + Text(text = "Cancel") + } + }, + title = { + Text(text = dialogTitle) + }, + text = { + Text(text = "This is an irreversible action") + }, + modifier = modifier + ) } @Preview(backgroundColor = 0xFFFFFFFF) @@ -193,7 +157,6 @@ private fun CacheAlertDialogPreview() { AppTheme { Scaffold { padding -> CacheAlertDialog( - isDialogVisible = true, dialogTitle = "Delete view history", onClickCancel = {}, onClick = {}, diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt index f929e387ab7..f1978bad4bd 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt @@ -14,79 +14,57 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import org.schabi.newpipe.R import org.schabi.newpipe.settings.components.switch_preference.SwitchPreferenceComponent -import org.schabi.newpipe.settings.presentation.history_cache.HistoryCacheEvent import org.schabi.newpipe.settings.presentation.history_cache.SwitchPreferencesUiState import org.schabi.newpipe.ui.theme.AppTheme @Composable fun HistoryPreferencesComponent( state: SwitchPreferencesUiState, - onEvent: (HistoryCacheEvent) -> Unit, + onEvent: (Int, Boolean) -> Unit, modifier: Modifier = Modifier, ) { Column( modifier = modifier, ) { - val preferences = rememberSwitchPreferencesUiState(state) - preferences.forEach { preference -> - val key = stringResource(preference.keyId) - SwitchPreferenceComponent( - title = stringResource(id = preference.titleId), - summary = stringResource(id = preference.summaryId), - isChecked = preference.isEnabled, - onCheckedChange = { - onEvent(HistoryCacheEvent.OnUpdateBooleanPreference(key, it)) - }, - modifier = Modifier.fillMaxWidth() - ) - } - } -} - -@Composable -private fun rememberSwitchPreferencesUiState( - state: SwitchPreferencesUiState, -): List { - val preferences by remember { - mutableStateOf( - listOf( - SwitchPreferencesIdState( - titleId = R.string.enable_watch_history_title, - summaryId = R.string.enable_watch_history_summary, - isEnabled = state.watchHistoryEnabled, - keyId = R.string.enable_watch_history_key - ), - SwitchPreferencesIdState( - titleId = R.string.enable_playback_resume_title, - summaryId = R.string.enable_playback_resume_summary, - isEnabled = state.resumePlaybackEnabled, - keyId = R.string.enable_playback_resume_key - ), - SwitchPreferencesIdState( - titleId = R.string.enable_playback_state_lists_title, - summaryId = R.string.enable_playback_state_lists_summary, - isEnabled = state.positionsInListsEnabled, - keyId = R.string.enable_playback_state_lists_key - ), - SwitchPreferencesIdState( - titleId = R.string.enable_search_history_title, - summaryId = R.string.enable_search_history_summary, - isEnabled = state.searchHistoryEnabled, - keyId = R.string.enable_search_history_key - ) - ) + SwitchPreferenceComponent( + title = stringResource(id = R.string.enable_watch_history_title), + summary = stringResource(id = R.string.enable_watch_history_summary), + isChecked = state.watchHistoryEnabled, + onCheckedChange = { + onEvent(R.string.enable_watch_history_key, it) + }, + modifier = Modifier.fillMaxWidth() + ) + SwitchPreferenceComponent( + title = stringResource(id = R.string.enable_playback_resume_title), + summary = stringResource(id = R.string.enable_playback_resume_summary), + isChecked = state.resumePlaybackEnabled, + onCheckedChange = { + onEvent(R.string.enable_playback_resume_key, it) + }, + modifier = Modifier.fillMaxWidth() + ) + SwitchPreferenceComponent( + title = stringResource(id = R.string.enable_playback_state_lists_title), + summary = stringResource(id = R.string.enable_playback_state_lists_summary), + isChecked = state.positionsInListsEnabled, + onCheckedChange = { + onEvent(R.string.enable_playback_state_lists_key, it) + }, + modifier = Modifier.fillMaxWidth() + ) + SwitchPreferenceComponent( + title = stringResource(id = R.string.enable_search_history_title), + summary = stringResource(id = R.string.enable_search_history_summary), + isChecked = state.searchHistoryEnabled, + onCheckedChange = { + onEvent(R.string.enable_search_history_key, it) + }, + modifier = Modifier.fillMaxWidth() ) } - return preferences } -private data class SwitchPreferencesIdState( - val titleId: Int, - val summaryId: Int, - val isEnabled: Boolean, - val keyId: Int, -) - @Preview(showBackground = true) @Composable private fun SwitchPreferencesComponentPreview() { @@ -101,7 +79,7 @@ private fun SwitchPreferencesComponentPreview() { Scaffold { padding -> HistoryPreferencesComponent( state = state, - onEvent = { + onEvent = { _, _ -> // Mock behaviour to preview state = state.copy( watchHistoryEnabled = !state.watchHistoryEnabled @@ -109,7 +87,7 @@ private fun SwitchPreferencesComponentPreview() { }, modifier = Modifier .fillMaxWidth() - .padding(padding) + .padding(padding), ) } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheEvent.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheEvent.kt new file mode 100644 index 00000000000..0bd5d49c596 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheEvent.kt @@ -0,0 +1,10 @@ +package org.schabi.newpipe.settings.presentation.history_cache.events + +sealed class HistoryCacheEvent { + data class OnUpdateBooleanPreference(val key: Int, val isEnabled: Boolean) : HistoryCacheEvent() + data class OnClickWipeCachedMetadata(val key: Int) : HistoryCacheEvent() + data class OnClickClearWatchHistory(val key: Int) : HistoryCacheEvent() + data class OnClickDeletePlaybackPositions(val key: Int) : HistoryCacheEvent() + data class OnClickClearSearchHistory(val key: Int) : HistoryCacheEvent() + data class OnClickReCaptchaCookies(val key: Int) : HistoryCacheEvent() +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheUiEvent.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheUiEvent.kt new file mode 100644 index 00000000000..c40c1b45fdc --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/events/HistoryCacheUiEvent.kt @@ -0,0 +1,9 @@ +package org.schabi.newpipe.settings.presentation.history_cache.events + +sealed class HistoryCacheUiEvent { + data object ShowDeletePlaybackSnackbar : HistoryCacheUiEvent() + data object ShowDeleteSearchHistorySnackbar : HistoryCacheUiEvent() + data object ShowClearWatchHistorySnackbar : HistoryCacheUiEvent() + data object ShowReCaptchaCookiesSnackbar : HistoryCacheUiEvent() + data object ShowWipeCachedMetadataSnackbar : HistoryCacheUiEvent() +} From 86dbfea7cd5053b7ca0eb4b5acaaece7a96d385b Mon Sep 17 00:00:00 2001 From: brais Date: Tue, 13 Aug 2024 16:16:41 +0200 Subject: [PATCH 18/22] updated gradle --- app/build.gradle | 4 ++-- build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ec3493828a0..65bf4a74b3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -328,8 +328,8 @@ dependencies { androidTestImplementation "org.assertj:assertj-core:3.24.2" // dagger - testImplementation("com.google.dagger:hilt-android-testing${daggerVersion}") - androidTestImplementation("com.google.dagger:hilt-android-testing${daggerVersion}") + testImplementation("com.google.dagger:hilt-android-testing:${daggerVersion}") + androidTestImplementation("com.google.dagger:hilt-android-testing:${daggerVersion}") } static String getGitWorkingBranch() { diff --git a/build.gradle b/build.gradle index 35c1b25da38..97a619d4d53 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.5.1' + classpath 'com.android.tools.build:gradle:8.5.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath("com.google.dagger:hilt-android-gradle-plugin:$dagger_version") // NOTE: Do not place your application dependencies here; they belong From 035c394cf6704c0af9077c01ebfa55b810d02140 Mon Sep 17 00:00:00 2001 From: Mihael_River <154642338+Stackoverflow-addict@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:32:42 +0200 Subject: [PATCH 19/22] Fixing the 404 page not found, when clicking on "contribution notes" in multiple README.md's translated into different languages (#11487) Link to contribution notes wasn't working * Update README.de.md, fix grammar in README.de.md * Update README.asm.md * Update README.fr.md * Update README.hi.md * Update README.it.md * Update README.pa.md * Update README.pt_BR.md * Update README.ru.md * Update README.sr.md --------- Co-authored-by: Tobi --- doc/README.asm.md | 2 +- doc/README.de.md | 2 +- doc/README.fr.md | 2 +- doc/README.hi.md | 2 +- doc/README.it.md | 2 +- doc/README.pa.md | 2 +- doc/README.pt_BR.md | 2 +- doc/README.ru.md | 2 +- doc/README.sr.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/README.asm.md b/doc/README.asm.md index 2a7c10f510a..370319c15da 100644 --- a/doc/README.asm.md +++ b/doc/README.asm.md @@ -106,7 +106,7 @@ NewPipe এ আপুনি ব্যৱহাৰ কৰা সেৱাৰ অ ## অৱদান -আপোনাৰ ধাৰণা, অনুবাদ, ডিজাইন পৰিবৰ্তন, ক'ড পৰিষ্কাৰ কৰা, বা আনকি ডাঙৰ ক'ড পৰিৱৰ্তন হওক, সহায় সদায় আদৰণীয়। প্ৰতিটো অৱদানৰ লগে লগে এপটো ভাল হৈ পৰে, যিমানেই ডাঙৰ বা সৰু নহওক কিয়! যদি আপুনি জড়িত হ'ব বিচাৰে তেন্তে চাওক আমাৰ [অবদানৰ টোকা সমূহ](.github/CONTRIBUTING.md).Translation status +আপোনাৰ ধাৰণা, অনুবাদ, ডিজাইন পৰিবৰ্তন, ক'ড পৰিষ্কাৰ কৰা, বা আনকি ডাঙৰ ক'ড পৰিৱৰ্তন হওক, সহায় সদায় আদৰণীয়। প্ৰতিটো অৱদানৰ লগে লগে এপটো ভাল হৈ পৰে, যিমানেই ডাঙৰ বা সৰু নহওক কিয়! যদি আপুনি জড়িত হ'ব বিচাৰে তেন্তে চাওক আমাৰ [অবদানৰ টোকা সমূহ](/.github/CONTRIBUTING.md).Translation status ## অনুদান diff --git a/doc/README.de.md b/doc/README.de.md index e269da05ce9..be7744332d1 100644 --- a/doc/README.de.md +++ b/doc/README.de.md @@ -126,7 +126,7 @@ So eine Aktion wird nicht unterstützt und du solltest sie nur in Erwägung zieh ## Beitrag Egal ob du neue Ideen, Übersetzungen, Designvorschläge, kleine Code-Bereinigungen, oder sogar große Code-Verbesserungen hast, jegliche Unterstützung ist immer gern gesehen. Die App wird mit _jedem_ Beitrag besser und besser - egal wie viel Arbeit in ihn gesteckt wird! -Wenn du dich einbringen willst, sehe dir die [Beitragshinweise](.github/CONTRIBUTING.md) an. +Wenn du dich einbringen willst, sieh dir die [Beitragshinweise](/.github/CONTRIBUTING.md) an. Übersetzt diff --git a/doc/README.fr.md b/doc/README.fr.md index 7d4673b6938..864cc927a3b 100644 --- a/doc/README.fr.md +++ b/doc/README.fr.md @@ -109,7 +109,7 @@ Entre temps, si vous voulez changer de source pour une raison quelconque (par ex ## Contribuer -Que vous ayez des idées, des traductions, des changements de design, du nettoyage de code, ou encore un changement de code majeur, toute aide est la bienvenue. L'app s'améliore un peu plus à chaque contribution, peu importe qu'elle soit grosse ou petite ! Si vous aimeriez être impliqué, jetez un coup d'oeil à nos [notes pour contribuer](.github/CONTRIBUTING.md). +Que vous ayez des idées, des traductions, des changements de design, du nettoyage de code, ou encore un changement de code majeur, toute aide est la bienvenue. L'app s'améliore un peu plus à chaque contribution, peu importe qu'elle soit grosse ou petite ! Si vous aimeriez être impliqué, jetez un coup d'oeil à nos [notes pour contribuer](/.github/CONTRIBUTING.md). Translation status diff --git a/doc/README.hi.md b/doc/README.hi.md index 282e7542056..d503f43a5f7 100644 --- a/doc/README.hi.md +++ b/doc/README.hi.md @@ -105,7 +105,7 @@ NewPipe पर कई सेवाएँ उपलब्ध हैं। हम चाहे आप अपने विचार जोड़ना चाहे, या अनुवाद, डिज़ाइन में बदलाव, कोड में सफ़ाई, या कोड में भारी बदलाव, सहायता ज़रूर करें। जितने योगदान हो, ऐप उतनी ही बेहतर होती जाती है! -अगर आप योगदान करना चाहते हैं, हमारे [योगदान के दिशानिर्देश](.github/CONTRIBUTING.md) देखें। +अगर आप योगदान करना चाहते हैं, हमारे [योगदान के दिशानिर्देश](/.github/CONTRIBUTING.md) देखें। अनुवाद की स्थिति diff --git a/doc/README.it.md b/doc/README.it.md index 55ae1238090..8bf1eb380f1 100644 --- a/doc/README.it.md +++ b/doc/README.it.md @@ -107,7 +107,7 @@ Nel frattempo, se vuoi cambiare fonte per la stessa ragione (ad es. la funzional ## Contribuire -Se hai idee, traduzioni, cambiamenti di *design*, pulizia di codice, o addirittura grossi cambiamenti di codice, l'aiuto è sempre apprezzato. L'app diventa sempre meglio con ogni contribuzione, non importa quanto grande o piccola essa sia! Se ti piacerebbe essere parte del progetto, vedi le nostre [note di contribuzione](.github/CONTRIBUTING.md). +Se hai idee, traduzioni, cambiamenti di *design*, pulizia di codice, o addirittura grossi cambiamenti di codice, l'aiuto è sempre apprezzato. L'app diventa sempre meglio con ogni contribuzione, non importa quanto grande o piccola essa sia! Se ti piacerebbe essere parte del progetto, vedi le nostre [note di contribuzione](/.github/CONTRIBUTING.md). Stato traduzione diff --git a/doc/README.pa.md b/doc/README.pa.md index 321e6b7d0d0..0ad5e0625ee 100644 --- a/doc/README.pa.md +++ b/doc/README.pa.md @@ -105,7 +105,7 @@ NewPipe ਤੁਹਾਡੇ ਦੁਆਰਾ ਵਰਤੀ ਜਾ ਰਹੀ ਸੇ ਨੋਟ: ਜਦੋਂ ਤੁਸੀਂ ਅਧਿਕਾਰਤ ਐਪ ਵਿੱਚ ਇੱਕ ਡੇਟਾਬੇਸ ਨੂੰ ਆਯਾਤ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਹਮੇਸ਼ਾਂ ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਇਹ ਉਹੀ ਹੈ ਜੋ ਤੁਸੀਂ ਅਧਿਕਾਰਤ ਐਪ ਤੋਂ ਨਿਰਯਾਤ ਕੀਤਾ ਹੈ। ਜੇਕਰ ਤੁਸੀਂ ਅਧਿਕਾਰਤ ਐਪ ਤੋਂ ਇਲਾਵਾ ਕਿਸੇ ਏਪੀਕੇ ਤੋਂ ਨਿਰਯਾਤ ਕੀਤੇ ਡੇਟਾਬੇਸ ਨੂੰ ਆਯਾਤ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਹ ਚੀਜ਼ਾਂ ਨੂੰ ਤੋੜ ਸਕਦਾ ਹੈ। ਅਜਿਹੀ ਕਾਰਵਾਈ ਅਸਮਰਥਿਤ ਹੈ, ਅਤੇ ਤੁਹਾਨੂੰ ਅਜਿਹਾ ਉਦੋਂ ਹੀ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਨੂੰ ਪੂਰੀ ਤਰ੍ਹਾਂ ਯਕੀਨ ਹੋਵੇ ਕਿ ਤੁਸੀਂ ਜਾਣਦੇ ਹੋ ਕਿ ਤੁਸੀਂ ਕੀ ਕਰ ਰਹੇ ਹੋ। ## ਯੋਗਦਾਨ -ਭਾਵੇਂ ਤੁਹਾਡੇ ਕੋਲ ਵਿਚਾਰ, ਅਨੁਵਾਦ, ਡਿਜ਼ਾਈਨ ਤਬਦੀਲੀਆਂ, ਕੋਡ ਦੀ ਸਫਾਈ, ਜਾਂ ਇੱਥੋਂ ਤੱਕ ਕਿ ਵੱਡੀਆਂ ਕੋਡ ਤਬਦੀਲੀਆਂ ਹੋਣ, ਮਦਦ ਦਾ ਹਮੇਸ਼ਾ ਸਵਾਗਤ ਹੈ। ਐਪ ਹਰੇਕ ਯੋਗਦਾਨ ਦੇ ਨਾਲ ਬਿਹਤਰ ਅਤੇ ਬਿਹਤਰ ਹੋ ਜਾਂਦੀ ਹੈ, ਚਾਹੇ ਉਹ ਕਿੰਨਾ ਵੱਡਾ ਜਾਂ ਛੋਟਾ ਹੋਵੇ! ਜੇਕਰ ਤੁਸੀਂ ਸ਼ਾਮਲ ਹੋਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਸਾਡੀ ਜਾਂਚ ਕਰੋ [contribution notes](.github/CONTRIBUTING.md). +ਭਾਵੇਂ ਤੁਹਾਡੇ ਕੋਲ ਵਿਚਾਰ, ਅਨੁਵਾਦ, ਡਿਜ਼ਾਈਨ ਤਬਦੀਲੀਆਂ, ਕੋਡ ਦੀ ਸਫਾਈ, ਜਾਂ ਇੱਥੋਂ ਤੱਕ ਕਿ ਵੱਡੀਆਂ ਕੋਡ ਤਬਦੀਲੀਆਂ ਹੋਣ, ਮਦਦ ਦਾ ਹਮੇਸ਼ਾ ਸਵਾਗਤ ਹੈ। ਐਪ ਹਰੇਕ ਯੋਗਦਾਨ ਦੇ ਨਾਲ ਬਿਹਤਰ ਅਤੇ ਬਿਹਤਰ ਹੋ ਜਾਂਦੀ ਹੈ, ਚਾਹੇ ਉਹ ਕਿੰਨਾ ਵੱਡਾ ਜਾਂ ਛੋਟਾ ਹੋਵੇ! ਜੇਕਰ ਤੁਸੀਂ ਸ਼ਾਮਲ ਹੋਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਸਾਡੀ ਜਾਂਚ ਕਰੋ [contribution notes](/.github/CONTRIBUTING.md). Translation status diff --git a/doc/README.pt_BR.md b/doc/README.pt_BR.md index 59ff65db3df..73489bb41aa 100644 --- a/doc/README.pt_BR.md +++ b/doc/README.pt_BR.md @@ -106,7 +106,7 @@ Enquanto isso, se você quiser trocar de fontes por algum motivo (por exemplo, a 4. Importe os dados da etapa 1 via Configurações > Backup e Restauração > Importar Base de Dados ## Contribuições -Se você tem ideias, traduções, alterações de design, limpeza de códigos ou mudanças reais de código, a ajuda é sempre bem-vinda. O aplicativo fica cada vez melhor a cada contribuição, não importa quão grande ou pequena! Se você quiser se envolver, verifique nossas [notas de contribuição](.github/CONTRIBUTING.md). +Se você tem ideias, traduções, alterações de design, limpeza de códigos ou mudanças reais de código, a ajuda é sempre bem-vinda. O aplicativo fica cada vez melhor a cada contribuição, não importa quão grande ou pequena! Se você quiser se envolver, verifique nossas [notas de contribuição](/.github/CONTRIBUTING.md). Estado da tradução diff --git a/doc/README.ru.md b/doc/README.ru.md index 35058c981b5..35867b8bf94 100644 --- a/doc/README.ru.md +++ b/doc/README.ru.md @@ -106,7 +106,7 @@ NewPipe работает, извлекая необходимые данные Примечание: когда вы импортируете базу данных в официальное приложение, убедитесь, что это именно та база данных, которую вы экспортировали _из_ официального приложения. Если вы импортируете базу данных, экспортированную из APK, отличного от официального приложения, это может привести к ошибке. Такое действие не поддерживается, и вы должны делать его только тогда, когда абсолютно уверены, что знаете, что делаете. ## Участие -Если у вас есть идеи, переводы, изменения дизайна, очистка кода или даже серьезные изменения кода, помощь всегда приветствуется. Приложение становится всё лучше и лучше с каждым вкладом, независимо от того, большой он или маленький! Если вы хотите принять участие, ознакомьтесь с нашими [заметками об участии](.github/CONTRIBUTING.md). +Если у вас есть идеи, переводы, изменения дизайна, очистка кода или даже серьезные изменения кода, помощь всегда приветствуется. Приложение становится всё лучше и лучше с каждым вкладом, независимо от того, большой он или маленький! Если вы хотите принять участие, ознакомьтесь с нашими [заметками об участии](/.github/CONTRIBUTING.md). Состояние перевода diff --git a/doc/README.sr.md b/doc/README.sr.md index 7f0ee65b7aa..60a21ce694c 100644 --- a/doc/README.sr.md +++ b/doc/README.sr.md @@ -104,7 +104,7 @@ NewPipe ради тако што преузима потребне податк Напомена: када увозите базу података у званичну апликацију, увек се уверите да је то она коју сте извезли _из_ званичне апликације. Ако увезете базу података извезену из APK-а, који није званична апликација, то може покварити ствари. Таква радња није подржана и требало би да то урадите само када сте потпуно сигурни да знате шта радите. ## Допринос -Без обзира да ли имате идеје, преводе, промене дизајна, чишћење кода или чак велике промене кода, помоћ је увек добродошла. Апликација постаје све боља и боља са сваким доприносом, без обзира колико је он велики или мали! Ако желите да се укључите, погледајте наше [напомене о доприносима](.github/CONTRIBUTING.md). +Без обзира да ли имате идеје, преводе, промене дизајна, чишћење кода или чак велике промене кода, помоћ је увек добродошла. Апликација постаје све боља и боља са сваким доприносом, без обзира колико је он велики или мали! Ако желите да се укључите, погледајте наше [напомене о доприносима](/.github/CONTRIBUTING.md). Статус превода From 005719215d001be5c2f364deba2cfdd12b2943ff Mon Sep 17 00:00:00 2001 From: brais Date: Sun, 1 Sep 2024 18:31:24 +0200 Subject: [PATCH 20/22] Changed business logic to be in its own files --- .../newpipe/dependency_injection/AppModule.kt | 27 ++++ .../dependency_injection/DatabaseModule.kt | 56 +++++++ .../error/usecases/OpenErrorActivity.kt | 18 +++ .../dependency_injection/SettingsModule.kt | 138 ++++++++++++++++++ .../repositories/HistoryRecordRepository.kt | 11 ++ .../HistoryRecordRepositoryFake.kt | 64 ++++++++ .../HistoryRecordRepositoryImpl.kt | 39 +++++ .../usecases/DeleteCompleteSearchHistory.kt | 20 +++ .../DeleteCompleteStreamStateHistory.kt | 20 +++ .../domain/usecases/DeletePlaybackStates.kt | 20 +++ .../domain/usecases/DeleteWatchHistory.kt | 69 +++++++++ .../domain/usecases/RemoveOrphanedRecords.kt | 21 +++ .../usecases/get_preference/GetPreference.kt | 7 + .../get_preference/GetPreferenceFake.kt | 16 ++ .../get_preference/GetPreferenceImpl.kt | 49 +++++++ .../update_preference/UpdatePreference.kt | 5 + .../update_preference/UpdatePreferenceFake.kt | 16 ++ .../update_preference/UpdatePreferenceImpl.kt | 18 +++ 18 files changed, 614 insertions(+) create mode 100644 app/src/main/java/org/schabi/newpipe/dependency_injection/AppModule.kt create mode 100644 app/src/main/java/org/schabi/newpipe/dependency_injection/DatabaseModule.kt create mode 100644 app/src/main/java/org/schabi/newpipe/error/usecases/OpenErrorActivity.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/dependency_injection/SettingsModule.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepository.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryFake.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryImpl.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteSearchHistory.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteStreamStateHistory.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeletePlaybackStates.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteWatchHistory.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/RemoveOrphanedRecords.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreference.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceFake.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceImpl.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreference.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceFake.kt create mode 100644 app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceImpl.kt diff --git a/app/src/main/java/org/schabi/newpipe/dependency_injection/AppModule.kt b/app/src/main/java/org/schabi/newpipe/dependency_injection/AppModule.kt new file mode 100644 index 00000000000..1365f80f8d0 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/dependency_injection/AppModule.kt @@ -0,0 +1,27 @@ +package org.schabi.newpipe.dependency_injection + +import android.content.Context +import android.content.SharedPreferences +import androidx.preference.PreferenceManager +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import org.schabi.newpipe.error.usecases.OpenErrorActivity +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object AppModule { + @Provides + @Singleton + fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences = + PreferenceManager.getDefaultSharedPreferences(context) + + @Provides + @Singleton + fun provideOpenActivity( + @ApplicationContext context: Context, + ): OpenErrorActivity = OpenErrorActivity(context) +} diff --git a/app/src/main/java/org/schabi/newpipe/dependency_injection/DatabaseModule.kt b/app/src/main/java/org/schabi/newpipe/dependency_injection/DatabaseModule.kt new file mode 100644 index 00000000000..4e20fe30c06 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/dependency_injection/DatabaseModule.kt @@ -0,0 +1,56 @@ +package org.schabi.newpipe.dependency_injection + +import android.content.Context +import androidx.room.Room +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import org.schabi.newpipe.database.AppDatabase +import org.schabi.newpipe.database.AppDatabase.DATABASE_NAME +import org.schabi.newpipe.database.Migrations.MIGRATION_1_2 +import org.schabi.newpipe.database.Migrations.MIGRATION_2_3 +import org.schabi.newpipe.database.Migrations.MIGRATION_3_4 +import org.schabi.newpipe.database.Migrations.MIGRATION_4_5 +import org.schabi.newpipe.database.Migrations.MIGRATION_5_6 +import org.schabi.newpipe.database.Migrations.MIGRATION_6_7 +import org.schabi.newpipe.database.Migrations.MIGRATION_7_8 +import org.schabi.newpipe.database.Migrations.MIGRATION_8_9 +import org.schabi.newpipe.database.history.dao.SearchHistoryDAO +import org.schabi.newpipe.database.history.dao.StreamHistoryDAO +import org.schabi.newpipe.database.stream.dao.StreamDAO +import org.schabi.newpipe.database.stream.dao.StreamStateDAO +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +class DatabaseModule { + + @Provides + @Singleton + fun provideAppDatabase(@ApplicationContext appContext: Context): AppDatabase = + Room.databaseBuilder( + appContext, + AppDatabase::class.java, + DATABASE_NAME + ).addMigrations( + MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, + MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9 + ).build() + + @Provides + fun provideStreamStateDao(appDatabase: AppDatabase): StreamStateDAO = + appDatabase.streamStateDAO() + + @Provides + fun providesStreamDao(appDatabase: AppDatabase): StreamDAO = appDatabase.streamDAO() + + @Provides + fun provideStreamHistoryDao(appDatabase: AppDatabase): StreamHistoryDAO = + appDatabase.streamHistoryDAO() + + @Provides + fun provideSearchHistoryDao(appDatabase: AppDatabase): SearchHistoryDAO = + appDatabase.searchHistoryDAO() +} diff --git a/app/src/main/java/org/schabi/newpipe/error/usecases/OpenErrorActivity.kt b/app/src/main/java/org/schabi/newpipe/error/usecases/OpenErrorActivity.kt new file mode 100644 index 00000000000..5168c0d3c59 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/error/usecases/OpenErrorActivity.kt @@ -0,0 +1,18 @@ +package org.schabi.newpipe.error.usecases + +import android.content.Context +import android.content.Intent +import org.schabi.newpipe.error.ErrorActivity +import org.schabi.newpipe.error.ErrorInfo + +class OpenErrorActivity( + private val context: Context, +) { + operator fun invoke(errorInfo: ErrorInfo) { + val intent = Intent(context, ErrorActivity::class.java) + intent.putExtra(ErrorActivity.ERROR_INFO, errorInfo) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + context.startActivity(intent) + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/dependency_injection/SettingsModule.kt b/app/src/main/java/org/schabi/newpipe/settings/dependency_injection/SettingsModule.kt new file mode 100644 index 00000000000..d0f271025cc --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/dependency_injection/SettingsModule.kt @@ -0,0 +1,138 @@ +package org.schabi.newpipe.settings.dependency_injection + +import android.content.Context +import android.content.SharedPreferences +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import org.schabi.newpipe.database.history.dao.SearchHistoryDAO +import org.schabi.newpipe.database.history.dao.StreamHistoryDAO +import org.schabi.newpipe.database.stream.dao.StreamDAO +import org.schabi.newpipe.database.stream.dao.StreamStateDAO +import org.schabi.newpipe.error.usecases.OpenErrorActivity +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepository +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepositoryImpl +import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteSearchHistory +import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteStreamStateHistory +import org.schabi.newpipe.settings.domain.usecases.DeletePlaybackStates +import org.schabi.newpipe.settings.domain.usecases.DeleteWatchHistory +import org.schabi.newpipe.settings.domain.usecases.RemoveOrphanedRecords +import org.schabi.newpipe.settings.domain.usecases.get_preference.GetPreference +import org.schabi.newpipe.settings.domain.usecases.get_preference.GetPreferenceImpl +import org.schabi.newpipe.settings.domain.usecases.update_preference.UpdatePreference +import org.schabi.newpipe.settings.domain.usecases.update_preference.UpdatePreferenceImpl +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object SettingsModule { + + @Provides + @Singleton + fun provideGetBooleanPreference( + sharedPreferences: SharedPreferences, + @ApplicationContext context: Context, + ): GetPreference = GetPreferenceImpl(sharedPreferences, context) + + @Provides + @Singleton + fun provideGetStringPreference( + sharedPreferences: SharedPreferences, + @ApplicationContext context: Context, + ): GetPreference = GetPreferenceImpl(sharedPreferences, context) + + @Provides + @Singleton + fun provideUpdateBooleanPreference( + sharedPreferences: SharedPreferences, + @ApplicationContext context: Context, + ): UpdatePreference = UpdatePreferenceImpl(context, sharedPreferences) { key, value -> + putBoolean( + key, + value + ) + } + + @Provides + @Singleton + fun provideUpdateStringPreference( + sharedPreferences: SharedPreferences, + @ApplicationContext context: Context, + ): UpdatePreference = UpdatePreferenceImpl(context, sharedPreferences) { key, value -> + putString( + key, + value + ) + } + + @Provides + @Singleton + fun provideUpdateIntPreference( + sharedPreferences: SharedPreferences, + @ApplicationContext context: Context, + ): UpdatePreference = UpdatePreferenceImpl(context, sharedPreferences) { key, value -> + putInt(key, value) + } + + @Provides + @Singleton + fun provideHistoryRecordRepository( + streamStateDao: StreamStateDAO, + streamHistoryDAO: StreamHistoryDAO, + streamDAO: StreamDAO, + searchHistoryDAO: SearchHistoryDAO, + ): HistoryRecordRepository = HistoryRecordRepositoryImpl( + streamStateDao = streamStateDao, + streamHistoryDAO = streamHistoryDAO, + streamDAO = streamDAO, + searchHistoryDAO = searchHistoryDAO, + ) + + @Provides + @Singleton + fun provideDeletePlaybackStatesUseCase( + historyRecordRepository: HistoryRecordRepository, + ): DeletePlaybackStates = DeletePlaybackStates( + historyRecordRepository = historyRecordRepository, + ) + + @Provides + @Singleton + fun provideDeleteWholeStreamHistoryUseCase( + historyRecordRepository: HistoryRecordRepository, + ): DeleteCompleteStreamStateHistory = DeleteCompleteStreamStateHistory( + historyRecordRepository = historyRecordRepository, + ) + + @Provides + @Singleton + fun provideRemoveOrphanedRecordsUseCase( + historyRecordRepository: HistoryRecordRepository, + ): RemoveOrphanedRecords = RemoveOrphanedRecords( + historyRecordRepository = historyRecordRepository, + ) + + @Provides + @Singleton + fun provideDeleteCompleteSearchHistoryUseCase( + historyRecordRepository: HistoryRecordRepository, + ): DeleteCompleteSearchHistory = DeleteCompleteSearchHistory( + historyRecordRepository = historyRecordRepository, + ) + + @Provides + @Singleton + fun provideDeleteWatchHistoryUseCase( + deletePlaybackStates: DeletePlaybackStates, + deleteCompleteStreamStateHistory: DeleteCompleteStreamStateHistory, + removeOrphanedRecords: RemoveOrphanedRecords, + openErrorActivity: OpenErrorActivity, + ): DeleteWatchHistory = DeleteWatchHistory( + deletePlaybackStates = deletePlaybackStates, + deleteCompleteStreamStateHistory = deleteCompleteStreamStateHistory, + removeOrphanedRecords = removeOrphanedRecords, + openErrorActivity = openErrorActivity + ) +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepository.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepository.kt new file mode 100644 index 00000000000..3b9edaa48ff --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepository.kt @@ -0,0 +1,11 @@ +package org.schabi.newpipe.settings.domain.repositories + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow + +interface HistoryRecordRepository { + fun deleteCompleteStreamState(dispatcher: CoroutineDispatcher): Flow + fun deleteWholeStreamHistory(dispatcher: CoroutineDispatcher): Flow + fun removeOrphanedRecords(dispatcher: CoroutineDispatcher): Flow + fun deleteCompleteSearchHistory(dispatcher: CoroutineDispatcher): Flow +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryFake.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryFake.kt new file mode 100644 index 00000000000..6e03fec475d --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryFake.kt @@ -0,0 +1,64 @@ +package org.schabi.newpipe.settings.domain.repositories + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.update +import org.schabi.newpipe.database.history.model.SearchHistoryEntry +import org.schabi.newpipe.database.history.model.StreamHistoryEntity +import org.schabi.newpipe.database.stream.model.StreamEntity +import org.schabi.newpipe.database.stream.model.StreamStateEntity + +class HistoryRecordRepositoryFake : HistoryRecordRepository { + private val _searchHistory: MutableStateFlow> = MutableStateFlow( + emptyList() + ) + val searchHistory = _searchHistory.asStateFlow() + private val _streamHistory = MutableStateFlow>(emptyList()) + val streamHistory = _streamHistory.asStateFlow() + private val _streams = MutableStateFlow>(emptyList()) + val streams = _streams.asStateFlow() + private val _streamStates = MutableStateFlow>(emptyList()) + val streamStates = _streamStates.asStateFlow() + + override fun deleteCompleteStreamState(dispatcher: CoroutineDispatcher): Flow = flow { + val count = streamStates.value.size + _streamStates.update { + emptyList() + } + emit(count) + }.flowOn(dispatcher) + + override fun deleteWholeStreamHistory(dispatcher: CoroutineDispatcher): Flow = flow { + val count = streamHistory.value.size + _streamHistory.update { + emptyList() + } + emit(count) + }.flowOn(dispatcher) + + override fun removeOrphanedRecords(dispatcher: CoroutineDispatcher): Flow = flow { + val orphanedStreams = streams.value.filter { stream -> + !streamHistory.value.any { it.streamUid == stream.uid } + } + + val deletedCount = orphanedStreams.size + + _streams.update { oldStreams -> + oldStreams.filter { it !in orphanedStreams } + } + + emit(deletedCount) + }.flowOn(dispatcher) + + override fun deleteCompleteSearchHistory(dispatcher: CoroutineDispatcher): Flow = flow { + val count = searchHistory.value.size + _searchHistory.update { + emptyList() + } + emit(count) + }.flowOn(dispatcher) +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryImpl.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryImpl.kt new file mode 100644 index 00000000000..b1d4abeebcb --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/repositories/HistoryRecordRepositoryImpl.kt @@ -0,0 +1,39 @@ +package org.schabi.newpipe.settings.domain.repositories + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import org.schabi.newpipe.database.history.dao.SearchHistoryDAO +import org.schabi.newpipe.database.history.dao.StreamHistoryDAO +import org.schabi.newpipe.database.stream.dao.StreamDAO +import org.schabi.newpipe.database.stream.dao.StreamStateDAO + +class HistoryRecordRepositoryImpl( + private val streamStateDao: StreamStateDAO, + private val streamHistoryDAO: StreamHistoryDAO, + private val streamDAO: StreamDAO, + private val searchHistoryDAO: SearchHistoryDAO, +) : HistoryRecordRepository { + override fun deleteCompleteStreamState(dispatcher: CoroutineDispatcher): Flow = + flow { + val deletedCount = streamStateDao.deleteAll() + emit(deletedCount) + }.flowOn(dispatcher) + + override fun deleteWholeStreamHistory(dispatcher: CoroutineDispatcher): Flow = + flow { + val deletedCount = streamHistoryDAO.deleteAll() + emit(deletedCount) + }.flowOn(dispatcher) + + override fun removeOrphanedRecords(dispatcher: CoroutineDispatcher): Flow = flow { + val deletedCount = streamDAO.deleteOrphans() + emit(deletedCount) + }.flowOn(dispatcher) + + override fun deleteCompleteSearchHistory(dispatcher: CoroutineDispatcher): Flow = flow { + val deletedCount = searchHistoryDAO.deleteAll() + emit(deletedCount) + }.flowOn(dispatcher) +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteSearchHistory.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteSearchHistory.kt new file mode 100644 index 00000000000..7b2c2d99a88 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteSearchHistory.kt @@ -0,0 +1,20 @@ +package org.schabi.newpipe.settings.domain.usecases + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.take +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepository + +class DeleteCompleteSearchHistory( + private val historyRecordRepository: HistoryRecordRepository, +) { + suspend operator fun invoke( + dispatcher: CoroutineDispatcher, + onError: (Throwable) -> Unit, + onSuccess: () -> Unit, + ) = historyRecordRepository.deleteCompleteSearchHistory(dispatcher).catch { error -> + onError(error) + }.take(1).collect { + onSuccess() + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteStreamStateHistory.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteStreamStateHistory.kt new file mode 100644 index 00000000000..0b516966dca --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteCompleteStreamStateHistory.kt @@ -0,0 +1,20 @@ +package org.schabi.newpipe.settings.domain.usecases + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.take +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepository + +class DeleteCompleteStreamStateHistory( + private val historyRecordRepository: HistoryRecordRepository, +) { + suspend operator fun invoke( + dispatcher: CoroutineDispatcher, + onError: (Throwable) -> Unit, + onSuccess: () -> Unit, + ) = historyRecordRepository.deleteWholeStreamHistory(dispatcher).catch { + onError(it) + }.take(1).collect { + onSuccess() + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeletePlaybackStates.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeletePlaybackStates.kt new file mode 100644 index 00000000000..e8416a492e1 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeletePlaybackStates.kt @@ -0,0 +1,20 @@ +package org.schabi.newpipe.settings.domain.usecases + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.take +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepository + +class DeletePlaybackStates( + private val historyRecordRepository: HistoryRecordRepository, +) { + suspend operator fun invoke( + dispatcher: CoroutineDispatcher, + onError: (Throwable) -> Unit, + onSuccess: () -> Unit, + ) = historyRecordRepository.deleteCompleteStreamState(dispatcher).catch { + onError(it) + }.take(1).collect { + onSuccess() + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteWatchHistory.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteWatchHistory.kt new file mode 100644 index 00000000000..403f6f1c026 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/DeleteWatchHistory.kt @@ -0,0 +1,69 @@ +package org.schabi.newpipe.settings.domain.usecases + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import org.schabi.newpipe.error.ErrorInfo +import org.schabi.newpipe.error.UserAction +import org.schabi.newpipe.error.usecases.OpenErrorActivity + +class DeleteWatchHistory( + private val deletePlaybackStates: DeletePlaybackStates, + private val deleteCompleteStreamStateHistory: DeleteCompleteStreamStateHistory, + private val removeOrphanedRecords: RemoveOrphanedRecords, + private val openErrorActivity: OpenErrorActivity, +) { + suspend operator fun invoke( + onDeletePlaybackStates: () -> Unit, + onDeleteWholeStreamHistory: () -> Unit, + onRemoveOrphanedRecords: () -> Unit, + dispatcher: CoroutineDispatcher = Dispatchers.IO, + ) = coroutineScope { + launch { + deletePlaybackStates( + dispatcher, + onError = { error -> + openErrorActivity( + ErrorInfo( + error, + UserAction.DELETE_FROM_HISTORY, + "Delete playback states" + ) + ) + }, + onSuccess = onDeletePlaybackStates + ) + } + launch { + deleteCompleteStreamStateHistory( + dispatcher, + onError = { error -> + openErrorActivity( + ErrorInfo( + error, + UserAction.DELETE_FROM_HISTORY, + "Delete from history" + ) + ) + }, + onSuccess = onDeleteWholeStreamHistory + ) + } + launch { + removeOrphanedRecords( + dispatcher, + onError = { error -> + openErrorActivity( + ErrorInfo( + error, + UserAction.DELETE_FROM_HISTORY, + "Clear orphaned records" + ) + ) + }, + onSuccess = onRemoveOrphanedRecords + ) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/RemoveOrphanedRecords.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/RemoveOrphanedRecords.kt new file mode 100644 index 00000000000..42e9cd00d4d --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/RemoveOrphanedRecords.kt @@ -0,0 +1,21 @@ +package org.schabi.newpipe.settings.domain.usecases + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.take +import org.schabi.newpipe.settings.domain.repositories.HistoryRecordRepository + +class RemoveOrphanedRecords( + private val historyRecordRepository: HistoryRecordRepository, +) { + suspend operator fun invoke( + dispatcher: CoroutineDispatcher, + onError: (Throwable) -> Unit, + onSuccess: () -> Unit, + ) = + historyRecordRepository.removeOrphanedRecords(dispatcher).catch { + onError(it) + }.take(1).collect { + onSuccess() + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreference.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreference.kt new file mode 100644 index 00000000000..19ed9d226d8 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreference.kt @@ -0,0 +1,7 @@ +package org.schabi.newpipe.settings.domain.usecases.get_preference + +import kotlinx.coroutines.flow.Flow + +fun interface GetPreference { + operator fun invoke(key: Int, defaultValue: T): Flow +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceFake.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceFake.kt new file mode 100644 index 00000000000..805a3008356 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceFake.kt @@ -0,0 +1,16 @@ +package org.schabi.newpipe.settings.domain.usecases.get_preference + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.map + +class GetPreferenceFake( + private val preferences: MutableStateFlow>, +) : GetPreference { + override fun invoke(key: Int, defaultValue: T): Flow { + return preferences.asStateFlow().map { + it[key] ?: defaultValue + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceImpl.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceImpl.kt new file mode 100644 index 00000000000..bb87025b761 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/get_preference/GetPreferenceImpl.kt @@ -0,0 +1,49 @@ +package org.schabi.newpipe.settings.domain.usecases.get_preference + +import android.content.Context +import android.content.SharedPreferences +import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow + +class GetPreferenceImpl( + private val sharedPreferences: SharedPreferences, + private val context: Context, +) : GetPreference { + override fun invoke(key: Int, defaultValue: T): Flow { + val keyString = context.getString(key) + return sharedPreferences.getFlowForKey(keyString, defaultValue) + } + + private fun SharedPreferences.getFlowForKey(key: String, defaultValue: T) = callbackFlow { + val listener = + SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey -> + if (key == changedKey) { + val updated = getPreferenceValue(key, defaultValue) + trySend(updated) + } + } + registerOnSharedPreferenceChangeListener(listener) + println("Current value for $key: ${getPreferenceValue(key, defaultValue)}") + if (contains(key)) { + send(getPreferenceValue(key, defaultValue)) + } + awaitClose { + unregisterOnSharedPreferenceChangeListener(listener) + cancel() + } + } + + @Suppress("UNCHECKED_CAST") + private fun SharedPreferences.getPreferenceValue(key: String, defaultValue: T): T { + return when (defaultValue) { + is Boolean -> getBoolean(key, defaultValue) as T + is Int -> getInt(key, defaultValue) as T + is Long -> getLong(key, defaultValue) as T + is Float -> getFloat(key, defaultValue) as T + is String -> getString(key, defaultValue) as T + else -> throw IllegalArgumentException("Unsupported type") + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreference.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreference.kt new file mode 100644 index 00000000000..0a1b0e966f2 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreference.kt @@ -0,0 +1,5 @@ +package org.schabi.newpipe.settings.domain.usecases.update_preference + +fun interface UpdatePreference { + suspend operator fun invoke(key: Int, value: T) +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceFake.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceFake.kt new file mode 100644 index 00000000000..a67677584e9 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceFake.kt @@ -0,0 +1,16 @@ +package org.schabi.newpipe.settings.domain.usecases.update_preference + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update + +class UpdatePreferenceFake( + private val preferences: MutableStateFlow>, +) : UpdatePreference { + override suspend fun invoke(key: Int, value: T) { + preferences.update { + it.apply { + put(key, value) + } + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceImpl.kt b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceImpl.kt new file mode 100644 index 00000000000..e51ec731b1c --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/domain/usecases/update_preference/UpdatePreferenceImpl.kt @@ -0,0 +1,18 @@ +package org.schabi.newpipe.settings.domain.usecases.update_preference + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit + +class UpdatePreferenceImpl( + private val context: Context, + private val sharedPreferences: SharedPreferences, + private val setter: SharedPreferences.Editor.(String, T) -> SharedPreferences.Editor, +) : UpdatePreference { + override suspend operator fun invoke(key: Int, value: T) { + val stringKey = context.getString(key) + sharedPreferences.edit { + setter(stringKey, value) + } + } +} From ff42678dd3301be9135e25ee02bd0d708f911573 Mon Sep 17 00:00:00 2001 From: brais Date: Sun, 1 Sep 2024 18:35:06 +0200 Subject: [PATCH 21/22] Updated view and viewmodel and remapped the fragments/activities --- .../history/StatisticsPlaylistFragment.java | 67 +++++++++++++++++-- .../newpipe/settings/SettingsActivity.java | 2 + .../IrreversiblePreference.kt | 13 ++-- .../history_cache/HistoryCacheFragment.kt | 39 +++++++++++ .../HistoryCacheSettingsScreen.kt | 19 ++++-- .../HistoryCacheSettingsViewModel.kt | 37 +++++++--- .../components/CachePreferences.kt | 11 ++- .../components/HistoryPreferences.kt | 2 +- .../{ => state}/SwitchPreferencesUiState.kt | 2 +- app/src/main/res/xml/main_settings.xml | 2 +- 10 files changed, 161 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheFragment.kt rename app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/{ => state}/SwitchPreferencesUiState.kt (80%) diff --git a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java index 1fea7e1559c..4801936e615 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java @@ -13,6 +13,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.viewbinding.ViewBinding; import com.google.android.material.snackbar.Snackbar; @@ -26,6 +27,7 @@ import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.databinding.StatisticPlaylistControlBinding; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.list.playlist.PlaylistControlViewHolder; @@ -34,7 +36,6 @@ import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; -import org.schabi.newpipe.settings.HistorySettingsFragment; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.PlayButtonHelper; @@ -161,14 +162,72 @@ public void held(final LocalItem selectedItem) { @Override public boolean onOptionsItemSelected(final MenuItem item) { if (item.getItemId() == R.id.action_history_clear) { - HistorySettingsFragment - .openDeleteWatchHistoryDialog(requireContext(), recordManager, disposables); + openDeleteWatchHistoryDialog(requireContext(), recordManager, disposables); } else { return super.onOptionsItemSelected(item); } return true; } + private static void openDeleteWatchHistoryDialog( + @NonNull final Context context, + final HistoryRecordManager recordManager, + final CompositeDisposable disposables + ) { + new AlertDialog.Builder(context) + .setTitle(R.string.delete_view_history_alert) + .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) + .setPositiveButton(R.string.delete, ((dialog, which) -> { + disposables.add(getDeletePlaybackStatesDisposable(context, recordManager)); + disposables.add(getWholeStreamHistoryDisposable(context, recordManager)); + disposables.add(getRemoveOrphanedRecordsDisposable(context, recordManager)); + })) + .show(); + } + + private static Disposable getDeletePlaybackStatesDisposable( + @NonNull final Context context, + final HistoryRecordManager recordManager + ) { + return recordManager.deleteCompleteStreamStateHistory() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> Toast.makeText(context, + R.string.watch_history_states_deleted, Toast.LENGTH_SHORT).show(), + throwable -> ErrorUtil.openActivity(context, + new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Delete playback states")) + ); + } + + private static Disposable getWholeStreamHistoryDisposable( + @NonNull final Context context, + final HistoryRecordManager recordManager + ) { + return recordManager.deleteWholeStreamHistory() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> Toast.makeText(context, + R.string.watch_history_deleted, Toast.LENGTH_SHORT).show(), + throwable -> ErrorUtil.openActivity(context, + new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Delete from history")) + ); + } + + private static Disposable getRemoveOrphanedRecordsDisposable( + @NonNull final Context context, final HistoryRecordManager recordManager) { + return recordManager.removeOrphanedRecords() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> { + }, + throwable -> ErrorUtil.openActivity(context, + new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Clear orphaned records")) + ); + } + /////////////////////////////////////////////////////////////////////////// // Fragment LifeCycle - Loading /////////////////////////////////////////////////////////////////////////// @@ -307,7 +366,7 @@ private void toggleSortMode() { sortMode = StatisticSortMode.LAST_PLAYED; setTitle(getString(R.string.title_last_played)); headerBinding.sortButtonIcon.setImageResource( - R.drawable.ic_filter_list); + R.drawable.ic_filter_list); headerBinding.sortButtonText.setText(R.string.title_most_played); } startLoading(true); diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java index 529e5344220..0c349ec4056 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit; +import dagger.hilt.android.AndroidEntryPoint; import icepick.Icepick; import icepick.State; @@ -64,6 +65,7 @@ * along with NewPipe. If not, see . */ +@AndroidEntryPoint public class SettingsActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, PreferenceSearchResultListener { diff --git a/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt b/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt index b66e4eb5fc6..f9cc79099fe 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/components/irreversible_preference/IrreversiblePreference.kt @@ -28,14 +28,13 @@ fun IrreversiblePreferenceComponent( modifier: Modifier = Modifier, enabled: Boolean = true, ) { + val clickModifier = if (enabled) { + Modifier.clickable { onClick() } + } else { + Modifier + } Row( - modifier = Modifier - .clickable { - if (enabled) { - onClick() - } - } - .then(modifier), + modifier = clickModifier.then(modifier), verticalAlignment = Alignment.CenterVertically, ) { val alpha by remember { diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheFragment.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheFragment.kt new file mode 100644 index 00000000000..d9a2f49c555 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheFragment.kt @@ -0,0 +1,39 @@ +package org.schabi.newpipe.settings.presentation.history_cache + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import org.schabi.newpipe.fragments.list.comments.CommentsFragment +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.util.KEY_SERVICE_ID +import org.schabi.newpipe.util.KEY_URL + +class HistoryCacheFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ) = ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + AppTheme { + HistoryCacheSettingsScreen( + modifier = Modifier.fillMaxSize() + ) + } + } + } + + companion object { + @JvmStatic + fun getInstance(serviceId: Int, url: String?) = CommentsFragment().apply { + arguments = bundleOf(KEY_SERVICE_ID to serviceId, KEY_URL to url) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt index f512a3d652b..9a246257a7e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsScreen.kt @@ -32,6 +32,7 @@ import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCach import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeleteSearchHistorySnackbar import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowReCaptchaCookiesSnackbar import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar +import org.schabi.newpipe.settings.presentation.history_cache.state.SwitchPreferencesUiState import org.schabi.newpipe.ui.theme.AppTheme @Composable @@ -47,6 +48,7 @@ fun HistoryCacheSettingsScreen( val clearReCaptchaCookiesSnackbar = stringResource(R.string.recaptcha_cookies_cleared) LaunchedEffect(key1 = true) { + viewModel.onInit() viewModel.eventFlow.collect { event -> val message = when (event) { is ShowDeletePlaybackSnackbar -> playBackPositionsDeleted @@ -60,10 +62,12 @@ fun HistoryCacheSettingsScreen( } } - val state by viewModel.state.collectAsState() + val switchPreferencesUiState by viewModel.switchState.collectAsState() + val recaptchaCookiesEnabled by viewModel.captchaCookies.collectAsState() HistoryCacheComponent( - state = state, - onEvent = viewModel::onEvent, + switchPreferences = switchPreferencesUiState, + recaptchaCookiesEnabled = recaptchaCookiesEnabled, + onEvent = { viewModel.onEvent(it) }, snackBarHostState = snackBarHostState, modifier = modifier ) @@ -71,7 +75,8 @@ fun HistoryCacheSettingsScreen( @Composable fun HistoryCacheComponent( - state: SwitchPreferencesUiState, + switchPreferences: SwitchPreferencesUiState, + recaptchaCookiesEnabled: Boolean, onEvent: (HistoryCacheEvent) -> Unit, snackBarHostState: SnackbarHostState, modifier: Modifier = Modifier, @@ -91,7 +96,7 @@ fun HistoryCacheComponent( verticalArrangement = Arrangement.Center, ) { HistoryPreferencesComponent( - state = state, + state = switchPreferences, onEvent = { key, value -> onEvent(HistoryCacheEvent.OnUpdateBooleanPreference(key, value)) }, @@ -99,6 +104,7 @@ fun HistoryCacheComponent( ) HorizontalDivider(Modifier.fillMaxWidth()) CachePreferencesComponent( + recaptchaCookiesEnabled = recaptchaCookiesEnabled, onEvent = { onEvent(it) }, modifier = Modifier.fillMaxWidth() ) @@ -119,7 +125,8 @@ private fun HistoryCacheComponentPreview() { ) { Surface { HistoryCacheComponent( - state = state, + switchPreferences = state, + recaptchaCookiesEnabled = false, onEvent = { }, snackBarHostState = SnackbarHostState(), diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt index 94f056ed338..49a8d3f1f62 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/HistoryCacheSettingsViewModel.kt @@ -21,7 +21,7 @@ import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteSearchHistory import org.schabi.newpipe.settings.domain.usecases.DeleteCompleteStreamStateHistory import org.schabi.newpipe.settings.domain.usecases.DeleteWatchHistory import org.schabi.newpipe.settings.domain.usecases.get_preference.GetPreference -import org.schabi.newpipe.settings.domain.usecases.update_boolean_preference.UpdatePreference +import org.schabi.newpipe.settings.domain.usecases.update_preference.UpdatePreference import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickClearSearchHistory import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheEvent.OnClickClearWatchHistory @@ -34,29 +34,44 @@ import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCach import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeletePlaybackSnackbar import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowDeleteSearchHistorySnackbar import org.schabi.newpipe.settings.presentation.history_cache.events.HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar +import org.schabi.newpipe.settings.presentation.history_cache.state.SwitchPreferencesUiState import org.schabi.newpipe.util.InfoCache import javax.inject.Inject @HiltViewModel class HistoryCacheSettingsViewModel @Inject constructor( - private val updateBooleanPreference: UpdatePreference, private val updateStringPreference: UpdatePreference, + private val updateBooleanPreference: UpdatePreference, + private val getStringPreference: GetPreference, private val getBooleanPreference: GetPreference, private val deleteWatchHistory: DeleteWatchHistory, private val deleteCompleteStreamStateHistory: DeleteCompleteStreamStateHistory, private val deleteCompleteSearchHistory: DeleteCompleteSearchHistory, private val openErrorActivity: OpenErrorActivity, ) : ViewModel() { - private val _state = MutableStateFlow(SwitchPreferencesUiState()) - val state: StateFlow = _state.asStateFlow() + private val _switchState = MutableStateFlow(SwitchPreferencesUiState()) + val switchState: StateFlow = _switchState.asStateFlow() + + private val _captchaCookies = MutableStateFlow(false) + val captchaCookies: StateFlow = _captchaCookies.asStateFlow() private val _eventFlow = MutableSharedFlow() val eventFlow = _eventFlow.asSharedFlow() - init { + fun onInit() { + + viewModelScope.launch { + val flow = getStringPreference(R.string.recaptcha_cookies_key, "") + flow.collect { preference -> + _captchaCookies.update { + preference.isNotEmpty() + } + } + } + viewModelScope.launch { getBooleanPreference(R.string.enable_watch_history_key, true).collect { preference -> - _state.update { oldState -> + _switchState.update { oldState -> oldState.copy( watchHistoryEnabled = preference ) @@ -66,7 +81,7 @@ class HistoryCacheSettingsViewModel @Inject constructor( viewModelScope.launch { getBooleanPreference(R.string.enable_playback_resume_key, true).collect { preference -> - _state.update { oldState -> + _switchState.update { oldState -> oldState.copy( resumePlaybackEnabled = preference ) @@ -79,7 +94,7 @@ class HistoryCacheSettingsViewModel @Inject constructor( R.string.enable_playback_state_lists_key, true ).collect { preference -> - _state.update { oldState -> + _switchState.update { oldState -> oldState.copy( positionsInListsEnabled = preference ) @@ -88,7 +103,7 @@ class HistoryCacheSettingsViewModel @Inject constructor( } viewModelScope.launch { getBooleanPreference(R.string.enable_search_history_key, true).collect { preference -> - _state.update { oldState -> + _switchState.update { oldState -> oldState.copy( searchHistoryEnabled = preference ) @@ -126,7 +141,7 @@ class HistoryCacheSettingsViewModel @Inject constructor( } }, onRemoveOrphanedRecords = { - // TODO: ask why original did nothing + // TODO: ask why original in android fragments did nothing } ) } @@ -181,7 +196,7 @@ class HistoryCacheSettingsViewModel @Inject constructor( updateStringPreference(event.key, "") DownloaderImpl.getInstance() .setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, "") - _eventFlow.emit(HistoryCacheUiEvent.ShowWipeCachedMetadataSnackbar) + _eventFlow.emit(ShowWipeCachedMetadataSnackbar) } } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt index 6f967085411..c525938141c 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/CachePreferences.kt @@ -24,6 +24,7 @@ import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium @Composable fun CachePreferencesComponent( + recaptchaCookiesEnabled: Boolean, onEvent: (HistoryCacheEvent) -> Unit, modifier: Modifier = Modifier, ) { @@ -55,7 +56,9 @@ fun CachePreferencesComponent( IrreversiblePreferenceComponent( title = stringResource(id = R.string.metadata_cache_wipe_title), summary = stringResource(id = R.string.metadata_cache_wipe_summary), - onClick = { onEvent(HistoryCacheEvent.OnClickWipeCachedMetadata(R.string.metadata_cache_wipe_key)) }, + onClick = { + onEvent(HistoryCacheEvent.OnClickWipeCachedMetadata(R.string.metadata_cache_wipe_key)) + }, modifier = Modifier.fillMaxWidth() ) IrreversiblePreferenceComponent( @@ -94,7 +97,10 @@ fun CachePreferencesComponent( IrreversiblePreferenceComponent( title = stringResource(id = R.string.clear_cookie_title), summary = stringResource(id = R.string.clear_cookie_summary), - onClick = { onEvent(HistoryCacheEvent.OnClickReCaptchaCookies(R.string.recaptcha_cookies_key)) }, + onClick = { + onEvent(HistoryCacheEvent.OnClickReCaptchaCookies(R.string.recaptcha_cookies_key)) + }, + enabled = recaptchaCookiesEnabled, modifier = Modifier.fillMaxWidth() ) if (isDialogVisible) { @@ -113,6 +119,7 @@ private fun CachePreferencesComponentPreview() { AppTheme { Scaffold { padding -> CachePreferencesComponent( + recaptchaCookiesEnabled = false, onEvent = {}, modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt index f1978bad4bd..c9ae14e413f 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/components/HistoryPreferences.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import org.schabi.newpipe.R import org.schabi.newpipe.settings.components.switch_preference.SwitchPreferenceComponent -import org.schabi.newpipe.settings.presentation.history_cache.SwitchPreferencesUiState +import org.schabi.newpipe.settings.presentation.history_cache.state.SwitchPreferencesUiState import org.schabi.newpipe.ui.theme.AppTheme @Composable diff --git a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/state/SwitchPreferencesUiState.kt similarity index 80% rename from app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt rename to app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/state/SwitchPreferencesUiState.kt index 77de7a45552..887aaf5acb9 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/SwitchPreferencesUiState.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/presentation/history_cache/state/SwitchPreferencesUiState.kt @@ -1,4 +1,4 @@ -package org.schabi.newpipe.settings.presentation.history_cache +package org.schabi.newpipe.settings.presentation.history_cache.state import androidx.compose.runtime.Stable @Stable diff --git a/app/src/main/res/xml/main_settings.xml b/app/src/main/res/xml/main_settings.xml index 5f96989f979..7920b7a0644 100644 --- a/app/src/main/res/xml/main_settings.xml +++ b/app/src/main/res/xml/main_settings.xml @@ -23,7 +23,7 @@ app:iconSpaceReserved="false" /> From 0530a6bd65b8d668eed1fd5c526137d54eed5479 Mon Sep 17 00:00:00 2001 From: brais Date: Sun, 1 Sep 2024 18:36:10 +0200 Subject: [PATCH 22/22] fix imports in some files --- .../java/org/schabi/newpipe/error/ReCaptchaActivity.java | 4 +--- .../schabi/newpipe/settings/DownloadSettingsFragment.java | 7 +------ .../schabi/newpipe/settings/SettingsResourceRegistry.java | 3 --- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java index 3c14cfe4cac..625932b914b 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java @@ -27,8 +27,6 @@ import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.util.ThemeHelper; -import java.io.UnsupportedEncodingException; - /* * Created by beneth on 06.12.16. * @@ -190,7 +188,7 @@ private void handleCookiesFromUrl(@Nullable final String url) { String abuseCookie = url.substring(abuseStart + 13, abuseEnd); abuseCookie = Utils.decodeUrlUtf8(abuseCookie); handleCookies(abuseCookie); - } catch (UnsupportedEncodingException | StringIndexOutOfBoundsException e) { + } catch (final StringIndexOutOfBoundsException e) { if (MainActivity.DEBUG) { e.printStackTrace(); Log.d(TAG, "handleCookiesFromUrl: invalid google abuse starting at " diff --git a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java index 472db6afe6f..0738b6f72f3 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java @@ -30,7 +30,6 @@ import java.io.File; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URI; public class DownloadSettingsFragment extends BasePreferenceFragment { @@ -123,11 +122,7 @@ private void showPathInSummary(final String prefKey, @StringRes final int defaul return; } - try { - rawUri = decodeUrlUtf8(rawUri); - } catch (final UnsupportedEncodingException e) { - // nothing to do - } + rawUri = decodeUrlUtf8(rawUri); target.setSummary(rawUri); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java index 06e0a7c1eae..b41ad904b07 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsResourceRegistry.java @@ -3,9 +3,7 @@ import androidx.annotation.NonNull; import androidx.annotation.XmlRes; import androidx.fragment.app.Fragment; - import org.schabi.newpipe.R; - import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -35,7 +33,6 @@ private SettingsResourceRegistry() { add(ContentSettingsFragment.class, R.xml.content_settings); add(DebugSettingsFragment.class, R.xml.debug_settings).setSearchable(false); add(DownloadSettingsFragment.class, R.xml.download_settings); - add(HistorySettingsFragment.class, R.xml.history_settings); add(NotificationSettingsFragment.class, R.xml.notifications_settings); add(PlayerNotificationSettingsFragment.class, R.xml.player_notification_settings); add(UpdateSettingsFragment.class, R.xml.update_settings);