mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-10-02 03:20:51 +02:00
Compare commits
446 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7ba71e3b37 | ||
![]() |
670a95a01d | ||
![]() |
acea26717c | ||
![]() |
e6bcb4628a | ||
![]() |
c4f08d541d | ||
![]() |
58546751dd | ||
![]() |
5470c9a002 | ||
![]() |
8885b45259 | ||
![]() |
85632b24fc | ||
![]() |
96802c7b5c | ||
![]() |
e5207f8b42 | ||
![]() |
9d573e1b1d | ||
![]() |
dd276aabc1 | ||
![]() |
e4d0635ae1 | ||
![]() |
60f534d7a1 | ||
![]() |
223ddaa9bf | ||
![]() |
1d6c722c28 | ||
![]() |
9c9dd6c7bf | ||
![]() |
7ff48a6d84 | ||
![]() |
645e16fd90 | ||
![]() |
1bb58a10e2 | ||
![]() |
118788436e | ||
![]() |
0b0f7919a2 | ||
![]() |
c8e23fb6ce | ||
![]() |
bc10717f61 | ||
![]() |
e621dd3b28 | ||
![]() |
20208be556 | ||
![]() |
9074733aab | ||
![]() |
ae0ee61e7d | ||
![]() |
ac797196f5 | ||
![]() |
30aa64e9c6 | ||
![]() |
b992add77b | ||
![]() |
88ebd963f7 | ||
![]() |
96baa2978d | ||
![]() |
c01609b858 | ||
![]() |
c89f0e5547 | ||
![]() |
10dfcbf0b9 | ||
![]() |
43446d56c5 | ||
![]() |
e66f2ab36b | ||
![]() |
63def07a0e | ||
![]() |
1ba7710af8 | ||
![]() |
8f13a7ec97 | ||
![]() |
93dff5cf7a | ||
![]() |
6a0450b9f6 | ||
![]() |
fffeadd8ea | ||
![]() |
b697e058d9 | ||
![]() |
14db8b1283 | ||
![]() |
45ad8621cf | ||
![]() |
dee3a18ea8 | ||
![]() |
950cf714d9 | ||
![]() |
652184506b | ||
![]() |
6457cac797 | ||
![]() |
f66c2ba171 | ||
![]() |
6133c97f45 | ||
![]() |
0dc71ce37a | ||
![]() |
c96a05a8f9 | ||
![]() |
c190dc4792 | ||
![]() |
ebf91d27c7 | ||
![]() |
63301ee771 | ||
![]() |
7da827a06a | ||
![]() |
00fc5217f5 | ||
![]() |
04e725bb50 | ||
![]() |
e6617ff8e8 | ||
![]() |
1b0a958436 | ||
![]() |
5053d470f6 | ||
![]() |
8de5c53485 | ||
![]() |
ec3ae7c7b8 | ||
![]() |
c46af7d194 | ||
![]() |
5254e85840 | ||
![]() |
5883f6e763 | ||
![]() |
c02383d7d9 | ||
![]() |
f98e5cc22d | ||
![]() |
9fbb61a744 | ||
![]() |
5191907af0 | ||
![]() |
35a69b4b1d | ||
![]() |
a64f520644 | ||
![]() |
5aced46345 | ||
![]() |
3cd485069d | ||
![]() |
fabb07bb28 | ||
![]() |
2328ea6d07 | ||
![]() |
0375194e7d | ||
![]() |
5a6a6bcc78 | ||
![]() |
c8f475bba1 | ||
![]() |
31f3757880 | ||
![]() |
a60a9bb144 | ||
![]() |
21a90bb7ee | ||
![]() |
2f66913813 | ||
![]() |
d9b042d9e3 | ||
![]() |
ef9044d933 | ||
![]() |
12c9dbf1bf | ||
![]() |
8cc8aa8693 | ||
![]() |
e529b16956 | ||
![]() |
ffe8d4b689 | ||
![]() |
4e5a20ec45 | ||
![]() |
7c9ef58acd | ||
![]() |
d076fe72cd | ||
![]() |
25fbbfaf94 | ||
![]() |
9df27f43de | ||
![]() |
759e9846ad | ||
![]() |
3aeba7ca8a | ||
![]() |
2a44a091c8 | ||
![]() |
4c92aebc3c | ||
![]() |
d4ecd0dfab | ||
![]() |
3f790d01fa | ||
![]() |
e7b068ed8e | ||
![]() |
bd485937c4 | ||
![]() |
8edc332a4e | ||
![]() |
bb5028364b | ||
![]() |
ef070a4e0e | ||
![]() |
6787d0224c | ||
![]() |
8a43e24095 | ||
![]() |
f879f549e4 | ||
![]() |
db55484163 | ||
![]() |
4d8f66f28e | ||
![]() |
7a44061fa3 | ||
![]() |
5d4bb42e39 | ||
![]() |
3a6c22da5c | ||
![]() |
064f0e414a | ||
![]() |
77db3cb6fa | ||
![]() |
b83a1fd102 | ||
![]() |
99c519c065 | ||
![]() |
632e52b38d | ||
![]() |
1b66ffac6c | ||
![]() |
ee9052ad3d | ||
![]() |
550c74da77 | ||
![]() |
ccdd450283 | ||
![]() |
224a607bc3 | ||
![]() |
8fcd23663c | ||
![]() |
ad79a71fbd | ||
![]() |
d862a59349 | ||
![]() |
2d6362dddb | ||
![]() |
ee3ec3a4ea | ||
![]() |
daecfd97c2 | ||
![]() |
200a81d536 | ||
![]() |
8059ac89d3 | ||
![]() |
60f5f07dd6 | ||
![]() |
372d5ce413 | ||
![]() |
6f97819ca7 | ||
![]() |
2b2ee56712 | ||
![]() |
3715326034 | ||
![]() |
6cbb8b1753 | ||
![]() |
806896ea05 | ||
![]() |
fc8746e077 | ||
![]() |
e11df5bb49 | ||
![]() |
37a9e98ebc | ||
![]() |
80b4975188 | ||
![]() |
c4ef40f4dc | ||
![]() |
6a4bb6e3e1 | ||
![]() |
05ef926a7f | ||
![]() |
0007451735 | ||
![]() |
e599de038a | ||
![]() |
61472a995f | ||
![]() |
2a41802f36 | ||
![]() |
1d1cee17c3 | ||
![]() |
e99266f9d8 | ||
![]() |
1f2cd064f7 | ||
![]() |
9c2cf9eef7 | ||
![]() |
38b0b79644 | ||
![]() |
5252834075 | ||
![]() |
162df5eb6c | ||
![]() |
ac5e2e0532 | ||
![]() |
f0ba6afbdf | ||
![]() |
04a5f43472 | ||
![]() |
a15ef4b7ce | ||
![]() |
f1f9147433 | ||
![]() |
3c0d7de377 | ||
![]() |
2a57d74f1a | ||
![]() |
79717859b3 | ||
![]() |
be423939ed | ||
![]() |
086cceb271 | ||
![]() |
a14033afb7 | ||
![]() |
cc89a342ed | ||
![]() |
25c3669564 | ||
![]() |
21eff0b2ec | ||
![]() |
472fd72c82 | ||
![]() |
429a9a42d3 | ||
![]() |
90c525e99a | ||
![]() |
196117998a | ||
![]() |
630cbc77a8 | ||
![]() |
b6e4afe321 | ||
![]() |
59085ff8c8 | ||
![]() |
a4274c6301 | ||
![]() |
b4ef44b343 | ||
![]() |
08bc97582b | ||
![]() |
3952c88510 | ||
![]() |
b1f27b9da7 | ||
![]() |
171b258d5c | ||
![]() |
af971b6a19 | ||
![]() |
7ca026393b | ||
![]() |
f8784ae3c7 | ||
![]() |
3ddc3acf4c | ||
![]() |
ff430f5e33 | ||
![]() |
daf2890161 | ||
![]() |
4ca639323d | ||
![]() |
a92bf155a3 | ||
![]() |
d153772eb2 | ||
![]() |
cdc8fe86ce | ||
![]() |
4844037ce9 | ||
![]() |
691c1e1a37 | ||
![]() |
bd55b91a86 | ||
![]() |
8842f53696 | ||
![]() |
ffed9f6116 | ||
![]() |
50e8f45601 | ||
![]() |
8cbfe9e6cf | ||
![]() |
99ad3dc292 | ||
![]() |
6908355d38 | ||
![]() |
7b948f83c3 | ||
![]() |
34b2b96158 | ||
![]() |
d1573a0a6e | ||
![]() |
16d6bda85d | ||
![]() |
4b3eb2ece5 | ||
![]() |
1089de6321 | ||
![]() |
d00dc798f4 | ||
![]() |
f6b32823ba | ||
![]() |
9e34fee58c | ||
![]() |
1684a2110c | ||
![]() |
5e00e34552 | ||
![]() |
ce204eba62 | ||
![]() |
c7cb652322 | ||
![]() |
f8ccc3128e | ||
![]() |
4a8baaef45 | ||
![]() |
a9f3939c83 | ||
![]() |
d8cb950248 | ||
![]() |
aefc51db4b | ||
![]() |
fb18ea7ff8 | ||
![]() |
407c61e212 | ||
![]() |
d8e6ad48ca | ||
![]() |
bd42f4188f | ||
![]() |
f766f383ea | ||
![]() |
1a9922d790 | ||
![]() |
6213623431 | ||
![]() |
2809ee7a3e | ||
![]() |
281cae7a18 | ||
![]() |
1670751c94 | ||
![]() |
e1ead9d2ef | ||
![]() |
359a9a96d6 | ||
![]() |
b6cfb8a3dc | ||
![]() |
6f028ecb19 | ||
![]() |
8695466690 | ||
![]() |
bdb1be9967 | ||
![]() |
9395df4cc3 | ||
![]() |
93edb333d4 | ||
![]() |
30eeef46c2 | ||
![]() |
8b584f3922 | ||
![]() |
0c354c4fdb | ||
![]() |
bd7413119a | ||
![]() |
f26915aab6 | ||
![]() |
f6068dc69d | ||
![]() |
bd2c65cd94 | ||
![]() |
4777910644 | ||
![]() |
66b26e52ce | ||
![]() |
a758267d72 | ||
![]() |
72eae64698 | ||
![]() |
d63c18f7f0 | ||
![]() |
b05e3ca8d8 | ||
![]() |
0a88100b67 | ||
![]() |
43b859f778 | ||
![]() |
d1bd7f695f | ||
![]() |
312e1378d3 | ||
![]() |
55d6825f63 | ||
![]() |
e4f9af7076 | ||
![]() |
ff52fe4884 | ||
![]() |
0ab29b7c1f | ||
![]() |
d742ed7b65 | ||
![]() |
a684e380b7 | ||
![]() |
c90feaf3db | ||
![]() |
460610f672 | ||
![]() |
46511533aa | ||
![]() |
40efed6580 | ||
![]() |
78b1c1eb4a | ||
![]() |
5a59a3dd50 | ||
![]() |
0763280196 | ||
![]() |
93f2518159 | ||
![]() |
273f731dd5 | ||
![]() |
c7cd9e86ac | ||
![]() |
41fb6f5464 | ||
![]() |
03b1a8bd41 | ||
![]() |
e7d0685ebc | ||
![]() |
aadbfe1eed | ||
![]() |
4a54fbb872 | ||
![]() |
8b1836d699 | ||
![]() |
c47d4fd35a | ||
![]() |
a58af1275c | ||
![]() |
1d63b39553 | ||
![]() |
c300d52b29 | ||
![]() |
5314e275bc | ||
![]() |
08f8b9770a | ||
![]() |
a9c64b2fec | ||
![]() |
1edfa78a05 | ||
![]() |
1df8af35d4 | ||
![]() |
f47c5e53b1 | ||
![]() |
a48cbc6971 | ||
![]() |
73be8cf074 | ||
![]() |
002a1412cb | ||
![]() |
049cd2d236 | ||
![]() |
e99714eba6 | ||
![]() |
4e1423d224 | ||
![]() |
4751075e87 | ||
![]() |
416e0fb609 | ||
![]() |
f96a371464 | ||
![]() |
e423192265 | ||
![]() |
e9444e058c | ||
![]() |
037632fbf0 | ||
![]() |
6cdea85a49 | ||
![]() |
f86d755890 | ||
![]() |
98cc97251a | ||
![]() |
562f414e3e | ||
![]() |
1afc301432 | ||
![]() |
115b44585b | ||
![]() |
3ff47623d5 | ||
![]() |
943e03f9d8 | ||
![]() |
f7a534a0d0 | ||
![]() |
72e30d8e40 | ||
![]() |
eb265300fc | ||
![]() |
704b8f61dd | ||
![]() |
40957c445f | ||
![]() |
8eead9fda2 | ||
![]() |
aadc8168be | ||
![]() |
cb33f04bfc | ||
![]() |
82cb71bf3f | ||
![]() |
c37b88a239 | ||
![]() |
de59bf695d | ||
![]() |
592627b013 | ||
![]() |
9ed1fb2588 | ||
![]() |
8232a92653 | ||
![]() |
09eeaa92d1 | ||
![]() |
1e4b1a2c70 | ||
![]() |
0a1e7a7c86 | ||
![]() |
e5f3b2bf6e | ||
![]() |
29183c10ff | ||
![]() |
46b8bdace7 | ||
![]() |
9b6924ec9f | ||
![]() |
c69de107e5 | ||
![]() |
c4d451e420 | ||
![]() |
be6bce5771 | ||
![]() |
9bcccc87e6 | ||
![]() |
bf845be727 | ||
![]() |
e92a5414d1 | ||
![]() |
657125f43c | ||
![]() |
e98f68e93b | ||
![]() |
bef84e9eec | ||
![]() |
6a5f2402c7 | ||
![]() |
d6cc6ba144 | ||
![]() |
07f8dcb3ca | ||
![]() |
a026143a84 | ||
![]() |
73a5b6738d | ||
![]() |
3e2b12ae4a | ||
![]() |
8073364b7a | ||
![]() |
b141d96e7c | ||
![]() |
a86e8b98fe | ||
![]() |
a7d77716f3 | ||
![]() |
b017e439b1 | ||
![]() |
a7156f665a | ||
![]() |
44e34d084e | ||
![]() |
065820ffa4 | ||
![]() |
26991928ae | ||
![]() |
f4fa68c390 | ||
![]() |
8b86f9ea6d | ||
![]() |
48f966e7db | ||
![]() |
d8746dc592 | ||
![]() |
6421d3017e | ||
![]() |
f9e771f8f7 | ||
![]() |
09456ce421 | ||
![]() |
716f7e722b | ||
![]() |
ffa4b1483f | ||
![]() |
76f7165462 | ||
![]() |
fdf0d8e9c8 | ||
![]() |
6651aa924f | ||
![]() |
369fd95e2b | ||
![]() |
e242adec66 | ||
![]() |
58e562f7d4 | ||
![]() |
70238fd773 | ||
![]() |
fc4e007cc4 | ||
![]() |
b7667ce97a | ||
![]() |
1315da0da7 | ||
![]() |
c4d8eae547 | ||
![]() |
b01fc1be62 | ||
![]() |
c46e3cf5cb | ||
![]() |
1a6b915112 | ||
![]() |
2f38943488 | ||
![]() |
06711dc6c3 | ||
![]() |
cc7e342ab7 | ||
![]() |
5b64743987 | ||
![]() |
a84ad031d9 | ||
![]() |
c4c2fe2a9c | ||
![]() |
8ccaef454c | ||
![]() |
27579dff37 | ||
![]() |
389d08c233 | ||
![]() |
5412a087fe | ||
![]() |
dd0f3ac651 | ||
![]() |
4d4d776e4d | ||
![]() |
7877b107c1 | ||
![]() |
a2aa0aa9a8 | ||
![]() |
b3475d30c0 | ||
![]() |
6484c8d636 | ||
![]() |
587cf554f2 | ||
![]() |
1d4e4eb6b3 | ||
![]() |
31c4ed7d0e | ||
![]() |
7f246b2d3d | ||
![]() |
7d68cff700 | ||
![]() |
4d80bdcc9f | ||
![]() |
8b4a94e5aa | ||
![]() |
111ad14ad3 | ||
![]() |
aec3f19d23 | ||
![]() |
d8b80f961a | ||
![]() |
891bb7fa40 | ||
![]() |
0e3af45466 | ||
![]() |
6aebbc3109 | ||
![]() |
15eb7f3186 | ||
![]() |
fb4cd98014 | ||
![]() |
eb692dea59 | ||
![]() |
d8039fb542 | ||
![]() |
5e06d19d77 | ||
![]() |
963f390336 | ||
![]() |
2309e15261 | ||
![]() |
8491035b2f | ||
![]() |
4d4107aefc | ||
![]() |
67d2b9131e | ||
![]() |
da8644168c | ||
![]() |
c0004e988a | ||
![]() |
b9187445e0 | ||
![]() |
554ebf7ab9 | ||
![]() |
3e54cd7284 | ||
![]() |
a7afc23a9a | ||
![]() |
fa3a047519 | ||
![]() |
f4d215664e | ||
![]() |
84894a557a | ||
![]() |
ffad6e4c61 | ||
![]() |
93b266e6be | ||
![]() |
f92ea28581 | ||
![]() |
85213e4b6c | ||
![]() |
4e46119e18 | ||
![]() |
fdc6e9f1c3 | ||
![]() |
cb20f1e212 | ||
![]() |
e3fccd7125 | ||
![]() |
15142c1ec3 | ||
![]() |
49fe8a427a | ||
![]() |
4587428d13 | ||
![]() |
5318e77035 | ||
![]() |
0cb5197ccf | ||
![]() |
c0aca723da | ||
![]() |
28e5ee51ec | ||
![]() |
7ab10aeb80 | ||
![]() |
9316962e47 | ||
![]() |
505c528194 | ||
![]() |
e4409e8ea4 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
liberapay: TeamNewPipe
|
11
README.md
11
README.md
@@ -66,15 +66,22 @@ NewPipe does not use any Google framework libraries, nor the YouTube API. Websit
|
|||||||
* Enqueue videos
|
* Enqueue videos
|
||||||
* Local playlists
|
* Local playlists
|
||||||
* Subtitles
|
* Subtitles
|
||||||
* Multi-service support (e.g. SoundCloud \[beta\])
|
|
||||||
* Livestream support
|
* Livestream support
|
||||||
|
* Show comments
|
||||||
|
|
||||||
### Coming Features
|
### Coming Features
|
||||||
|
|
||||||
* Cast to UPnP and Cast
|
* Cast to UPnP and Cast
|
||||||
* Show comments
|
|
||||||
* … and many more
|
* … and many more
|
||||||
|
|
||||||
|
### Supported Services
|
||||||
|
|
||||||
|
NewPipe supports multiple services. Our [docs](https://teamnewpipe.github.io/documentation/) provide more info on how a new service can be added to the app and the extractor. Please get in touch with us if you intend to add a new one. Currently supported services are:
|
||||||
|
|
||||||
|
* YouTube
|
||||||
|
* SoundCloud \[beta\]
|
||||||
|
* media.ccc.de \[beta\]
|
||||||
|
|
||||||
## Updates
|
## 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:
|
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:
|
||||||
* 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.
|
* 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.
|
||||||
|
@@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 720
|
versionCode 760
|
||||||
versionName "0.16.0"
|
versionName "0.17.1"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@@ -44,10 +44,10 @@ android {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
supportLibVersion = '28.0.0'
|
supportLibVersion = '28.0.0'
|
||||||
exoPlayerLibVersion = '2.8.4' //2.9.0
|
exoPlayerLibVersion = '2.9.6'
|
||||||
roomDbLibVersion = '1.1.1'
|
roomDbLibVersion = '1.1.1'
|
||||||
leakCanaryLibVersion = '1.5.4' //1.6.1
|
leakCanaryLibVersion = '1.5.4' //1.6.1
|
||||||
okHttpLibVersion = '3.11.0'
|
okHttpLibVersion = '3.12.1'
|
||||||
icepickLibVersion = '3.2.0'
|
icepickLibVersion = '3.2.0'
|
||||||
stethoLibVersion = '1.5.0'
|
stethoLibVersion = '1.5.0'
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ dependencies {
|
|||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
})
|
})
|
||||||
|
|
||||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:8de53111d9'
|
implementation 'com.github.teamnewpipe:NewPipeExtractor:cfc72d8dc9d'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation 'org.mockito:mockito-core:2.23.0'
|
testImplementation 'org.mockito:mockito-core:2.23.0'
|
||||||
|
@@ -2,16 +2,19 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationManagerCompat;
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -45,6 +48,8 @@ import okhttp3.Response;
|
|||||||
*/
|
*/
|
||||||
public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
private static final String TAG = CheckForNewAppVersionTask.class.getSimpleName();
|
||||||
private static final Application app = App.getApp();
|
private static final Application app = App.getApp();
|
||||||
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 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 newPipeApiUrl = "https://newpipe.schabi.org/api/data.json";
|
private static final String newPipeApiUrl = "https://newpipe.schabi.org/api/data.json";
|
||||||
@@ -69,6 +74,8 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
@Override
|
@Override
|
||||||
protected String doInBackground(Void... voids) {
|
protected String doInBackground(Void... voids) {
|
||||||
|
|
||||||
|
if(isCancelled() || !isConnected()) return null;
|
||||||
|
|
||||||
// Make a network request to get latest NewPipe data.
|
// Make a network request to get latest NewPipe data.
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
|
||||||
@@ -86,9 +93,8 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
Response response = client.newCall(request).execute();
|
Response response = client.newCall(request).execute();
|
||||||
return response.body().string();
|
return response.body().string();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ErrorActivity.reportError(app, ex, null, null,
|
// connectivity problems, do not alarm user and fail silently
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
if (DEBUG) Log.w(TAG, Log.getStackTraceString(ex));
|
||||||
"app update API fail", R.string.app_ui_crash));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -113,9 +119,8 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
||||||
|
|
||||||
} catch (JSONException ex) {
|
} catch (JSONException ex) {
|
||||||
ErrorActivity.reportError(app, ex, null, null,
|
// connectivity problems, do not alarm user and fail silently
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
if (DEBUG) Log.w(TAG, Log.getStackTraceString(ex));
|
||||||
"could not parse app update JSON data", R.string.app_ui_crash));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,4 +232,12 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
|
|
||||||
return getCertificateSHA1Fingerprint().equals(GITHUB_APK_SHA1);
|
return getCertificateSHA1Fingerprint().equals(GITHUB_APK_SHA1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isConnected() {
|
||||||
|
|
||||||
|
ConnectivityManager cm =
|
||||||
|
(ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
return cm.getActiveNetworkInfo() != null
|
||||||
|
&& cm.getActiveNetworkInfo().isConnected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -164,7 +164,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||||||
final ResponseBody body = response.body();
|
final ResponseBody body = response.body();
|
||||||
|
|
||||||
if (response.code() == 429) {
|
if (response.code() == 429) {
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested");
|
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
@@ -214,7 +214,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||||||
final ResponseBody body = response.body();
|
final ResponseBody body = response.body();
|
||||||
|
|
||||||
if (response.code() == 429) {
|
if (response.code() == 429) {
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested");
|
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
@@ -268,7 +268,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||||||
final ResponseBody body = response.body();
|
final ResponseBody body = response.body();
|
||||||
|
|
||||||
if (response.code() == 429) {
|
if (response.code() == 429) {
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested");
|
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
|
@@ -37,15 +37,24 @@ import android.webkit.WebViewClient;
|
|||||||
*/
|
*/
|
||||||
public class ReCaptchaActivity extends AppCompatActivity {
|
public class ReCaptchaActivity extends AppCompatActivity {
|
||||||
public static final int RECAPTCHA_REQUEST = 10;
|
public static final int RECAPTCHA_REQUEST = 10;
|
||||||
|
public static final String RECAPTCHA_URL_EXTRA = "recaptcha_url_extra";
|
||||||
|
|
||||||
public static final String TAG = ReCaptchaActivity.class.toString();
|
public static final String TAG = ReCaptchaActivity.class.toString();
|
||||||
public static final String YT_URL = "https://www.youtube.com";
|
public static final String YT_URL = "https://www.youtube.com";
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_recaptcha);
|
setContentView(R.layout.activity_recaptcha);
|
||||||
|
|
||||||
|
url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
|
||||||
|
if (url == null || url.isEmpty()) {
|
||||||
|
url = YT_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set return to Cancel by default
|
// Set return to Cancel by default
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
|
|
||||||
@@ -73,15 +82,12 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
myWebView.clearHistory();
|
myWebView.clearHistory();
|
||||||
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
cookieManager.removeAllCookies(new ValueCallback<Boolean>() {
|
cookieManager.removeAllCookies(aBoolean -> {});
|
||||||
@Override
|
|
||||||
public void onReceiveValue(Boolean aBoolean) {}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
cookieManager.removeAllCookie();
|
cookieManager.removeAllCookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
myWebView.loadUrl(YT_URL);
|
myWebView.loadUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReCaptchaWebViewClient extends WebViewClient {
|
private class ReCaptchaWebViewClient extends WebViewClient {
|
||||||
|
@@ -36,12 +36,12 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
@@ -74,17 +74,23 @@ import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
|
|||||||
*/
|
*/
|
||||||
public class RouterActivity extends AppCompatActivity {
|
public class RouterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@State protected int currentServiceId = -1;
|
@State
|
||||||
|
protected int currentServiceId = -1;
|
||||||
private StreamingService currentService;
|
private StreamingService currentService;
|
||||||
@State protected LinkType currentLinkType;
|
@State
|
||||||
@State protected int selectedRadioPosition = -1;
|
protected LinkType currentLinkType;
|
||||||
|
@State
|
||||||
|
protected int selectedRadioPosition = -1;
|
||||||
protected int selectedPreviously = -1;
|
protected int selectedPreviously = -1;
|
||||||
|
|
||||||
protected String currentUrl;
|
protected String currentUrl;
|
||||||
|
protected boolean internalRoute = false;
|
||||||
protected final CompositeDisposable disposables = new CompositeDisposable();
|
protected final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private boolean selectionIsDownload = false;
|
private boolean selectionIsDownload = false;
|
||||||
|
|
||||||
|
public static final String internalRouteKey = "internalRoute";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -94,11 +100,13 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
currentUrl = getUrl(getIntent());
|
currentUrl = getUrl(getIntent());
|
||||||
|
|
||||||
if (TextUtils.isEmpty(currentUrl)) {
|
if (TextUtils.isEmpty(currentUrl)) {
|
||||||
Toast.makeText(this, R.string.invalid_url_toast, Toast.LENGTH_LONG).show();
|
handleText();
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internalRoute = getIntent().getBooleanExtra(internalRouteKey, false);
|
||||||
|
|
||||||
setTheme(ThemeHelper.isLightThemeSelected(this)
|
setTheme(ThemeHelper.isLightThemeSelected(this)
|
||||||
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
|
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
|
||||||
}
|
}
|
||||||
@@ -252,7 +260,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
|
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
|
||||||
.setPositiveButton(R.string.always, dialogButtonsClickListener)
|
.setPositiveButton(R.string.always, dialogButtonsClickListener)
|
||||||
.setOnDismissListener((dialog) -> {
|
.setOnDismissListener((dialog) -> {
|
||||||
if(!selectionIsDownload) finish();
|
if (!selectionIsDownload) finish();
|
||||||
})
|
})
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
@@ -353,6 +361,15 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
positiveButton.setEnabled(state);
|
positiveButton.setEnabled(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleText() {
|
||||||
|
String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
|
Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(intent);
|
||||||
|
NavigationHelper.openSearch(getThemeWrapperContext(), serviceId, searchString);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleChoice(final String selectedChoiceKey) {
|
private void handleChoice(final String selectedChoiceKey) {
|
||||||
final List<String> validChoicesList = Arrays.asList(getResources().getStringArray(R.array.preferred_open_action_values_list));
|
final List<String> validChoicesList = Arrays.asList(getResources().getStringArray(R.array.preferred_open_action_values_list));
|
||||||
if (validChoicesList.contains(selectedChoiceKey)) {
|
if (validChoicesList.contains(selectedChoiceKey)) {
|
||||||
@@ -383,8 +400,10 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(intent -> {
|
.subscribe(intent -> {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
if (!internalRoute) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
}
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
@@ -431,8 +450,8 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
for (int i: grantResults){
|
for (int i : grantResults) {
|
||||||
if (i == PackageManager.PERMISSION_DENIED){
|
if (i == PackageManager.PERMISSION_DENIED) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -444,7 +463,8 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static class AdapterChoiceItem {
|
private static class AdapterChoiceItem {
|
||||||
final String description, key;
|
final String description, key;
|
||||||
@DrawableRes final int icon;
|
@DrawableRes
|
||||||
|
final int icon;
|
||||||
|
|
||||||
AdapterChoiceItem(String key, String description, int icon) {
|
AdapterChoiceItem(String key, String description, int icon) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
@@ -542,7 +562,8 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
|
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
|
||||||
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);;
|
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
|
||||||
|
;
|
||||||
|
|
||||||
PlayQueue playQueue;
|
PlayQueue playQueue;
|
||||||
String playerChoice = choice.playerChoice;
|
String playerChoice = choice.playerChoice;
|
||||||
@@ -558,7 +579,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
playQueue = new SinglePlayQueue((StreamInfo) info);
|
playQueue = new SinglePlayQueue((StreamInfo) info);
|
||||||
|
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
if (playerChoice.equals(videoPlayerKey)) {
|
||||||
NavigationHelper.playOnMainPlayer(this, playQueue);
|
NavigationHelper.playOnMainPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
||||||
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
|
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
} else if (playerChoice.equals(popupPlayerKey)) {
|
||||||
@@ -571,11 +592,11 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
|
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
|
||||||
|
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
if (playerChoice.equals(videoPlayerKey)) {
|
||||||
NavigationHelper.playOnMainPlayer(this, playQueue);
|
NavigationHelper.playOnMainPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
||||||
NavigationHelper.playOnBackgroundPlayer(this, playQueue);
|
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
} else if (playerChoice.equals(popupPlayerKey)) {
|
||||||
NavigationHelper.playOnPopupPlayer(this, playQueue);
|
NavigationHelper.playOnPopupPlayer(this, playQueue, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -3,15 +3,24 @@ package org.schabi.newpipe.database;
|
|||||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.arch.persistence.room.migration.Migration;
|
import android.arch.persistence.room.migration.Migration;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.BuildConfig;
|
||||||
|
|
||||||
public class Migrations {
|
public class Migrations {
|
||||||
|
|
||||||
public static final int DB_VER_11_0 = 1;
|
public static final int DB_VER_11_0 = 1;
|
||||||
public static final int DB_VER_12_0 = 2;
|
public static final int DB_VER_12_0 = 2;
|
||||||
|
|
||||||
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
|
private static final String TAG = Migrations.class.getName();
|
||||||
|
|
||||||
public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) {
|
public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) {
|
||||||
@Override
|
@Override
|
||||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||||
|
if(DEBUG) {
|
||||||
|
Log.d(TAG, "Start migrating database");
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Unfortunately these queries must be hardcoded due to the possibility of
|
* Unfortunately these queries must be hardcoded due to the possibility of
|
||||||
* schema and names changing at a later date, thus invalidating the older migration
|
* schema and names changing at a later date, thus invalidating the older migration
|
||||||
@@ -56,6 +65,10 @@ public class Migrations {
|
|||||||
"ORDER BY creation_date DESC");
|
"ORDER BY creation_date DESC");
|
||||||
|
|
||||||
database.execSQL("DROP TABLE IF EXISTS watch_history");
|
database.execSQL("DROP TABLE IF EXISTS watch_history");
|
||||||
|
|
||||||
|
if(DEBUG) {
|
||||||
|
Log.d(TAG, "Stop migrating database");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,11 @@ public abstract class StreamHistoryDAO implements HistoryDAO<StreamHistoryEntity
|
|||||||
" ORDER BY " + STREAM_ACCESS_DATE + " DESC")
|
" ORDER BY " + STREAM_ACCESS_DATE + " DESC")
|
||||||
public abstract Flowable<List<StreamHistoryEntry>> getHistory();
|
public abstract Flowable<List<StreamHistoryEntry>> getHistory();
|
||||||
|
|
||||||
|
@Query("SELECT * FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID +
|
||||||
|
" = :streamId ORDER BY " + STREAM_ACCESS_DATE + " DESC LIMIT 1")
|
||||||
|
@Nullable
|
||||||
|
public abstract StreamHistoryEntity getLatestEntry(final long streamId);
|
||||||
|
|
||||||
@Query("DELETE FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
|
@Query("DELETE FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
|
||||||
public abstract int deleteStreamHistory(final long streamId);
|
public abstract int deleteStreamHistory(final long streamId);
|
||||||
|
|
||||||
|
@@ -4,6 +4,9 @@ package org.schabi.newpipe.database.stream.model;
|
|||||||
import android.arch.persistence.room.ColumnInfo;
|
import android.arch.persistence.room.ColumnInfo;
|
||||||
import android.arch.persistence.room.Entity;
|
import android.arch.persistence.room.Entity;
|
||||||
import android.arch.persistence.room.ForeignKey;
|
import android.arch.persistence.room.ForeignKey;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static android.arch.persistence.room.ForeignKey.CASCADE;
|
import static android.arch.persistence.room.ForeignKey.CASCADE;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
||||||
@@ -22,6 +25,12 @@ public class StreamStateEntity {
|
|||||||
final public static String JOIN_STREAM_ID = "stream_id";
|
final public static String JOIN_STREAM_ID = "stream_id";
|
||||||
final public static String STREAM_PROGRESS_TIME = "progress_time";
|
final public static String STREAM_PROGRESS_TIME = "progress_time";
|
||||||
|
|
||||||
|
|
||||||
|
/** Playback state will not be saved, if playback time less than this threshold */
|
||||||
|
private static final int PLAYBACK_SAVE_THRESHOLD_START_SECONDS = 5;
|
||||||
|
/** Playback state will not be saved, if time left less than this threshold */
|
||||||
|
private static final int PLAYBACK_SAVE_THRESHOLD_END_SECONDS = 10;
|
||||||
|
|
||||||
@ColumnInfo(name = JOIN_STREAM_ID)
|
@ColumnInfo(name = JOIN_STREAM_ID)
|
||||||
private long streamUid;
|
private long streamUid;
|
||||||
|
|
||||||
@@ -48,4 +57,18 @@ public class StreamStateEntity {
|
|||||||
public void setProgressTime(long progressTime) {
|
public void setProgressTime(long progressTime) {
|
||||||
this.progressTime = progressTime;
|
this.progressTime = progressTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValid(int durationInSeconds) {
|
||||||
|
final int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(progressTime);
|
||||||
|
return seconds > PLAYBACK_SAVE_THRESHOLD_START_SECONDS
|
||||||
|
&& seconds < durationInSeconds - PLAYBACK_SAVE_THRESHOLD_END_SECONDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
if (obj instanceof StreamStateEntity) {
|
||||||
|
return ((StreamStateEntity) obj).streamUid == streamUid
|
||||||
|
&& ((StreamStateEntity) obj).progressTime == progressTime;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,7 +47,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
updateFragments();
|
updateFragments();
|
||||||
getWindow().getDecorView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -55,12 +55,13 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
private void updateFragments() {
|
private void updateFragments() {
|
||||||
MissionsFragment fragment = new MissionsFragment();
|
MissionsFragment fragment = new MissionsFragment();
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
||||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
@@ -86,9 +87,4 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRestoreInstanceState(Bundle inState){
|
|
||||||
super.onRestoreInstanceState(inState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -180,7 +180,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (exception instanceof ReCaptchaException) {
|
if (exception instanceof ReCaptchaException) {
|
||||||
onReCaptchaException();
|
onReCaptchaException((ReCaptchaException) exception);
|
||||||
return true;
|
return true;
|
||||||
} else if (exception instanceof IOException) {
|
} else if (exception instanceof IOException) {
|
||||||
showError(getString(R.string.network_error), true);
|
showError(getString(R.string.network_error), true);
|
||||||
@@ -190,11 +190,13 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onReCaptchaException() {
|
public void onReCaptchaException(ReCaptchaException exception) {
|
||||||
if (DEBUG) Log.d(TAG, "onReCaptchaException() called");
|
if (DEBUG) Log.d(TAG, "onReCaptchaException() called");
|
||||||
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
||||||
// Starting ReCaptcha Challenge Activity
|
// Starting ReCaptcha Challenge Activity
|
||||||
startActivityForResult(new Intent(activity, ReCaptchaActivity.class), ReCaptchaActivity.RECAPTCHA_REQUEST);
|
Intent intent = new Intent(activity, ReCaptchaActivity.class);
|
||||||
|
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl());
|
||||||
|
startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST);
|
||||||
|
|
||||||
showError(getString(R.string.recaptcha_request_toast), false);
|
showError(getString(R.string.recaptcha_request_toast), false);
|
||||||
}
|
}
|
||||||
@@ -230,21 +232,4 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
|||||||
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView,
|
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView,
|
||||||
ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
|
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)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.BaseFragment;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
public class EmptyFragment extends BaseFragment {
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.fragment_empty, container, false);
|
||||||
|
}
|
||||||
|
}
|
@@ -50,6 +50,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
|
destroyOldFragments();
|
||||||
|
|
||||||
tabsManager = TabsManager.getManager(activity);
|
tabsManager = TabsManager.getManager(activity);
|
||||||
tabsManager.setSavedTabsListener(() -> {
|
tabsManager.setSavedTabsListener(() -> {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -63,6 +65,17 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void destroyOldFragments() {
|
||||||
|
for (Fragment fragment : getChildFragmentManager().getFragments()) {
|
||||||
|
if (fragment != null) {
|
||||||
|
getChildFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.remove(fragment)
|
||||||
|
.commitNowAllowingStateLoss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.fragment_main, container, false);
|
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||||
@@ -98,6 +111,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
tabsManager.unsetSavedTabsListener();
|
tabsManager.unsetSavedTabsListener();
|
||||||
|
pagerAdapter = null;
|
||||||
|
viewPager.setAdapter(pagerAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -177,6 +192,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class SelectedTabsPagerAdapter extends FragmentPagerAdapter {
|
private class SelectedTabsPagerAdapter extends FragmentPagerAdapter {
|
||||||
|
|
||||||
private SelectedTabsPagerAdapter(FragmentManager fragmentManager) {
|
private SelectedTabsPagerAdapter(FragmentManager fragmentManager) {
|
||||||
super(fragmentManager);
|
super(fragmentManager);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
import android.support.v4.app.FragmentPagerAdapter;
|
||||||
@@ -61,6 +62,18 @@ public class TabAdaptor extends FragmentPagerAdapter {
|
|||||||
else return POSITION_NONE;
|
else return POSITION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getItemPositionByTitle(String title) {
|
||||||
|
return mFragmentTitleList.indexOf(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getItemTitle(int position) {
|
||||||
|
if (position < 0 || position >= mFragmentTitleList.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mFragmentTitleList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
public void notifyDataSetUpdate(){
|
public void notifyDataSetUpdate(){
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ package org.schabi.newpipe.fragments.list;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -25,18 +24,17 @@ import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
|||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
|
import org.schabi.newpipe.util.StreamDialogEntry;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
@@ -64,6 +62,11 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||||||
infoListAdapter = new InfoListAdapter(activity);
|
infoListAdapter = new InfoListAdapter(activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach() {
|
||||||
|
super.onDetach();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -249,41 +252,32 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void showStreamDialog(final StreamInfoItem item) {
|
protected void showStreamDialog(final StreamInfoItem item) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
if (context == null || context.getResources() == null || getActivity() == null) return;
|
if (context == null || context.getResources() == null || activity == null) return;
|
||||||
|
|
||||||
final String[] commands = new String[]{
|
if (item.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||||
context.getResources().getString(R.string.enqueue_on_background),
|
StreamDialogEntry.setEnabledEntries(
|
||||||
context.getResources().getString(R.string.enqueue_on_popup),
|
StreamDialogEntry.enqueue_on_background,
|
||||||
context.getResources().getString(R.string.append_playlist),
|
StreamDialogEntry.start_here_on_background,
|
||||||
context.getResources().getString(R.string.share)
|
StreamDialogEntry.append_playlist,
|
||||||
};
|
StreamDialogEntry.share);
|
||||||
|
} else {
|
||||||
|
StreamDialogEntry.setEnabledEntries(
|
||||||
|
StreamDialogEntry.enqueue_on_background,
|
||||||
|
StreamDialogEntry.enqueue_on_popup,
|
||||||
|
StreamDialogEntry.start_here_on_background,
|
||||||
|
StreamDialogEntry.start_here_on_popup,
|
||||||
|
StreamDialogEntry.append_playlist,
|
||||||
|
StreamDialogEntry.share);
|
||||||
|
}
|
||||||
|
|
||||||
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
|
new InfoItemDialog(activity, item, StreamDialogEntry.getCommands(context), (dialog, which) ->
|
||||||
switch (i) {
|
StreamDialogEntry.clickOn(which, this, item)).show();
|
||||||
case 0:
|
|
||||||
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (getFragmentManager() != null) {
|
|
||||||
PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item))
|
|
||||||
.show(getFragmentManager(), TAG);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
shareUrl(item.getName(), item.getUrl());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
package org.schabi.newpipe.fragments.list.channel;
|
package org.schabi.newpipe.fragments.list.channel;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -34,21 +32,18 @@ import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
|||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
|
||||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
import org.schabi.newpipe.util.ShareUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -149,56 +144,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
return headerRootLayout;
|
return headerRootLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void showStreamDialog(final StreamInfoItem item) {
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
final Context context = getContext();
|
|
||||||
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),
|
|
||||||
context.getResources().getString(R.string.append_playlist),
|
|
||||||
context.getResources().getString(R.string.share)
|
|
||||||
};
|
|
||||||
|
|
||||||
final DialogInterface.OnClickListener actions = (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;
|
|
||||||
case 5:
|
|
||||||
if (getFragmentManager() != null) {
|
|
||||||
PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item))
|
|
||||||
.show(getFragmentManager(), TAG);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
shareUrl(item.getName(), item.getUrl());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
|
||||||
}
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Menu
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
@@ -233,10 +178,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
openRssFeed();
|
openRssFeed();
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_openInBrowser:
|
case R.id.menu_item_openInBrowser:
|
||||||
openUrlInBrowser(currentInfo.getOriginalUrl());
|
ShareUtils.openUrlInBrowser(this.getContext(), currentInfo.getOriginalUrl());
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_share:
|
case R.id.menu_item_share:
|
||||||
shareUrl(name, currentInfo.getOriginalUrl());
|
ShareUtils.shareUrl(this.getContext(), name, currentInfo.getOriginalUrl());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
@@ -439,11 +384,11 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
monitorSubscription(result);
|
monitorSubscription(result);
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(
|
headerPlayAllButton.setOnClickListener(
|
||||||
view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
|
||||||
headerPopupButton.setOnClickListener(
|
headerPopupButton.setOnClickListener(
|
||||||
view -> NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
view -> NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(
|
headerBackgroundButton.setOnClickListener(
|
||||||
view -> NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
view -> NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayQueue getPlayQueue() {
|
private PlayQueue getPlayQueue() {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe.fragments.list.kiosk;
|
package org.schabi.newpipe.fragments.list.kiosk;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
@@ -155,9 +154,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
|||||||
super.handleResult(result);
|
super.handleResult(result);
|
||||||
|
|
||||||
name = kioskTranslatedName;
|
name = kioskTranslatedName;
|
||||||
if(!useAsFrontPage) {
|
setTitle(kioskTranslatedName);
|
||||||
setTitle(kioskTranslatedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.getErrors().isEmpty()) {
|
if (!result.getErrors().isEmpty()) {
|
||||||
showSnackBarError(result.getErrors(),
|
showSnackBarError(result.getErrors(),
|
||||||
|
@@ -2,10 +2,10 @@ package org.schabi.newpipe.fragments.list.playlist;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -29,17 +29,19 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
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 org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -134,48 +136,40 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
infoListAdapter.useMiniItemVariants(true);
|
infoListAdapter.useMiniItemVariants(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PlayQueue getPlayQueueStartingAt(StreamInfoItem infoItem) {
|
||||||
|
return getPlayQueue(Math.max(infoListAdapter.getItemsList().indexOf(infoItem), 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void showStreamDialog(final StreamInfoItem item) {
|
protected void showStreamDialog(StreamInfoItem item) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
if (context == null || context.getResources() == null || getActivity() == null) return;
|
if (context == null || context.getResources() == null || activity == null) return;
|
||||||
|
|
||||||
final String[] commands = new String[]{
|
if (item.getStreamType() == StreamType.AUDIO_STREAM) {
|
||||||
context.getResources().getString(R.string.enqueue_on_background),
|
StreamDialogEntry.setEnabledEntries(
|
||||||
context.getResources().getString(R.string.enqueue_on_popup),
|
StreamDialogEntry.enqueue_on_background,
|
||||||
context.getResources().getString(R.string.start_here_on_main),
|
StreamDialogEntry.start_here_on_background,
|
||||||
context.getResources().getString(R.string.start_here_on_background),
|
StreamDialogEntry.append_playlist,
|
||||||
context.getResources().getString(R.string.start_here_on_popup),
|
StreamDialogEntry.share);
|
||||||
context.getResources().getString(R.string.share)
|
} else {
|
||||||
};
|
StreamDialogEntry.setEnabledEntries(
|
||||||
|
StreamDialogEntry.enqueue_on_background,
|
||||||
|
StreamDialogEntry.enqueue_on_popup,
|
||||||
|
StreamDialogEntry.start_here_on_background,
|
||||||
|
StreamDialogEntry.start_here_on_popup,
|
||||||
|
StreamDialogEntry.append_playlist,
|
||||||
|
StreamDialogEntry.share);
|
||||||
|
|
||||||
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
|
StreamDialogEntry.start_here_on_popup.setCustomAction(
|
||||||
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
|
(fragment, infoItem) -> NavigationHelper.playOnPopupPlayer(context, getPlayQueueStartingAt(infoItem), true));
|
||||||
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;
|
|
||||||
case 5:
|
|
||||||
shareUrl(item.getName(), item.getUrl());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
StreamDialogEntry.start_here_on_background.setCustomAction(
|
||||||
|
(fragment, infoItem) -> NavigationHelper.playOnBackgroundPlayer(context, getPlayQueueStartingAt(infoItem), true));
|
||||||
|
|
||||||
|
new InfoItemDialog(activity, item, StreamDialogEntry.getCommands(context), (dialog, which) ->
|
||||||
|
StreamDialogEntry.clickOn(which, this, item)).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,10 +224,10 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.menu_item_openInBrowser:
|
case R.id.menu_item_openInBrowser:
|
||||||
openUrlInBrowser(url);
|
ShareUtils.openUrlInBrowser(this.getContext(), url);
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_share:
|
case R.id.menu_item_share:
|
||||||
shareUrl(name, url);
|
ShareUtils.shareUrl(this.getContext(), name, url);
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_bookmark:
|
case R.id.menu_item_bookmark:
|
||||||
onBookmarkClicked();
|
onBookmarkClicked();
|
||||||
@@ -300,11 +294,21 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
.subscribe(getPlaylistBookmarkSubscriber());
|
.subscribe(getPlaylistBookmarkSubscriber());
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
|
||||||
headerPopupButton.setOnClickListener(view ->
|
headerPopupButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false));
|
||||||
|
|
||||||
|
headerPopupButton.setOnLongClickListener(view -> {
|
||||||
|
NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
headerBackgroundButton.setOnLongClickListener(view -> {
|
||||||
|
NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayQueue getPlayQueue() {
|
private PlayQueue getPlayQueue() {
|
||||||
|
@@ -12,6 +12,7 @@ import android.support.v7.app.ActionBar;
|
|||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.TooltipCompat;
|
import android.support.v7.widget.TooltipCompat;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@@ -45,10 +46,9 @@ import org.schabi.newpipe.fragments.list.BaseListFragment;
|
|||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.Constants;
|
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.LayoutManagerSmoothScroller;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ import io.reactivex.disposables.Disposable;
|
|||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import io.reactivex.subjects.PublishSubject;
|
import io.reactivex.subjects.PublishSubject;
|
||||||
|
|
||||||
|
import static android.support.v7.widget.helper.ItemTouchHelper.Callback.makeMovementFlags;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class SearchFragment
|
public class SearchFragment
|
||||||
@@ -298,7 +298,23 @@ public class SearchFragment
|
|||||||
suggestionsPanel = rootView.findViewById(R.id.suggestions_panel);
|
suggestionsPanel = rootView.findViewById(R.id.suggestions_panel);
|
||||||
suggestionsRecyclerView = rootView.findViewById(R.id.suggestions_list);
|
suggestionsRecyclerView = rootView.findViewById(R.id.suggestions_list);
|
||||||
suggestionsRecyclerView.setAdapter(suggestionListAdapter);
|
suggestionsRecyclerView.setAdapter(suggestionListAdapter);
|
||||||
suggestionsRecyclerView.setLayoutManager(new LayoutManagerSmoothScroller(activity));
|
new ItemTouchHelper(new ItemTouchHelper.Callback() {
|
||||||
|
@Override
|
||||||
|
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
|
return getSuggestionMovementFlags(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder,
|
||||||
|
@NonNull RecyclerView.ViewHolder viewHolder1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
|
||||||
|
onSuggestionItemSwiped(viewHolder, i);
|
||||||
|
}
|
||||||
|
}).attachToRecyclerView(suggestionsRecyclerView);
|
||||||
|
|
||||||
searchToolbarContainer = activity.findViewById(R.id.toolbar_search_container);
|
searchToolbarContainer = activity.findViewById(R.id.toolbar_search_container);
|
||||||
searchEditText = searchToolbarContainer.findViewById(R.id.toolbar_search_edit_text);
|
searchEditText = searchToolbarContainer.findViewById(R.id.toolbar_search_edit_text);
|
||||||
@@ -901,4 +917,28 @@ public class SearchFragment
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Suggestion item touch helper
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public int getSuggestionMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
|
final int position = viewHolder.getAdapterPosition();
|
||||||
|
final SuggestionItem item = suggestionListAdapter.getItem(position);
|
||||||
|
return item.fromHistory ? makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSuggestionItemSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
|
||||||
|
final int position = viewHolder.getAdapterPosition();
|
||||||
|
final String query = suggestionListAdapter.getItem(position).query;
|
||||||
|
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
howManyDeleted -> suggestionPublisher
|
||||||
|
.onNext(searchEditText.getText().toString()),
|
||||||
|
throwable -> showSnackBarError(throwable,
|
||||||
|
UserAction.DELETE_FROM_HISTORY, "none",
|
||||||
|
"Deleting item failed", R.string.general_error));
|
||||||
|
disposables.add(onDelete);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -75,7 +75,7 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private SuggestionItem getItem(int position) {
|
SuggestionItem getItem(int position) {
|
||||||
return items.get(position);
|
return items.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,6 @@ package org.schabi.newpipe.info_list;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
@@ -22,6 +21,7 @@ import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
|||||||
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -59,13 +59,14 @@ public class InfoItemBuilder {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem) {
|
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
return buildView(parent, infoItem, false);
|
return buildView(parent, infoItem, historyRecordManager, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, boolean useMiniVariant) {
|
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem,
|
||||||
|
final HistoryRecordManager historyRecordManager, boolean useMiniVariant) {
|
||||||
InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
|
InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
|
||||||
holder.updateFromItem(infoItem);
|
holder.updateFromItem(infoItem, historyRecordManager);
|
||||||
return holder.itemView;
|
return holder.itemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +81,6 @@ public class InfoItemBuilder {
|
|||||||
case COMMENT:
|
case COMMENT:
|
||||||
return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent);
|
return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent);
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
|
||||||
throw new RuntimeException("InfoType not expected = " + infoType.name());
|
throw new RuntimeException("InfoType not expected = " + infoType.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +1,25 @@
|
|||||||
package org.schabi.newpipe.info_list;
|
package org.schabi.newpipe.info_list;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.widget.GridLayoutManager;
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
||||||
@@ -24,6 +27,7 @@ import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
|||||||
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.FallbackViewHolder;
|
import org.schabi.newpipe.util.FallbackViewHolder;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
||||||
@@ -71,6 +75,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
|
|
||||||
private final InfoItemBuilder infoItemBuilder;
|
private final InfoItemBuilder infoItemBuilder;
|
||||||
private final ArrayList<InfoItem> infoItemList;
|
private final ArrayList<InfoItem> infoItemList;
|
||||||
|
private final HistoryRecordManager recordManager;
|
||||||
|
|
||||||
private boolean useMiniVariant = false;
|
private boolean useMiniVariant = false;
|
||||||
private boolean useGridVariant = false;
|
private boolean useGridVariant = false;
|
||||||
private boolean showFooter = false;
|
private boolean showFooter = false;
|
||||||
@@ -86,8 +92,9 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InfoListAdapter(Activity a) {
|
public InfoListAdapter(Context context) {
|
||||||
infoItemBuilder = new InfoItemBuilder(a);
|
this.recordManager = new HistoryRecordManager(context);
|
||||||
|
infoItemBuilder = new InfoItemBuilder(context);
|
||||||
infoItemList = new ArrayList<>();
|
infoItemList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,50 +122,53 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
this.useGridVariant = useGridVariant;
|
this.useGridVariant = useGridVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInfoItemList(List<InfoItem> data) {
|
public void addInfoItemList(@Nullable final List<InfoItem> data) {
|
||||||
if (data != null) {
|
if (data == null) {
|
||||||
if (DEBUG) {
|
return;
|
||||||
Log.d(TAG, "addInfoItemList() before > infoItemList.size() = " + infoItemList.size() + ", data.size() = " + data.size());
|
}
|
||||||
}
|
if (DEBUG) Log.d(TAG, "addInfoItemList() before > infoItemList.size() = " +
|
||||||
|
infoItemList.size() + ", data.size() = " + data.size());
|
||||||
|
|
||||||
int offsetStart = sizeConsideringHeaderOffset();
|
int offsetStart = sizeConsideringHeaderOffset();
|
||||||
infoItemList.addAll(data);
|
infoItemList.addAll(data);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart +
|
||||||
Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter);
|
", infoItemList.size() = " + infoItemList.size() +
|
||||||
}
|
", header = " + header + ", footer = " + footer +
|
||||||
|
", showFooter = " + showFooter);
|
||||||
|
notifyItemRangeInserted(offsetStart, data.size());
|
||||||
|
|
||||||
notifyItemRangeInserted(offsetStart, data.size());
|
if (footer != null && showFooter) {
|
||||||
|
int footerNow = sizeConsideringHeaderOffset();
|
||||||
|
notifyItemMoved(offsetStart, footerNow);
|
||||||
|
|
||||||
if (footer != null && showFooter) {
|
if (DEBUG) Log.d(TAG, "addInfoItemList() footer from " + offsetStart +
|
||||||
int footerNow = sizeConsideringHeaderOffset();
|
" to " + footerNow);
|
||||||
notifyItemMoved(offsetStart, footerNow);
|
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "addInfoItemList() footer from " + offsetStart + " to " + footerNow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInfoItem(InfoItem data) {
|
public void addInfoItem(@Nullable InfoItem data) {
|
||||||
if (data != null) {
|
if (data == null) {
|
||||||
if (DEBUG) {
|
return;
|
||||||
Log.d(TAG, "addInfoItem() before > infoItemList.size() = " + infoItemList.size() + ", thread = " + Thread.currentThread());
|
}
|
||||||
}
|
if (DEBUG) Log.d(TAG, "addInfoItem() before > infoItemList.size() = " +
|
||||||
|
infoItemList.size() + ", thread = " + Thread.currentThread());
|
||||||
|
|
||||||
int positionInserted = sizeConsideringHeaderOffset();
|
int positionInserted = sizeConsideringHeaderOffset();
|
||||||
infoItemList.add(data);
|
infoItemList.add(data);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) Log.d(TAG, "addInfoItem() after > position = " + positionInserted +
|
||||||
Log.d(TAG, "addInfoItem() after > position = " + positionInserted + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter);
|
", infoItemList.size() = " + infoItemList.size() +
|
||||||
}
|
", header = " + header + ", footer = " + footer +
|
||||||
notifyItemInserted(positionInserted);
|
", showFooter = " + showFooter);
|
||||||
|
notifyItemInserted(positionInserted);
|
||||||
|
|
||||||
if (footer != null && showFooter) {
|
if (footer != null && showFooter) {
|
||||||
int footerNow = sizeConsideringHeaderOffset();
|
int footerNow = sizeConsideringHeaderOffset();
|
||||||
notifyItemMoved(positionInserted, footerNow);
|
notifyItemMoved(positionInserted, footerNow);
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "addInfoItem() footer from " + positionInserted + " to " + footerNow);
|
if (DEBUG) Log.d(TAG, "addInfoItem() footer from " + positionInserted +
|
||||||
}
|
" to " + footerNow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,13 +245,13 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
case COMMENT:
|
case COMMENT:
|
||||||
return useMiniVariant ? MINI_COMMENT_HOLDER_TYPE : COMMENT_HOLDER_TYPE;
|
return useMiniVariant ? MINI_COMMENT_HOLDER_TYPE : COMMENT_HOLDER_TYPE;
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) {
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
|
Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -272,19 +282,18 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
case COMMENT_HOLDER_TYPE:
|
case COMMENT_HOLDER_TYPE:
|
||||||
return new CommentsInfoItemHolder(infoItemBuilder, parent);
|
return new CommentsInfoItemHolder(infoItemBuilder, parent);
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
|
||||||
return new FallbackViewHolder(new View(parent.getContext()));
|
return new FallbackViewHolder(new View(parent.getContext()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
if (DEBUG) Log.d(TAG, "onBindViewHolder() called with: holder = [" + holder.getClass().getSimpleName() + "], position = [" + position + "]");
|
if (DEBUG) Log.d(TAG, "onBindViewHolder() called with: holder = [" + holder.getClass().getSimpleName() + "], position = [" + position + "]");
|
||||||
if (holder instanceof InfoItemHolder) {
|
if (holder instanceof InfoItemHolder) {
|
||||||
// If header isn't null, offset the items by -1
|
// If header isn't null, offset the items by -1
|
||||||
if (header != null) position--;
|
if (header != null) position--;
|
||||||
|
|
||||||
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position));
|
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position), recordManager);
|
||||||
} else if (holder instanceof HFHolder && position == 0 && header != null) {
|
} else if (holder instanceof HFHolder && position == 0 && header != null) {
|
||||||
((HFHolder) holder).view = header;
|
((HFHolder) holder).view = header;
|
||||||
} else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset() && footer != null && showFooter) {
|
} else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset() && footer != null && showFooter) {
|
||||||
@@ -292,6 +301,21 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
|
||||||
|
if (!payloads.isEmpty() && holder instanceof InfoItemHolder) {
|
||||||
|
for (Object payload : payloads) {
|
||||||
|
if (payload instanceof StreamStateEntity) {
|
||||||
|
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1), recordManager);
|
||||||
|
} else if (payload instanceof Boolean) {
|
||||||
|
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1), recordManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onBindViewHolder(holder, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
|
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
|
||||||
return new GridLayoutManager.SpanSizeLookup() {
|
return new GridLayoutManager.SpanSizeLookup() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -7,6 +7,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -38,8 +39,8 @@ public class ChannelInfoItemHolder extends ChannelMiniInfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
super.updateFromItem(infoItem);
|
super.updateFromItem(infoItem, historyRecordManager);
|
||||||
|
|
||||||
if (!(infoItem instanceof ChannelInfoItem)) return;
|
if (!(infoItem instanceof ChannelInfoItem)) return;
|
||||||
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
||||||
|
@@ -7,6 +7,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof ChannelInfoItem)) return;
|
if (!(infoItem instanceof ChannelInfoItem)) return;
|
||||||
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
||||||
|
|
||||||
|
@@ -5,10 +5,9 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 12.02.17.
|
* Created by Christian Schabesberger on 12.02.17.
|
||||||
@@ -41,8 +40,8 @@ public class CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
super.updateFromItem(infoItem);
|
super.updateFromItem(infoItem, historyRecordManager);
|
||||||
|
|
||||||
if (!(infoItem instanceof CommentsInfoItem)) return;
|
if (!(infoItem instanceof CommentsInfoItem)) return;
|
||||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||||
|
@@ -1,19 +1,24 @@
|
|||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.text.TextUtils;
|
import android.text.util.Linkify;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.jsoup.helper.StringUtil;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.util.CommentTextOnTouchListener;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
|
|
||||||
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@@ -26,6 +31,25 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
private static final int commentDefaultLines = 2;
|
private static final int commentDefaultLines = 2;
|
||||||
private static final int commentExpandedLines = 1000;
|
private static final int commentExpandedLines = 1000;
|
||||||
|
|
||||||
|
private String commentText;
|
||||||
|
private String streamUrl;
|
||||||
|
|
||||||
|
private static final Pattern pattern = Pattern.compile("(\\d+:)?(\\d+)?:(\\d+)");
|
||||||
|
|
||||||
|
private final Linkify.TransformFilter timestampLink = new Linkify.TransformFilter() {
|
||||||
|
@Override
|
||||||
|
public String transformUrl(Matcher match, String url) {
|
||||||
|
int timestamp = 0;
|
||||||
|
String hours = match.group(1);
|
||||||
|
String minutes = match.group(2);
|
||||||
|
String seconds = match.group(3);
|
||||||
|
if(hours != null) timestamp += (Integer.parseInt(hours.replace(":", ""))*3600);
|
||||||
|
if(minutes != null) timestamp += (Integer.parseInt(minutes.replace(":", ""))*60);
|
||||||
|
if(seconds != null) timestamp += (Integer.parseInt(seconds));
|
||||||
|
return streamUrl + url.replace(match.group(0), "#timestamp=" + timestamp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
||||||
super(infoItemBuilder, layoutId, parent);
|
super(infoItemBuilder, layoutId, parent);
|
||||||
|
|
||||||
@@ -41,7 +65,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof CommentsInfoItem)) return;
|
if (!(infoItem instanceof CommentsInfoItem)) return;
|
||||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||||
|
|
||||||
@@ -50,50 +74,74 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
itemThumbnailView,
|
itemThumbnailView,
|
||||||
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
|
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
|
||||||
|
|
||||||
itemThumbnailView.setOnClickListener(new View.OnClickListener() {
|
itemThumbnailView.setOnClickListener(view -> {
|
||||||
@Override
|
if(StringUtil.isBlank(item.getAuthorEndpoint())) return;
|
||||||
public void onClick(View view) {
|
try {
|
||||||
try {
|
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
|
||||||
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
|
NavigationHelper.openChannelFragment(
|
||||||
NavigationHelper.openChannelFragment(
|
activity.getSupportFragmentManager(),
|
||||||
activity.getSupportFragmentManager(),
|
item.getServiceId(),
|
||||||
item.getServiceId(),
|
item.getAuthorEndpoint(),
|
||||||
item.getAuthorEndpoint(),
|
item.getAuthorName());
|
||||||
item.getAuthorName());
|
} catch (Exception e) {
|
||||||
} catch (Exception e) {
|
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ellipsize if not already ellipsized
|
streamUrl = item.getUrl();
|
||||||
if (null == itemContentView.getEllipsize()) {
|
|
||||||
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
|
itemContentView.setLines(commentDefaultLines);
|
||||||
itemContentView.setMaxLines(commentDefaultLines);
|
commentText = item.getCommentText();
|
||||||
|
itemContentView.setText(commentText);
|
||||||
|
itemContentView.setOnTouchListener(CommentTextOnTouchListener.INSTANCE);
|
||||||
|
|
||||||
|
if (itemContentView.getLineCount() == 0) {
|
||||||
|
itemContentView.post(this::ellipsize);
|
||||||
|
} else {
|
||||||
|
ellipsize();
|
||||||
}
|
}
|
||||||
|
|
||||||
itemContentView.setText(item.getCommentText());
|
|
||||||
if (null != item.getLikeCount()) {
|
if (null != item.getLikeCount()) {
|
||||||
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
|
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
|
||||||
}
|
}
|
||||||
itemPublishedTime.setText(item.getPublishedTime());
|
itemPublishedTime.setText(item.getPublishedTime());
|
||||||
|
|
||||||
itemView.setOnClickListener(view -> {
|
itemView.setOnClickListener(view -> {
|
||||||
toggleEllipsize(item.getCommentText());
|
toggleEllipsize();
|
||||||
if (itemBuilder.getOnCommentsSelectedListener() != null) {
|
if (itemBuilder.getOnCommentsSelectedListener() != null) {
|
||||||
itemBuilder.getOnCommentsSelectedListener().selected(item);
|
itemBuilder.getOnCommentsSelectedListener().selected(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleEllipsize(String text) {
|
private void ellipsize() {
|
||||||
// toggle ellipsize
|
if (itemContentView.getLineCount() > commentDefaultLines){
|
||||||
if (null == itemContentView.getEllipsize()) {
|
int endOfLastLine = itemContentView.getLayout().getLineEnd(commentDefaultLines - 1);
|
||||||
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
|
int end = itemContentView.getText().toString().lastIndexOf(' ', endOfLastLine -2);
|
||||||
itemContentView.setMaxLines(commentDefaultLines);
|
if(end == -1) end = Math.max(endOfLastLine -2, 0);
|
||||||
|
String newVal = itemContentView.getText().subSequence(0, end) + " …";
|
||||||
|
itemContentView.setText(newVal);
|
||||||
|
}
|
||||||
|
linkify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleEllipsize() {
|
||||||
|
if (itemContentView.getText().toString().equals(commentText)) {
|
||||||
|
if (itemContentView.getLineCount() > commentDefaultLines) ellipsize();
|
||||||
} else {
|
} else {
|
||||||
itemContentView.setEllipsize(null);
|
expand();
|
||||||
itemContentView.setMaxLines(commentExpandedLines);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expand() {
|
||||||
|
itemContentView.setMaxLines(commentExpandedLines);
|
||||||
|
itemContentView.setText(commentText);
|
||||||
|
linkify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkify(){
|
||||||
|
Linkify.addLinks(itemContentView, Linkify.WEB_URLS);
|
||||||
|
Linkify.addLinks(itemContentView, pattern, null, null, timestampLink);
|
||||||
|
itemContentView.setMovementMethod(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 12.02.17.
|
* Created by Christian Schabesberger on 12.02.17.
|
||||||
@@ -35,5 +36,8 @@ public abstract class InfoItemHolder extends RecyclerView.ViewHolder {
|
|||||||
this.itemBuilder = infoItemBuilder;
|
this.itemBuilder = infoItemBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void updateFromItem(final InfoItem infoItem);
|
public abstract void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager);
|
||||||
|
|
||||||
|
public void updateState(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
|
|
||||||
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@@ -30,7 +31,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof PlaylistInfoItem)) return;
|
if (!(infoItem instanceof PlaylistInfoItem)) return;
|
||||||
final PlaylistInfoItem item = (PlaylistInfoItem) infoItem;
|
final PlaylistInfoItem item = (PlaylistInfoItem) infoItem;
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -40,8 +41,8 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem) {
|
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
|
||||||
super.updateFromItem(infoItem);
|
super.updateFromItem(infoItem, historyRecordManager);
|
||||||
|
|
||||||
if (!(infoItem instanceof StreamInfoItem)) return;
|
if (!(infoItem instanceof StreamInfoItem)) return;
|
||||||
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user