mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-11-06 14:52:32 +01:00
Compare commits
227 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ada0cee656 | ||
|
|
6dde524d2c | ||
|
|
6a631e1915 | ||
|
|
bb6fa343cf | ||
|
|
7557acde6c | ||
|
|
25ed8952f9 | ||
|
|
b93d94b0bd | ||
|
|
33d75fd2fb | ||
|
|
28a9855fd2 | ||
|
|
9aad07621c | ||
|
|
384cde6eaa | ||
|
|
5ae98661ad | ||
|
|
8f4d9ceca9 | ||
|
|
83d9a1233e | ||
|
|
522a287d79 | ||
|
|
e052d4660d | ||
|
|
39b0b2f032 | ||
|
|
0223d6d200 | ||
|
|
808ce72078 | ||
|
|
3a84c47176 | ||
|
|
20c2426128 | ||
|
|
bf11d4c9fa | ||
|
|
783c0f79d7 | ||
|
|
98b94bd9c4 | ||
|
|
ff0178f965 | ||
|
|
7f88c3d0a9 | ||
|
|
11e8e38f2c | ||
|
|
50c5314eaf | ||
|
|
a7a76d4f58 | ||
|
|
4df4f68fe1 | ||
|
|
7db8d37137 | ||
|
|
b7503a7d81 | ||
|
|
9f5d4034e3 | ||
|
|
3c941f6c4b | ||
|
|
ec8fff421a | ||
|
|
a47a0b5432 | ||
|
|
96ba46f21d | ||
|
|
90f48d5817 | ||
|
|
7288dd097a | ||
|
|
0119d62a35 | ||
|
|
4d6ab73fa9 | ||
|
|
f58c95840a | ||
|
|
ecf24f81ec | ||
|
|
dd3306a940 | ||
|
|
bbb2b98f27 | ||
|
|
bc7332780d | ||
|
|
6f3bc3ac8f | ||
|
|
cd04d869b7 | ||
|
|
909e15cbdd | ||
|
|
33fa30ab78 | ||
|
|
44933ac17a | ||
|
|
bb2af96deb | ||
|
|
1fe6da14ea | ||
|
|
b7b9653c21 | ||
|
|
8adc5918f8 | ||
|
|
0db593b1bb | ||
|
|
a0c9dbeb78 | ||
|
|
61d5546d89 | ||
|
|
f97b7c943b | ||
|
|
97549b633b | ||
|
|
1949e4a9d4 | ||
|
|
ecb5f7a5ba | ||
|
|
6021f72cf0 | ||
|
|
c00ef74f96 | ||
|
|
962e070150 | ||
|
|
221cbf5e07 | ||
|
|
a72d37ab69 | ||
|
|
f92227e5df | ||
|
|
c50617452f | ||
|
|
3957eca94d | ||
|
|
70111cf614 | ||
|
|
f9e03c9a40 | ||
|
|
88fbdf1cc4 | ||
|
|
7b76bd79e8 | ||
|
|
f4b58e649d | ||
|
|
91ff301d53 | ||
|
|
f5e1c99259 | ||
|
|
abdcd3cc30 | ||
|
|
23615a39ac | ||
|
|
5fa5fc39fc | ||
|
|
01b3c7e91b | ||
|
|
e4e364af3f | ||
|
|
f2358692af | ||
|
|
26ed6299e3 | ||
|
|
3a85187111 | ||
|
|
4261a2eed3 | ||
|
|
fef17163a9 | ||
|
|
9dd447a14f | ||
|
|
ecf4407ba4 | ||
|
|
039c0d3ee6 | ||
|
|
5808aead55 | ||
|
|
e797e2e7f1 | ||
|
|
23cacbfe65 | ||
|
|
4f94ee9b72 | ||
|
|
0d1a26298a | ||
|
|
8ccd0b23e9 | ||
|
|
9d8b991354 | ||
|
|
d273f69852 | ||
|
|
eee3ccafc3 | ||
|
|
3686e90e81 | ||
|
|
1a5d9da2bf | ||
|
|
21a7a73f6d | ||
|
|
5090b41eef | ||
|
|
0e55aa6249 | ||
|
|
dd2dcf4df2 | ||
|
|
2e84b28998 | ||
|
|
e6cbfea5a7 | ||
|
|
641d662944 | ||
|
|
09208e183b | ||
|
|
fba3ece688 | ||
|
|
f7d849a3cc | ||
|
|
709c700cc6 | ||
|
|
2da411c1ec | ||
|
|
d6e4f3c809 | ||
|
|
1bb08db8ba | ||
|
|
2ba116b1e6 | ||
|
|
7088de0fb9 | ||
|
|
7084f73d6c | ||
|
|
69374e25fe | ||
|
|
5e16969d61 | ||
|
|
0fe5a44e5a | ||
|
|
98e617001d | ||
|
|
979bd09b29 | ||
|
|
77678b8f31 | ||
|
|
3575cac9d7 | ||
|
|
8cdeaf1b27 | ||
|
|
08a8c6c414 | ||
|
|
fa5c1b22ae | ||
|
|
a99e7f3288 | ||
|
|
a29506ed2f | ||
|
|
1434b40d03 | ||
|
|
6d6609187b | ||
|
|
9682eaae2a | ||
|
|
1cdb4ccc17 | ||
|
|
2a878dffbc | ||
|
|
49f4fb7ed7 | ||
|
|
caa985660a | ||
|
|
3842a1e4fb | ||
|
|
e06d83cb93 | ||
|
|
67df894448 | ||
|
|
d1ec6cf21b | ||
|
|
537c561cee | ||
|
|
a65ddc5b36 | ||
|
|
1fb1b3a784 | ||
|
|
b80879765c | ||
|
|
10919fe15b | ||
|
|
9e5fe1edca | ||
|
|
03ee3f3d2a | ||
|
|
4113283069 | ||
|
|
56c5f696df | ||
|
|
9beb76e641 | ||
|
|
f71403be58 | ||
|
|
d0e5d36b1b | ||
|
|
fdeb7543ca | ||
|
|
90716f4f5b | ||
|
|
54d41bc288 | ||
|
|
d63c7a9042 | ||
|
|
cd5b60cbed | ||
|
|
6d60e6698a | ||
|
|
d53cb01396 | ||
|
|
8baaecab1b | ||
|
|
1368f9f89e | ||
|
|
ce36f3ae3b | ||
|
|
cf147aa161 | ||
|
|
7700cff5e5 | ||
|
|
b883f313ba | ||
|
|
b1ee22cde6 | ||
|
|
b32f149a1b | ||
|
|
1d136c6c35 | ||
|
|
b8a17580c5 | ||
|
|
87febf8679 | ||
|
|
38b2ffd450 | ||
|
|
01e031e7e7 | ||
|
|
0b1eda3050 | ||
|
|
52cdf96dfe | ||
|
|
1f5eba59c5 | ||
|
|
372c2f2be0 | ||
|
|
25e0b46396 | ||
|
|
d3332583b6 | ||
|
|
cb5cf9bb09 | ||
|
|
6cb2c2a84e | ||
|
|
633137fd79 | ||
|
|
9627fdf33f | ||
|
|
b39366c80a | ||
|
|
ac01c49666 | ||
|
|
80d16ea407 | ||
|
|
4f44f26333 | ||
|
|
a21bdb1487 | ||
|
|
4d6a2f40d3 | ||
|
|
e6773aac0e | ||
|
|
997381d0c3 | ||
|
|
ac53eeb76d | ||
|
|
a09c8934fc | ||
|
|
b4120c39e6 | ||
|
|
5d6320d925 | ||
|
|
985bf50f7f | ||
|
|
84d21af644 | ||
|
|
267cd99b04 | ||
|
|
401960079c | ||
|
|
1fbc8a2850 | ||
|
|
16fe5a94ac | ||
|
|
1c20a4d9eb | ||
|
|
3a9f30d954 | ||
|
|
856aacf8ce | ||
|
|
441b510775 | ||
|
|
88a10b5af1 | ||
|
|
65205ace95 | ||
|
|
1a4ef06ee9 | ||
|
|
64ac631040 | ||
|
|
4e4cabb929 | ||
|
|
b242c86869 | ||
|
|
d37fee346a | ||
|
|
cc52d3b0af | ||
|
|
d5b1bae305 | ||
|
|
04e22faf85 | ||
|
|
48cb3ed138 | ||
|
|
ebdeee8b3c | ||
|
|
6449d7d4ee | ||
|
|
4b775d15a2 | ||
|
|
e4d6a453b0 | ||
|
|
9dcbcd57cb | ||
|
|
17aa44c88b | ||
|
|
60dc266e13 | ||
|
|
60ed308caa | ||
|
|
c485e7e167 | ||
|
|
71a8361580 | ||
|
|
3d1cc348c8 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -32,7 +32,7 @@ Do not report crashes in the GitHub issue tracker. NewPipe has an automated cras
|
||||
* Please test (compile and run) your code before you submit changes! Ideally, provide test feedback in the PR description. Untested code will **not** be merged!
|
||||
* Try to figure out yourself why builds on our CI fail.
|
||||
* Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job, but if not, you are asked to merge the master branch manually and resolve the problems on your own. That will make the maintainers' jobs way easier.
|
||||
* Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again about sumission, or clearly state that in the description of your PR.
|
||||
* Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again about submission, or clearly state that in the description of your PR.
|
||||
* Respond yourselves if someone requests changes or otherwise raises issues about your PRs.
|
||||
* Check if your contributions align with the [fdroid inclusion guidelines](https://f-droid.org/en/docs/Inclusion_Policy/).
|
||||
* Check if your submission can be build with the current fdroid build server setup.
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1 +1 @@
|
||||
- [ ] I carefully reed the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.
|
||||
- [ ] I carefully read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@
|
||||
gradle.properties
|
||||
*~
|
||||
.weblate
|
||||
*.class
|
||||
|
||||
@@ -5,11 +5,13 @@ android:
|
||||
components:
|
||||
# The BuildTools version used by NewPipe
|
||||
- tools
|
||||
- build-tools-26.0.1
|
||||
- build-tools-27.0.1
|
||||
|
||||
# The SDK version used to compile NewPipe
|
||||
- android-26
|
||||
- android-27
|
||||
|
||||
before_install:
|
||||
- yes | sdkmanager "platforms;android-27"
|
||||
script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest
|
||||
|
||||
licenses:
|
||||
|
||||
170
CheckTranslations.java
Normal file
170
CheckTranslations.java
Normal file
@@ -0,0 +1,170 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public final class CheckTranslations {
|
||||
|
||||
private static boolean debug = false;
|
||||
private static boolean plurals = false;
|
||||
private static boolean empty = false;
|
||||
private static boolean remove = false;
|
||||
private static int checks = 0;
|
||||
private static int matches = 0;
|
||||
private static int changes = 0;
|
||||
private static Pattern p, pb, pe, e, o;
|
||||
|
||||
/**
|
||||
* Search translated strings.xml files for empty item / plural tags
|
||||
* and remove them.
|
||||
* @param args directories which contain string.xml files (in any subdirectory)
|
||||
* -e option to find all empty string tags
|
||||
* -p option to find all empty plurals and item tags
|
||||
* -r option to remove all occurrences from the files
|
||||
* -d option to see more details
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length < 1 || (args[0].equals("-d") && args.length < 2)) {
|
||||
System.out.println("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "-d":
|
||||
debug = true;
|
||||
break;
|
||||
case "-p":
|
||||
plurals = true;
|
||||
break;
|
||||
case "-e":
|
||||
empty = true;
|
||||
break;
|
||||
case "-r":
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!plurals && !empty) {
|
||||
plurals = true;
|
||||
empty = true;
|
||||
}
|
||||
|
||||
p = Pattern.compile("(<item quantity=\")(zero|one|two|three|few|many|other)(\"></item>|\"/>)");
|
||||
pb = Pattern.compile("(<plurals[\\sa-zA-Z=\"]*>)");
|
||||
pe = Pattern.compile("(</plurals>)");
|
||||
e = Pattern.compile("(<string[\\sa-z_\\\"=]*)((><\\/string>|\\/>){1})");
|
||||
o = Pattern.compile("(<item quantity=\"other\">)[^</>]*(<\\/item>)");
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!args[i].equals("-d") && !args[i].equals("-p") && !args[i].equals("-e") && !args[i].equals("-r")) {
|
||||
File f = new File(args[i]);
|
||||
if (f.exists() && !f.isDirectory()) {
|
||||
checkFile(f);
|
||||
} else if (f.isDirectory()) {
|
||||
checkFiles(f.listFiles());
|
||||
} else {
|
||||
System.out.println("'" + args[i] + "' does not exist!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(checks + " files were checked.");
|
||||
System.out.println(matches + " corrupt lines detected.");
|
||||
if (remove) {
|
||||
System.out.println(matches + " corrupt lines removed and " + changes + " lines fixed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void checkFiles(File[] f) {
|
||||
for (int i = 0; i < f.length; i++) {
|
||||
if (f[i].exists() && !f[i].isDirectory()) {
|
||||
if (f[i].toString().contains("strings.xml")) {
|
||||
checkFile(f[i]);
|
||||
}
|
||||
} else if (f[i].isDirectory()) {
|
||||
checkFiles(f[i].listFiles());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkFile(File f) {
|
||||
// Do not check our original English strings to cause no unwanted changes
|
||||
// Btw. there should not be empty plural/item tags
|
||||
if (f.toString().contains("values/strings.xml")) {
|
||||
return;
|
||||
}
|
||||
if (debug) System.out.println("Checking " + f.toString());
|
||||
checks++;
|
||||
|
||||
|
||||
List<String> lines = new ArrayList<String>();
|
||||
boolean checkFailed = false;
|
||||
boolean otherDetected = false;
|
||||
boolean inPlurals = false;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
|
||||
String line;
|
||||
int ln = 0;
|
||||
while ((line = br.readLine()) != null) {
|
||||
ln++;
|
||||
if (plurals && p.matcher(line).find()) {
|
||||
matches++;
|
||||
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
|
||||
checkFailed = true;
|
||||
} else if (empty && e.matcher(line).find()) {
|
||||
matches++;
|
||||
checkFailed = true;
|
||||
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
|
||||
} else {
|
||||
if (remove) lines.add(line);
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
int pluralsLine = 0;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (o.matcher(lines.get(i)).find()) {
|
||||
otherDetected = true;
|
||||
}
|
||||
if (plurals && pb.matcher(lines.get(i)).find()) {
|
||||
inPlurals = true;
|
||||
pluralsLine = i;
|
||||
} else if (plurals && pe.matcher(lines.get(i)).find()) {
|
||||
inPlurals = false;
|
||||
if (!otherDetected) {
|
||||
boolean b = false;
|
||||
check: for(int j = pluralsLine; j < i; j++) {
|
||||
if (lines.get(j).contains("many")) {
|
||||
b = true;
|
||||
pluralsLine = j;
|
||||
break check;
|
||||
}
|
||||
}
|
||||
if (remove && b) {
|
||||
if (debug) System.out.println(" Line " + (pluralsLine + 1) + " was " + ((remove) ? "changed" : "detected") + ": '" + lines.get(pluralsLine) + "'");
|
||||
lines.set(pluralsLine, lines.get(pluralsLine).replace("many", "other"));
|
||||
changes++;
|
||||
checkFailed = true;
|
||||
} else if (debug) {
|
||||
if (debug) System.out.println(" WARNING: Line " + (i + 1) + " - No <item quantity=\"other\"> found!");
|
||||
}
|
||||
}
|
||||
otherDetected = false;
|
||||
}
|
||||
|
||||
}
|
||||
if (remove && checkFailed) {
|
||||
Files.write(f.toPath(), lines, Charset.forName("UTF-8"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
README.md
21
README.md
@@ -13,21 +13,22 @@
|
||||
</p>
|
||||
<hr />
|
||||
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#description">Description</a> • <a href="#features">Features</a> • <a href="#contribution">Contribution</a> • <a href="#donate">Donate</a> • <a href="#license">License</a></p>
|
||||
<p align="center"><a href="https://newpipe.schabi.org">Website</a> • <a href="https://newpipe.schabi.org/blog/">Blog</a> • <a href="https://newpipe.schabi.org/press/">Press</a></p>
|
||||
<hr />
|
||||
WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
|
||||
|
||||
## Screenshots
|
||||
|
||||
[<img src="screenshots/shot_1.png" width=160>](screenshots/shot_1.png)
|
||||
[<img src="screenshots/shot_2.png" width=160>](screenshots/shot_2.png)
|
||||
[<img src="screenshots/shot_3.png" width=160>](screenshots/shot_3.png)
|
||||
[<img src="screenshots/shot_4.png" width=160>](screenshots/shot_4.png)
|
||||
[<img src="screenshots/shot_5.png" width=160>](screenshots/shot_5.png)
|
||||
[<img src="screenshots/shot_6.png" width=160>](screenshots/shot_6.png)
|
||||
[<img src="screenshots/shot_7.png" width=160>](screenshots/shot_7.png)
|
||||
[<img src="screenshots/shot_8.png" width=160>](screenshots/shot_8.png)
|
||||
[<img src="screenshots/shot_9.png" width=160>](screenshots/shot_9.png)
|
||||
[<img src="screenshots/shot_10.png" width=160>](screenshots/shot_10.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_1.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_1.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_2.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_2.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_3.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_3.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_4.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_4.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_5.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_5.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_6.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_6.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_7.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_7.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
|
||||
## Description
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.1'
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '27.0.1'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.schabi.newpipe"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 26
|
||||
versionCode 41
|
||||
versionName "0.11.0"
|
||||
targetSdkVersion 27
|
||||
versionCode 45
|
||||
versionName "0.11.4"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@@ -27,6 +27,10 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
beta {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
||||
applicationIdSuffix ".beta"
|
||||
}
|
||||
}
|
||||
@@ -38,48 +42,51 @@ android {
|
||||
abortOnError false
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
supportLibVersion = '27.0.2'
|
||||
}
|
||||
dependencies {
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
|
||||
compile 'com.github.TeamNewPipe:NewPipeExtractor:b9d0941'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:9de63f8c0a170a066'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:1.10.19'
|
||||
|
||||
compile 'com.android.support:appcompat-v7:26.0.1'
|
||||
compile 'com.android.support:support-v4:26.0.1'
|
||||
compile 'com.android.support:design:26.0.1'
|
||||
compile 'com.android.support:recyclerview-v7:26.0.1'
|
||||
compile 'com.android.support:preference-v14:26.0.1'
|
||||
implementation "com.android.support:appcompat-v7:$supportLibVersion"
|
||||
implementation "com.android.support:support-v4:$supportLibVersion"
|
||||
implementation "com.android.support:design:$supportLibVersion"
|
||||
implementation "com.android.support:recyclerview-v7:$supportLibVersion"
|
||||
implementation "com.android.support:preference-v14:$supportLibVersion"
|
||||
|
||||
compile 'com.google.code.gson:gson:2.7'
|
||||
compile 'ch.acra:acra:4.9.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.2'
|
||||
implementation 'ch.acra:acra:4.9.2'
|
||||
|
||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||
compile 'de.hdodenhof:circleimageview:2.1.0'
|
||||
compile 'com.github.nirhart:parallaxscroll:1.0'
|
||||
compile 'com.nononsenseapps:filepicker:3.0.1'
|
||||
compile 'com.google.android.exoplayer:exoplayer:r2.5.4'
|
||||
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
||||
implementation 'com.github.nirhart:ParallaxScroll:dd53d1f9d1'
|
||||
implementation 'com.nononsenseapps:filepicker:3.0.1'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:r2.5.4'
|
||||
|
||||
debugCompile 'com.facebook.stetho:stetho:1.5.0'
|
||||
debugCompile 'com.facebook.stetho:stetho-urlconnection:1.5.0'
|
||||
debugCompile 'com.android.support:multidex:1.0.1'
|
||||
debugImplementation 'com.facebook.stetho:stetho:1.5.0'
|
||||
debugImplementation 'com.facebook.stetho:stetho-urlconnection:1.5.0'
|
||||
debugImplementation 'com.android.support:multidex:1.0.2'
|
||||
|
||||
compile 'io.reactivex.rxjava2:rxjava:2.1.2'
|
||||
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.1.7'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||
implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
||||
|
||||
compile 'android.arch.persistence.room:runtime:1.0.0-alpha8'
|
||||
compile 'android.arch.persistence.room:rxjava2:1.0.0-alpha8'
|
||||
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0-alpha8'
|
||||
implementation 'android.arch.persistence.room:runtime:1.0.0'
|
||||
implementation 'android.arch.persistence.room:rxjava2:1.0.0'
|
||||
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
|
||||
|
||||
compile 'frankiesardo:icepick:3.2.0'
|
||||
provided 'frankiesardo:icepick-processor:3.2.0'
|
||||
implementation 'frankiesardo:icepick:3.2.0'
|
||||
annotationProcessor 'frankiesardo:icepick-processor:3.2.0'
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
android:name=".RouterPopupActivity"
|
||||
android:label="@string/popup_mode_share_menu_title"
|
||||
android:taskAffinity=""
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
android:theme="@style/PopupPermissionsTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
|
||||
|
||||
@@ -18,9 +18,9 @@ public class RouterPopupActivity extends RouterActivity {
|
||||
|
||||
@Override
|
||||
protected void handleUrl(String url) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& !PermissionHelper.checkSystemAlertWindowPermission(this)) {
|
||||
Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
|
||||
if (!PermissionHelper.isPopupEnabled(this)) {
|
||||
PermissionHelper.showPopupEnablementToast(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
StreamingService service;
|
||||
|
||||
@@ -135,8 +135,12 @@ public class AboutActivity extends AppCompatActivity {
|
||||
View githubLink = rootView.findViewById(R.id.github_link);
|
||||
githubLink.setOnClickListener(new OnGithubLinkClickListener());
|
||||
|
||||
View licenseLink = rootView.findViewById(R.id.app_read_license);
|
||||
licenseLink.setOnClickListener(new OnReadFullLicenseClickListener());
|
||||
View donationLink = rootView.findViewById(R.id.donation_link);
|
||||
donationLink.setOnClickListener(new OnDonationLinkClickListener());
|
||||
|
||||
View websiteLink = rootView.findViewById(R.id.website_link);
|
||||
websiteLink.setOnClickListener(new OnWebsiteLinkClickListener());
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@@ -149,10 +153,21 @@ public class AboutActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private static class OnReadFullLicenseClickListener implements View.OnClickListener {
|
||||
private static class OnDonationLinkClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LicenseFragment.showLicense(v.getContext(), StandardLicenses.GPL3);
|
||||
public void onClick(final View view) {
|
||||
final Context context = view.getContext();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.donation_url)));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private static class OnWebsiteLinkClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
final Context context = view.getContext();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.website_url)));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ public class LicenseFragment extends Fragment {
|
||||
View rootView = inflater.inflate(R.layout.fragment_licenses, container, false);
|
||||
ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
|
||||
|
||||
View licenseLink = rootView.findViewById(R.id.app_read_license);
|
||||
licenseLink.setOnClickListener(new OnReadFullLicenseClickListener());
|
||||
|
||||
for (final SoftwareComponent component : softwareComponents) {
|
||||
View componentView = inflater.inflate(R.layout.item_software_component, container, false);
|
||||
TextView softwareName = componentView.findViewById(R.id.name);
|
||||
@@ -119,4 +122,11 @@ public class LicenseFragment extends Fragment {
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(componentLink));
|
||||
startActivity(browserIntent);
|
||||
}
|
||||
|
||||
private static class OnReadFullLicenseClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LicenseFragment.showLicense(v.getContext(), StandardLicenses.GPL3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class WatchHistoryEntry extends HistoryEntry {
|
||||
}
|
||||
|
||||
public WatchHistoryEntry(StreamInfo streamInfo) {
|
||||
this(new Date(), streamInfo.service_id, streamInfo.name, streamInfo.url,
|
||||
this(new Date(), streamInfo.getServiceId(), streamInfo.getName(), streamInfo.getUrl(),
|
||||
streamInfo.id, streamInfo.thumbnail_url, streamInfo.uploader_name, streamInfo.duration);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,10 +116,7 @@ public class SubscriptionEntity {
|
||||
|
||||
@Ignore
|
||||
public ChannelInfoItem toChannelInfoItem() {
|
||||
ChannelInfoItem item = new ChannelInfoItem();
|
||||
item.url = getUrl();
|
||||
item.service_id = getServiceId();
|
||||
item.name = getName();
|
||||
ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
||||
item.thumbnail_url = getAvatarUrl();
|
||||
item.subscriber_count = getSubscriberCount();
|
||||
item.description = getDescription();
|
||||
|
||||
@@ -108,8 +108,8 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
nameEditText = view.findViewById(R.id.file_name);
|
||||
nameEditText.setText(FilenameUtils.createFilename(getContext(), currentInfo.name));
|
||||
selectedAudioIndex = ListHelper.getDefaultAudioFormat(getContext(), currentInfo.audio_streams);
|
||||
nameEditText.setText(FilenameUtils.createFilename(getContext(), currentInfo.getName()));
|
||||
selectedAudioIndex = ListHelper.getDefaultAudioFormat(getContext(), currentInfo.getAudioStreams());
|
||||
|
||||
streamsSpinner = view.findViewById(R.id.quality_spinner);
|
||||
streamsSpinner.setOnItemSelectedListener(this);
|
||||
@@ -183,7 +183,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||
String[] items = new String[audioStreams.size()];
|
||||
for (int i = 0; i < audioStreams.size(); i++) {
|
||||
AudioStream audioStream = audioStreams.get(i);
|
||||
items[i] = MediaFormat.getNameById(audioStream.format) + " " + audioStream.average_bitrate + "kbps";
|
||||
items[i] = audioStream.getFormat().getName() + " " + audioStream.getAverageBitrate() + "kbps";
|
||||
}
|
||||
|
||||
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, items);
|
||||
@@ -242,7 +242,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||
RadioButton audioButton = view.findViewById(R.id.audio_button);
|
||||
RadioButton videoButton = view.findViewById(R.id.video_button);
|
||||
|
||||
if (currentInfo.audio_streams == null || currentInfo.audio_streams.size() == 0) {
|
||||
if (currentInfo.getAudioStreams() == null || currentInfo.getAudioStreams().size() == 0) {
|
||||
audioButton.setVisibility(View.GONE);
|
||||
videoButton.setChecked(true);
|
||||
} else if (sortedStreamVideosList == null || sortedStreamVideosList.size() == 0) {
|
||||
@@ -256,14 +256,18 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||
String url, location;
|
||||
|
||||
String fileName = nameEditText.getText().toString().trim();
|
||||
if (fileName.isEmpty()) fileName = FilenameUtils.createFilename(getContext(), currentInfo.name);
|
||||
if (fileName.isEmpty()) fileName = FilenameUtils.createFilename(getContext(), currentInfo.getName());
|
||||
|
||||
boolean isAudio = radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button;
|
||||
url = isAudio ? currentInfo.audio_streams.get(selectedAudioIndex).url : sortedStreamVideosList.get(selectedVideoIndex).url;
|
||||
location = isAudio ? NewPipeSettings.getAudioDownloadPath(getContext()) : NewPipeSettings.getVideoDownloadPath(getContext());
|
||||
|
||||
if (isAudio) fileName += "." + MediaFormat.getSuffixById(currentInfo.audio_streams.get(selectedAudioIndex).format);
|
||||
else fileName += "." + MediaFormat.getSuffixById(sortedStreamVideosList.get(selectedVideoIndex).format);
|
||||
if (isAudio) {
|
||||
url = currentInfo.getAudioStreams().get(selectedAudioIndex).getUrl();
|
||||
location = NewPipeSettings.getAudioDownloadPath(getContext());
|
||||
fileName += "." + currentInfo.getAudioStreams().get(selectedAudioIndex).getFormat().getSuffix();
|
||||
} else {
|
||||
url = sortedStreamVideosList.get(selectedVideoIndex).getUrl();
|
||||
location = NewPipeSettings.getVideoDownloadPath(getContext());
|
||||
fileName += "." + sortedStreamVideosList.get(selectedVideoIndex).getFormat().getSuffix();
|
||||
}
|
||||
|
||||
DownloadManagerService.startMission(getContext(), url, location, fileName, isAudio, threadsSeekBar.getProgress() + 1);
|
||||
getDialog().dismiss();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.schabi.newpipe.fragments;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
@@ -18,6 +19,7 @@ import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.ReCaptchaActivity;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
@@ -50,6 +52,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
protected Button errorButtonRetry;
|
||||
protected TextView errorTextView;
|
||||
|
||||
@State
|
||||
protected boolean useAsFrontPage = false;
|
||||
|
||||
@Override
|
||||
@@ -218,6 +221,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
|
||||
if (serviceName == null) serviceName = "none";
|
||||
if (request == null) request = "none";
|
||||
|
||||
ErrorActivity.reportError(getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
|
||||
}
|
||||
|
||||
@@ -238,4 +242,22 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
||||
|
||||
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
protected void openUrlInBrowser(String url) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title)));
|
||||
}
|
||||
|
||||
protected void shareUrl(String subject, String url) {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, url);
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.schabi.newpipe.fragments;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -30,30 +31,28 @@ import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||
import org.schabi.newpipe.fragments.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
||||
private ViewPager viewPager;
|
||||
private boolean showBlankTab = false;
|
||||
|
||||
private static final int FALLBACK_SERVICE_ID = 0; // Youtbe
|
||||
public int currentServiceId = -1;
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
private static final int FALLBACK_SERVICE_ID = 0; // Youtube
|
||||
private static final String FALLBACK_CHANNEL_URL =
|
||||
"https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ";
|
||||
private static final String FALLBACK_CHANNEL_NAME = "Music";
|
||||
private static final String FALLBACK_KIOSK_ID = "Trending";
|
||||
|
||||
public int currentServiceId = -1;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Konst
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private static final int KIOSK_MENU_OFFSETT = 2000;
|
||||
private static final int KIOSK_MENU_OFFSET = 2000;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Fragment's LifeCycle
|
||||
@@ -66,7 +65,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
currentServiceId = Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.getString(getString(R.string.current_service_key), "0"));
|
||||
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||
@@ -86,27 +85,27 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
if(ThemeHelper.isLightThemeSelected(getActivity())) {
|
||||
int channelIcon;
|
||||
int whatsHotIcon;
|
||||
|
||||
if (ThemeHelper.isLightThemeSelected(getActivity())) {
|
||||
tabLayout.setBackgroundColor(getResources().getColor(R.color.light_youtube_primary_color));
|
||||
channelIcon = R.drawable.ic_channel_black_24dp;
|
||||
whatsHotIcon = R.drawable.ic_whatshot_black_24dp;
|
||||
} else {
|
||||
channelIcon = R.drawable.ic_channel_white_24dp;
|
||||
whatsHotIcon = R.drawable.ic_whatshot_white_24dp;
|
||||
}
|
||||
|
||||
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
|
||||
if (PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
|
||||
.equals(getString(R.string.subscription_page_key))) {
|
||||
if(ThemeHelper.isLightThemeSelected(getActivity())) {
|
||||
tabLayout.getTabAt(0).setIcon(R.drawable.ic_channel_black_24dp);
|
||||
} else{
|
||||
tabLayout.getTabAt(0).setIcon(R.drawable.ic_channel_white_24dp);
|
||||
}
|
||||
} else {
|
||||
if(ThemeHelper.isLightThemeSelected(getActivity())) {
|
||||
tabLayout.getTabAt(0).setIcon(R.drawable.ic_whatshot_black_24dp);
|
||||
tabLayout.getTabAt(1).setIcon(R.drawable.ic_channel_black_24dp);
|
||||
} else {
|
||||
tabLayout.getTabAt(0).setIcon(R.drawable.ic_whatshot_white_24dp);
|
||||
tabLayout.getTabAt(1).setIcon(R.drawable.ic_channel_white_24dp);
|
||||
}
|
||||
}
|
||||
tabLayout.getTabAt(0).setIcon(channelIcon);
|
||||
} else {
|
||||
tabLayout.getTabAt(0).setIcon(whatsHotIcon);
|
||||
tabLayout.getTabAt(1).setIcon(channelIcon);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@@ -182,7 +181,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
.equals(getString(R.string.subscription_page_key))) {
|
||||
return new SubscriptionFragment();
|
||||
} else {
|
||||
return getMainPageFramgent();
|
||||
return getMainPageFragment();
|
||||
}
|
||||
case 1:
|
||||
return new SubscriptionFragment();
|
||||
@@ -213,7 +212,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
// Main page content
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private Fragment getMainPageFramgent() {
|
||||
private Fragment getMainPageFragment() {
|
||||
try {
|
||||
SharedPreferences preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
@@ -268,7 +267,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
KioskList kl = service.getKioskList();
|
||||
int i = 0;
|
||||
for(final String ks : kl.getAvailableKiosks()) {
|
||||
menu.add(0, KIOSK_MENU_OFFSETT + i, Menu.NONE,
|
||||
menu.add(0, KIOSK_MENU_OFFSET + i, Menu.NONE,
|
||||
KioskTranslator.getTranslatedKioskName(ks, getContext()))
|
||||
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
|
||||
@@ -60,7 +60,7 @@ public class SpinnerToolbarAdapter extends BaseAdapter {
|
||||
ImageView woSoundIcon = convertView.findViewById(R.id.wo_sound_icon);
|
||||
TextView text = convertView.findViewById(android.R.id.text1);
|
||||
VideoStream item = (VideoStream) getItem(position);
|
||||
text.setText(MediaFormat.getNameById(item.format) + " " + item.resolution);
|
||||
text.setText(item.getFormat().getName() + " " + item.getResolution());
|
||||
|
||||
int visibility = !showIconNoAudio ? View.GONE
|
||||
: item.isVideoOnly ? View.VISIBLE
|
||||
|
||||
@@ -4,7 +4,8 @@ import java.io.Serializable;
|
||||
|
||||
class StackItem implements Serializable {
|
||||
private int serviceId;
|
||||
private String title, url;
|
||||
private String title;
|
||||
private String url;
|
||||
|
||||
StackItem(int serviceId, String url, String title) {
|
||||
this.serviceId = serviceId;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,21 @@
|
||||
package org.schabi.newpipe.fragments.list;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
@@ -19,8 +25,11 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.StateSaver;
|
||||
|
||||
import java.util.List;
|
||||
@@ -137,7 +146,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openVideoDetailFragment(
|
||||
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
|
||||
selectedItem.service_id, selectedItem.url, selectedItem.name);
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void held(StreamInfoItem selectedItem) {
|
||||
showStreamDialog(selectedItem);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -147,8 +161,11 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openChannelFragment(
|
||||
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
|
||||
selectedItem.service_id, selectedItem.url, selectedItem.name);
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void held(ChannelInfoItem selectedItem) {}
|
||||
});
|
||||
|
||||
infoListAdapter.setOnPlaylistSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<PlaylistInfoItem>() {
|
||||
@@ -157,8 +174,11 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(
|
||||
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
|
||||
selectedItem.service_id, selectedItem.url, selectedItem.name);
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void held(PlaylistInfoItem selectedItem) {}
|
||||
});
|
||||
|
||||
itemsList.clearOnScrollListeners();
|
||||
@@ -176,6 +196,34 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
}
|
||||
}
|
||||
|
||||
protected void showStreamDialog(final StreamInfoItem item) {
|
||||
final Context context = getContext();
|
||||
final Activity activity = getActivity();
|
||||
if (context == null || context.getResources() == null || getActivity() == null) return;
|
||||
|
||||
final String[] commands = new String[]{
|
||||
context.getResources().getString(R.string.enqueue_on_background),
|
||||
context.getResources().getString(R.string.enqueue_on_popup)
|
||||
};
|
||||
|
||||
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
|
||||
break;
|
||||
case 1:
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
||||
}
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Menu
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@@ -190,8 +190,8 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
|
||||
public void handleResult(@NonNull I result) {
|
||||
super.handleResult(result);
|
||||
|
||||
url = result.url;
|
||||
name = result.name;
|
||||
url = result.getUrl();
|
||||
name = result.getName();
|
||||
setTitle(name);
|
||||
|
||||
if (infoListAdapter.getItemsList().size() == 0) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -297,12 +297,12 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
// Called only when response is non-empty
|
||||
@Override
|
||||
public void onSuccess(final ChannelInfo channelInfo) {
|
||||
if (infoListAdapter == null || channelInfo.related_streams.isEmpty()) {
|
||||
if (infoListAdapter == null || channelInfo.getRelatedStreams().isEmpty()) {
|
||||
onDone();
|
||||
return;
|
||||
}
|
||||
|
||||
final InfoItem item = channelInfo.related_streams.get(0);
|
||||
final InfoItem item = channelInfo.getRelatedStreams().get(0);
|
||||
// Keep requesting new items if the current one already exists
|
||||
boolean itemExists = doesItemExist(infoListAdapter.getItemsList(), item);
|
||||
if (!itemExists) {
|
||||
@@ -412,9 +412,9 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
||||
private boolean doesItemExist(final List<InfoItem> items, final InfoItem item) {
|
||||
for (final InfoItem existingItem : items) {
|
||||
if (existingItem.info_type == item.info_type &&
|
||||
existingItem.service_id == item.service_id &&
|
||||
existingItem.name.equals(item.name) &&
|
||||
existingItem.url.equals(item.url)) return true;
|
||||
existingItem.getServiceId() == item.getServiceId() &&
|
||||
existingItem.getName().equals(item.getName()) &&
|
||||
existingItem.getUrl().equals(item.getUrl())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -27,6 +28,7 @@ import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import icepick.State;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
@@ -53,16 +55,13 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
|
||||
private String kioskId = "";
|
||||
|
||||
@State
|
||||
protected String kioskId = "";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private View headerRootLayout;
|
||||
private TextView headerTitleView;
|
||||
|
||||
public static KioskFragment getInstance(int serviceId)
|
||||
throws ExtractionException {
|
||||
return getInstance(serviceId, NewPipe.getService(serviceId)
|
||||
@@ -87,21 +86,40 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
// LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedState) {
|
||||
super.onActivityCreated(savedState);
|
||||
try {
|
||||
activity.getSupportActionBar()
|
||||
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
|
||||
} catch (Exception e) {
|
||||
onUnrecoverableError(e, UserAction.UI_ERROR,
|
||||
"none",
|
||||
"none", R.string.app_ui_crash);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if(useAsFrontPage && isVisibleToUser) {
|
||||
if(useAsFrontPage && isVisibleToUser && activity != null) {
|
||||
try {
|
||||
activity.getSupportActionBar().setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
|
||||
activity.getSupportActionBar()
|
||||
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
|
||||
} catch (Exception e) {
|
||||
onError(e);
|
||||
onUnrecoverableError(e, UserAction.UI_ERROR,
|
||||
"none",
|
||||
"none", R.string.app_ui_crash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_kiosk, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_kiosk, container, false);
|
||||
activity.getSupportActionBar()
|
||||
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
|
||||
return view;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@@ -125,14 +143,18 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
public Single<KioskInfo> loadResult(boolean forceReload) {
|
||||
String contentCountry = PreferenceManager
|
||||
.getDefaultSharedPreferences(activity)
|
||||
.getString(getString(R.string.search_language_key),
|
||||
getString(R.string.default_language_value));
|
||||
.getString(getString(R.string.content_country_key),
|
||||
getString(R.string.default_country_value));
|
||||
return ExtractorHelper.getKioskInfo(serviceId, url, contentCountry, forceReload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<ListExtractor.NextItemsResult> loadMoreItemsLogic() {
|
||||
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextItemsUrl);
|
||||
String contentCountry = PreferenceManager
|
||||
.getDefaultSharedPreferences(activity)
|
||||
.getString(getString(R.string.content_country_key),
|
||||
getString(R.string.default_country_value));
|
||||
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextItemsUrl, contentCountry);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@@ -153,10 +175,10 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||
supportActionBar.setTitle(title);
|
||||
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors,
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(),
|
||||
UserAction.REQUESTED_PLAYLIST,
|
||||
NewPipe.getNameOfService(result.service_id), result.url, 0);
|
||||
NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +186,8 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
public void handleNextItems(ListExtractor.NextItemsResult result) {
|
||||
super.handleNextItems(result);
|
||||
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors,
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(),
|
||||
UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
|
||||
, "Get next page of: " + url, 0);
|
||||
}
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
package org.schabi.newpipe.fragments.list.playlist;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.player.BackgroundPlayer;
|
||||
import org.schabi.newpipe.player.MainVideoPlayer;
|
||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
||||
import org.schabi.newpipe.playlist.ExternalPlayQueue;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
|
||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
|
||||
import io.reactivex.Single;
|
||||
|
||||
@@ -50,10 +48,11 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
private TextView headerUploaderName;
|
||||
private ImageView headerUploaderAvatar;
|
||||
private TextView headerStreamCount;
|
||||
private View playlistCtrl;
|
||||
|
||||
private Button headerPlayAllButton;
|
||||
private Button headerPopupButton;
|
||||
private Button headerBackgroundButton;
|
||||
private View headerPlayAllButton;
|
||||
private View headerPopupButton;
|
||||
private View headerBackgroundButton;
|
||||
|
||||
public static PlaylistFragment getInstance(int serviceId, String url, String name) {
|
||||
PlaylistFragment instance = new PlaylistFragment();
|
||||
@@ -81,10 +80,11 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
headerUploaderName = headerRootLayout.findViewById(R.id.uploader_name);
|
||||
headerUploaderAvatar = headerRootLayout.findViewById(R.id.uploader_avatar_view);
|
||||
headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count);
|
||||
playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control);
|
||||
|
||||
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_play_all_button);
|
||||
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_play_popup_button);
|
||||
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_play_bg_button);
|
||||
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
|
||||
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
|
||||
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
|
||||
|
||||
return headerRootLayout;
|
||||
}
|
||||
@@ -96,6 +96,49 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
infoListAdapter.useMiniItemVariants(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showStreamDialog(final StreamInfoItem item) {
|
||||
final Context context = getContext();
|
||||
final Activity activity = getActivity();
|
||||
if (context == null || context.getResources() == null || getActivity() == null) return;
|
||||
|
||||
final String[] commands = new String[]{
|
||||
context.getResources().getString(R.string.enqueue_on_background),
|
||||
context.getResources().getString(R.string.enqueue_on_popup),
|
||||
context.getResources().getString(R.string.start_here_on_main),
|
||||
context.getResources().getString(R.string.start_here_on_background),
|
||||
context.getResources().getString(R.string.start_here_on_popup),
|
||||
};
|
||||
|
||||
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
|
||||
switch (i) {
|
||||
case 0:
|
||||
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
|
||||
break;
|
||||
case 1:
|
||||
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
|
||||
break;
|
||||
case 2:
|
||||
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
|
||||
break;
|
||||
case 3:
|
||||
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
|
||||
break;
|
||||
case 4:
|
||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
|
||||
@@ -117,6 +160,23 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
return ExtractorHelper.getPlaylistInfo(serviceId, url, forceLoad);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_item_openInBrowser:
|
||||
openUrlInBrowser(url);
|
||||
break;
|
||||
case R.id.menu_item_share: {
|
||||
shareUrl(name, url);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Contract
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@@ -138,69 +198,67 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
animateView(headerRootLayout, true, 100);
|
||||
animateView(headerUploaderLayout, true, 300);
|
||||
headerUploaderLayout.setOnClickListener(null);
|
||||
if (!TextUtils.isEmpty(result.uploader_name)) {
|
||||
headerUploaderName.setText(result.uploader_name);
|
||||
if (!TextUtils.isEmpty(result.uploader_url)) {
|
||||
if (!TextUtils.isEmpty(result.getUploaderName())) {
|
||||
headerUploaderName.setText(result.getUploaderName());
|
||||
if (!TextUtils.isEmpty(result.getUploaderUrl())) {
|
||||
headerUploaderLayout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
NavigationHelper.openChannelFragment(getFragmentManager(), result.service_id, result.uploader_url, result.uploader_name);
|
||||
NavigationHelper.openChannelFragment(getFragmentManager(), result.getServiceId(), result.getUploaderUrl(), result.getUploaderName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
imageLoader.displayImage(result.uploader_avatar_url, headerUploaderAvatar, DISPLAY_AVATAR_OPTIONS);
|
||||
playlistCtrl.setVisibility(View.VISIBLE);
|
||||
|
||||
imageLoader.displayImage(result.getUploaderAvatarUrl(), headerUploaderAvatar, DISPLAY_AVATAR_OPTIONS);
|
||||
headerStreamCount.setText(getResources().getQuantityString(R.plurals.videos, (int) result.stream_count, (int) result.stream_count));
|
||||
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(result.service_id), result.url, 0);
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
|
||||
}
|
||||
|
||||
headerPlayAllButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
startActivity(buildPlaylistIntent(MainVideoPlayer.class));
|
||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue());
|
||||
}
|
||||
});
|
||||
headerPopupButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
|
||||
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
|
||||
TextView messageView = toast.getView().findViewById(android.R.id.message);
|
||||
if (messageView != null) messageView.setGravity(Gravity.CENTER);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
activity.startService(buildPlaylistIntent(PopupVideoPlayer.class));
|
||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue());
|
||||
}
|
||||
});
|
||||
headerBackgroundButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
activity.startService(buildPlaylistIntent(BackgroundPlayer.class));
|
||||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Intent buildPlaylistIntent(final Class targetClazz) {
|
||||
final PlayQueue playQueue = new ExternalPlayQueue(
|
||||
currentInfo.service_id,
|
||||
currentInfo.url,
|
||||
currentInfo.next_streams_url,
|
||||
private PlayQueue getPlayQueue() {
|
||||
return getPlayQueue(0);
|
||||
}
|
||||
|
||||
private PlayQueue getPlayQueue(final int index) {
|
||||
return new PlaylistPlayQueue(
|
||||
currentInfo.getServiceId(),
|
||||
currentInfo.getUrl(),
|
||||
currentInfo.getNextStreamsUrl(),
|
||||
infoListAdapter.getItemsList(),
|
||||
0
|
||||
index
|
||||
);
|
||||
return NavigationHelper.getPlayerIntent(activity, targetClazz, playQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleNextItems(ListExtractor.NextItemsResult result) {
|
||||
super.handleNextItems(result);
|
||||
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId)
|
||||
, "Get next page of: " + url, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
|
||||
private int currentPage = 0;
|
||||
private int currentNextPage = 0;
|
||||
private String searchLanguage;
|
||||
private String contentCountry;
|
||||
private boolean isSuggestionsEnabled = true;
|
||||
private boolean isSearchHistoryEnabled = true;
|
||||
|
||||
@@ -165,7 +165,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
suggestionListAdapter = new SuggestionListAdapter(activity);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
|
||||
suggestionListAdapter.setShowSugestinHistory(isSearchHistoryEnabled);
|
||||
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
||||
|
||||
searchHistoryDAO = NewPipeDatabase.getInstance().searchHistoryDAO();
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
isSuggestionsEnabled = preferences.getBoolean(getString(R.string.show_search_suggestions_key), true);
|
||||
searchLanguage = preferences.getString(getString(R.string.search_language_key), getString(R.string.default_language_value));
|
||||
contentCountry = preferences.getString(getString(R.string.content_country_key), getString(R.string.default_country_value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -446,6 +446,12 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
searchEditText.setText(item.query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuggestionItemInserted(SuggestionItem item) {
|
||||
searchEditText.setText(item.query);
|
||||
searchEditText.setSelection(searchEditText.getText().length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuggestionItemLongClick(SuggestionItem item) {
|
||||
if (item.fromHistory) showDeleteSuggestionDialog(item);
|
||||
@@ -613,7 +619,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
return local.materialize();
|
||||
}
|
||||
|
||||
final Observable<List<SuggestionItem>> network = ExtractorHelper.suggestionsFor(serviceId, query, searchLanguage).toObservable()
|
||||
final Observable<List<SuggestionItem>> network = ExtractorHelper.suggestionsFor(serviceId, query, contentCountry).toObservable()
|
||||
.map(new Function<List<String>, List<SuggestionItem>>() {
|
||||
@Override
|
||||
public List<SuggestionItem> apply(@io.reactivex.annotations.NonNull List<String> strings) throws Exception {
|
||||
@@ -725,7 +731,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
super.startLoading(forceLoad);
|
||||
if (disposables != null) disposables.clear();
|
||||
if (searchDisposable != null) searchDisposable.dispose();
|
||||
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, searchLanguage, filter)
|
||||
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, contentCountry, filter)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<SearchResult>() {
|
||||
@@ -749,7 +755,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
showListFooter(true);
|
||||
if (searchDisposable != null) searchDisposable.dispose();
|
||||
currentNextPage = currentPage + 1;
|
||||
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, searchLanguage, filter)
|
||||
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, contentCountry, filter)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<ListExtractor.NextItemsResult>() {
|
||||
@@ -855,8 +861,8 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
lastSearchedQuery = searchQuery;
|
||||
|
||||
if (infoListAdapter.getItemsList().size() == 0) {
|
||||
if (result.resultList.size() > 0) {
|
||||
infoListAdapter.addInfoItemList(result.resultList);
|
||||
if (!result.getResults().isEmpty()) {
|
||||
infoListAdapter.addInfoItemList(result.getResults());
|
||||
} else {
|
||||
infoListAdapter.clearStreamItemList();
|
||||
showEmptyState();
|
||||
@@ -870,11 +876,11 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
|
||||
@Override
|
||||
public void handleNextItems(ListExtractor.NextItemsResult result) {
|
||||
showListFooter(false);
|
||||
currentPage = Integer.parseInt(result.nextItemsUrl);
|
||||
infoListAdapter.addInfoItemList(result.nextItemsList);
|
||||
currentPage = Integer.parseInt(result.getNextItemsUrl());
|
||||
infoListAdapter.addInfoItemList(result.getNextItemsList());
|
||||
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors, UserAction.SEARCHED, NewPipe.getNameOfService(serviceId)
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED, NewPipe.getNameOfService(serviceId)
|
||||
, "\"" + searchQuery + "\" → page " + currentPage, 0);
|
||||
}
|
||||
super.handleNextItems(result);
|
||||
|
||||
@@ -19,10 +19,11 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
private final ArrayList<SuggestionItem> items = new ArrayList<>();
|
||||
private final Context context;
|
||||
private OnSuggestionItemSelected listener;
|
||||
private boolean showSugestinHistory = true;
|
||||
private boolean showSuggestionHistory = true;
|
||||
|
||||
public interface OnSuggestionItemSelected {
|
||||
void onSuggestionItemSelected(SuggestionItem item);
|
||||
void onSuggestionItemInserted(SuggestionItem item);
|
||||
void onSuggestionItemLongClick(SuggestionItem item);
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
|
||||
public void setItems(List<SuggestionItem> items) {
|
||||
this.items.clear();
|
||||
if (showSugestinHistory) {
|
||||
if (showSuggestionHistory) {
|
||||
this.items.addAll(items);
|
||||
} else {
|
||||
// remove history items if history is disabled
|
||||
@@ -49,8 +50,8 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setShowSugestinHistory(boolean v) {
|
||||
showSugestinHistory = v;
|
||||
public void setShowSuggestionHistory(boolean v) {
|
||||
showSuggestionHistory = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,19 +63,25 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
public void onBindViewHolder(SuggestionItemHolder holder, int position) {
|
||||
final SuggestionItem currentItem = getItem(position);
|
||||
holder.updateFrom(currentItem);
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
holder.queryView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) listener.onSuggestionItemSelected(currentItem);
|
||||
}
|
||||
});
|
||||
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
holder.queryView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (listener != null) listener.onSuggestionItemLongClick(currentItem);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
holder.insertView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) listener.onSuggestionItemInserted(currentItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SuggestionItem getItem(int position) {
|
||||
@@ -93,6 +100,8 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
public static class SuggestionItemHolder extends RecyclerView.ViewHolder {
|
||||
private final TextView itemSuggestionQuery;
|
||||
private final ImageView suggestionIcon;
|
||||
private final View queryView;
|
||||
private final View insertView;
|
||||
|
||||
// Cache some ids, as they can potentially be constantly updated/recycled
|
||||
private final int historyResId;
|
||||
@@ -103,6 +112,9 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
||||
suggestionIcon = rootView.findViewById(R.id.item_suggestion_icon);
|
||||
itemSuggestionQuery = rootView.findViewById(R.id.item_suggestion_query);
|
||||
|
||||
queryView = rootView.findViewById(R.id.suggestion_search);
|
||||
insertView = rootView.findViewById(R.id.suggestion_insert);
|
||||
|
||||
historyResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.history);
|
||||
searchResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.search);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -131,9 +129,12 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
@Override
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name);
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), selectedItem.getServiceId(), selectedItem.url, selectedItem.getName());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void held(ChannelInfoItem selectedItem) {}
|
||||
});
|
||||
|
||||
headerRootLayout.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class SubscriptionService {
|
||||
// Subscriber count changes very often, making this check almost unnecessary.
|
||||
// Consider removing it later.
|
||||
if (!isSubscriptionUpToDate(info, subscription)) {
|
||||
subscription.setData(info.name, info.avatar_url, info.description, info.subscriber_count);
|
||||
subscription.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount());
|
||||
|
||||
return update(subscription);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class SubscriptionService {
|
||||
}
|
||||
};
|
||||
|
||||
return subscriptionTable().getSubscription(info.service_id, info.url)
|
||||
return subscriptionTable().getSubscription(info.getServiceId(), info.getUrl())
|
||||
.firstOrError()
|
||||
.flatMapCompletable(update);
|
||||
}
|
||||
@@ -137,11 +137,11 @@ public class SubscriptionService {
|
||||
}
|
||||
|
||||
private boolean isSubscriptionUpToDate(final ChannelInfo info, final SubscriptionEntity entity) {
|
||||
return info.url.equals(entity.getUrl()) &&
|
||||
info.service_id == entity.getServiceId() &&
|
||||
info.name.equals(entity.getName()) &&
|
||||
info.avatar_url.equals(entity.getAvatarUrl()) &&
|
||||
info.description.equals(entity.getDescription()) &&
|
||||
info.subscriber_count == entity.getSubscriberCount();
|
||||
return info.getUrl().equals(entity.getUrl()) &&
|
||||
info.getServiceId() == entity.getServiceId() &&
|
||||
info.getName().equals(entity.getName()) &&
|
||||
info.getAvatarUrl().equals(entity.getAvatarUrl()) &&
|
||||
info.getDescription().equals(entity.getDescription()) &&
|
||||
info.getSubscriberCount() == entity.getSubscriberCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class InfoItemBuilder {
|
||||
|
||||
public interface OnInfoItemSelectedListener<T extends InfoItem> {
|
||||
void selected(T selectedItem);
|
||||
void held(T selectedItem);
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.schabi.newpipe.info_list;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
|
||||
public class InfoItemDialog {
|
||||
private final AlertDialog dialog;
|
||||
|
||||
public InfoItemDialog(@NonNull final Activity activity,
|
||||
@NonNull final StreamInfoItem info,
|
||||
@NonNull final String[] commands,
|
||||
@NonNull final DialogInterface.OnClickListener actions) {
|
||||
this(activity, commands, actions, info.getName(), info.uploader_name);
|
||||
}
|
||||
|
||||
public InfoItemDialog(@NonNull final Activity activity,
|
||||
@NonNull final String[] commands,
|
||||
@NonNull final DialogInterface.OnClickListener actions,
|
||||
@NonNull final String title,
|
||||
@Nullable final String additionalDetail) {
|
||||
|
||||
final LayoutInflater inflater = activity.getLayoutInflater();
|
||||
final View bannerView = inflater.inflate(R.layout.dialog_title, null);
|
||||
bannerView.setSelected(true);
|
||||
|
||||
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
|
||||
titleView.setText(title);
|
||||
|
||||
TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
|
||||
if (additionalDetail != null) {
|
||||
detailsView.setText(additionalDetail);
|
||||
detailsView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
detailsView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
dialog = new AlertDialog.Builder(activity)
|
||||
.setCustomTitle(bannerView)
|
||||
.setItems(commands, actions)
|
||||
.create();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
||||
if (!(infoItem instanceof ChannelInfoItem)) return;
|
||||
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
||||
|
||||
itemTitleView.setText(item.name);
|
||||
itemTitleView.setText(item.getName());
|
||||
itemAdditionalDetailView.setText(getDetailLine(item));
|
||||
|
||||
itemBuilder.getImageLoader()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user