From 03b2fda9093ceaa9941e4ab73c166bb7c9839bf1 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 6fd62aebe..35e987cb8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -227,20 +227,18 @@
+
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
From dc7f2bf894d20305889421446e514af966837082 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 b0425ebfa..6ef2f732e 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.report.UserAction;
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 class ContentSettingsFragment extends BasePreferenceFragment {
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 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
//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 000000000..b0ea89993
--- /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 000000000..9809fd5fc
--- /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 000000000..cd3fc4717
--- /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 000000000..e69de29bb
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index add17d42d..0a5190b29 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 d9c892099..28ce176f0 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 2d86452c5d943e3eaa86938eaa1ecae71adf7752 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 28ce176f0..af741fdc8 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 ae03327f4cf7d01f4347ee73ddb339a11f322b91 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 af741fdc8..aff6205f2 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 de2e4722ad9e0903c608aae85cbb21507765a348 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 f51ecf2d3..4a8582df2 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 @@ public class MainActivity extends AppCompatActivity {
}
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 @@ public class MainActivity extends AppCompatActivity {
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 5efffe118..ca3da9d24 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 @@ public class Mp4FromDashWriter {
// 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 13ba64602bce4a6a28fd7a88fdaa61c62f651f0e 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 000000000..6419c65dd
--- /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 1714c70d5..000000000
--- 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 0b6bd53c81743251d36e36b52d3d274d46c32ee3 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 6effa7615..121f74ee1 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 49b8dd0eba550b414cc0edc15a173aed025c711a 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 0217368da..e120750fc 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 288a9ce2affb2a83d7ce72058d37e73eb3f18ee5 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 de401d4f5..e6dce4d67 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 @@ public class App extends MultiDexApplication {
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 @@ public class App extends MultiDexApplication {
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 be7d78299..f102206c1 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 android.widget.Toast;
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 @@ public class MissionAdapter extends Adapter implements Handler.Callb
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 f96518ccf..bc70e793b 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 342a003cd21a15129aa225125ba00e689c9187ce 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 87215b385..5a8689f70 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 d1a964fb2..6fa7eb700 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.MenuInflater;
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.database.playlist.model.PlaylistRemoteEntity;
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.Localization;
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.CompositeDisposable;
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 class PlaylistFragment extends BaseListInfoFragment {
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 @@ public class PlaylistFragment extends BaseListInfoFragment {
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 c93d36eb5..74da07998 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 bc68d6f95f759c05d1ad29ea83c5417f612c7c5d 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 | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 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 b0425ebfa..1ef52cd82 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 android.widget.Toast;
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 class ContentSettingsFragment extends BasePreferenceFragment {
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
+ 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");
- 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");
+ newpipeSettings = new File(homeDir, "/databases/newpipe.settings");
newpipeSettings.delete();
addPreferencesFromResource(R.xml.content_settings);
From 3712843a78060d1a950619ac3cf92d74ce3eaff6 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 4a8582df2..a5c963ee6 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.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;
import androidx.fragment.app.Fragment;
@@ -218,7 +219,7 @@ public class MainActivity extends AppCompatActivity {
toggleServices();
}
if (lastService != ServiceHelper.getSelectedServiceId(MainActivity.this)) {
- new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
+ ActivityCompat.recreate(MainActivity.this);
}
}
});
@@ -497,10 +498,7 @@ public class MainActivity extends AppCompatActivity {
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 d1c2be014..4bf6ef9ae 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 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;
import androidx.recyclerview.widget.RecyclerView;
@@ -140,7 +141,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 ab875ed5d..8126bd2c5 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.provider.Settings;
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 class AppearanceSettingsFragment extends BasePreferenceFragment {
if (!newValue.equals(startThemeKey) && getActivity() != null) {
// If it's not the current theme
- getActivity().recreate();
+ ActivityCompat.recreate(requireActivity());
}
return false;
From 571bf8e51281cc8c7530254f10f6fd4af2a536cc 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 916630ae6..0fecc3f96 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 @@ public final class 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 ab82bad2da0a1c28935e17eefc35cd0108a90395 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 bc70e793b..ecb690044 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 be8716c0ea06985714dc189cbfeaf69bfe869314 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 b0ea89993..2682ac5e0 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 8455bafdef5c8747fd9053e2452b05931472b9c5 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 9809fd5fc..5ac132f7f 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
+ companion object {
+ private lateinit var newpipeDb: File
+ private lateinit var newpipeSettings: File
- @Before
- fun beforeClass() {
+ @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)
- 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!!)
+ 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 14584b2f12852f2fd3628655720b2ca791d43136 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 c962ed99d..03c9ae4af 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 @@ public class ReCaptchaActivity extends AppCompatActivity {
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 000000000..b9f6887f9
--- /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 c93d36eb5..74da07998 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 53885fe61b82480d51286ddcf849d7111b99fea6 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 03c9ae4af..b6f65c355 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 @@ public class ReCaptchaActivity extends AppCompatActivity {
// 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 class ReCaptchaActivity extends AppCompatActivity {
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 class ReCaptchaActivity extends AppCompatActivity {
@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 f078cebcc9eae74863158dad335847450d3c63c0 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 5a8689f70..4acff01bf 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 d3627002792341cd9430a8ead472a3be1c1c287d 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 13e3c1b5f..8aee89ab0 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 a5c963ee6..ff078fa2c 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.View;
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.fragment.app.FragmentManager;
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 @@ public class MainActivity extends AppCompatActivity {
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 @@ public class MainActivity extends AppCompatActivity {
}
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 @@ public class MainActivity extends AppCompatActivity {
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 class MainActivity extends AppCompatActivity {
}
});
- drawerItems.setNavigationItemSelectedListener(this::drawerItemSelected);
+ drawerLayoutBinding.navigation.setNavigationItemSelectedListener(this::drawerItemSelected);
setupDrawerHeader();
}
@@ -247,15 +248,17 @@ public class MainActivity extends AppCompatActivity {
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 @@ public class MainActivity extends AppCompatActivity {
}
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 @@ public class MainActivity extends AppCompatActivity {
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 @@ public class MainActivity extends AppCompatActivity {
}
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 @@ public class MainActivity extends AppCompatActivity {
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 class MainActivity extends AppCompatActivity {
}
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 class MainActivity extends AppCompatActivity {
}
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 @@ public class MainActivity extends AppCompatActivity {
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 @@ public class MainActivity extends AppCompatActivity {
// 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 @@ public class MainActivity extends AppCompatActivity {
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 class MainActivity extends AppCompatActivity {
}
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 class MainActivity extends AppCompatActivity {
// 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 class MainActivity extends AppCompatActivity {
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 @@ public class MainActivity extends AppCompatActivity {
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 class MainActivity extends AppCompatActivity {
}
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 4a8befa2c..6d25ed097 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 02f7f1d50132a2565d32329039680ad18ae2bf43 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 e3e56816c..6ff691561 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.LayoutInflater;
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 class AboutActivity extends AppCompatActivity {
}
@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 54b45404a02dce0cd25a639d87629b7a62da0287 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.
---
.../schabi/newpipe/download/DownloadActivity.java | 13 ++++++++-----
app/src/main/res/layout/activity_downloader.xml | 4 +++-
2 files changed, 11 insertions(+), 6 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 979f8be75..37eefed96 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 android.view.ViewTreeObserver;
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 @@ public class DownloadActivity extends AppCompatActivity {
assureCorrectAppLanguage(this);
ThemeHelper.setTheme(this);
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_downloader);
- final Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ super.onCreate(savedInstanceState);
+
+ 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 272f6e76e..d91b943e7 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 b6f65c355..dfe062a16 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.Nullable;
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 class ReCaptchaActivity extends AppCompatActivity {
}
}
-
- 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 class ReCaptchaActivity extends AppCompatActivity {
});
// 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 class ReCaptchaActivity extends AppCompatActivity {
}
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 6ba6323b6564afe3703ff92fd00e89a29a04b157 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 9ad993de1..e04970e86 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.LayoutInflater;
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.core.widget.TextViewCompat;
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 @@ public class RouterActivity extends AppCompatActivity {
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 @@ public class RouterActivity extends AppCompatActivity {
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 9c7e1ecfa0a12b5073132fde26ebab2ee4d1616e 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 4bf6ef9ae..41d66dc90 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.Menu;
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.PlaybackParameters;
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
}
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 abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 abstract class ServicePlayerActivity extends AppCompatActivity
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 abstract class ServicePlayerActivity extends AppCompatActivity
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 abstract class ServicePlayerActivity extends AppCompatActivity
if (player != null) {
player.seekTo(seekBar.getProgress());
}
- seekDisplay.setVisibility(View.GONE);
+ queueControlBinding.seekDisplay.setVisibility(View.GONE);
seeking = false;
}
@@ -602,45 +557,46 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
}
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 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
//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 2c5d9ee1a9b48cc806e68efc01d93a53b3aade1d 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 3213821cd..a4b6af2ab 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.Menu;
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.ActivityCommunicator;
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 @@ public class ErrorActivity extends AppCompatActivity {
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 @@ public class ErrorActivity extends AppCompatActivity {
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 @@ public class ErrorActivity extends AppCompatActivity {
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 @@ public class ErrorActivity extends AppCompatActivity {
}
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 @@ public class ErrorActivity extends AppCompatActivity {
+ BuildConfig.VERSION_NAME + "\n"
+ getOsString();
- infoView.setText(text);
+ activityErrorBinding.errorInfosView.setText(text);
}
private String buildJson() {
@@ -374,7 +362,8 @@ public class ErrorActivity extends AppCompatActivity {
.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 @@ public class ErrorActivity extends AppCompatActivity {
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 @@ public class ErrorActivity extends AppCompatActivity {
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 f265c2658..4feea549c 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 d2d4c2404..4de166a55 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 android.view.MenuItem;
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 @@ public class SettingsActivity extends AppCompatActivity
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 d50924c46..32c6c6b91 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 8e0671554b13f78340b11b802d79c39a0c588c6f 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 4acff01bf..15561b2d2 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 f7d4e5800ffcbf588ad7adbf968d71a40d1a312c 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 dfe062a16..463fc24ac 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.util.Log;
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 @@ public class ReCaptchaActivity extends AppCompatActivity {
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 da095794a41cb3e43e3c168b79daae6435a7c785 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 e04970e86..98a0921e4 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.AlertDialog;
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 class RouterActivity extends AppCompatActivity {
@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 ddbbea23d..2a0aa1c90 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 73c0d23a0..34543b565 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.Nullable;
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 @@ public abstract class BaseImportExportService extends Service {
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 860ace84c..c1c2e4eba 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.Nullable;
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 @@ public final class NotificationUtil {
}
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 b43733a51..e77196445 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.IBinder;
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 class DownloadManagerService extends Service {
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 class DownloadManagerService extends Service {
if (state) {
startForeground(FOREGROUND_NOTIFICATION_ID, mNotification);
} else {
- stopForeground(true);
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
}
manageLock(state);
From ef4a1e16e73b0fbfcfea5fe08d2aa39e78e8be59 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 15561b2d2..3ac8ff525 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 342c248a91997953b8c9394b185972e53fa4d8f2 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 3cbcb87a3..a304b4430 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 org.schabi.newpipe.util.ShareUtils;
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 @@ public class VideoPlayerImpl extends VideoPlayer
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 a88d3a8a68c4d5578acbd8e7ae10ba427611a30f 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 15561b2d2..fadfc3221 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 866b324ec..a77109f86 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 @@ package org.schabi.newpipe.fragments;
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.appcompat.app.AppCompatActivity;
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 427cff06e..b9cb4ab2b 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.Bundle;
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.R;
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.CompositeDisposable;
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 final class VideoDetailFragment
}
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 final class VideoDetailFragment
}
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 @@ public final class VideoDetailFragment
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 @@ public final class VideoDetailFragment
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 final class VideoDetailFragment
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 @@ public final class VideoDetailFragment
}
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 @@ public final class VideoDetailFragment
}
}
+ 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 final class VideoDetailFragment
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 final class VideoDetailFragment
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 @@ public final class VideoDetailFragment
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 final class VideoDetailFragment
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 02dbf176b..f44e5e330 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.Editable;
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.ReCaptchaActivity;
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 io.reactivex.rxjava3.subjects.PublishSubject;
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 @@ 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/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 8aee89ab0..d59d2db73 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 0df85fe95..3bf2bb025 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 ecb690044..d2dd8afd5 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 c885366ec..914fb2e59 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 b9cb4ab2b..6560ab404 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.Bundle;
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.R;
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 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;
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 @@ public final class VideoDetailFragment
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 @@ public final class VideoDetailFragment
}
}
- 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 final class VideoDetailFragment
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 f44e5e330..2dac6d11b 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.Editable;
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 io.reactivex.rxjava3.subjects.PublishSubject;
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 650c5ae11..1f1b94545 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 @@ package org.schabi.newpipe.util;
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.Info;
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 java.util.List;
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 final class ExtractorHelper {
}
});
}
+
+ /**
+ * 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 710827864..978f558c4 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 @@ import java.util.Locale;
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 d59d2db73..d90c782ef 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 3bf2bb025..758a88f19 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 2568b7624..c66bcfa7f 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 4d13cd5ccc6b391d3c1feaf58fc50bb2dccf3da0 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 bb6bd653b..a86eae8d9 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)를 방문하여 주십시오.