From b822c5a039e2e478cab6661aa0c790c473125ad3 Mon Sep 17 00:00:00 2001
From: opusforlife2 <53176348+opusforlife2@users.noreply.github.com>
Date: Wed, 11 Nov 2020 15:20:42 +0000
Subject: [PATCH 01/52] Update Invidious URL list in the manifest
---
app/src/main/AndroidManifest.xml | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6fd62aebe84..35e987cb853 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -227,20 +227,18 @@
+
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
From f7f00293cc5a7b37c10c29bb80e483a8091bc766 Mon Sep 17 00:00:00 2001
From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com>
Date: Tue, 1 Dec 2020 20:12:42 +0100
Subject: [PATCH 02/52] Extract export database logic into own class
- Separate it from the UI.
- Add happy path unit test.
---
.../settings/ContentSettingsFragment.java | 33 +++------
.../settings/ContentSettingsManager.kt | 45 ++++++++++++
.../settings/ContentSettingsManagerTest.kt | 72 +++++++++++++++++++
app/src/test/resources/settings/newpipe.db | 1 +
.../test/resources/settings/newpipe.settings | 0
checkstyle-suppressions.xml | 2 +-
6 files changed, 127 insertions(+), 26 deletions(-)
create mode 100644 app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
create mode 100644 app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
create mode 100644 app/src/test/resources/settings/newpipe.db
create mode 100644 app/src/test/resources/settings/newpipe.settings
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
index b0425ebfaba..6ef2f732e9d 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
@@ -30,19 +30,15 @@
import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.ZipHelper;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@@ -50,6 +46,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
private static final int REQUEST_IMPORT_PATH = 8945;
private static final int REQUEST_EXPORT_PATH = 30945;
+ private ContentSettingsManager manager;
+
private File databasesDir;
private File newpipeDb;
private File newpipeDbJournal;
@@ -131,6 +129,8 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro
newpipeSettings = new File(homeDir + "/databases/newpipe.settings");
newpipeSettings.delete();
+ manager = new ContentSettingsManager(homeDir);
+
addPreferencesFromResource(R.xml.content_settings);
final Preference importDataPreference = findPreference(getString(R.string.import_data));
@@ -212,33 +212,16 @@ private void exportDatabase(final String path) {
//checkpoint before export
NewPipeDatabase.checkpoint();
- try (ZipOutputStream outZip = new ZipOutputStream(new BufferedOutputStream(
- new FileOutputStream(path)))) {
- ZipHelper.addFileToZip(outZip, newpipeDb.getPath(), "newpipe.db");
+ final SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(requireContext());
+ manager.exportDatabase(preferences, path);
- saveSharedPreferencesToFile(newpipeSettings);
- ZipHelper.addFileToZip(outZip, newpipeSettings.getPath(),
- "newpipe.settings");
- }
-
- Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT).show();
} catch (final Exception e) {
onError(e);
}
}
- private void saveSharedPreferencesToFile(final File dst) {
- try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(dst))) {
- final SharedPreferences pref
- = PreferenceManager.getDefaultSharedPreferences(requireContext());
- output.writeObject(pref.getAll());
- output.flush();
- } catch (final IOException e) {
- e.printStackTrace();
- }
- }
-
private void importDatabase(final String filePath) {
// check if file is supported
try (ZipFile zipFile = new ZipFile(filePath)) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
new file mode 100644
index 00000000000..b0ea89993f5
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
@@ -0,0 +1,45 @@
+package org.schabi.newpipe.settings
+
+import android.content.SharedPreferences
+import org.schabi.newpipe.util.ZipHelper
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.ObjectOutputStream
+import java.lang.Exception
+import java.util.zip.ZipOutputStream
+
+class ContentSettingsManager(
+ private val newpipeDb: File,
+ private val newpipeSettings: File
+) {
+
+ constructor(homeDir: String) : this(
+ File("$homeDir/databases/newpipe.db"),
+ File("$homeDir/databases/newpipe.settings")
+ )
+
+ /**
+ * Exports given [SharedPreferences] to the file in given outputPath.
+ * It also creates the file.
+ */
+ @Throws(Exception::class)
+ fun exportDatabase(preferences: SharedPreferences, outputPath: String) {
+ ZipOutputStream(BufferedOutputStream(FileOutputStream(outputPath)))
+ .use { outZip ->
+ ZipHelper.addFileToZip(outZip, newpipeDb.path, "newpipe.db")
+
+ try {
+ ObjectOutputStream(FileOutputStream(newpipeSettings)).use { output ->
+ output.writeObject(preferences.all)
+ output.flush()
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+
+ ZipHelper.addFileToZip(outZip, newpipeSettings.path, "newpipe.settings")
+ }
+ }
+}
diff --git a/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt b/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
new file mode 100644
index 00000000000..9809fd5fc80
--- /dev/null
+++ b/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
@@ -0,0 +1,72 @@
+package org.schabi.newpipe.settings
+
+import android.content.SharedPreferences
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Suite
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnitRunner
+import org.schabi.newpipe.settings.ContentSettingsManagerTest.ExportTest
+import java.io.File
+import java.io.ObjectInputStream
+import java.util.zip.ZipFile
+
+@RunWith(Suite::class)
+@Suite.SuiteClasses(ExportTest::class)
+class ContentSettingsManagerTest {
+
+ @RunWith(MockitoJUnitRunner::class)
+ class ExportTest {
+
+ private lateinit var preferences: SharedPreferences
+ private lateinit var newpipeDb: File
+ private lateinit var newpipeSettings: File
+
+ @Before
+ fun beforeClass() {
+
+ val dbPath = javaClass.classLoader?.getResource("settings/newpipe.db")?.file
+ val settingsPath = javaClass.classLoader?.getResource("settings/newpipe.settings")?.path
+ Assume.assumeNotNull(dbPath)
+ Assume.assumeNotNull(settingsPath)
+
+ newpipeDb = File(dbPath!!)
+ newpipeSettings = File(settingsPath!!)
+ }
+
+ @Before
+ fun before() {
+ preferences = Mockito.mock(SharedPreferences::class.java, Mockito.withSettings().stubOnly())
+ }
+
+ @Test
+ fun `The settings must be exported successfully in the correct format`() {
+ val expectedPreferences = mapOf("such pref" to "much wow")
+ `when`(preferences.all).thenReturn(expectedPreferences)
+
+ val manager = ContentSettingsManager(newpipeDb, newpipeSettings)
+
+ val output = File.createTempFile("newpipe_", "")
+ manager.exportDatabase(preferences, output.absolutePath)
+
+ val zipFile = ZipFile(output.absoluteFile)
+ val entries = zipFile.entries().toList()
+ Assert.assertEquals(2, entries.size)
+
+ zipFile.getInputStream(entries.first { it.name == "newpipe.db" }).use { actual ->
+ newpipeDb.inputStream().use { expected ->
+ Assert.assertEquals(expected.reader().readText(), actual.reader().readText())
+ }
+ }
+
+ zipFile.getInputStream(entries.first { it.name == "newpipe.settings" }).use { actual ->
+ val actualPreferences = ObjectInputStream(actual).readObject()
+ Assert.assertEquals(expectedPreferences, actualPreferences)
+ }
+ }
+ }
+}
diff --git a/app/src/test/resources/settings/newpipe.db b/app/src/test/resources/settings/newpipe.db
new file mode 100644
index 00000000000..cd3fc471737
--- /dev/null
+++ b/app/src/test/resources/settings/newpipe.db
@@ -0,0 +1 @@
+such db much wow
\ No newline at end of file
diff --git a/app/src/test/resources/settings/newpipe.settings b/app/src/test/resources/settings/newpipe.settings
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index add17d42dbb..0a5190b295d 100644
--- a/checkstyle-suppressions.xml
+++ b/checkstyle-suppressions.xml
@@ -17,7 +17,7 @@
+ lines="227,245"/>
Date: Sun, 6 Dec 2020 23:40:38 +0100
Subject: [PATCH 03/52] [FIX] - Crash while deleting a video from a playlist
while refreshing
---
.../database/playlist/PlaylistStreamEntry.kt | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
index d9c892099aa..28ce176f094 100644
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
@@ -7,7 +7,6 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem
-import kotlin.jvm.Throws
class PlaylistStreamEntry(
@Embedded
@@ -36,4 +35,20 @@ class PlaylistStreamEntry(
override fun getLocalItemType(): LocalItem.LocalItemType {
return LocalItem.LocalItemType.PLAYLIST_STREAM_ITEM
}
+
+ override fun equals(other: Any?): Boolean {
+ if (other == null || other !is PlaylistStreamEntry || streamEntity != other.streamEntity ||
+ progressTime != other.progressTime || streamId != other.streamId || joinIndex != other.joinIndex
+ ) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = streamEntity.hashCode()
+ result = 31 * result + progressTime.hashCode()
+ result = 31 * result + streamId.hashCode()
+ result = 31 * result + joinIndex
+ return result
+ }
}
From 5f3eb4871a69aeb6d5502fc48a66d6b2d45a56d5 Mon Sep 17 00:00:00 2001
From: hlloreda
Date: Mon, 7 Dec 2020 00:06:56 +0100
Subject: [PATCH 04/52] [IMPORT] - import got deleted
---
.../org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
index 28ce176f094..af741fdc853 100644
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
@@ -7,6 +7,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem
+import kotlin.jvm.Throws
class PlaylistStreamEntry(
@Embedded
From b30e025bdac1167466d497a112d3510a2f575120 Mon Sep 17 00:00:00 2001
From: hlloreda
Date: Mon, 7 Dec 2020 10:53:33 +0100
Subject: [PATCH 05/52] [FIX] - Use of a Data class instead of overriding
equals method
---
.../database/playlist/PlaylistStreamEntry.kt | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
index af741fdc853..aff6205f27e 100644
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
@@ -9,7 +9,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem
import kotlin.jvm.Throws
-class PlaylistStreamEntry(
+data class PlaylistStreamEntry(
@Embedded
val streamEntity: StreamEntity,
@@ -36,20 +36,4 @@ class PlaylistStreamEntry(
override fun getLocalItemType(): LocalItem.LocalItemType {
return LocalItem.LocalItemType.PLAYLIST_STREAM_ITEM
}
-
- override fun equals(other: Any?): Boolean {
- if (other == null || other !is PlaylistStreamEntry || streamEntity != other.streamEntity ||
- progressTime != other.progressTime || streamId != other.streamId || joinIndex != other.joinIndex
- ) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = streamEntity.hashCode()
- result = 31 * result + progressTime.hashCode()
- result = 31 * result + streamId.hashCode()
- result = 31 * result + joinIndex
- return result
- }
}
From ac86fe80c85bae126d956484d9e27e9d8c2919ee Mon Sep 17 00:00:00 2001
From: mhmdanas <32234660+mhmdanas@users.noreply.github.com>
Date: Sun, 6 Dec 2020 18:28:46 +0300
Subject: [PATCH 06/52] Fix typos
---
app/src/main/java/org/schabi/newpipe/MainActivity.java | 6 +++---
.../java/org/schabi/newpipe/streams/Mp4FromDashWriter.java | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index f51ecf2d370..4a8582df2b1 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -369,8 +369,8 @@ private void showServices() {
}
private void enhancePeertubeMenu(final StreamingService s, final MenuItem menuItem) {
- final PeertubeInstance currentInstace = PeertubeHelper.getCurrentInstance();
- menuItem.setTitle(currentInstace.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""));
+ final PeertubeInstance currentInstance = PeertubeHelper.getCurrentInstance();
+ menuItem.setTitle(currentInstance.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""));
final Spinner spinner = (Spinner) LayoutInflater.from(this)
.inflate(R.layout.instance_spinner_layout, null);
final List instances = PeertubeHelper.getInstanceList(this);
@@ -378,7 +378,7 @@ private void enhancePeertubeMenu(final StreamingService s, final MenuItem menuIt
int defaultSelect = 0;
for (final PeertubeInstance instance : instances) {
items.add(instance.getName());
- if (instance.getUrl().equals(currentInstace.getUrl())) {
+ if (instance.getUrl().equals(currentInstance.getUrl())) {
defaultSelect = items.size() - 1;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java
index 5efffe118bc..ca3da9d2449 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java
@@ -483,7 +483,7 @@ private void initChunkTables(final TablesInfo tables, final int firstCount,
// stsc_table_entry = [first_chunk, samples_per_chunk, sample_description_index]
tables.stscBEntries = new int[tables.stsc * 3];
- tables.stco = remainChunkOffset + 1; // total entrys in chunk offset box
+ tables.stco = remainChunkOffset + 1; // total entries in chunk offset box
tables.stscBEntries[index++] = 1;
tables.stscBEntries[index++] = firstCount;
From a00ac6b9ca53d69180ce419728cd3e7864f5c76a Mon Sep 17 00:00:00 2001
From: FireMasterK <20838718+FireMasterK@users.noreply.github.com>
Date: Wed, 9 Dec 2020 12:25:57 +0530
Subject: [PATCH 07/52] Migrate to GitHub actions from Travis.
---
.github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++++
.travis.yml | 18 ------------------
2 files changed, 30 insertions(+), 18 deletions(-)
create mode 100644 .github/workflows/ci.yml
delete mode 100644 .travis.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000000..6419c65dd52
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,30 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ build-and-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: set up JDK 1.8
+ uses: actions/setup-java@v1.4.3
+ with:
+ java-version: 1.8
+
+ - name: Cache Gradle dependencies
+ uses: actions/cache@v2
+ with:
+ path: ~/.gradle/caches
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
+ restore-keys: ${{ runner.os }}-gradle
+
+ - name: Build debug APK and run Tests
+ run: ./gradlew assembleDebug lintDebug testDebugUnitTest --stacktrace
+
+ - name: Upload APK
+ uses: actions/upload-artifact@v2
+ with:
+ name: app
+ path: app/build/outputs/apk/debug/*.apk
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1714c70d563..00000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: android
-jdk:
- - oraclejdk8
-android:
- components:
- # The BuildTools version used by NewPipe
- - tools
- - build-tools-29.0.3
-
- # The SDK version used to compile NewPipe
- - android-29
-
-before_install:
- - yes | sdkmanager "platforms;android-29"
-script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest
-
-licenses:
- - '.+'
From 69ed531a5c804a929b2a802b5ed9e9efa34144c6 Mon Sep 17 00:00:00 2001
From: Stefan Br
Date: Thu, 10 Dec 2020 18:54:31 +0000
Subject: [PATCH 08/52] Translated using Weblate (German)
Currently translated at 100.0% (609 of 609 strings)
---
app/src/main/res/values-de/strings.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 6effa7615d2..121f74ee126 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -105,7 +105,7 @@
Nicht unterstützter ServerKonnte Bild nicht ladenApp/UI abgestürzt
- Threads
+ ThemenNewPipe lädt herunterFür Details antippenUngültige URL oder Internet nicht verfügbar
@@ -317,7 +317,7 @@
\nMöchtest du fortfahren\?
Vorschaubilder ladenBilder-Cache gelöscht
- Zwischengespeicherte Metadaten löschen
+ Zwischengespeicherte (Metadaten) löschenAlle zwischengespeicherten Website-Daten entfernenMetadatencache gelöschtDebug
@@ -636,7 +636,7 @@
Automatische WarteschlangeDen Player zu wechseln könnte deine Warteschlange überschreibenBestätige das Leeren der Warteschlange
- Die aktive Wiedergabeliste wird ersetzt werden
+ Die aktive Player-Warteschlange wird ersetztEingereihtYouTube bietet einen „Eingeschränkten Modus“, der potenzielle Inhalte für Erwachsene ausblendetSpeicherlecks anzeigen
@@ -644,7 +644,7 @@
reCAPTCHA-Cookies wurden gelöschtreCAPTCHA-Cookies löschenZeige altersbeschränkte Inhalte (bspw. 18+), welche möglicherweise unpassend für Kinder sein könnten
- Wiedergabe einreihen
+ In Wiedergabe einreihenAndroid kann die Farbe der Benachrichtigung entsprechend der Hauptfarbe in der Miniaturansicht anpassen (beachte, dass dies nicht auf allen Geräten verfügbar ist)Benachrichtigung farblich anpassenVorschaubild auf dem Sperrbildschirm als Hintergrund und innerhalb von Benachrichtigungen anzeigen
From 5c2d4c4d9df672030fb2a56175463b256df8b720 Mon Sep 17 00:00:00 2001
From: Terry Louwers
Date: Thu, 10 Dec 2020 06:16:38 +0000
Subject: [PATCH 09/52] Translated using Weblate (Dutch)
Currently translated at 100.0% (609 of 609 strings)
---
app/src/main/res/values-nl/strings.xml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 0217368da30..e120750fc75 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -264,8 +264,8 @@
Bezig met laden van gevraagde inhoudDatabank importerenDatabank exporteren
- Dit overschrijft je huidige geschiedenis en abonnementen
- Exporteer geschiedenis, abonnementen en afspeellijsten
+ Dit overschrijft je huidige geschiedenis, abonnementen, afspeellijsten en (optionele) settings
+ Exporteer geschiedenis, abonnementen, afspeellijsten en settingsGeëxporteerdGeïmporteerdGeen geldig ZIP-bestand
@@ -647,4 +647,6 @@
Toon inhoud die mogelijk niet geschikt is voor kinderen omwille van een leeftijdslimiet (zoals 18+)Laat Android de kleur van de notificatie aanpassen, op basis van de meest voorkomende kleur in de thumbnail (let op: niet beschikbaar op elk apparaat)Notificatie kleur aanpassen
+ Toon miniatuurafbeelding op het vergrendelscherm als achtergrond en binnen meldingen
+ Toon miniatuurafbeelding
\ No newline at end of file
From 917f4595690f2ccd67cc8395caa41ca02ff4ea4e Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Fri, 11 Dec 2020 07:29:24 +0530
Subject: [PATCH 10/52] Use a notification instead of a ProgressDialog in
MissionAdapter.
---
app/src/main/java/org/schabi/newpipe/App.java | 15 ++++++--
.../giga/ui/adapter/MissionAdapter.java | 37 ++++++++++---------
app/src/main/res/values/strings.xml | 4 ++
3 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java
index de401d4f5d9..e6dce4d6763 100644
--- a/app/src/main/java/org/schabi/newpipe/App.java
+++ b/app/src/main/java/org/schabi/newpipe/App.java
@@ -242,8 +242,9 @@ private void initNotificationChannels() {
String name = getString(R.string.notification_channel_name);
String description = getString(R.string.notification_channel_description);
- // Keep this below DEFAULT to avoid making noise on every notification update
- final int importance = NotificationManager.IMPORTANCE_LOW;
+ // Keep this below DEFAULT to avoid making noise on every notification update for the main
+ // and update channels
+ int importance = NotificationManager.IMPORTANCE_LOW;
final NotificationChannel mainChannel = new NotificationChannel(id, name, importance);
mainChannel.setDescription(description);
@@ -255,9 +256,17 @@ private void initNotificationChannels() {
final NotificationChannel appUpdateChannel = new NotificationChannel(id, name, importance);
appUpdateChannel.setDescription(description);
+ id = getString(R.string.hash_channel_id);
+ name = getString(R.string.hash_channel_name);
+ description = getString(R.string.hash_channel_description);
+ importance = NotificationManager.IMPORTANCE_HIGH;
+
+ final NotificationChannel hashChannel = new NotificationChannel(id, name, importance);
+ hashChannel.setDescription(description);
+
final NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannels(Arrays.asList(mainChannel,
- appUpdateChannel));
+ appUpdateChannel, hashChannel));
}
protected boolean isDisposedRxExceptionsReported() {
diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
index be7d78299cb..f102206c132 100644
--- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
+++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
@@ -1,7 +1,7 @@
package us.shandian.giga.ui.adapter;
import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
@@ -26,6 +26,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.DiffUtil;
@@ -91,6 +93,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb
private static final String DEFAULT_MIME_TYPE = "*/*";
private static final String UNDEFINED_ETA = "--:--";
+ private static final int HASH_NOTIFICATION_ID = 123790;
static {
ALGORITHMS.put(R.id.md5, "MD5");
@@ -678,28 +681,28 @@ private boolean handlePopupItem(@NonNull ViewHolderItem h, @NonNull MenuItem opt
return true;
case R.id.md5:
case R.id.sha1:
- ProgressDialog progressDialog = null;
- if (mContext != null) {
- // Create dialog
- progressDialog = new ProgressDialog(mContext);
- progressDialog.setCancelable(false);
- progressDialog.setMessage(mContext.getString(R.string.msg_wait));
- progressDialog.show();
- }
- final ProgressDialog finalProgressDialog = progressDialog;
+ final NotificationManager notificationManager
+ = ContextCompat.getSystemService(mContext, NotificationManager.class);
+ final NotificationCompat.Builder progressNotificationBuilder
+ = new NotificationCompat.Builder(mContext,
+ mContext.getString(R.string.hash_channel_id))
+ .setPriority(NotificationCompat.PRIORITY_HIGH)
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setContentTitle(mContext.getString(R.string.msg_calculating_hash))
+ .setContentText(mContext.getString(R.string.msg_wait))
+ .setProgress(0, 0, true)
+ .setOngoing(true);
+
+ notificationManager.notify(HASH_NOTIFICATION_ID, progressNotificationBuilder
+ .build());
final StoredFileHelper storage = h.item.mission.storage;
compositeDisposable.add(
Observable.fromCallable(() -> Utility.checksum(storage, ALGORITHMS.get(id)))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- if (finalProgressDialog != null) {
- Utility.copyToClipboard(finalProgressDialog.getContext(),
- result);
- if (mContext != null) {
- finalProgressDialog.dismiss();
- }
- }
+ Utility.copyToClipboard(mContext, result);
+ notificationManager.cancel(HASH_NOTIFICATION_ID);
})
);
return true;
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f96518ccf14..bc70e793bce 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -195,6 +195,9 @@
newpipeAppUpdateApp Update NotificationNotifications for new NewPipe version
+ newpipeHash
+ Video Hash Notification
+ Notifications for video hashing progress[Unknown]Toggle OrientationSwitch to Background
@@ -347,6 +350,7 @@
Malformed URL or Internet not availableNewPipe DownloadingTap for details
+ Calculating hashPlease wait…Copied to clipboardPlease define a download folder later in settings
From c2210330b6d70f08b194065accaef2a067b639fb Mon Sep 17 00:00:00 2001
From: Stypox
Date: Tue, 17 Mar 2020 18:41:39 +0100
Subject: [PATCH 11/52] Show radio instead of Youtube logo in mixes
YouTube mixes have YouTube as a creator, though YouTube's logo is not safe to use as it is a trademark (better safe than sorry)
---
app/build.gradle | 2 +-
.../list/playlist/PlaylistFragment.java | 29 +++++++++++++++----
.../ktx/OffsetDateTimeToCalendarTest.kt | 3 +-
3 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 87215b38523..5a8689f70e7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -175,7 +175,7 @@ dependencies {
// NewPipe dependencies
// You can use a local version by uncommenting a few lines in settings.gradle
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:b3835bd616ab28b861c83dcefd56e1754c6d20be'
+ implementation 'com.github.TeamNewPipe:NewPipeExtractor:85fa006214b003f21eacb76c445a167732f19981'
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "org.jsoup:jsoup:1.13.1"
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
index d1a964fb2b5..6fa7eb700b9 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
@@ -11,12 +11,12 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.content.res.AppCompatResources;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
@@ -26,8 +26,10 @@
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
+import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
@@ -44,13 +46,13 @@
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.StreamDialogEntry;
-import org.schabi.newpipe.util.ThemeHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import de.hdodenhof.circleimageview.CircleImageView;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
@@ -58,6 +60,7 @@
import io.reactivex.rxjava3.disposables.Disposable;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
+import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
public class PlaylistFragment extends BaseListInfoFragment {
private CompositeDisposable disposables;
@@ -74,7 +77,7 @@ public class PlaylistFragment extends BaseListInfoFragment {
private TextView headerTitleView;
private View headerUploaderLayout;
private TextView headerUploaderName;
- private ImageView headerUploaderAvatar;
+ private CircleImageView headerUploaderAvatar;
private TextView headerStreamCount;
private View playlistCtrl;
@@ -301,8 +304,22 @@ public void handleResult(@NonNull final PlaylistInfo result) {
playlistCtrl.setVisibility(View.VISIBLE);
- IMAGE_LOADER.displayImage(result.getUploaderAvatarUrl(), headerUploaderAvatar,
- ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
+ final String avatarUrl = result.getUploaderAvatarUrl();
+ if (result.getServiceId() == ServiceList.YouTube.getServiceId()
+ && (YoutubeParsingHelper.isYoutubeMixId(result.getId())
+ || YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) {
+ // this is an auto-generated playlist (e.g. Youtube mix), so a radio is shown
+ headerUploaderAvatar.setDisableCircularTransformation(true);
+ headerUploaderAvatar.setBorderColor(
+ getResources().getColor(R.color.transparent_background_color));
+ headerUploaderAvatar.setImageDrawable(AppCompatResources.getDrawable(requireContext(),
+ resolveResourceIdFromAttr(requireContext(), R.attr.ic_radio)));
+
+ } else {
+ IMAGE_LOADER.displayImage(avatarUrl, headerUploaderAvatar,
+ ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
+ }
+
headerStreamCount.setText(Localization
.localizeStreamCount(getContext(), result.getStreamCount()));
@@ -476,7 +493,7 @@ private void updateBookmarkButtons() {
final int titleRes = playlistEntity == null
? R.string.bookmark_playlist : R.string.unbookmark_playlist;
- playlistBookmarkButton.setIcon(ThemeHelper.resolveResourceIdFromAttr(activity, iconAttr));
+ playlistBookmarkButton.setIcon(resolveResourceIdFromAttr(activity, iconAttr));
playlistBookmarkButton.setTitle(titleRes);
}
}
diff --git a/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt b/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
index c93d36eb597..74da0799883 100644
--- a/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
+++ b/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
@@ -4,7 +4,6 @@ import org.junit.Assert.assertEquals
import org.junit.Test
import java.time.LocalDate
import java.time.OffsetDateTime
-import java.time.ZoneId
import java.time.ZoneOffset
import java.util.Calendar
import java.util.TimeZone
@@ -13,7 +12,7 @@ class OffsetDateTimeToCalendarTest {
@Test
fun testRelativeTimeWithCurrentOffsetDateTime() {
val calendar = LocalDate.of(2020, 1, 1).atStartOfDay().atOffset(ZoneOffset.UTC)
- .toCalendar()
+ .toCalendar()
assertEquals(2020, calendar[Calendar.YEAR])
assertEquals(0, calendar[Calendar.MONTH])
From 30613b7064d3988e181b6e601269dc1cfd9e827a Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Tue, 15 Dec 2020 08:02:25 +0530
Subject: [PATCH 12/52] Use ContextCompat.getDataDir().
---
.../settings/ContentSettingsFragment.java | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
index b0425ebfaba..1ef52cd8240 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java
@@ -11,6 +11,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
@@ -120,15 +121,14 @@ public boolean onPreferenceTreeClick(final Preference preference) {
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
-
- final String homeDir = getActivity().getApplicationInfo().dataDir;
- databasesDir = new File(homeDir + "/databases");
- newpipeDb = new File(homeDir + "/databases/newpipe.db");
- newpipeDbJournal = new File(homeDir + "/databases/newpipe.db-journal");
- newpipeDbShm = new File(homeDir + "/databases/newpipe.db-shm");
- newpipeDbWal = new File(homeDir + "/databases/newpipe.db-wal");
-
- newpipeSettings = new File(homeDir + "/databases/newpipe.settings");
+ final File homeDir = ContextCompat.getDataDir(requireContext());
+ databasesDir = new File(homeDir, "/databases");
+ newpipeDb = new File(homeDir, "/databases/newpipe.db");
+ newpipeDbJournal = new File(homeDir, "/databases/newpipe.db-journal");
+ newpipeDbShm = new File(homeDir, "/databases/newpipe.db-shm");
+ newpipeDbWal = new File(homeDir, "/databases/newpipe.db-wal");
+
+ newpipeSettings = new File(homeDir, "/databases/newpipe.settings");
newpipeSettings.delete();
addPreferencesFromResource(R.xml.content_settings);
From 807e4d4af9122a30e5c83e37ce04452c3c88c23b Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Tue, 15 Dec 2020 11:51:26 +0530
Subject: [PATCH 13/52] Use ActivityCompat.recreate().
---
app/src/main/java/org/schabi/newpipe/MainActivity.java | 8 +++-----
.../org/schabi/newpipe/player/ServicePlayerActivity.java | 3 ++-
.../newpipe/settings/AppearanceSettingsFragment.java | 3 ++-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index 4a8582df2b1..a5c963ee645 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -50,6 +50,7 @@
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
@@ -218,7 +219,7 @@ public void onDrawerClosed(final View drawerView) {
toggleServices();
}
if (lastService != ServiceHelper.getSelectedServiceId(MainActivity.this)) {
- new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
+ ActivityCompat.recreate(MainActivity.this);
}
}
});
@@ -497,10 +498,7 @@ protected void onResume() {
Log.d(TAG, "Theme has changed, recreating activity...");
}
sharedPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, false).apply();
- // https://stackoverflow.com/questions/10844112/
- // Briefly, let the activity resume
- // properly posting the recreate call to end of the message queue
- new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
+ ActivityCompat.recreate(this);
}
if (sharedPreferences.getBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false)) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index d1c2be014eb..4bf6ef9ae7b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -20,6 +20,7 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -140,7 +141,7 @@ protected void onCreate(final Bundle savedInstanceState) {
protected void onResume() {
super.onResume();
if (redraw) {
- recreate();
+ ActivityCompat.recreate(this);
redraw = false;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
index ab875ed5d32..8126bd2c56b 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
@@ -8,6 +8,7 @@
import android.widget.Toast;
import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import org.schabi.newpipe.R;
@@ -31,7 +32,7 @@ public boolean onPreferenceChange(final Preference preference, final Object newV
if (!newValue.equals(startThemeKey) && getActivity() != null) {
// If it's not the current theme
- getActivity().recreate();
+ ActivityCompat.recreate(requireActivity());
}
return false;
From 99b59f012676e85eff88338cbd7fbb4e4f2c70b9 Mon Sep 17 00:00:00 2001
From: TiA4f8R <74829229+TiA4f8R@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:57:36 +0100
Subject: [PATCH 14/52] Update NewPipe's API url for new app's version check
---
app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java
index 916630ae6e4..0fecc3f96d3 100644
--- a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java
+++ b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java
@@ -48,7 +48,7 @@ private CheckForNewAppVersion() { }
private static final String GITHUB_APK_SHA1
= "B0:2E:90:7C:1C:D6:FC:57:C3:35:F0:88:D0:8F:50:5F:94:E4:D2:15";
- private static final String NEWPIPE_API_URL = "https://newpipe.schabi.org/api/data.json";
+ private static final String NEWPIPE_API_URL = "https://newpipe.net/api/data.json";
/**
* Method to get the APK's SHA1 key. See https://stackoverflow.com/questions/9293019/#22506133.
From 5397a4e410e340fc52a6ebf452338ab074bc3cd7 Mon Sep 17 00:00:00 2001
From: TiA4f8R <74829229+TiA4f8R@users.noreply.github.com>
Date: Tue, 15 Dec 2020 19:01:33 +0100
Subject: [PATCH 15/52] Update NewPipe website URL strings
---
app/src/main/res/values/strings.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bc70e793bce..ecb690044aa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -391,14 +391,14 @@
View on GitHubDonateNewPipe is developed by volunteers spending their free time bringing you the best user experience. Give back to help developers make NewPipe even better while they enjoy a cup of coffee.
- https://newpipe.schabi.org/donate
+ https://newpipe.net/donateGive backWebsiteVisit the NewPipe Website for more info and news.
- https://newpipe.schabi.org/
+ https://newpipe.net/NewPipe\'s Privacy PolicyThe NewPipe project takes your privacy very seriously. Therefore, the app does not collect any data without your consent.\nNewPipe\'s privacy policy explains in detail what data is sent and stored when you send a crash report.
- https://newpipe.schabi.org/legal/privacy/
+ https://newpipe.net/legal/privacy/Read privacy policyNewPipe\'s LicenseNewPipe is copyleft libre software: You can use, study share and improve it at will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
From a7723373a0fc846323e34556c40688055e9f9a02 Mon Sep 17 00:00:00 2001
From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com>
Date: Tue, 15 Dec 2020 20:18:25 +0100
Subject: [PATCH 16/52] Fix compile error caused by auto merging
#5176 changed `homeDir` from type `String` to `File`. #5059 was based on `homeDir` being a `String`. It was incorrectly auto-resolved by git.
---
.../org/schabi/newpipe/settings/ContentSettingsManager.kt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
index b0ea89993f5..2682ac5e0a6 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
+++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsManager.kt
@@ -15,9 +15,9 @@ class ContentSettingsManager(
private val newpipeSettings: File
) {
- constructor(homeDir: String) : this(
- File("$homeDir/databases/newpipe.db"),
- File("$homeDir/databases/newpipe.settings")
+ constructor(homeDir: File) : this(
+ File(homeDir, "databases/newpipe.db"),
+ File(homeDir, "databases/newpipe.settings")
)
/**
From e0ee3dce40cb01567f2ebfb69dc1a134cd92d142 Mon Sep 17 00:00:00 2001
From: XiangRongLin <41164160+XiangRongLin@users.noreply.github.com>
Date: Thu, 17 Dec 2020 09:40:04 +0100
Subject: [PATCH 17/52] Use @BeforeClass for
ContentSettingsManagerTest.beforeClass
---
.../settings/ContentSettingsManagerTest.kt | 30 +++++++++++--------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt b/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
index 9809fd5fc80..5ac132f7fd4 100644
--- a/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
+++ b/app/src/test/java/org/schabi/newpipe/settings/ContentSettingsManagerTest.kt
@@ -4,6 +4,7 @@ import android.content.SharedPreferences
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
+import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Suite
@@ -22,24 +23,27 @@ class ContentSettingsManagerTest {
@RunWith(MockitoJUnitRunner::class)
class ExportTest {
- private lateinit var preferences: SharedPreferences
- private lateinit var newpipeDb: File
- private lateinit var newpipeSettings: File
-
- @Before
- fun beforeClass() {
+ companion object {
+ private lateinit var newpipeDb: File
+ private lateinit var newpipeSettings: File
- val dbPath = javaClass.classLoader?.getResource("settings/newpipe.db")?.file
- val settingsPath = javaClass.classLoader?.getResource("settings/newpipe.settings")?.path
- Assume.assumeNotNull(dbPath)
- Assume.assumeNotNull(settingsPath)
+ @JvmStatic
+ @BeforeClass
+ fun setupFiles() {
+ val dbPath = ExportTest::class.java.classLoader?.getResource("settings/newpipe.db")?.file
+ val settingsPath = ExportTest::class.java.classLoader?.getResource("settings/newpipe.settings")?.path
+ Assume.assumeNotNull(dbPath)
+ Assume.assumeNotNull(settingsPath)
- newpipeDb = File(dbPath!!)
- newpipeSettings = File(settingsPath!!)
+ newpipeDb = File(dbPath!!)
+ newpipeSettings = File(settingsPath!!)
+ }
}
+ private lateinit var preferences: SharedPreferences
+
@Before
- fun before() {
+ fun setupMocks() {
preferences = Mockito.mock(SharedPreferences::class.java, Mockito.withSettings().stubOnly())
}
From 10f79e13070b6e858b92a0bcfd55b32240e13197 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Thu, 17 Dec 2020 16:32:03 +0100
Subject: [PATCH 18/52] Remove pbj=1 parameter from YouYube urls in recaptcha
activity
---
.../org/schabi/newpipe/ReCaptchaActivity.java | 17 +++++++-----
.../schabi/newpipe/ReCaptchaActivityTest.kt | 27 +++++++++++++++++++
.../ktx/OffsetDateTimeToCalendarTest.kt | 3 +--
3 files changed, 39 insertions(+), 8 deletions(-)
create mode 100644 app/src/test/java/org/schabi/newpipe/ReCaptchaActivityTest.kt
diff --git a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
index c962ed99dc4..03c9ae4af52 100644
--- a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
@@ -53,6 +53,16 @@ public class ReCaptchaActivity extends AppCompatActivity {
public static final String YT_URL = "https://www.youtube.com";
public static final String RECAPTCHA_COOKIES_KEY = "recaptcha_cookies";
+ public static String sanitizeRecaptchaUrl(@Nullable final String url) {
+ if (url == null || url.trim().isEmpty()) {
+ return YT_URL; // YouTube is the most likely service to have thrown a recaptcha
+ } else {
+ // remove "pbj=1" parameter from YouYube urls, as it makes the page JSON and not HTML
+ return url.replace("&pbj=1", "").replace("pbj=1&", "").replace("?pbj=1", "");
+ }
+ }
+
+
private WebView webView;
private String foundCookies = "";
@@ -64,15 +74,10 @@ protected void onCreate(final Bundle savedInstanceState) {
final Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
- String url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
- if (url == null || url.isEmpty()) {
- url = YT_URL;
- }
-
+ final String url = sanitizeRecaptchaUrl(getIntent().getStringExtra(RECAPTCHA_URL_EXTRA));
// set return to Cancel by default
setResult(RESULT_CANCELED);
-
webView = findViewById(R.id.reCaptchaWebView);
// enable Javascript
diff --git a/app/src/test/java/org/schabi/newpipe/ReCaptchaActivityTest.kt b/app/src/test/java/org/schabi/newpipe/ReCaptchaActivityTest.kt
new file mode 100644
index 00000000000..b9f6887f9db
--- /dev/null
+++ b/app/src/test/java/org/schabi/newpipe/ReCaptchaActivityTest.kt
@@ -0,0 +1,27 @@
+package org.schabi.newpipe
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.schabi.newpipe.ReCaptchaActivity.YT_URL
+
+class ReCaptchaActivityTest {
+ private fun assertSanitized(expected: String, actual: String?) {
+ assertEquals(expected, ReCaptchaActivity.sanitizeRecaptchaUrl(actual))
+ }
+
+ @Test fun `null, empty or blank url is sanitized correctly`() {
+ assertSanitized(YT_URL, null)
+ assertSanitized(YT_URL, "")
+ assertSanitized(YT_URL, " \n \t ")
+ }
+
+ @Test fun `YouTube url containing pbj=1 is sanitized correctly`() {
+ val sanitizedUrl = "https://m.youtube.com/results?search_query=test"
+ assertSanitized(sanitizedUrl, "https://m.youtube.com/results?search_query=test")
+ assertSanitized(sanitizedUrl, "https://m.youtube.com/results?search_query=test&pbj=1&pbj=1")
+ assertSanitized(sanitizedUrl, "https://m.youtube.com/results?pbj=1&search_query=test")
+ assertSanitized("pbj://pbj.pbj.pbj/pbj", "pbj://pbj.pbj.pbj/pbj?pbj=1")
+ assertSanitized("http://www.host.com/b?p1=7&p2=9", "http://www.host.com/b?p1=7&pbj=1&p2=9")
+ assertSanitized("http://www.host.com/a?pbj=0", "http://www.host.com/a?pbj=0")
+ }
+}
diff --git a/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt b/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
index c93d36eb597..74da0799883 100644
--- a/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
+++ b/app/src/test/java/org/schabi/newpipe/ktx/OffsetDateTimeToCalendarTest.kt
@@ -4,7 +4,6 @@ import org.junit.Assert.assertEquals
import org.junit.Test
import java.time.LocalDate
import java.time.OffsetDateTime
-import java.time.ZoneId
import java.time.ZoneOffset
import java.util.Calendar
import java.util.TimeZone
@@ -13,7 +12,7 @@ class OffsetDateTimeToCalendarTest {
@Test
fun testRelativeTimeWithCurrentOffsetDateTime() {
val calendar = LocalDate.of(2020, 1, 1).atStartOfDay().atOffset(ZoneOffset.UTC)
- .toCalendar()
+ .toCalendar()
assertEquals(2020, calendar[Calendar.YEAR])
assertEquals(0, calendar[Calendar.MONTH])
From aacb1f46a80d9dce55ab4d216279f4dbc205cbc0 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Fri, 18 Dec 2020 18:36:40 +0100
Subject: [PATCH 19/52] Use user agent of DownloaderImpl also in
ReCapthaActivity
Does not contain device info and should also fix some issues about recaptchas not showing up
---
.../org/schabi/newpipe/ReCaptchaActivity.java | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
index 03c9ae4af52..b6f65c355fd 100644
--- a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
@@ -83,6 +83,7 @@ protected void onCreate(final Bundle savedInstanceState) {
// enable Javascript
final WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
+ webSettings.setUserAgentString(DownloaderImpl.USER_AGENT);
webView.setWebViewClient(new WebViewClient() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@@ -120,8 +121,7 @@ public void onPageFinished(final WebView view, final String url) {
webView.clearHistory();
final android.webkit.CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- cookieManager.removeAllCookies(aBoolean -> {
- });
+ cookieManager.removeAllCookies(value -> { });
} else {
cookieManager.removeAllCookie();
}
@@ -150,14 +150,11 @@ public void onBackPressed() {
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
- final int id = item.getItemId();
- switch (id) {
- case R.id.menu_item_done:
- saveCookiesAndFinish();
- return true;
- default:
- return false;
+ if (item.getItemId() == R.id.menu_item_done) {
+ saveCookiesAndFinish();
+ return true;
}
+ return false;
}
private void saveCookiesAndFinish() {
From 31bb70e3334ecb05a8624283058bb054c05e7a34 Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 10:07:18 +0530
Subject: [PATCH 20/52] Enable view binding.
---
app/build.gradle | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/app/build.gradle b/app/build.gradle
index 5a8689f70e7..4acff01bfca 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -85,6 +85,10 @@ android {
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
+
+ buildFeatures {
+ viewBinding true
+ }
}
ext {
From 18d530021c04f63f5d153a3e527de58825485eb9 Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 11:19:07 +0530
Subject: [PATCH 21/52] Fix view binding issue.
---
app/src/main/res/layout-large-land/fragment_video_detail.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 13e3c1b5fac..8aee89ab086 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -2,12 +2,12 @@
Date: Sat, 31 Oct 2020 11:23:28 +0530
Subject: [PATCH 22/52] Use view binding in MainActivity.
---
.../java/org/schabi/newpipe/MainActivity.java | 168 +++++++++---------
app/src/main/res/layout/activity_main.xml | 9 +-
2 files changed, 87 insertions(+), 90 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index a5c963ee645..ff078fa2c49 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -39,17 +39,13 @@
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
-import android.widget.Button;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.Spinner;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
@@ -58,8 +54,12 @@
import androidx.preference.PreferenceManager;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
-import com.google.android.material.navigation.NavigationView;
+import org.schabi.newpipe.databinding.ActivityMainBinding;
+import org.schabi.newpipe.databinding.DrawerHeaderBinding;
+import org.schabi.newpipe.databinding.DrawerLayoutBinding;
+import org.schabi.newpipe.databinding.InstanceSpinnerLayoutBinding;
+import org.schabi.newpipe.databinding.ToolbarLayoutBinding;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@@ -97,15 +97,14 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
+ private ActivityMainBinding mainBinding;
+ private DrawerHeaderBinding drawerHeaderBinding;
+ private DrawerLayoutBinding drawerLayoutBinding;
+ private ToolbarLayoutBinding toolbarLayoutBinding;
+
private ActionBarDrawerToggle toggle;
- private DrawerLayout drawer;
- private NavigationView drawerItems;
- private ImageView headerServiceIcon;
- private TextView headerServiceView;
- private Button toggleServiceButton;
private boolean servicesShown = false;
- private ImageView serviceArrow;
private BroadcastReceiver broadcastReceiver;
@@ -138,13 +137,19 @@ protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
+
+ mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
+ drawerLayoutBinding = mainBinding.drawerLayout;
+ drawerHeaderBinding = DrawerHeaderBinding.bind(drawerLayoutBinding.navigation
+ .getHeaderView(0));
+ toolbarLayoutBinding = mainBinding.toolbarLayout;
+ setContentView(mainBinding.getRoot());
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
initFragments();
}
- setSupportActionBar(findViewById(R.id.toolbar));
+ setSupportActionBar(toolbarLayoutBinding.toolbar);
try {
setupDrawer();
} catch (final Exception e) {
@@ -158,10 +163,6 @@ protected void onCreate(final Bundle savedInstanceState) {
}
private void setupDrawer() throws Exception {
- final Toolbar toolbar = findViewById(R.id.toolbar);
- drawer = findViewById(R.id.drawer_layout);
- drawerItems = findViewById(R.id.navigation);
-
//Tabs
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
final StreamingService service = NewPipe.getService(currentServiceId);
@@ -169,43 +170,43 @@ private void setupDrawer() throws Exception {
int kioskId = 0;
for (final String ks : service.getKioskList().getAvailableKiosks()) {
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, kioskId, 0, KioskTranslator
.getTranslatedKioskName(ks, this))
.setIcon(KioskTranslator.getKioskIcon(ks, this));
kioskId++;
}
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_SUBSCRIPTIONS, ORDER,
R.string.tab_subscriptions)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_channel));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_FEED, ORDER, R.string.fragment_feed_title)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_rss));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_BOOKMARKS, ORDER, R.string.tab_bookmarks)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_bookmark));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_DOWNLOADS, ORDER, R.string.downloads)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_file_download));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_HISTORY, ORDER, R.string.action_history)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_history));
//Settings and About
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_settings));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_options_about_group, ITEM_ID_ABOUT, ORDER, R.string.tab_about)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_info_outline));
- toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open,
- R.string.drawer_close);
+ toggle = new ActionBarDrawerToggle(this, mainBinding.getRoot(),
+ toolbarLayoutBinding.toolbar, R.string.drawer_open, R.string.drawer_close);
toggle.syncState();
- drawer.addDrawerListener(toggle);
- drawer.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
+ mainBinding.getRoot().addDrawerListener(toggle);
+ mainBinding.getRoot().addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
private int lastService;
@Override
@@ -224,7 +225,7 @@ public void onDrawerClosed(final View drawerView) {
}
});
- drawerItems.setNavigationItemSelectedListener(this::drawerItemSelected);
+ drawerLayoutBinding.navigation.setNavigationItemSelectedListener(this::drawerItemSelected);
setupDrawerHeader();
}
@@ -247,15 +248,17 @@ private boolean drawerItemSelected(final MenuItem item) {
return false;
}
- drawer.closeDrawers();
+ mainBinding.getRoot().closeDrawers();
return true;
}
private void changeService(final MenuItem item) {
- drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this))
+ drawerLayoutBinding.navigation.getMenu()
+ .getItem(ServiceHelper.getSelectedServiceId(this))
.setChecked(false);
ServiceHelper.setSelectedServiceId(this, item.getItemId());
- drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this))
+ drawerLayoutBinding.navigation.getMenu()
+ .getItem(ServiceHelper.getSelectedServiceId(this))
.setChecked(true);
}
@@ -307,26 +310,19 @@ private void optionsAboutSelected(final MenuItem item) {
}
private void setupDrawerHeader() {
- final NavigationView navigationView = findViewById(R.id.navigation);
- final View hView = navigationView.getHeaderView(0);
-
- serviceArrow = hView.findViewById(R.id.drawer_arrow);
- headerServiceIcon = hView.findViewById(R.id.drawer_header_service_icon);
- headerServiceView = hView.findViewById(R.id.drawer_header_service_view);
- toggleServiceButton = hView.findViewById(R.id.drawer_header_action_button);
- toggleServiceButton.setOnClickListener(view -> toggleServices());
+ drawerHeaderBinding.drawerHeaderActionButton.setOnClickListener(view -> toggleServices());
// If the current app name is bigger than the default "NewPipe" (7 chars),
// let the text view grow a little more as well.
if (getString(R.string.app_name).length() > "NewPipe".length()) {
- final TextView headerTitle = hView.findViewById(R.id.drawer_header_newpipe_title);
- final ViewGroup.LayoutParams layoutParams = headerTitle.getLayoutParams();
+ final ViewGroup.LayoutParams layoutParams =
+ drawerHeaderBinding.drawerHeaderNewpipeTitle.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
- headerTitle.setLayoutParams(layoutParams);
- headerTitle.setMaxLines(2);
- headerTitle.setMinWidth(getResources()
+ drawerHeaderBinding.drawerHeaderNewpipeTitle.setLayoutParams(layoutParams);
+ drawerHeaderBinding.drawerHeaderNewpipeTitle.setMaxLines(2);
+ drawerHeaderBinding.drawerHeaderNewpipeTitle.setMinWidth(getResources()
.getDimensionPixelSize(R.dimen.drawer_header_newpipe_title_default_width));
- headerTitle.setMaxWidth(getResources()
+ drawerHeaderBinding.drawerHeaderNewpipeTitle.setMaxWidth(getResources()
.getDimensionPixelSize(R.dimen.drawer_header_newpipe_title_max_width));
}
}
@@ -334,9 +330,9 @@ private void setupDrawerHeader() {
private void toggleServices() {
servicesShown = !servicesShown;
- drawerItems.getMenu().removeGroup(R.id.menu_services_group);
- drawerItems.getMenu().removeGroup(R.id.menu_tabs_group);
- drawerItems.getMenu().removeGroup(R.id.menu_options_about_group);
+ drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_services_group);
+ drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_tabs_group);
+ drawerLayoutBinding.navigation.getMenu().removeGroup(R.id.menu_options_about_group);
if (servicesShown) {
showServices();
@@ -350,13 +346,13 @@ private void toggleServices() {
}
private void showServices() {
- serviceArrow.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
+ drawerHeaderBinding.drawerArrow.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
for (final StreamingService s : NewPipe.getServices()) {
final String title = s.getServiceInfo().getName()
+ (ServiceHelper.isBeta(s) ? " (beta)" : "");
- final MenuItem menuItem = drawerItems.getMenu()
+ final MenuItem menuItem = drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_services_group, s.getServiceId(), ORDER, title)
.setIcon(ServiceHelper.getIcon(s.getServiceId()));
@@ -365,15 +361,16 @@ private void showServices() {
enhancePeertubeMenu(s, menuItem);
}
}
- drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this))
+ drawerLayoutBinding.navigation.getMenu()
+ .getItem(ServiceHelper.getSelectedServiceId(this))
.setChecked(true);
}
private void enhancePeertubeMenu(final StreamingService s, final MenuItem menuItem) {
final PeertubeInstance currentInstance = PeertubeHelper.getCurrentInstance();
menuItem.setTitle(currentInstance.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""));
- final Spinner spinner = (Spinner) LayoutInflater.from(this)
- .inflate(R.layout.instance_spinner_layout, null);
+ final Spinner spinner = InstanceSpinnerLayoutBinding.inflate(LayoutInflater.from(this))
+ .getRoot();
final List instances = PeertubeHelper.getInstanceList(this);
final List items = new ArrayList<>();
int defaultSelect = 0;
@@ -398,7 +395,7 @@ public void onItemSelected(final AdapterView> parent, final View view,
}
PeertubeHelper.selectInstance(newInstance, getApplicationContext());
changeService(menuItem);
- drawer.closeDrawers();
+ mainBinding.getRoot().closeDrawers();
new Handler(Looper.getMainLooper()).postDelayed(() -> {
getSupportFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
@@ -415,7 +412,7 @@ public void onNothingSelected(final AdapterView> parent) {
}
private void showTabs() throws ExtractionException {
- serviceArrow.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
+ drawerHeaderBinding.drawerArrow.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
//Tabs
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
@@ -424,34 +421,34 @@ private void showTabs() throws ExtractionException {
int kioskId = 0;
for (final String ks : service.getKioskList().getAvailableKiosks()) {
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, kioskId, ORDER,
KioskTranslator.getTranslatedKioskName(ks, this))
.setIcon(KioskTranslator.getKioskIcon(ks, this));
kioskId++;
}
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_SUBSCRIPTIONS, ORDER, R.string.tab_subscriptions)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_channel));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_FEED, ORDER, R.string.fragment_feed_title)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_rss));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_BOOKMARKS, ORDER, R.string.tab_bookmarks)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_bookmark));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_DOWNLOADS, ORDER, R.string.downloads)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_file_download));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_tabs_group, ITEM_ID_HISTORY, ORDER, R.string.action_history)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_history));
//Settings and About
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_options_about_group, ITEM_ID_SETTINGS, ORDER, R.string.settings)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_settings));
- drawerItems.getMenu()
+ drawerLayoutBinding.navigation.getMenu()
.add(R.id.menu_options_about_group, ITEM_ID_ABOUT, ORDER, R.string.tab_about)
.setIcon(ThemeHelper.resolveResourceIdFromAttr(this, R.attr.ic_info_outline));
}
@@ -476,16 +473,18 @@ protected void onResume() {
// Close drawer on return, and don't show animation,
// so it looks like the drawer isn't open when the user returns to MainActivity
- drawer.closeDrawer(GravityCompat.START, false);
+ mainBinding.getRoot().closeDrawer(GravityCompat.START, false);
try {
final int selectedServiceId = ServiceHelper.getSelectedServiceId(this);
final String selectedServiceName = NewPipe.getService(selectedServiceId)
.getServiceInfo().getName();
- headerServiceView.setText(selectedServiceName);
- headerServiceIcon.setImageResource(ServiceHelper.getIcon(selectedServiceId));
+ drawerHeaderBinding.drawerHeaderServiceView.setText(selectedServiceName);
+ drawerHeaderBinding.drawerHeaderServiceIcon.setImageResource(ServiceHelper
+ .getIcon(selectedServiceId));
- headerServiceView.post(() -> headerServiceView.setSelected(true));
- toggleServiceButton.setContentDescription(
+ drawerHeaderBinding.drawerHeaderServiceView.post(() -> drawerHeaderBinding
+ .drawerHeaderServiceView.setSelected(true));
+ drawerHeaderBinding.drawerHeaderActionButton.setContentDescription(
getString(R.string.drawer_header_description) + selectedServiceName);
} catch (final Exception e) {
ErrorActivity.reportUiError(this, e);
@@ -511,7 +510,8 @@ protected void onResume() {
final boolean isHistoryEnabled = sharedPreferences.getBoolean(
getString(R.string.enable_watch_history_key), true);
- drawerItems.getMenu().findItem(ITEM_ID_HISTORY).setVisible(isHistoryEnabled);
+ drawerLayoutBinding.navigation.getMenu().findItem(ITEM_ID_HISTORY)
+ .setVisible(isHistoryEnabled);
}
@Override
@@ -555,9 +555,8 @@ public void onBackPressed() {
}
if (DeviceUtils.isTv(this)) {
- final View drawerPanel = findViewById(R.id.navigation);
- if (drawer.isDrawerOpen(drawerPanel)) {
- drawer.closeDrawers();
+ if (mainBinding.getRoot().isDrawerOpen(drawerLayoutBinding.navigation)) {
+ mainBinding.getRoot().closeDrawers();
return;
}
}
@@ -583,9 +582,7 @@ public void onBackPressed() {
// delegate the back press to it
if (fragmentPlayer instanceof BackPressable) {
if (!((BackPressable) fragmentPlayer).onBackPressed()) {
- final FrameLayout bottomSheetLayout =
- findViewById(R.id.fragment_player_holder);
- BottomSheetBehavior.from(bottomSheetLayout)
+ BottomSheetBehavior.from(mainBinding.fragmentPlayerHolder)
.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
return;
@@ -668,8 +665,7 @@ public boolean onCreateOptionsMenu(final Menu menu) {
final Fragment fragment
= getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
if (!(fragment instanceof SearchFragment)) {
- findViewById(R.id.toolbar).findViewById(R.id.toolbar_search_container)
- .setVisibility(View.GONE);
+ toolbarLayoutBinding.toolbarSearchContainer.getRoot().setVisibility(View.GONE);
}
final ActionBar actionBar = getSupportActionBar();
@@ -730,21 +726,20 @@ private void updateDrawerNavigation() {
return;
}
- final Toolbar toolbar = findViewById(R.id.toolbar);
-
final Fragment fragment = getSupportFragmentManager()
.findFragmentById(R.id.fragment_holder);
if (fragment instanceof MainFragment) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
if (toggle != null) {
toggle.syncState();
- toolbar.setNavigationOnClickListener(v -> drawer.openDrawer(GravityCompat.START));
- drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);
+ toolbarLayoutBinding.toolbar.setNavigationOnClickListener(v -> mainBinding.getRoot()
+ .openDrawer(GravityCompat.START));
+ mainBinding.getRoot().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);
}
} else {
- drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ mainBinding.getRoot().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- toolbar.setNavigationOnClickListener(v -> onHomeButtonPressed());
+ toolbarLayoutBinding.toolbar.setNavigationOnClickListener(v -> onHomeButtonPressed());
}
}
@@ -852,9 +847,8 @@ public void onReceive(final Context context, final Intent intent) {
}
private boolean bottomSheetHiddenOrCollapsed() {
- final FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
final BottomSheetBehavior bottomSheetBehavior =
- BottomSheetBehavior.from(bottomSheetLayout);
+ BottomSheetBehavior.from(mainBinding.fragmentPlayerHolder);
final int sheetState = bottomSheetBehavior.getState();
return sheetState == BottomSheetBehavior.STATE_HIDDEN
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 4a8befa2cdc..6d25ed097a0 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,7 +1,6 @@
@@ -15,7 +14,9 @@
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
-
+
-
+
From 4545b8e92d147354feae925377ec1f167b5f9cce Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 11:34:48 +0530
Subject: [PATCH 23/52] Use view binding in AboutActivity.
---
.../schabi/newpipe/about/AboutActivity.java | 59 ++++++-------------
1 file changed, 19 insertions(+), 40 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
index e3e56816c61..6ff69156112 100644
--- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
@@ -6,22 +6,19 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
-import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.databinding.ActivityAboutBinding;
+import org.schabi.newpipe.databinding.FragmentAboutBinding;
import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@@ -68,40 +65,27 @@ public class AboutActivity extends AppCompatActivity {
private static final int POS_ABOUT = 0;
private static final int POS_LICENSE = 1;
private static final int TOTAL_COUNT = 2;
- /**
- * The {@link RecyclerView.Adapter} that will provide
- * fragments for each of the sections. We use a
- * {@link FragmentStateAdapter} derivative, which will keep every
- * loaded fragment in memory.
- */
- private SectionsPagerAdapter mSectionsPagerAdapter;
- /**
- * The {@link ViewPager2} that will host the section contents.
- */
- private ViewPager2 mViewPager;
@Override
protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
- this.setTitle(getString(R.string.title_activity_about));
+ setTitle(getString(R.string.title_activity_about));
- setContentView(R.layout.activity_about);
+ final ActivityAboutBinding aboutBinding = ActivityAboutBinding.inflate(getLayoutInflater());
+ setContentView(aboutBinding.getRoot());
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ setSupportActionBar(aboutBinding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
- mSectionsPagerAdapter = new SectionsPagerAdapter(this);
+ final SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(this);
// Set up the ViewPager with the sections adapter.
- mViewPager = findViewById(R.id.container);
- mViewPager.setAdapter(mSectionsPagerAdapter);
+ aboutBinding.container.setAdapter(mSectionsPagerAdapter);
- final TabLayout tabLayout = findViewById(R.id.tabs);
- new TabLayoutMediator(tabLayout, mViewPager, (tab, position) -> {
+ new TabLayoutMediator(aboutBinding.tabs, aboutBinding.container, (tab, position) -> {
switch (position) {
default:
case POS_ABOUT:
@@ -143,33 +127,28 @@ public static AboutFragment newInstance() {
}
@Override
- public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
- final View rootView = inflater.inflate(R.layout.fragment_about, container, false);
- final Context context = this.getContext();
+ final FragmentAboutBinding aboutBinding =
+ FragmentAboutBinding.inflate(inflater, container, false);
+ final Context context = getContext();
- final TextView version = rootView.findViewById(R.id.app_version);
- version.setText(BuildConfig.VERSION_NAME);
+ aboutBinding.appVersion.setText(BuildConfig.VERSION_NAME);
- final View githubLink = rootView.findViewById(R.id.github_link);
- githubLink.setOnClickListener(nv ->
+ aboutBinding.githubLink.setOnClickListener(nv ->
openUrlInBrowser(context, context.getString(R.string.github_url)));
- final View donationLink = rootView.findViewById(R.id.donation_link);
- donationLink.setOnClickListener(v ->
+ aboutBinding.donationLink.setOnClickListener(v ->
openUrlInBrowser(context, context.getString(R.string.donation_url)));
- final View websiteLink = rootView.findViewById(R.id.website_link);
- websiteLink.setOnClickListener(nv ->
+ aboutBinding.websiteLink.setOnClickListener(nv ->
openUrlInBrowser(context, context.getString(R.string.website_url)));
- final View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
- privacyPolicyLink.setOnClickListener(v ->
+ aboutBinding.privacyPolicyLink.setOnClickListener(v ->
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url)));
- return rootView;
+ return aboutBinding.getRoot();
}
-
}
/**
From a65ed7e914bdc8c75bfecc9856a7a452598c64db Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 13:41:01 +0530
Subject: [PATCH 24/52] Use view binding in DownloadActivity.
---
.../org/schabi/newpipe/download/DownloadActivity.java | 11 +++++++----
app/src/main/res/layout/activity_downloader.xml | 4 +++-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
index 979f8be7533..37eefed96c6 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
@@ -9,10 +9,10 @@
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentTransaction;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.databinding.ActivityDownloaderBinding;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
@@ -35,11 +35,14 @@ protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
ThemeHelper.setTheme(this);
+
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_downloader);
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ final ActivityDownloaderBinding downloaderBinding =
+ ActivityDownloaderBinding.inflate(getLayoutInflater());
+ setContentView(downloaderBinding.getRoot());
+
+ setSupportActionBar(downloaderBinding.toolbarLayout.toolbar);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
diff --git a/app/src/main/res/layout/activity_downloader.xml b/app/src/main/res/layout/activity_downloader.xml
index 272f6e76e30..d91b943e7e5 100644
--- a/app/src/main/res/layout/activity_downloader.xml
+++ b/app/src/main/res/layout/activity_downloader.xml
@@ -3,7 +3,9 @@
android:layout_height="match_parent"
android:orientation="vertical">
-
+
Date: Sat, 31 Oct 2020 14:10:00 +0530
Subject: [PATCH 25/52] Use view binding in ReCaptchaActivity.
---
.../org/schabi/newpipe/ReCaptchaActivity.java | 29 +++++++++----------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
index b6f65c355fd..dfe062a1643 100644
--- a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
@@ -18,10 +18,10 @@
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.core.app.NavUtils;
import androidx.preference.PreferenceManager;
+import org.schabi.newpipe.databinding.ActivityRecaptchaBinding;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.UnsupportedEncodingException;
@@ -62,30 +62,28 @@ public static String sanitizeRecaptchaUrl(@Nullable final String url) {
}
}
-
- private WebView webView;
+ private ActivityRecaptchaBinding recaptchaBinding;
private String foundCookies = "";
@Override
protected void onCreate(final Bundle savedInstanceState) {
ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_recaptcha);
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+
+ recaptchaBinding = ActivityRecaptchaBinding.inflate(getLayoutInflater());
+ setContentView(recaptchaBinding.getRoot());
+ setSupportActionBar(recaptchaBinding.toolbar);
final String url = sanitizeRecaptchaUrl(getIntent().getStringExtra(RECAPTCHA_URL_EXTRA));
// set return to Cancel by default
setResult(RESULT_CANCELED);
- webView = findViewById(R.id.reCaptchaWebView);
-
// enable Javascript
- final WebSettings webSettings = webView.getSettings();
+ final WebSettings webSettings = recaptchaBinding.reCaptchaWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setUserAgentString(DownloaderImpl.USER_AGENT);
- webView.setWebViewClient(new WebViewClient() {
+ recaptchaBinding.reCaptchaWebView.setWebViewClient(new WebViewClient() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(final WebView view,
@@ -117,16 +115,16 @@ public void onPageFinished(final WebView view, final String url) {
});
// cleaning cache, history and cookies from webView
- webView.clearCache(true);
- webView.clearHistory();
- final android.webkit.CookieManager cookieManager = CookieManager.getInstance();
+ recaptchaBinding.reCaptchaWebView.clearCache(true);
+ recaptchaBinding.reCaptchaWebView.clearHistory();
+ final CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(value -> { });
} else {
cookieManager.removeAllCookie();
}
- webView.loadUrl(url);
+ recaptchaBinding.reCaptchaWebView.loadUrl(url);
}
@Override
@@ -158,7 +156,8 @@ public boolean onOptionsItemSelected(final MenuItem item) {
}
private void saveCookiesAndFinish() {
- handleCookiesFromUrl(webView.getUrl()); // try to get cookies of unclosed page
+ // try to get cookies of unclosed page
+ handleCookiesFromUrl(recaptchaBinding.reCaptchaWebView.getUrl());
if (MainActivity.DEBUG) {
Log.d(TAG, "saveCookiesAndFinish: foundCookies=" + foundCookies);
}
From 22ec70e94d16408d165cb38fba77e1da40d70a9e Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 14:36:12 +0530
Subject: [PATCH 26/52] Use view binding in RouterActivity.
---
.../main/java/org/schabi/newpipe/RouterActivity.java | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 9ad993de183..e04970e86c0 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -14,7 +14,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
@@ -30,6 +29,8 @@
import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceManager;
+import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
+import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.NewPipe;
@@ -267,9 +268,8 @@ private void showDialog(final List choices) {
final Context themeWrapperContext = getThemeWrapperContext();
final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext);
- final LinearLayout rootLayout = (LinearLayout) inflater.inflate(
- R.layout.single_choice_dialog_view, null, false);
- final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
+ final RadioGroup radioGroup = SingleChoiceDialogViewBinding.inflate(getLayoutInflater())
+ .list;
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
final int indexOfChild = radioGroup.indexOfChild(
@@ -322,8 +322,7 @@ private void showDialog(final List choices) {
int id = 12345;
for (final AdapterChoiceItem item : choices) {
- final RadioButton radioButton
- = (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
+ final RadioButton radioButton = ListRadioIconItemBinding.inflate(inflater).getRoot();
radioButton.setText(item.description);
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(radioButton,
AppCompatResources.getDrawable(getApplicationContext(), item.icon),
From e6021465f677d91afe68ef17bacaf5251f4e200a Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 15:33:00 +0530
Subject: [PATCH 27/52] Use view binding in ServicePlayerActivity.
---
.../newpipe/player/ServicePlayerActivity.java | 214 ++++++++----------
1 file changed, 89 insertions(+), 125 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index 4bf6ef9ae7b..41d66dc90df 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -1,6 +1,7 @@
package org.schabi.newpipe.player;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
@@ -11,15 +12,10 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
import android.widget.PopupMenu;
-import android.widget.ProgressBar;
import android.widget.SeekBar;
-import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -29,6 +25,7 @@
import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.databinding.ActivityPlayerQueueControlBinding;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
@@ -70,30 +67,10 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
// Views
////////////////////////////////////////////////////////////////////////////
- private View rootView;
+ private ActivityPlayerQueueControlBinding queueControlBinding;
- private RecyclerView itemsList;
private ItemTouchHelper itemTouchHelper;
- private LinearLayout metadata;
- private TextView metadataTitle;
- private TextView metadataArtist;
-
- private SeekBar progressSeekBar;
- private TextView progressCurrentTime;
- private TextView progressEndTime;
- private TextView progressLiveSync;
- private TextView seekDisplay;
-
- private ImageButton repeatButton;
- private ImageButton backwardButton;
- private ImageButton fastRewindButton;
- private ImageButton playPauseButton;
- private ImageButton fastForwardButton;
- private ImageButton forwardButton;
- private ImageButton shuffleButton;
- private ProgressBar progressBar;
-
private Menu menu;
////////////////////////////////////////////////////////////////////////////
@@ -123,11 +100,11 @@ protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
- setContentView(R.layout.activity_player_queue_control);
- rootView = findViewById(R.id.main_content);
- final Toolbar toolbar = rootView.findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ queueControlBinding = ActivityPlayerQueueControlBinding.inflate(getLayoutInflater());
+ setContentView(queueControlBinding.getRoot());
+
+ setSupportActionBar(queueControlBinding.toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(getSupportActionTitle());
@@ -230,14 +207,11 @@ private void unbind() {
if (player != null && player.getPlayQueueAdapter() != null) {
player.getPlayQueueAdapter().unsetSelectedListener();
}
- if (itemsList != null) {
- itemsList.setAdapter(null);
- }
+ queueControlBinding.playQueue.setAdapter(null);
if (itemTouchHelper != null) {
itemTouchHelper.attachToRecyclerView(null);
}
- itemsList = null;
itemTouchHelper = null;
player = null;
}
@@ -284,58 +258,38 @@ private void buildComponents() {
}
private void buildQueue() {
- itemsList = findViewById(R.id.play_queue);
- itemsList.setLayoutManager(new LinearLayoutManager(this));
- itemsList.setAdapter(player.getPlayQueueAdapter());
- itemsList.setClickable(true);
- itemsList.setLongClickable(true);
- itemsList.clearOnScrollListeners();
- itemsList.addOnScrollListener(getQueueScrollListener());
+ queueControlBinding.playQueue.setLayoutManager(new LinearLayoutManager(this));
+ queueControlBinding.playQueue.setAdapter(player.getPlayQueueAdapter());
+ queueControlBinding.playQueue.setClickable(true);
+ queueControlBinding.playQueue.setLongClickable(true);
+ queueControlBinding.playQueue.clearOnScrollListeners();
+ queueControlBinding.playQueue.addOnScrollListener(getQueueScrollListener());
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
- itemTouchHelper.attachToRecyclerView(itemsList);
+ itemTouchHelper.attachToRecyclerView(queueControlBinding.playQueue);
player.getPlayQueueAdapter().setSelectedListener(getOnSelectedListener());
}
private void buildMetadata() {
- metadata = rootView.findViewById(R.id.metadata);
- metadataTitle = rootView.findViewById(R.id.song_name);
- metadataArtist = rootView.findViewById(R.id.artist_name);
-
- metadata.setOnClickListener(this);
- metadataTitle.setSelected(true);
- metadataArtist.setSelected(true);
+ queueControlBinding.metadata.setOnClickListener(this);
+ queueControlBinding.songName.setSelected(true);
+ queueControlBinding.artistName.setSelected(true);
}
private void buildSeekBar() {
- progressCurrentTime = rootView.findViewById(R.id.current_time);
- progressSeekBar = rootView.findViewById(R.id.seek_bar);
- progressEndTime = rootView.findViewById(R.id.end_time);
- progressLiveSync = rootView.findViewById(R.id.live_sync);
- seekDisplay = rootView.findViewById(R.id.seek_display);
-
- progressSeekBar.setOnSeekBarChangeListener(this);
- progressLiveSync.setOnClickListener(this);
+ queueControlBinding.seekBar.setOnSeekBarChangeListener(this);
+ queueControlBinding.liveSync.setOnClickListener(this);
}
private void buildControls() {
- repeatButton = rootView.findViewById(R.id.control_repeat);
- backwardButton = rootView.findViewById(R.id.control_backward);
- fastRewindButton = rootView.findViewById(R.id.control_fast_rewind);
- playPauseButton = rootView.findViewById(R.id.control_play_pause);
- fastForwardButton = rootView.findViewById(R.id.control_fast_forward);
- forwardButton = rootView.findViewById(R.id.control_forward);
- shuffleButton = rootView.findViewById(R.id.control_shuffle);
- progressBar = rootView.findViewById(R.id.control_progress_bar);
-
- repeatButton.setOnClickListener(this);
- backwardButton.setOnClickListener(this);
- fastRewindButton.setOnClickListener(this);
- playPauseButton.setOnClickListener(this);
- fastForwardButton.setOnClickListener(this);
- forwardButton.setOnClickListener(this);
- shuffleButton.setOnClickListener(this);
+ queueControlBinding.controlRepeat.setOnClickListener(this);
+ queueControlBinding.controlBackward.setOnClickListener(this);
+ queueControlBinding.controlFastRewind.setOnClickListener(this);
+ queueControlBinding.controlPlayPause.setOnClickListener(this);
+ queueControlBinding.controlFastForward.setOnClickListener(this);
+ queueControlBinding.controlForward.setOnClickListener(this);
+ queueControlBinding.controlShuffle.setOnClickListener(this);
}
private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
@@ -391,8 +345,8 @@ public void onScrolledDown(final RecyclerView recyclerView) {
if (player != null && player.getPlayQueue() != null
&& !player.getPlayQueue().isComplete()) {
player.getPlayQueue().fetch();
- } else if (itemsList != null) {
- itemsList.clearOnScrollListeners();
+ } else {
+ queueControlBinding.playQueue.clearOnScrollListeners();
}
}
};
@@ -453,8 +407,9 @@ private void scrollToSelected() {
final int currentPlayingIndex = player.getPlayQueue().getIndex();
final int currentVisibleIndex;
- if (itemsList.getLayoutManager() instanceof LinearLayoutManager) {
- final LinearLayoutManager layout = ((LinearLayoutManager) itemsList.getLayoutManager());
+ if (queueControlBinding.playQueue.getLayoutManager() instanceof LinearLayoutManager) {
+ final LinearLayoutManager layout =
+ (LinearLayoutManager) queueControlBinding.playQueue.getLayoutManager();
currentVisibleIndex = layout.findFirstVisibleItemPosition();
} else {
currentVisibleIndex = 0;
@@ -462,9 +417,9 @@ private void scrollToSelected() {
final int distance = Math.abs(currentPlayingIndex - currentVisibleIndex);
if (distance < SMOOTH_SCROLL_MAXIMUM_DISTANCE) {
- itemsList.smoothScrollToPosition(currentPlayingIndex);
+ queueControlBinding.playQueue.smoothScrollToPosition(currentPlayingIndex);
} else {
- itemsList.scrollToPosition(currentPlayingIndex);
+ queueControlBinding.playQueue.scrollToPosition(currentPlayingIndex);
}
}
@@ -478,23 +433,23 @@ public void onClick(final View view) {
return;
}
- if (view.getId() == repeatButton.getId()) {
+ if (view.getId() == queueControlBinding.controlRepeat.getId()) {
player.onRepeatClicked();
- } else if (view.getId() == backwardButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlBackward.getId()) {
player.onPlayPrevious();
- } else if (view.getId() == fastRewindButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlFastRewind.getId()) {
player.onFastRewind();
- } else if (view.getId() == playPauseButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlPlayPause.getId()) {
player.onPlayPause();
- } else if (view.getId() == fastForwardButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlFastForward.getId()) {
player.onFastForward();
- } else if (view.getId() == forwardButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlForward.getId()) {
player.onPlayNext();
- } else if (view.getId() == shuffleButton.getId()) {
+ } else if (view.getId() == queueControlBinding.controlShuffle.getId()) {
player.onShuffleClicked();
- } else if (view.getId() == metadata.getId()) {
+ } else if (view.getId() == queueControlBinding.metadata.getId()) {
scrollToSelected();
- } else if (view.getId() == progressLiveSync.getId()) {
+ } else if (view.getId() == queueControlBinding.liveSync.getId()) {
player.seekToDefault();
}
}
@@ -528,15 +483,15 @@ public void onProgressChanged(final SeekBar seekBar, final int progress,
final boolean fromUser) {
if (fromUser) {
final String seekTime = Localization.getDurationString(progress / 1000);
- progressCurrentTime.setText(seekTime);
- seekDisplay.setText(seekTime);
+ queueControlBinding.currentTime.setText(seekTime);
+ queueControlBinding.seekDisplay.setText(seekTime);
}
}
@Override
public void onStartTrackingTouch(final SeekBar seekBar) {
seeking = true;
- seekDisplay.setVisibility(View.VISIBLE);
+ queueControlBinding.seekDisplay.setVisibility(View.VISIBLE);
}
@Override
@@ -544,7 +499,7 @@ public void onStopTrackingTouch(final SeekBar seekBar) {
if (player != null) {
player.seekTo(seekBar.getProgress());
}
- seekDisplay.setVisibility(View.GONE);
+ queueControlBinding.seekDisplay.setVisibility(View.GONE);
seeking = false;
}
@@ -602,45 +557,46 @@ public void onPlaybackUpdate(final int state, final int repeatMode, final boolea
public void onProgressUpdate(final int currentProgress, final int duration,
final int bufferPercent) {
// Set buffer progress
- progressSeekBar.setSecondaryProgress((int) (progressSeekBar.getMax()
+ queueControlBinding.seekBar.setSecondaryProgress((int) (queueControlBinding.seekBar.getMax()
* ((float) bufferPercent / 100)));
// Set Duration
- progressSeekBar.setMax(duration);
- progressEndTime.setText(Localization.getDurationString(duration / 1000));
+ queueControlBinding.seekBar.setMax(duration);
+ queueControlBinding.endTime.setText(Localization.getDurationString(duration / 1000));
// Set current time if not seeking
if (!seeking) {
- progressSeekBar.setProgress(currentProgress);
- progressCurrentTime.setText(Localization.getDurationString(currentProgress / 1000));
+ queueControlBinding.seekBar.setProgress(currentProgress);
+ queueControlBinding.currentTime.setText(Localization
+ .getDurationString(currentProgress / 1000));
}
if (player != null) {
- progressLiveSync.setClickable(!player.isLiveEdge());
+ queueControlBinding.liveSync.setClickable(!player.isLiveEdge());
}
// this will make sure progressCurrentTime has the same width as progressEndTime
- final ViewGroup.LayoutParams endTimeParams = progressEndTime.getLayoutParams();
- final ViewGroup.LayoutParams currentTimeParams = progressCurrentTime.getLayoutParams();
- currentTimeParams.width = progressEndTime.getWidth();
- progressCurrentTime.setLayoutParams(currentTimeParams);
+ final ViewGroup.LayoutParams currentTimeParams =
+ queueControlBinding.currentTime.getLayoutParams();
+ currentTimeParams.width = queueControlBinding.endTime.getWidth();
+ queueControlBinding.currentTime.setLayoutParams(currentTimeParams);
}
@Override
public void onMetadataUpdate(final StreamInfo info, final PlayQueue queue) {
if (info != null) {
- metadataTitle.setText(info.getName());
- metadataArtist.setText(info.getUploaderName());
+ queueControlBinding.songName.setText(info.getName());
+ queueControlBinding.artistName.setText(info.getUploaderName());
- progressEndTime.setVisibility(View.GONE);
- progressLiveSync.setVisibility(View.GONE);
+ queueControlBinding.endTime.setVisibility(View.GONE);
+ queueControlBinding.liveSync.setVisibility(View.GONE);
switch (info.getStreamType()) {
case LIVE_STREAM:
case AUDIO_LIVE_STREAM:
- progressLiveSync.setVisibility(View.VISIBLE);
+ queueControlBinding.liveSync.setVisibility(View.VISIBLE);
break;
default:
- progressEndTime.setVisibility(View.VISIBLE);
+ queueControlBinding.endTime.setVisibility(View.VISIBLE);
break;
}
@@ -661,13 +617,16 @@ public void onServiceStopped() {
private void onStateChanged(final int state) {
switch (state) {
case BasePlayer.STATE_PAUSED:
- playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
+ queueControlBinding.controlPlayPause
+ .setImageResource(R.drawable.ic_play_arrow_white_24dp);
break;
case BasePlayer.STATE_PLAYING:
- playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
+ queueControlBinding.controlPlayPause
+ .setImageResource(R.drawable.ic_pause_white_24dp);
break;
case BasePlayer.STATE_COMPLETED:
- playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp);
+ queueControlBinding.controlPlayPause
+ .setImageResource(R.drawable.ic_replay_white_24dp);
break;
default:
break;
@@ -677,14 +636,14 @@ private void onStateChanged(final int state) {
case BasePlayer.STATE_PAUSED:
case BasePlayer.STATE_PLAYING:
case BasePlayer.STATE_COMPLETED:
- playPauseButton.setClickable(true);
- playPauseButton.setVisibility(View.VISIBLE);
- progressBar.setVisibility(View.GONE);
+ queueControlBinding.controlPlayPause.setClickable(true);
+ queueControlBinding.controlPlayPause.setVisibility(View.VISIBLE);
+ queueControlBinding.progressBar.setVisibility(View.GONE);
break;
default:
- playPauseButton.setClickable(false);
- playPauseButton.setVisibility(View.INVISIBLE);
- progressBar.setVisibility(View.VISIBLE);
+ queueControlBinding.controlPlayPause.setClickable(false);
+ queueControlBinding.controlPlayPause.setVisibility(View.INVISIBLE);
+ queueControlBinding.progressBar.setVisibility(View.VISIBLE);
break;
}
}
@@ -692,18 +651,21 @@ private void onStateChanged(final int state) {
private void onPlayModeChanged(final int repeatMode, final boolean shuffled) {
switch (repeatMode) {
case Player.REPEAT_MODE_OFF:
- repeatButton.setImageResource(R.drawable.exo_controls_repeat_off);
+ queueControlBinding.controlRepeat
+ .setImageResource(R.drawable.exo_controls_repeat_off);
break;
case Player.REPEAT_MODE_ONE:
- repeatButton.setImageResource(R.drawable.exo_controls_repeat_one);
+ queueControlBinding.controlRepeat
+ .setImageResource(R.drawable.exo_controls_repeat_one);
break;
case Player.REPEAT_MODE_ALL:
- repeatButton.setImageResource(R.drawable.exo_controls_repeat_all);
+ queueControlBinding.controlRepeat
+ .setImageResource(R.drawable.exo_controls_repeat_all);
break;
}
final int shuffleAlpha = shuffled ? 255 : 77;
- shuffleButton.setImageAlpha(shuffleAlpha);
+ queueControlBinding.controlShuffle.setImageAlpha(shuffleAlpha);
}
private void onPlaybackParameterChanged(final PlaybackParameters parameters) {
@@ -716,12 +678,13 @@ private void onPlaybackParameterChanged(final PlaybackParameters parameters) {
}
private void onMaybePlaybackAdapterChanged() {
- if (itemsList == null || player == null) {
+ if (player == null) {
return;
}
final PlayQueueAdapter maybeNewAdapter = player.getPlayQueueAdapter();
- if (maybeNewAdapter != null && itemsList.getAdapter() != maybeNewAdapter) {
- itemsList.setAdapter(maybeNewAdapter);
+ if (maybeNewAdapter != null
+ && queueControlBinding.playQueue.getAdapter() != maybeNewAdapter) {
+ queueControlBinding.playQueue.setAdapter(maybeNewAdapter);
}
}
@@ -735,7 +698,8 @@ private void onMaybeMuteChanged() {
//2) Icon change accordingly to current App Theme
// using rootView.getContext() because getApplicationContext() didn't work
- item.setIcon(ThemeHelper.resolveResourceIdFromAttr(rootView.getContext(),
+ final Context context = queueControlBinding.getRoot().getContext();
+ item.setIcon(ThemeHelper.resolveResourceIdFromAttr(context,
player.isMuted()
? R.attr.ic_volume_off
: R.attr.ic_volume_up));
From b4d77df1be3f06f8a44f153f3ab23d8c7b5c3788 Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 31 Oct 2020 15:44:11 +0530
Subject: [PATCH 28/52] Use view binding in ErrorActivity.
---
.../schabi/newpipe/report/ErrorActivity.java | 56 ++++++++-----------
app/src/main/res/layout/activity_error.xml | 4 +-
2 files changed, 25 insertions(+), 35 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
index 3213821cd3c..a4b6af2ab01 100644
--- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
@@ -14,15 +14,11 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.core.app.NavUtils;
import com.google.android.material.snackbar.Snackbar;
@@ -34,6 +30,7 @@
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;
import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.ThemeHelper;
@@ -87,7 +84,8 @@ public class ErrorActivity extends AppCompatActivity {
private ErrorInfo errorInfo;
private Class returnActivity;
private String currentTimeStamp;
- private EditText userCommentBox;
+
+ private ActivityErrorBinding activityErrorBinding;
public static void reportUiError(final AppCompatActivity activity, final Throwable el) {
reportError(activity, el, activity.getClass(), null, ErrorInfo.make(UserAction.UI_ERROR,
@@ -181,12 +179,13 @@ protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
- setContentView(R.layout.activity_error);
+
+ activityErrorBinding = ActivityErrorBinding.inflate(getLayoutInflater());
+ setContentView(activityErrorBinding.getRoot());
final Intent intent = getIntent();
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ setSupportActionBar(activityErrorBinding.toolbarLayout.toolbar);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@@ -195,15 +194,6 @@ protected void onCreate(final Bundle savedInstanceState) {
actionBar.setDisplayShowTitleEnabled(true);
}
- final Button reportEmailButton = findViewById(R.id.errorReportEmailButton);
- final Button copyButton = findViewById(R.id.errorReportCopyButton);
- final Button reportGithubButton = findViewById(R.id.errorReportGitHubButton);
-
- userCommentBox = findViewById(R.id.errorCommentBox);
- final TextView errorView = findViewById(R.id.errorView);
- final TextView infoView = findViewById(R.id.errorInfosView);
- final TextView errorMessageView = findViewById(R.id.errorMessageView);
-
final ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
returnActivity = ac.getReturnActivity();
errorInfo = intent.getParcelableExtra(ERROR_INFO);
@@ -213,28 +203,27 @@ protected void onCreate(final Bundle savedInstanceState) {
addGuruMeditation();
currentTimeStamp = getCurrentTimeStamp();
- reportEmailButton.setOnClickListener(v ->
+ activityErrorBinding.errorReportEmailButton.setOnClickListener(v ->
openPrivacyPolicyDialog(this, "EMAIL"));
- copyButton.setOnClickListener(v -> {
+ activityErrorBinding.errorReportCopyButton.setOnClickListener(v -> {
ShareUtils.copyToClipboard(this, buildMarkdown());
Toast.makeText(this, R.string.msg_copied, Toast.LENGTH_SHORT).show();
});
- reportGithubButton.setOnClickListener(v ->
+ activityErrorBinding.errorReportGitHubButton.setOnClickListener(v ->
openPrivacyPolicyDialog(this, "GITHUB"));
-
// normal bugreport
buildInfo(errorInfo);
if (errorInfo.getMessage() != 0) {
- errorMessageView.setText(errorInfo.getMessage());
+ activityErrorBinding.errorMessageView.setText(errorInfo.getMessage());
} else {
- errorMessageView.setVisibility(View.GONE);
- findViewById(R.id.messageWhatHappenedView).setVisibility(View.GONE);
+ activityErrorBinding.errorMessageView.setVisibility(View.GONE);
+ activityErrorBinding.messageWhatHappenedView.setVisibility(View.GONE);
}
- errorView.setText(formErrorText(errorList));
+ activityErrorBinding.errorView.setText(formErrorText(errorList));
// print stack trace once again for debugging:
for (final String e : errorList) {
@@ -339,11 +328,10 @@ private void goToReturnActivity() {
}
private void buildInfo(final ErrorInfo info) {
- final TextView infoLabelView = findViewById(R.id.errorInfoLabelsView);
- final TextView infoView = findViewById(R.id.errorInfosView);
String text = "";
- infoLabelView.setText(getString(R.string.info_labels).replace("\\n", "\n"));
+ activityErrorBinding.errorInfoLabelsView.setText(getString(R.string.info_labels)
+ .replace("\\n", "\n"));
text += getUserActionString(info.getUserAction()) + "\n"
+ info.getRequest() + "\n"
@@ -356,7 +344,7 @@ private void buildInfo(final ErrorInfo info) {
+ BuildConfig.VERSION_NAME + "\n"
+ getOsString();
- infoView.setText(text);
+ activityErrorBinding.errorInfosView.setText(text);
}
private String buildJson() {
@@ -374,7 +362,8 @@ private String buildJson() {
.value("os", getOsString())
.value("time", currentTimeStamp)
.array("exceptions", Arrays.asList(errorList))
- .value("user_comment", userCommentBox.getText().toString())
+ .value("user_comment", activityErrorBinding.errorCommentBox.getText()
+ .toString())
.end()
.done();
} catch (final Throwable e) {
@@ -389,7 +378,7 @@ private String buildMarkdown() {
try {
final StringBuilder htmlErrorReport = new StringBuilder();
- final String userComment = userCommentBox.getText().toString();
+ final String userComment = activityErrorBinding.errorCommentBox.getText().toString();
if (!userComment.isEmpty()) {
htmlErrorReport.append(userComment).append("\n");
}
@@ -473,10 +462,9 @@ private String getOsString() {
private void addGuruMeditation() {
//just an easter egg
- final TextView sorryView = findViewById(R.id.errorSorryView);
- String text = sorryView.getText().toString();
+ String text = activityErrorBinding.errorSorryView.getText().toString();
text += "\n" + getString(R.string.guru_meditation);
- sorryView.setText(text);
+ activityErrorBinding.errorSorryView.setText(text);
}
@Override
diff --git a/app/src/main/res/layout/activity_error.xml b/app/src/main/res/layout/activity_error.xml
index f265c26585c..4feea549c5b 100644
--- a/app/src/main/res/layout/activity_error.xml
+++ b/app/src/main/res/layout/activity_error.xml
@@ -5,7 +5,9 @@
android:layout_height="match_parent"
tools:context=".report.ErrorActivity">
-
+
Date: Sat, 31 Oct 2020 15:46:46 +0530
Subject: [PATCH 29/52] Use view binding in SettingsActivity.
---
.../org/schabi/newpipe/settings/SettingsActivity.java | 10 ++++++----
app/src/main/res/layout/settings_layout.xml | 4 +++-
2 files changed, 9 insertions(+), 5 deletions(-)
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 d2d4c240439..4de166a5599 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
@@ -7,12 +7,12 @@
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.databinding.SettingsLayoutBinding;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
@@ -51,10 +51,12 @@ protected void onCreate(final Bundle savedInstanceBundle) {
setTheme(ThemeHelper.getSettingsThemeStyle(this));
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceBundle);
- setContentView(R.layout.settings_layout);
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ final SettingsLayoutBinding settingsLayoutBinding =
+ SettingsLayoutBinding.inflate(getLayoutInflater());
+ setContentView(settingsLayoutBinding.getRoot());
+
+ setSupportActionBar(settingsLayoutBinding.toolbarLayout.toolbar);
if (savedInstanceBundle == null) {
getSupportFragmentManager().beginTransaction()
diff --git a/app/src/main/res/layout/settings_layout.xml b/app/src/main/res/layout/settings_layout.xml
index d50924c46ad..32c6c6b91cf 100644
--- a/app/src/main/res/layout/settings_layout.xml
+++ b/app/src/main/res/layout/settings_layout.xml
@@ -12,6 +12,8 @@
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
-
+
From e4d94b1a4e4fbfdaeb1336f9a416e23dec60cb02 Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 19 Dec 2020 04:25:42 +0530
Subject: [PATCH 30/52] Add AndroidX Webkit.
---
app/build.gradle | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/build.gradle b/app/build.gradle
index 4acff01bfca..15561b2d21a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -203,6 +203,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
+ implementation 'androidx.webkit:webkit:1.4.0'
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
From 173150591dcb91cb2e8e3f5c42c709087a9ec3bc Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 19 Dec 2020 04:41:01 +0530
Subject: [PATCH 31/52] Use WebViewClientCompat in ReCaptchaActivity.
---
.../org/schabi/newpipe/ReCaptchaActivity.java | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
index dfe062a1643..463fc24acab 100644
--- a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java
@@ -8,18 +8,16 @@
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.CookieManager;
-import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
-import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NavUtils;
import androidx.preference.PreferenceManager;
+import androidx.webkit.WebViewClientCompat;
import org.schabi.newpipe.databinding.ActivityRecaptchaBinding;
import org.schabi.newpipe.util.ThemeHelper;
@@ -83,20 +81,7 @@ protected void onCreate(final Bundle savedInstanceState) {
webSettings.setJavaScriptEnabled(true);
webSettings.setUserAgentString(DownloaderImpl.USER_AGENT);
- recaptchaBinding.reCaptchaWebView.setWebViewClient(new WebViewClient() {
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- @Override
- public boolean shouldOverrideUrlLoading(final WebView view,
- final WebResourceRequest request) {
- final String url = request.getUrl().toString();
- if (MainActivity.DEBUG) {
- Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
- }
-
- handleCookiesFromUrl(url);
- return false;
- }
-
+ recaptchaBinding.reCaptchaWebView.setWebViewClient(new WebViewClientCompat() {
@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
if (MainActivity.DEBUG) {
From 0fe3fe7594d5815c71e6b667570e9cd7523dc9ea Mon Sep 17 00:00:00 2001
From: Isira Seneviratne
Date: Sat, 19 Dec 2020 16:52:17 +0530
Subject: [PATCH 32/52] Use ServiceCompat.stopForeground().
---
app/src/main/java/org/schabi/newpipe/RouterActivity.java | 3 ++-
.../org/schabi/newpipe/local/feed/service/FeedLoadService.kt | 3 ++-
.../local/subscription/services/BaseImportExportService.java | 3 ++-
.../java/org/schabi/newpipe/player/NotificationUtil.java | 3 ++-
.../us/shandian/giga/service/DownloadManagerService.java | 5 +++--
5 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index e04970e86c0..98a0921e4ea 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -25,6 +25,7 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.app.NotificationCompat;
+import androidx.core.app.ServiceCompat;
import androidx.core.widget.TextViewCompat;
import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceManager;
@@ -695,7 +696,7 @@ public Consumer getResultHandler(final Choice choice) {
@Override
public void onDestroy() {
super.onDestroy();
- stopForeground(true);
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
if (fetcher != null) {
fetcher.dispose();
}
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
index ddbbea23dfe..2a0aa1c90fd 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
@@ -30,6 +30,7 @@ import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
+import androidx.core.app.ServiceCompat
import androidx.preference.PreferenceManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable
@@ -147,7 +148,7 @@ class FeedLoadService : Service() {
private fun stopService() {
disposeAll()
- stopForeground(true)
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
notificationManager.cancel(NOTIFICATION_ID)
stopSelf()
}
diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java
index 73c0d23a031..34543b56587 100644
--- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java
+++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java
@@ -31,6 +31,7 @@
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
+import androidx.core.app.ServiceCompat;
import org.reactivestreams.Publisher;
import org.schabi.newpipe.R;
@@ -162,7 +163,7 @@ protected void stopAndReportError(@Nullable final Throwable error, final String
protected void postErrorResult(final String title, final String text) {
disposeAll();
- stopForeground(true);
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
stopSelf();
if (title == null) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
index 860ace84c31..c1c2e4eba87 100644
--- a/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
+++ b/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
@@ -15,6 +15,7 @@
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
+import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat;
import org.schabi.newpipe.MainActivity;
@@ -188,7 +189,7 @@ void createNotificationAndStartForeground(final VideoPlayerImpl player, final Se
}
void cancelNotificationAndStopForeground(final Service service) {
- service.stopForeground(true);
+ ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_REMOVE);
if (notificationManager != null) {
notificationManager.cancel(NOTIFICATION_ID);
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
index b43733a5140..e7719644581 100755
--- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
@@ -25,6 +25,7 @@
import android.os.Message;
import android.os.Parcelable;
+import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import android.util.Log;
@@ -235,7 +236,7 @@ public void onDestroy() {
Log.d(TAG, "Destroying");
}
- stopForeground(true);
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
if (mNotificationManager != null && downloadDoneNotification != null) {
downloadDoneNotification.setDeleteIntent(null);// prevent NewPipe running when is killed, cleared from recent, etc
@@ -363,7 +364,7 @@ public void updateForegroundState(boolean state) {
if (state) {
startForeground(FOREGROUND_NOTIFICATION_ID, mNotification);
} else {
- stopForeground(true);
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
}
manageLock(state);
From 908dff39319e01bc1e314f1ee89e285f538ff04e Mon Sep 17 00:00:00 2001
From: TobiGr
Date: Sun, 20 Dec 2020 01:18:39 +0100
Subject: [PATCH 33/52] Fix security vulnerability in checkstyle / guava
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 15561b2d21a..3ac8ff525dd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -93,7 +93,7 @@ android {
ext {
icepickVersion = '3.2.0'
- checkstyleVersion = '8.37'
+ checkstyleVersion = '8.38'
stethoVersion = '1.5.1'
leakCanaryVersion = '2.5'
exoPlayerVersion = '2.11.8'
From 7a7a90bf79a613dad94fac4eea1af3747ccbb725 Mon Sep 17 00:00:00 2001
From: bopol
Date: Sun, 20 Dec 2020 00:03:19 +0100
Subject: [PATCH 34/52] remove timestamp from share url for all services except
youtube
It produces not found error for PeerTube, media.ccc.de, SoundCloud
---
.../org/schabi/newpipe/player/VideoPlayerImpl.java | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 3cbcb87a35b..a304b44300b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -103,6 +103,7 @@
import java.util.List;
+import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND;
@@ -889,10 +890,17 @@ private void onMoreOptionsClicked() {
private void onShareClicked() {
// share video at the current time (youtube.com/watch?v=ID&t=SECONDS)
// Timestamp doesn't make sense in a live stream so drop it
- final String ts = isLive() ? "" : ("&t=" + (getPlaybackSeekBar().getProgress() / 1000));
+
+ final int ts = getPlaybackSeekBar().getProgress() / 1000;
+ final MediaSourceTag metadata = getCurrentMetadata();
+ String videoUrl = getVideoUrl();
+ if (!isLive() && ts >= 0 && metadata != null
+ && metadata.getMetadata().getServiceId() == YouTube.getServiceId()) {
+ videoUrl += ("&t=" + ts);
+ }
ShareUtils.shareUrl(service,
getVideoTitle(),
- getVideoUrl() + ts);
+ videoUrl);
}
private void onPlayWithKodiClicked() {
From 0a831ec84e7a3c822ce1822d97bc9b934a510f33 Mon Sep 17 00:00:00 2001
From: TobiGr
Date: Tue, 15 Dec 2020 17:41:21 +0100
Subject: [PATCH 35/52] Display meta info about search query, stream creator or
topic
Closes #4614
---
app/build.gradle | 2 +-
.../newpipe/fragments/MainFragment.java | 2 +-
.../fragments/detail/VideoDetailFragment.java | 77 +++++++++++++++----
.../fragments/list/search/SearchFragment.java | 48 ++++++++++++
.../fragment_video_detail.xml | 32 ++++++++
app/src/main/res/layout/fragment_search.xml | 14 +++-
.../main/res/layout/fragment_video_detail.xml | 33 ++++++++
app/src/main/res/values/settings_keys.xml | 1 +
app/src/main/res/values/strings.xml | 2 +
app/src/main/res/xml/content_settings.xml | 7 ++
10 files changed, 200 insertions(+), 18 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 15561b2d21a..fadfc3221af 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -179,7 +179,7 @@ dependencies {
// NewPipe dependencies
// You can use a local version by uncommenting a few lines in settings.gradle
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:85fa006214b003f21eacb76c445a167732f19981'
+ implementation 'com.github.TeamNewPipe:NewPipeExtractor:79b5aa9760da52020821b68e2af41a9238943304'
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "org.jsoup:jsoup:1.13.1"
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java
index 866b324ecbe..a77109f86f2 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java
@@ -3,7 +3,6 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.os.Bundle;
-import androidx.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -19,6 +18,7 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround;
+import androidx.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 427cff06ee2..b9cb4ab2bda 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -16,7 +16,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -63,6 +63,7 @@
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.InfoItem;
+import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@@ -122,8 +123,10 @@
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
+import static android.text.TextUtils.isEmpty;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
+import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
@@ -218,6 +221,10 @@ public final class VideoDetailFragment
private TextView detailDurationView;
private TextView detailPositionView;
+ private LinearLayout detailMetadataInfo;
+ private View detailMetadataInfoSeparator;
+ private TextView detailMetadataInfoText;
+
private LinearLayout videoDescriptionRootLayout;
private TextView videoUploadDateView;
private TextView videoDescriptionView;
@@ -508,8 +515,8 @@ public void onClick(final View v) {
}
break;
case R.id.detail_uploader_root_layout:
- if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) {
- if (!TextUtils.isEmpty(currentInfo.getUploaderUrl())) {
+ if (isEmpty(currentInfo.getSubChannelUrl())) {
+ if (!isEmpty(currentInfo.getUploaderUrl())) {
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
}
@@ -583,7 +590,7 @@ public boolean onLongClick(final View v) {
}
break;
case R.id.detail_uploader_root_layout:
- if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) {
+ if (isEmpty(currentInfo.getSubChannelUrl())) {
Log.w(TAG,
"Can't open parent channel because we got no parent channel URL");
} else {
@@ -644,6 +651,10 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
detailDurationView = rootView.findViewById(R.id.detail_duration_view);
detailPositionView = rootView.findViewById(R.id.detail_position_view);
+ detailMetadataInfo = rootView.findViewById(R.id.detail_metadata_info);
+ detailMetadataInfoSeparator = rootView.findViewById(R.id.detail_metadata_info_separator);
+ detailMetadataInfoText = rootView.findViewById(R.id.detail_metadata_info_text);
+
videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout);
videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view);
videoDescriptionView = rootView.findViewById(R.id.detail_description_view);
@@ -748,7 +759,7 @@ private View.OnTouchListener getOnControlsTouchListener() {
private void initThumbnailViews(@NonNull final StreamInfo info) {
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
- if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
+ if (!isEmpty(info.getThumbnailUrl())) {
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() {
@Override
@@ -763,12 +774,12 @@ public void onLoadingFailed(final String imageUri, final View view,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener);
}
- if (!TextUtils.isEmpty(info.getSubChannelAvatarUrl())) {
+ if (!isEmpty(info.getSubChannelAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
}
- if (!TextUtils.isEmpty(info.getUploaderAvatarUrl())) {
+ if (!isEmpty(info.getUploaderAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
}
@@ -1217,7 +1228,7 @@ private void makeDefaultHeightForVideoPlaceholder() {
}
private void prepareDescription(final Description description) {
- if (description == null || TextUtils.isEmpty(description.getContent())
+ if (description == null || isEmpty(description.getContent())
|| description == Description.emptyDescription) {
return;
}
@@ -1247,6 +1258,42 @@ private void prepareDescription(final Description description) {
}
}
+ private void setMetaInfo(final StreamInfo info) {
+ final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+ requireContext());
+ final boolean showMetaInfo = sp.getBoolean(
+ requireContext().getString(R.string.show_meta_info_key), true);
+ if (info.getMetaInfo().isEmpty() || !showMetaInfo) {
+ detailMetadataInfo.setVisibility(View.GONE);
+ detailMetadataInfoSeparator.setVisibility(View.GONE);
+ } else {
+ final List metaIfs = info.getMetaInfo();
+ final StringBuilder stringBuilder = new StringBuilder();
+ for (final MetaInfo mi: metaIfs) {
+ if (!isNullOrEmpty(mi.getTitle())) {
+ stringBuilder.append("
").append(mi.getTitle()).append("
");
+ }
+ stringBuilder.append(mi.getContent().getContent());
+ for (int i = 0; i < mi.getUrls().size(); i++) {
+ stringBuilder
+ .append(" ")
+ .append(mi.getUrlTexts().get(i))
+ .append("");
+ if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) {
+ // append line break to all but the last URL if there are multiple URLs
+ stringBuilder.append(" ");
+ }
+ }
+ }
+
+ detailMetadataInfoSeparator.setVisibility(View.VISIBLE);
+ detailMetadataInfoText.setText(HtmlCompat.fromHtml(
+ stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
+ detailMetadataInfoText.setMovementMethod(LinkMovementMethod.getInstance());
+ detailMetadataInfo.setVisibility(View.VISIBLE);
+ }
+ }
+
private final ViewTreeObserver.OnPreDrawListener preDrawListener =
new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -1462,9 +1509,9 @@ public void handleResult(@NonNull final StreamInfo info) {
animateView(thumbnailPlayButton, true, 200);
videoTitleTextView.setText(title);
- if (!TextUtils.isEmpty(info.getSubChannelName())) {
+ if (!isEmpty(info.getSubChannelName())) {
displayBothUploaderAndSubChannel(info);
- } else if (!TextUtils.isEmpty(info.getUploaderName())) {
+ } else if (!isEmpty(info.getUploaderName())) {
displayUploaderAsSubChannel(info);
} else {
uploaderTextView.setVisibility(View.GONE);
@@ -1559,6 +1606,8 @@ public void handleResult(@NonNull final StreamInfo info) {
prepareDescription(info.getDescription());
updateProgressInfo(info);
initThumbnailViews(info);
+ setMetaInfo(info);
+
if (player == null || player.isPlayerStopped()) {
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
@@ -1610,7 +1659,7 @@ private void displayBothUploaderAndSubChannel(final StreamInfo info) {
subChannelThumb.setVisibility(View.VISIBLE);
- if (!TextUtils.isEmpty(info.getUploaderName())) {
+ if (!isEmpty(info.getUploaderName())) {
uploaderTextView.setText(
String.format(getString(R.string.video_detail_by), info.getUploaderName()));
uploaderTextView.setVisibility(View.VISIBLE);
@@ -2305,10 +2354,10 @@ public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
private void updateOverlayData(@Nullable final String overlayTitle,
@Nullable final String uploader,
@Nullable final String thumbnailUrl) {
- overlayTitleTextView.setText(TextUtils.isEmpty(overlayTitle) ? "" : overlayTitle);
- overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader);
+ overlayTitleTextView.setText(isEmpty(title) ? "" : title);
+ overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
- if (!TextUtils.isEmpty(thumbnailUrl)) {
+ if (!isEmpty(thumbnailUrl)) {
IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index 02dbf176bc5..f44e5e33086 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -9,6 +9,7 @@
import android.text.Html;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -39,6 +40,7 @@
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
+import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
@@ -78,6 +80,7 @@
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static java.util.Arrays.asList;
+import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class SearchFragment extends BaseListFragment>
@@ -129,6 +132,9 @@ public class SearchFragment extends BaseListFragment cannot be bundled without creating some containers
+ metaInfo = new MetaInfo[result.getMetaInfo().size()];
+ metaInfo = result.getMetaInfo().toArray(metaInfo);
+
handleSearchSuggestion();
+ handleMetaInfo();
lastSearchedString = searchString;
nextPage = result.getNextPage();
@@ -1021,6 +1036,39 @@ private void handleSearchSuggestion() {
}
}
+ private void handleMetaInfo() {
+ final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+ requireContext());
+ final boolean showMetaInfo = sp.getBoolean(
+ requireContext().getString(R.string.show_meta_info_key), true);
+ if (metaInfo == null || metaInfo.length == 0 || !showMetaInfo) {
+ metaInfoTextView.setVisibility(View.GONE);
+ } else {
+ final StringBuilder stringBuilder = new StringBuilder();
+ for (final MetaInfo mi: metaInfo) {
+ if (!isNullOrEmpty(mi.getTitle())) {
+ stringBuilder.append("
").append(mi.getTitle()).append("
");
+ }
+ stringBuilder.append(mi.getContent().getContent());
+ for (int i = 0; i < mi.getUrls().size(); i++) {
+ stringBuilder
+ .append(" ")
+ .append(mi.getUrlTexts().get(i))
+ .append("");
+ if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) {
+ // append line break to all but the last URL if there are multiple URLs
+ stringBuilder.append(" ");
+ }
+ }
+ }
+
+ metaInfoTextView.setText(HtmlCompat.fromHtml(
+ stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
+ metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance());
+ metaInfoTextView.setVisibility(View.VISIBLE);
+ }
+ }
+
@Override
public void handleNextItems(final ListExtractor.InfoItemsPage> result) {
showListFooter(false);
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 8aee89ab086..d59d2db730f 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -506,6 +506,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml
index 0df85fe959e..3bf2bb02569 100644
--- a/app/src/main/res/layout/fragment_video_detail.xml
+++ b/app/src/main/res/layout/fragment_video_detail.xml
@@ -491,6 +491,39 @@
+
+
+
+
+
+
+
+
+
+
show_play_with_kodi
show_next_videoshow_comments
+ show_meta_infostream_info_selected_tabshow_hold_to_appendcontent_language
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ecb690044aa..d2dd8afd514 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -93,6 +93,8 @@
Show commentsTurn off to hide commentsTurn off to prevent loading thumbnails, saving data and memory usage. Changes clear both in-memory and on-disk image cache.
+ Show meta info
+ Turn off to hide meta info boxes with additional information about the stream creator, stream content or a search request.Image cache wipedWipe cached metadataRemove all cached webpage data
diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml
index c885366ec61..914fb2e59d5 100644
--- a/app/src/main/res/xml/content_settings.xml
+++ b/app/src/main/res/xml/content_settings.xml
@@ -85,6 +85,13 @@
android:title="@string/show_comments_title"
app:iconSpaceReserved="false" />
+
+
Date: Sun, 20 Dec 2020 15:05:37 +0100
Subject: [PATCH 36/52] Improve meta info layout and merge duplicate code
---
.../fragments/detail/VideoDetailFragment.java | 52 ++----------
.../fragments/list/search/SearchFragment.java | 46 ++---------
.../schabi/newpipe/util/ExtractorHelper.java | 79 +++++++++++++++++++
.../org/schabi/newpipe/util/Localization.java | 2 +-
.../fragment_video_detail.xml | 29 ++-----
app/src/main/res/layout/fragment_search.xml | 15 +++-
.../main/res/layout/fragment_video_detail.xml | 30 ++-----
7 files changed, 120 insertions(+), 133 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index b9cb4ab2bda..6560ab404d2 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -16,7 +16,6 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -63,7 +62,6 @@
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.InfoItem;
-import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@@ -126,11 +124,11 @@
import static android.text.TextUtils.isEmpty;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
-import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
+import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public final class VideoDetailFragment
extends BaseStateFragment
@@ -221,9 +219,8 @@ public final class VideoDetailFragment
private TextView detailDurationView;
private TextView detailPositionView;
- private LinearLayout detailMetadataInfo;
- private View detailMetadataInfoSeparator;
- private TextView detailMetadataInfoText;
+ private View detailMetaInfoSeparator;
+ private TextView detailMetaInfoTextView;
private LinearLayout videoDescriptionRootLayout;
private TextView videoUploadDateView;
@@ -651,9 +648,8 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
detailDurationView = rootView.findViewById(R.id.detail_duration_view);
detailPositionView = rootView.findViewById(R.id.detail_position_view);
- detailMetadataInfo = rootView.findViewById(R.id.detail_metadata_info);
- detailMetadataInfoSeparator = rootView.findViewById(R.id.detail_metadata_info_separator);
- detailMetadataInfoText = rootView.findViewById(R.id.detail_metadata_info_text);
+ detailMetaInfoSeparator = rootView.findViewById(R.id.detail_meta_info_separator);
+ detailMetaInfoTextView = rootView.findViewById(R.id.detail_meta_info_text_view);
videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout);
videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view);
@@ -1258,42 +1254,6 @@ private void prepareDescription(final Description description) {
}
}
- private void setMetaInfo(final StreamInfo info) {
- final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
- requireContext());
- final boolean showMetaInfo = sp.getBoolean(
- requireContext().getString(R.string.show_meta_info_key), true);
- if (info.getMetaInfo().isEmpty() || !showMetaInfo) {
- detailMetadataInfo.setVisibility(View.GONE);
- detailMetadataInfoSeparator.setVisibility(View.GONE);
- } else {
- final List metaIfs = info.getMetaInfo();
- final StringBuilder stringBuilder = new StringBuilder();
- for (final MetaInfo mi: metaIfs) {
- if (!isNullOrEmpty(mi.getTitle())) {
- stringBuilder.append("
").append(mi.getTitle()).append("
");
- }
- stringBuilder.append(mi.getContent().getContent());
- for (int i = 0; i < mi.getUrls().size(); i++) {
- stringBuilder
- .append(" ")
- .append(mi.getUrlTexts().get(i))
- .append("");
- if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) {
- // append line break to all but the last URL if there are multiple URLs
- stringBuilder.append(" ");
- }
- }
- }
-
- detailMetadataInfoSeparator.setVisibility(View.VISIBLE);
- detailMetadataInfoText.setText(HtmlCompat.fromHtml(
- stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
- detailMetadataInfoText.setMovementMethod(LinkMovementMethod.getInstance());
- detailMetadataInfo.setVisibility(View.VISIBLE);
- }
- }
-
private final ViewTreeObserver.OnPreDrawListener preDrawListener =
new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -1606,7 +1566,7 @@ public void handleResult(@NonNull final StreamInfo info) {
prepareDescription(info.getDescription());
updateProgressInfo(info);
initThumbnailViews(info);
- setMetaInfo(info);
+ showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator);
if (player == null || player.isPlayerStopped()) {
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index f44e5e33086..2dac6d11b38 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -9,7 +9,6 @@
import android.text.Html;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -80,8 +79,8 @@
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static java.util.Arrays.asList;
-import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
+import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public class SearchFragment extends BaseListFragment>
implements BackPressable {
@@ -160,6 +159,7 @@ public class SearchFragment extends BaseListFragment").append(mi.getTitle()).append("");
- }
- stringBuilder.append(mi.getContent().getContent());
- for (int i = 0; i < mi.getUrls().size(); i++) {
- stringBuilder
- .append(" ")
- .append(mi.getUrlTexts().get(i))
- .append("");
- if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) {
- // append line break to all but the last URL if there are multiple URLs
- stringBuilder.append(" ");
- }
- }
- }
-
- metaInfoTextView.setText(HtmlCompat.fromHtml(
- stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
- metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance());
- metaInfoTextView.setVisibility(View.VISIBLE);
- }
- }
-
@Override
public void handleNextItems(final ListExtractor.InfoItemsPage> result) {
showListFooter(false);
diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
index 650c5ae116d..1f1b945452a 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
@@ -22,9 +22,16 @@
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
+import android.text.method.LinkMovementMethod;
import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.core.text.HtmlCompat;
+import androidx.preference.PreferenceManager;
+
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
@@ -32,6 +39,7 @@
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.ListInfo;
+import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
@@ -60,6 +68,8 @@
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single;
+import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
+
public final class ExtractorHelper {
private static final String TAG = ExtractorHelper.class.getSimpleName();
private static final InfoCache CACHE = InfoCache.getInstance();
@@ -306,4 +316,73 @@ public static void handleGeneralException(final Context context, final int servi
}
});
}
+
+ /**
+ * Formats the text contained in the meta info list as HTML and puts it into the text view,
+ * while also making the separator visible. If the list is null or empty, or the user chose not
+ * to see meta information, both the text view and the separator are hidden
+ * @param metaInfos a list of meta information, can be null or empty
+ * @param metaInfoTextView the text view in which to show the formatted HTML
+ * @param metaInfoSeparator another view to be shown or hidden accordingly to the text view
+ */
+ public static void showMetaInfoInTextView(@Nullable final List metaInfos,
+ final TextView metaInfoTextView,
+ final View metaInfoSeparator) {
+ final Context context = metaInfoTextView.getContext();
+ final boolean showMetaInfo = PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(context.getString(R.string.show_meta_info_key), true);
+
+ if (!showMetaInfo || metaInfos == null || metaInfos.isEmpty()) {
+ metaInfoTextView.setVisibility(View.GONE);
+ metaInfoSeparator.setVisibility(View.GONE);
+
+ } else {
+ final StringBuilder stringBuilder = new StringBuilder();
+ for (final MetaInfo metaInfo : metaInfos) {
+ if (!isNullOrEmpty(metaInfo.getTitle())) {
+ stringBuilder.append("").append(metaInfo.getTitle()).append("")
+ .append(Localization.DOT_SEPARATOR);
+ }
+
+ String content = metaInfo.getContent().getContent().trim();
+ if (content.endsWith(".")) {
+ content = content.substring(0, content.length() - 1); // remove . at end
+ }
+ stringBuilder.append(content);
+
+ for (int i = 0; i < metaInfo.getUrls().size(); i++) {
+ if (i == 0) {
+ stringBuilder.append(Localization.DOT_SEPARATOR);
+ } else {
+ stringBuilder.append("
");
+ }
+
+ stringBuilder
+ .append("")
+ .append(capitalizeIfAllUppercase(metaInfo.getUrlTexts().get(i).trim()))
+ .append("");
+ }
+ }
+
+ metaInfoTextView.setText(HtmlCompat.fromHtml(stringBuilder.toString(),
+ HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
+ metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance());
+ metaInfoTextView.setVisibility(View.VISIBLE);
+ metaInfoSeparator.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private static String capitalizeIfAllUppercase(final String text) {
+ for (int i = 0; i < text.length(); i++) {
+ if (Character.isLowerCase(text.charAt(i))) {
+ return text; // there is at least a lowercase letter -> not all uppercase
+ }
+ }
+
+ if (text.isEmpty()) {
+ return text;
+ } else {
+ return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase();
+ }
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java
index 71082786492..978f558c46a 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Localization.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java
@@ -57,7 +57,7 @@
public final class Localization {
- private static final String DOT_SEPARATOR = " • ";
+ public static final String DOT_SEPARATOR = " • ";
private static PrettyTime prettyTime;
private Localization() { }
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index d59d2db730f..d90c782ef24 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -507,36 +507,21 @@
-
-
-
-
-
-
+ android:gravity="center"
+ android:padding="12dp"
+ android:textSize="@dimen/video_item_detail_description_text_size"
+ tools:text="Stream meta info with link" />
+
diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml
index 3bf2bb02569..758a88f1993 100644
--- a/app/src/main/res/layout/fragment_video_detail.xml
+++ b/app/src/main/res/layout/fragment_video_detail.xml
@@ -492,37 +492,21 @@
-
-
-
-
-
-
-
+ android:gravity="center"
+ android:padding="12dp"
+ android:textSize="@dimen/video_item_detail_description_text_size"
+ tools:text="Stream meta info with link" />
Date: Sun, 20 Dec 2020 18:31:51 +0100
Subject: [PATCH 37/52] Change NewPipe's domain in original ReadMe
---
README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 2568b7624b8..c66bcfa7fb9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
NewPipe
A libre lightweight streaming frontend for Android.
*Read this in other languages: [English](README.md), [한국어](README.ko.md).*
@@ -83,7 +83,7 @@ NewPipe supports multiple services. Our [docs](https://teamnewpipe.github.io/doc
## Updates
When a change to the NewPipe code occurs (due to either adding features or bug fixing), eventually a release will occur. These are in the format x.xx.x . In order to get this new version, you can:
1. Build a debug APK yourself. This is the fastest way to get new features on your device, but is much more complicated, so we recommend using one of the other methods.
- 2. Add our custom repo to F-Droid and install it from there as soon as we publish a release. The instructions are here: https://newpipe.schabi.org/FAQ/tutorials/install-add-fdroid-repo/
+ 2. Add our custom repo to F-Droid and install it from there as soon as we publish a release. The instructions are here: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
3. Download the APK from [Github Releases](https://github.com/TeamNewPipe/NewPipe/releases) and install it as soon as we publish a release.
4. Update via F-droid. This is the slowest method of getting updates, as F-Droid must recognize changes, build the APK itself, sign it, then push the update to users.
@@ -106,7 +106,7 @@ If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTI
## Donate
-If you like NewPipe we'd be happy about a donation. You can either send bitcoin or donate via Bountysource or Liberapay. For further info on donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
+If you like NewPipe we'd be happy about a donation. You can either send bitcoin or donate via Bountysource or Liberapay. For further info on donating to NewPipe, please visit our [website](https://newpipe.net/donate).
@@ -129,7 +129,7 @@ If you like NewPipe we'd be happy about a donation. You can either send bitcoin
## Privacy Policy
The NewPipe project aims to provide a private, anonymous experience for using media web services.
-Therefore, the app does not collect any data without your consent. NewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report, or comment in our blog. You can find the document [here](https://newpipe.schabi.org/legal/privacy/).
+Therefore, the app does not collect any data without your consent. NewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report, or comment in our blog. You can find the document [here](https://newpipe.net/legal/privacy/).
## License
[](http://www.gnu.org/licenses/gpl-3.0.en.html)
From e4aa7a90c7351bd5479557ba09b82a89d7979e97 Mon Sep 17 00:00:00 2001
From: TiA4f8R <74829229+TiA4f8R@users.noreply.github.com>
Date: Sun, 20 Dec 2020 18:36:01 +0100
Subject: [PATCH 38/52] Change NewPipe's domain in Korean ReadMe
---
README.ko.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.ko.md b/README.ko.md
index bb6bd653b0a..a86eae8d939 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -1,4 +1,4 @@
-
+
NewPipe
A libre lightweight streaming frontend for Android.
*Read this in other languages: [English](README.md), [한국어](README.ko.md).*
@@ -86,7 +86,7 @@ NewPipe 코드의 변경이 있을 때(기능 추가 또는 버그 수정으로
1. 직접 디버그 APK를 생성할 수 있습니다. 이 방법은 당신의 기기에서 새로운 기능을 얻을 수 있는 가장 빠른 방법이지만, 꽤 많이 복잡합니다.
따라서 우리는 다른 방법들 중 하나를 사용하는 것을 추천합니다.
2. 우리의 커스텀 저장소를 F-Droid에 추가하고 우리가 릴리즈를 게시하는 대로 저곳에서 릴리즈를 설치할 수 있습니다.
- 이에 대한 설명서는 이곳에서 확인할 수 있습니다: https://newpipe.schabi.org/FAQ/tutorials/install-add-fdroid-repo/
+ 이에 대한 설명서는 이곳에서 확인할 수 있습니다: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
3. 우리가 릴리즈를 게시하는 대로 [Github Releases](https://github.com/TeamNewPipe/NewPipe/releases)에서 APK를 다운받고 이것을 설치할 수 있습니다.
4. F-Droid를 통해 업데이트 할 수 있습니다. F-Droid는 변화를 인식하고, 스스로 APK를 생성하고, 이것에 서명하고, 사용자들에서 업데이트를 전달해야만 하기 때문에,
이것은 업데이트를 받는 가장 느린 방법입니다.
@@ -111,7 +111,7 @@ NewPipe 코드의 변경이 있을 때(기능 추가 또는 버그 수정으로
## Donate
-만약 NewPipe가 마음에 들었다면, 우리는 기부에 대해 기꺼이 환영합니다. bitcoin을 보내거나, Bountysource 또는 Liberapay를 통해 기부할 수 있습니다. NewPipe에 기부하는 것에 대한 자세한 정보를 원한다면, 우리의 [웹사이트](https://newpipe.schabi.org/donate)를 방문하여 주십시오.
+만약 NewPipe가 마음에 들었다면, 우리는 기부에 대해 기꺼이 환영합니다. bitcoin을 보내거나, Bountysource 또는 Liberapay를 통해 기부할 수 있습니다. NewPipe에 기부하는 것에 대한 자세한 정보를 원한다면, 우리의 [웹사이트](https://newpipe.net/donate)를 방문하여 주십시오.