1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2026-01-13 18:22:41 +00:00

Compare commits

..

180 Commits

Author SHA1 Message Date
Christian Schabesberger
fba0a8036b Merge pull request #1825 from TeamNewPipe/release_0.14.2
Release 0.14.2
2018-10-27 09:58:56 +02:00
Christian Schabesberger
d82274f5d4 fucking android bullshit 2018-10-27 09:57:11 +02:00
Christian Schabesberger
3cf81230b2 Merge branch 'dev' into release_0.14.2 2018-10-26 15:02:11 +02:00
Christian Schabesberger
17bab456e4 Merge pull request #1845 from AndhikaWB/patch-1
Fix spelling of country names in settings
2018-10-26 15:01:34 +02:00
Christian Schabesberger
e1cc006db7 fix race condition when returning to main player 2018-10-26 14:59:49 +02:00
Tobias Groza
7e95dd3c76 Change from "Côte d'Ivoire" to "Côte d\'Ivoire"
Co-Authored-By: AndhikaWB <karagasnoelan@gmail.com>
2018-10-26 16:22:35 +07:00
AndhikaWB
ff3ce46a26 Update settings_keys.xml 2018-10-26 00:09:04 +07:00
AndhikaWB
4d61c2c5e0 Fix spelling in of country names in settings
- [x] I carefully read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) and agree to them.

Closes TeamNewPipe/NewPipe#1504
2018-10-26 00:04:36 +07:00
Christian Schabesberger
afaba7ccdf fix broken search result 2018-10-25 15:58:06 +02:00
Christian Schabesberger
ccb3ceae4f add release node 2018-10-25 10:58:37 +02:00
Christian Schabesberger
d0d93f6d2d Merge branch 'dev' into release_0.14.2 2018-10-25 10:57:39 +02:00
Christian Schabesberger
67f091c731 Merge pull request #1830 from boredomdenied/dev
Add foreground service permission for API 28+ devices
2018-10-25 10:54:52 +02:00
Christian Schabesberger
fa3aebb7b1 localisation to localization 2018-10-22 12:25:50 +02:00
Christian Schabesberger
988251deb6 fix weblate collision 2018-10-22 12:15:16 +02:00
Christian Schabesberger
d99a389c49 merge weblate 2018-10-22 12:07:12 +02:00
Marian Hanzel
7508f9d3bb Translated using Weblate (Slovak)
Currently translated at 100.0% (383 of 383 strings)
2018-10-21 09:45:21 +02:00
Heimen Stoffels
b2512d7aee Translated using Weblate (Dutch)
Currently translated at 100.0% (383 of 383 strings)
2018-10-21 09:45:18 +02:00
Olexandr Nesterenko
eb74e1e3b2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (383 of 383 strings)
2018-10-21 09:45:13 +02:00
boredomdenied
bd91e82b17 Update AndroidManifest.xml
remove needless additional line
2018-10-19 21:07:59 -05:00
boredomdenied
bae60acfe7 Update AndroidManifest.xml
Fix foreground playback in android Pie API 28. Tested in emulator & Pixel 3 device.
2018-10-19 20:52:22 -05:00
Emin Tufan Çetin
426cefe8ee Translated using Weblate (Turkish)
Currently translated at 100.0% (383 of 383 strings)
2018-10-20 01:33:46 +02:00
Allan Nordhøy
a36fe3ef21 Translated using Weblate (Swedish)
Currently translated at 100.0% (383 of 383 strings)
2018-10-20 01:33:46 +02:00
Allan Nordhøy
ee0756c7c0 Translated using Weblate (Russian)
Currently translated at 99.7% (382 of 383 strings)
2018-10-20 01:33:45 +02:00
Jaggie
44b96121e4 Translated using Weblate (Punjabi)
Currently translated at 7.3% (28 of 383 strings)
2018-10-20 01:33:44 +02:00
Allan Nordhøy
8add777b34 Translated using Weblate (German)
Currently translated at 100.0% (383 of 383 strings)
2018-10-20 01:33:42 +02:00
Allan Nordhøy
6932b15144 Translated using Weblate (English)
Currently translated at 100.0% (383 of 383 strings)
2018-10-20 01:33:41 +02:00
Allan Nordhøy
c09edda797 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.7% (382 of 383 strings)
2018-10-20 01:33:38 +02:00
Christian Schabesberger
0e86010565 move on to version 0.14.2 2018-10-19 15:53:19 +02:00
Tobias Groza
6fe3fdce11 Merge pull request #1828 from comradekingu/patch-8
Spelling and linguistic updates for readme
2018-10-19 11:00:39 +02:00
Allan Nordhøy
90769a12b1 Spelling and linguistic updates 2018-10-19 02:05:29 +02:00
Mostafa Ahangarha
1d49b725b6 Translated using Weblate (Persian)
Currently translated at 23.2% (89 of 383 strings)
2018-10-18 11:31:57 +02:00
Stjepan
204feb97ce Translated using Weblate (Croatian)
Currently translated at 86.9% (333 of 383 strings)
2018-10-18 11:31:56 +02:00
maa123
e12389a748 Translated using Weblate (Japanese)
Currently translated at 96.8% (371 of 383 strings)
2018-10-18 11:31:52 +02:00
Christian Schabesberger
670591e221 Merge pull request #1792 from TeamNewPipe/lang
Add support for Localization
2018-10-16 16:16:05 +02:00
Christian Schabesberger
8006a7d578 Merge branch 'dev' into lang 2018-10-16 16:01:32 +02:00
Christian Schabesberger
8b9078b82e Merge pull request #1801 from TacoTheDank/dev
simply update gradles to 28, AS 3.2.0, and a few dependencies
2018-10-16 16:00:44 +02:00
Christian Schabesberger
56d4edd3ae Merge branch 'dev' into dev 2018-10-16 03:47:29 +02:00
Christian Schabesberger
a7f5ea865e Merge branch 'dev' into lang 2018-10-16 03:47:11 +02:00
Christian Schabesberger
2a62144abd Merge pull request #1800 from TeamNewPipe/history-screenshot
Update screenshots and readme
2018-10-16 03:46:38 +02:00
Christian Schabesberger
c7ea7a4f65 Merge branch 'dev' into dev 2018-10-16 03:45:14 +02:00
TobiGr
7ea090ba8d Update video detail screenshot 2018-10-15 15:16:24 +02:00
TobiGr
9294e353d3 Add link to privacy policy to readme
Closes TeamNewPipe/NewPipe#1789
Part of TeamNewPipe/NewPipe#1817
2018-10-15 15:02:34 +02:00
TobiGr
71c50c58ee Move tablet screenshots for better F-Droid integration 2018-10-15 15:00:41 +02:00
TobiGr
e322299fda Update history screenshot 2018-10-15 14:52:07 +02:00
Ákos Surányi
06602a568a Translated using Weblate (Hungarian)
Currently translated at 90.8% (348 of 383 strings)
2018-10-14 21:31:53 +02:00
Tobias Groza
a0f0529ad8 Merge pull request #1810 from saderror256/patch-1
Fix broken bold
2018-10-14 15:01:24 +02:00
SadError256
c371d863d9 Fix broken bold
also removed useless backslash in html5
2018-10-13 18:20:47 -04:00
Ákos Surányi
16d8c75953 Translated using Weblate (Hungarian)
Currently translated at 41.5% (159 of 383 strings)
2018-10-13 17:20:53 +02:00
Toldi Balázs
fa48c0e76b Translated using Weblate (Hungarian)
Currently translated at 41.5% (159 of 383 strings)
2018-10-13 17:20:51 +02:00
Tobias Groza
2d17cfaf2b Merge pull request #1644 from ritiek/separate-gesture-options
Separate options for volume and brightness gestures
2018-10-11 17:41:34 +02:00
Matej U
f379de0a3a Translated using Weblate (Slovenian)
Currently translated at 62.6% (240 of 383 strings)
2018-10-11 11:34:26 +02:00
TacoTheDank
d3fcb0aa6a Update build.gradle 2018-10-10 14:29:26 -04:00
Ritiek Malhotra
046740f10b Merge branch 'dev' into separate-gesture-options 2018-10-10 08:41:42 -07:00
TacoTheDank
ffae2eda83 simply update gradles to 28, and some dependencies 2018-10-09 12:22:30 -04:00
Christian Schabesberger
8334b8fe46 Merge pull request #1798 from TeamNewPipe/screenshots
add tablet screenshot
2018-10-08 12:35:57 +02:00
Christian Schabesberger
c6c6e58d28 add tablet screenshot 2018-10-08 12:35:13 +02:00
Christian Schabesberger
2ff0d6665c Merge pull request #1617 from nv95/tablet_ui
Tablet ui and grid list layout
2018-10-08 12:15:02 +02:00
Christian Schabesberger
dc6108c970 Merge branch 'dev' into tablet_ui 2018-10-08 11:56:25 +02:00
Christian Schabesberger
6f52f9b4af Merge pull request #1796 from saderror256/patch-1
Update README.md
2018-10-08 11:39:31 +02:00
zelos-h
b6eb896f0b Translated using Weblate (Chinese (Traditional))
Currently translated at 99.7% (382 of 383 strings)
2018-10-08 10:57:24 +02:00
SadError256
adf861c36d Update README.md 2018-10-07 13:39:02 -04:00
Christian Schabesberger
4e1bcdf209 Merge pull request #1516 from Somethingweirdhere/LongTapInSubs
Long-tap delete and share in subscriptions
2018-10-07 14:08:09 +02:00
Christian Schabesberger
d107fe19f7 Merge branch 'dev' into LongTapInSubs 2018-10-07 13:59:39 +02:00
Christian Schabesberger
fa03ff51d4 Merge pull request #1651 from comradekingu/patch-7
Spelling: Language rework
2018-10-07 13:39:03 +02:00
Christian Schabesberger
f6c6536b48 Merge branch 'dev' into patch-7 2018-10-07 13:26:10 +02:00
Christian Schabesberger
38e4249182 Merge branch 'dev' into lang 2018-10-07 13:25:35 +02:00
Christian Schabesberger
2dd8c0beee Merge pull request #1773 from prg318/clarify-bookmarks
[Closes #1772] change 'tab_bookmarks' string to 'Bookmarked Playlists' for UI clarity
2018-10-06 18:16:38 +02:00
Christian Schabesberger
6a35494ef1 Merge branch 'dev' into patch-7 2018-10-06 18:16:10 +02:00
Christian Schabesberger
bf1c42e085 Merge branch 'dev' into clarify-bookmarks 2018-10-06 18:10:18 +02:00
Christian Schabesberger
0ef6bf8067 Merge pull request #1783 from coin3x/enqueue-autoplay
Enqueuing now triggers video playing if the play queue has already ended
2018-10-06 17:55:22 +02:00
Christian Schabesberger
9d63e2ae97 Merge branch 'dev' into enqueue-autoplay 2018-10-06 17:35:55 +02:00
Christian Schabesberger
fdd8060296 Merge branch 'dev' into lang 2018-10-06 17:29:42 +02:00
Christian Schabesberger
ebbb23ffbb fix bugs in country search 2018-10-06 17:18:19 +02:00
Christian Schabesberger
0e413109bd Merge pull request #1748 from MaX-Lo/store_last_aspect_ratio
store and reload the last used aspect ratio
2018-10-06 12:09:14 +02:00
Christian Schabesberger
f7e29c1e00 revert sdk upgrade 2018-10-06 12:06:03 +02:00
Christian Schabesberger
42f777d49a Merge branch 'dev' into clarify-bookmarks 2018-10-06 12:01:34 +02:00
Christian Schabesberger
efb8ea4c25 make local settings be live updated 2018-10-05 16:31:23 +02:00
Christian Schabesberger
52bf5690c0 add support for content language and content country 2018-10-05 16:20:27 +02:00
Jasmine Vyas
607dff9263 Translated using Weblate (Hindi)
Currently translated at 92.6% (355 of 383 strings)
2018-10-04 22:28:46 +02:00
Coin
0510db75fb Enqueuing now triggers video playing if the play queue has done playing 2018-10-03 00:31:28 +08:00
MaX
859eecabc0 Merge branch 'dev' into store_last_aspect_ratio 2018-10-02 10:44:04 +02:00
MadderRagax
7a0253631b Translated using Weblate (Swedish)
Currently translated at 100.0% (383 of 383 strings)
2018-10-01 18:21:22 +02:00
ezjerry liao
c12a60c1ad Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (383 of 383 strings)
2018-10-01 18:21:21 +02:00
ButterflyOfFire
df9dbd6130 Translated using Weblate (Arabic)
Currently translated at 100.0% (383 of 383 strings)
2018-10-01 18:21:16 +02:00
Tobias Groza
a98e745116 Merge pull request #1771 from jludden/dev
Enable linear layout in Downloads activity with full video names
2018-10-01 17:40:40 +02:00
Lukas Sabota
61f1b10a06 Change 'tab_bookmarks' string to 'Bookmarked Playlists' for UI clarity 2018-09-30 11:34:16 -04:00
jludden
4bcb2a5c9d update linear layout
re-arrange elements and allow the video title to display over multiple lines
2018-09-30 07:42:02 +08:00
MaX
7e48648f9e Merge branch 'dev' into store_last_aspect_ratio 2018-09-29 12:45:10 +02:00
jludden
bcc97d1aa7 Adding switch view button to downloads activity
Can now switch between linear and grid layouts in the downloads activity
2018-09-29 15:13:15 +08:00
Christian Schabesberger
49f9d36718 Merge pull request #1640 from BO41/code-clean
Code clean
2018-09-28 17:17:30 +02:00
O Passante
f9cb258a5e Translated using Weblate (Galician)
Currently translated at 100.0% (383 of 383 strings)
2018-09-28 11:26:41 +02:00
O Passante
97381a4908 Translated using Weblate (Galician)
Currently translated at 100.0% (383 of 383 strings)
2018-09-27 01:28:42 +02:00
RainSlide
7a15acc546 Translated using Weblate (Chinese (Simplified))
Currently translated at 29.2% (112 of 383 strings)
2018-09-25 18:13:16 +02:00
O Passante
0265de2137 Added translation using Weblate (Galician) 2018-09-25 18:13:14 +02:00
Nigel Ticknor
595b9910f5 Translated using Weblate (Japanese)
Currently translated at 93.9% (360 of 383 strings)
2018-09-25 14:22:36 +02:00
Heimen Stoffels
f4d4d2cc35 Translated using Weblate (Dutch)
Currently translated at 100.0% (383 of 383 strings)
2018-09-25 14:22:35 +02:00
zelos-h
b4fb4d7dcf Translated using Weblate (Chinese (Traditional))
Currently translated at 96.0% (368 of 383 strings)
2018-09-25 14:22:30 +02:00
RainSlide
1a375fb523 Translated using Weblate (Chinese (Simplified))
Currently translated at 29.2% (112 of 383 strings)
2018-09-25 14:22:27 +02:00
zelos-h
658c0ff5c4 Translated using Weblate (Chinese (Hong Kong))
Currently translated at 37.8% (145 of 383 strings)
2018-09-25 14:22:23 +02:00
MaX-Lo
6092f06d46 store the last used aspect ratio in SharedPreferences and reload them on
resuming the VideoPlayer Activity (similar to storing/reloading the last used: screen rotation)
2018-09-22 11:32:13 +02:00
ezjerry liao
4671b956b3 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (383 of 383 strings)
2018-09-21 16:22:02 +02:00
postsorino
552ba6999a Translated using Weblate (Greek)
Currently translated at 99.7% (382 of 383 strings)
2018-09-20 15:16:07 +02:00
zelos-h
b86bc4455f Translated using Weblate (Chinese (Traditional))
Currently translated at 94.2% (361 of 383 strings)
2018-09-20 15:16:03 +02:00
Allan Nordhøy
b6d36ee117 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (383 of 383 strings)
2018-09-19 08:30:03 +02:00
Tobias Groza
5d57f864dc Translated using Weblate (Vietnamese)
Currently translated at 97.1% (372 of 383 strings)
2018-09-17 23:21:52 +02:00
naofum
c6ee2816db Translated using Weblate (Japanese)
Currently translated at 93.7% (359 of 383 strings)
2018-09-17 23:21:51 +02:00
Tobias Groza
0aa898b13f Translated using Weblate (Chinese (Hong Kong))
Currently translated at 37.8% (145 of 383 strings)
2018-09-17 23:21:49 +02:00
Stjepan
b22e82c8ce Translated using Weblate (Croatian)
Currently translated at 85.6% (328 of 383 strings)
2018-09-17 23:21:47 +02:00
zelos-h
63dee1e1ac Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (383 of 383 strings)
2018-09-16 13:27:50 +02:00
epsimatt
91c87ac301 Translated using Weblate (Korean)
Currently translated at 96.0% (368 of 383 strings)
2018-09-16 13:27:46 +02:00
Shuuji TAKAHASHI (shuuji3)
42371a6e8d Translated using Weblate (Japanese)
Currently translated at 88.7% (340 of 383 strings)
2018-09-14 21:20:02 +02:00
Ritiek Malhotra
d7aae849f6 Merge branch 'dev' into separate-gesture-options 2018-09-12 21:41:47 +05:30
DanieLoche
4fe9413662 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (383 of 383 strings)
2018-09-12 12:20:25 +02:00
CaptainCrumble
37bf51cebf Translated using Weblate (Portuguese)
Currently translated at 91.3% (350 of 383 strings)
2018-09-12 12:20:25 +02:00
DanieLoche
eee9cb8b87 Translated using Weblate (Portuguese)
Currently translated at 91.3% (350 of 383 strings)
2018-09-12 12:20:24 +02:00
DanieLoche
1724bca5f0 Translated using Weblate (French)
Currently translated at 100.0% (383 of 383 strings)
2018-09-12 12:20:21 +02:00
Cipisek Rumcajsu
ae6581fb55 Translated using Weblate (Czech)
Currently translated at 99.7% (382 of 383 strings)
2018-09-12 12:20:20 +02:00
Michael Moroni
0c632307ea Translated using Weblate (Italian)
Currently translated at 100.0% (383 of 383 strings)
2018-09-12 12:20:15 +02:00
BO41
479887eb84 fix broken merge resolve
fixing merge conflicts broke build
2018-09-11 19:37:12 +02:00
BO41
af280a7343 Java language level + javadoc + xml
replace with <>
String builder

BUILD SUCCESSFUL in 4s
39 actionable tasks: 4 executed, 35 up-to-date
2018-09-11 19:20:10 +02:00
BO41
802b26e870 error handling + imports + unboxing 2018-09-11 19:18:50 +02:00
BO41
0ab86937d2 data flow issue + declaration redundancy
make final
unused methods
make final

BUILD SUCCESSFUL in 0s
39 actionable tasks: 39 up-to-date
2018-09-11 19:18:41 +02:00
BO41
3ab06bf383 class structure
BUILD SUCCESSFUL in 17s
39 actionable tasks: 6 executed, 33 up-to-date
2018-09-11 19:18:14 +02:00
BO41
5db0cc5241 performance + usability
obsolete layout params
Ellipsis string can be replaced with ellipsis character
Missing inputType
Usage of showAsAction=always

BUILD SUCCESSFUL in 5s
39 actionable tasks: 4 executed, 35 up-to-date
2018-09-11 19:18:14 +02:00
BO41
a588ec084b correctness
use apply() on SharedPreferences
use dp instead of sp for text sizes

BUILD SUCCESSFUL in 22s
39 actionable tasks: 10 executed, 29 up-to-date
2018-09-11 19:18:02 +02:00
BO41
5660b5ddc6 accessibility
image without contentDescription
Keyboard inaccessible widget

BUILD SUCCESSFUL in 6s
39 actionable tasks: 4 executed, 35 up-to-date
2018-09-11 19:14:42 +02:00
BO41
27fbe69033 code cleanup
mainly removes throw statements

automated using Android Studio, staged by hand

BUILD SUCCESSFUL in 52s
39 actionable tasks: 37 executed, 2 up-to-date
2018-09-11 19:14:21 +02:00
Christian Schabesberger
1672ecb892 Merge branch 'dev' into patch-7 2018-09-11 16:34:58 +02:00
Christian Schabesberger
784e01347c fix wrong subscriptini count 2018-09-11 15:16:39 +02:00
Emin Tufan Çetin
5cc21a831b Translated using Weblate (Turkish)
Currently translated at 100.0% (383 of 383 strings)
2018-09-10 19:13:10 +02:00
Robson Cassiano
dcb9380b50 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (383 of 383 strings)
2018-09-10 19:13:08 +02:00
ButterflyOfFire
b1957773bb Translated using Weblate (Arabic)
Currently translated at 100.0% (383 of 383 strings)
2018-09-10 19:13:05 +02:00
switchtegrax1
c4f4583f20 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (382 of 383 strings)
2018-09-09 18:58:19 +02:00
Dominik Zabicki
440cdbdb23 Translated using Weblate (Polish)
Currently translated at 100.0% (383 of 383 strings)
2018-09-09 18:58:18 +02:00
Duppadaadadii
58bfde33a9 Translated using Weblate (Finnish)
Currently translated at 99.7% (382 of 383 strings)
2018-09-09 18:58:17 +02:00
skil3z
7c33e49ef6 Translated using Weblate (Finnish)
Currently translated at 99.7% (382 of 383 strings)
2018-09-09 18:58:17 +02:00
Rex_sa
3bf318e2b7 Translated using Weblate (Arabic)
Currently translated at 100.0% (383 of 383 strings)
2018-09-09 18:58:10 +02:00
Ritiek Malhotra
f56193ac18 We don't need to check this 2018-09-08 23:13:04 +05:30
ScratchBuild
31efa7a8f8 Translated using Weblate (Japanese)
Currently translated at 74.1% (284 of 383 strings)
2018-09-08 19:15:24 +02:00
skil3z
372932abaf Translated using Weblate (Finnish)
Currently translated at 74.6% (286 of 383 strings)
2018-09-08 19:15:23 +02:00
M Andreev
4c6dd2cdf2 Translated using Weblate (Bulgarian)
Currently translated at 99.4% (381 of 383 strings)
2018-09-08 19:15:18 +02:00
Stjepan
6d04e39151 Translated using Weblate (Croatian)
Currently translated at 65.7% (252 of 383 strings)
2018-09-08 19:15:15 +02:00
Ritiek Malhotra
afa257e79a Merge branch 'dev' into separate-gesture-options 2018-09-08 10:05:51 -07:00
Christian Schabesberger
05f8ee9747 fix channel links in description part 2 2018-09-07 22:23:32 +02:00
Christian Schabesberger
818ae03928 fix decrypt url and move on to v0.14.1 2018-09-07 21:51:14 +02:00
Ritiek Malhotra
97555645f8 Merge branch 'dev' into separate-gesture-options 2018-09-05 09:21:05 -07:00
kaka Thic
e350f43adc Translated using Weblate (Vietnamese)
Currently translated at 95.8% (367 of 383 strings)
2018-09-05 08:26:05 +02:00
Çağdaş Tatar
2257f3484d Translated using Weblate (Turkish)
Currently translated at 100.0% (383 of 383 strings)
2018-09-05 08:25:35 +02:00
Christian Schabesberger
f4ba8df02b Merge branch 'dev' into patch-7 2018-09-04 17:53:39 +02:00
notramo
99ebf03876 Translated using Weblate (Hungarian)
Currently translated at 40.7% (156 of 383 strings)
2018-09-03 19:18:49 +02:00
postsorino
995d79e373 Translated using Weblate (Greek)
Currently translated at 98.1% (376 of 383 strings)
2018-09-03 19:18:46 +02:00
Allan Nordhøy
0cd153ab61 Spelling: Language rework 2018-09-03 13:07:10 +02:00
Vasily
b24baa68ba Tablet UI in player 2018-08-31 17:30:06 +03:00
Vasily
d4c1b8d321 Fix: remove title from PlaylistDialog 2018-08-31 17:12:56 +03:00
Vasily
1e53d6bfab Scroll top related streams when loading 2018-08-31 17:08:13 +03:00
Ritiek Malhotra
5931cd6af7 Separate options for volume and brightness gestures 2018-08-31 19:30:40 +05:30
u1
a1be03543c Grid layout for subscriptions 2018-08-31 16:49:25 +03:00
u1
b1a5547de2 Fix reordering playlist items on grid layout 2018-08-31 16:34:35 +03:00
Vasily
ee4942dfd7 Grid layout for local lists 2018-08-31 14:34:32 +03:00
Vasily
8aef24be1e Merge branch 'tablet_ui' of https://github.com/nv95/NewPipe into tablet_ui 2018-08-29 09:00:15 +03:00
Vasily
fb25f6c7ac Automatic list layout 2018-08-29 08:19:15 +03:00
Vasily
fbd983217d Hide related streams while loading 2018-08-29 08:08:35 +03:00
Vasily
ce21fe2087 Always show description on tablets 2018-08-29 08:01:18 +03:00
Christian Schabesberger
17cd395712 Merge branch 'dev' into tablet_ui 2018-08-28 21:28:10 +02:00
Christian Schabesberger
bfe9de05cd Merge branch 'dev' into LongTapInSubs 2018-08-28 18:39:11 +02:00
Somethingweirdhere
4326354ca6 Code cleanup 2018-08-22 13:59:12 +02:00
Vasily
4208c852e1 Update translations 2018-08-22 10:33:10 +03:00
Vasily
7330b4532e Fix crash on screen rotation 2018-08-22 10:29:37 +03:00
Vasily
1e0f6f9e41 Grid view 2018-08-22 10:14:01 +03:00
Vasily
216e2367c6 Video details tablet layout 2018-08-22 08:32:58 +03:00
Somethingweirdhere
f4416fe007 Doesn't use getChannelInfo() anymore. 2018-08-16 01:04:37 +02:00
Somethingweirdhere
510591ef0f Removed use of blockingFirst() and scheduleDirect() 2018-08-16 00:45:37 +02:00
Somethingweirdhere
a5e89d1dd1 Merge branch 'dev' into LongTapInSubs 2018-08-15 23:33:59 +02:00
Somethingweirdhere
b48c251b36 Added unsubscription toast
Added error handling
Corrected threads
2018-06-30 02:42:47 +02:00
Somethingweirdhere
181a14ce59 Disposable now is cleaned properly 2018-06-30 02:20:01 +02:00
Somethingweirdhere
b9ea7ce066 Code looking nicer 2018-06-29 00:39:44 +02:00
Somethingweirdhere
f2f275512d It looks good now 2018-06-29 00:39:16 +02:00
Somethingweirdhere
5150c2ee62 This thing actually works lol 2018-06-28 23:56:39 +02:00
Somethingweirdhere
0b7593ad28 Delete on long press 2018-06-28 20:43:46 +02:00
Somethingweirdhere
a68823491c Delete on long press 2018-06-28 20:37:05 +02:00
205 changed files with 4663 additions and 1473 deletions

View File

@@ -5,13 +5,13 @@ android:
components:
# The BuildTools version used by NewPipe
- tools
- build-tools-27.0.3
- build-tools-28.0.3
# The SDK version used to compile NewPipe
- android-27
- android-28
before_install:
- yes | sdkmanager "platforms;android-27"
- yes | sdkmanager "platforms;android-28"
script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug testDebugUnitTest
licenses:

View File

@@ -1,21 +1,22 @@
<p align="center"><a href="https://newpipe.schabi.org"><img src="assets/new_pipe_icon_5.png" width="150"/></a></p>
<p align="center"><a href="https://newpipe.schabi.org"><img src="assets/new_pipe_icon_5.png" width="150"></a></p>
<h2 align="center"><b>NewPipe</b></h2>
<h4 align="center">A free lightweight YouTube frontend for Android.</h4>
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png"/></a></p>
<h4 align="center">A libre lightweight streaming frontend for Android.</h4>
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png"></a></p>
<p align="center">
<a href="https://github.com/TeamNewPipe/NewPipe" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" /></a>
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPL v3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg" /></a>
<a href="https://travis-ci.org/TeamNewPipe/NewPipe" alt="Build Status"><img src="https://travis-ci.org/TeamNewPipe/NewPipe.svg" /></a>
<a href="https://hosted.weblate.org/engage/NewPipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg" /></a>
<a href="http://webchat.freenode.net/?channels=%23newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg" /></a>
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"/></a>
<a href="https://github.com/TeamNewPipe/NewPipe" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
<a href="https://travis-ci.org/TeamNewPipe/NewPipe" alt="Build Status"><img src="https://travis-ci.org/TeamNewPipe/NewPipe.svg"></a>
<a href="https://hosted.weblate.org/engage/NewPipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg"></a>
<a href="http://webchat.freenode.net/?channels=%23newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
</p>
<hr />
<hr>
<p align="center"><a href="#screenshots">Screenshots</a> &bull; <a href="#description">Description</a> &bull; <a href="#features">Features</a> &bull; <a href="#contribution">Contribution</a> &bull; <a href="#donate">Donate</a> &bull; <a href="#license">License</a></p>
<p align="center"><a href="https://newpipe.schabi.org">Website</a> &bull; <a href="https://newpipe.schabi.org/blog/">Blog</a> &bull; <a href="https://newpipe.schabi.org/press/">Press</a></p>
<hr />
WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
<hr>
<b>WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.</b>
## Screenshots
@@ -29,46 +30,48 @@ WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
[<img src="fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
[<img src="fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
## Description
NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without Google Services installed. Also, you don't need a YouTube account to use NewPipe, and it's FLOSS.
NewPipe does not use any Google framework libraries, nor the YouTube API. Websites are only parsed to fetch required info, so this app can be used on devices without Google services installed. Also, you don't need a YouTube account to use NewPipe, which is copylefted libre software.
### Features
* Search videos
* Display general information about a video
* Display general info about videos
* Watch YouTube videos
* Listen to YouTube videos
* Popup mode (floating player)
* Select the streaming player to watch the video with
* Download videos
* Select streaming player to watch video with
* Download videos
* Download audio only
* Open a video in Kodi
* Show Next/Related videos
* Show next/related videos
* Search YouTube in a specific language
* Watch/Block age restricted material
* Display general information about channels
* Display general info about channels
* Search channels
* Watch videos from a channel
* Orbot/Tor support (not yet directly)
* 1080p/2k/4k support
* 1080p/2K/4K support
* View history
* Subscribe to channels
* Search history
* Search/Watch Playlists
* Watch as queues Playlists
* Queuing videos
* Search/watch playlists
* Watch as enqueued playlists
* Enqueue videos
* Local playlists
* Subtitles
* Multi-service support (eg. SoundCloud in NewPipe Beta)
* Multi-service support (e.g. SoundCloud \[beta\])
* Livestream support
### Coming Features
* Livestream support
* Cast to UPnP and Cast
* Show comments
* ... and many more
* and many more
## Contribution
Whether you have ideas, translations, design changes, code cleaning, or real heavy code changes, help is always welcome.
@@ -77,26 +80,31 @@ The more is done the better it gets!
If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
## Donate
If you like NewPipe we'd be happy about a donation. You can either donate via Bitcoin, Bountysource or Liberapay. For further information about donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
If you like NewPipe we'd be happy about a donation. You can either send bitcoin or donate via Bountysource or Liberapay. For further info on donating to NewPipe, please visit our [website](https://newpipe.schabi.org/donate).
<table>
<tr>
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin" /></td>
<td><img src="assets/bitcoin_qr_code.png" alt="Bitcoin QR Code" width="100px"/></td>
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
<td><img src="assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
</tr>
<tr>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" /></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"/></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px" /></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
</tr>
<tr>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px" /></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"/></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn." /></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
</tr>
</table>
## Privacy Policy
The NewPipe project aims to provide a private, anonymous experience for using media web services.
Therefore, the app does not collect any data without your consent. NewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report, or comment in our blog. You can find the document [here](https://newpipe.schabi.org/legal/privacy/).
## License
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)

View File

@@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 27
versionCode 67
versionName "0.14.0"
targetSdkVersion 28
versionCode 69
versionName "0.14.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -22,7 +22,6 @@ android {
}
debug {
multiDexEnabled true
debuggable true
applicationIdSuffix ".debug"
}
@@ -41,62 +40,61 @@ android {
}
ext {
supportLibVersion = '27.1.1'
exoPlayerLibVersion = '2.8.2'
supportLibVersion = '28.0.0'
exoPlayerLibVersion = '2.8.4' //2.9.0
roomDbLibVersion = '1.1.1'
leakCanaryLibVersion = '1.5.4'
okHttpLibVersion = '3.10.0'
leakCanaryLibVersion = '1.5.4' //1.6.1
okHttpLibVersion = '3.11.0'
icepickLibVersion = '3.2.0'
stethoLibVersion = '1.5.0'
}
dependencies {
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2') {
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2', {
exclude module: 'support-annotations'
}
})
implementation 'com.github.TeamNewPipe:NewPipeExtractor:850670917fce'
implementation 'com.github.TeamNewPipe:NewPipeExtractor:32d316330c26'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.8.9'
testImplementation 'org.mockito:mockito-core:2.23.0'
implementation "com.android.support:appcompat-v7:$supportLibVersion"
implementation "com.android.support:support-v4:$supportLibVersion"
implementation "com.android.support:design:$supportLibVersion"
implementation "com.android.support:recyclerview-v7:$supportLibVersion"
implementation "com.android.support:preference-v14:$supportLibVersion"
implementation "com.android.support:appcompat-v7:${supportLibVersion}"
implementation "com.android.support:support-v4:${supportLibVersion}"
implementation "com.android.support:design:${supportLibVersion}"
implementation "com.android.support:recyclerview-v7:${supportLibVersion}"
implementation "com.android.support:preference-v14:${supportLibVersion}"
implementation "com.android.support:cardview-v7:${supportLibVersion}"
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'ch.acra:acra:4.9.2'
implementation 'ch.acra:acra:4.9.2' //4.11
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.github.nirhart:ParallaxScroll:dd53d1f9d1'
implementation 'com.nononsenseapps:filepicker:4.2.1'
implementation "com.google.android.exoplayer:exoplayer:$exoPlayerLibVersion"
implementation "com.google.android.exoplayer:extension-mediasession:$exoPlayerLibVersion"
implementation "com.google.android.exoplayer:exoplayer:${exoPlayerLibVersion}"
implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerLibVersion}"
debugImplementation "com.facebook.stetho:stetho:$stethoLibVersion"
debugImplementation "com.facebook.stetho:stetho-urlconnection:$stethoLibVersion"
debugImplementation "com.facebook.stetho:stetho:${stethoLibVersion}"
debugImplementation "com.facebook.stetho:stetho-urlconnection:${stethoLibVersion}"
debugImplementation 'com.android.support:multidex:1.0.3'
implementation 'io.reactivex.rxjava2:rxjava:2.1.14'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation "android.arch.persistence.room:runtime:$roomDbLibVersion"
implementation "android.arch.persistence.room:rxjava2:$roomDbLibVersion"
annotationProcessor "android.arch.persistence.room:compiler:$roomDbLibVersion"
implementation "android.arch.persistence.room:runtime:${roomDbLibVersion}"
implementation "android.arch.persistence.room:rxjava2:${roomDbLibVersion}"
annotationProcessor "android.arch.persistence.room:compiler:${roomDbLibVersion}"
implementation "frankiesardo:icepick:$icepickLibVersion"
annotationProcessor "frankiesardo:icepick-processor:$icepickLibVersion"
implementation "frankiesardo:icepick:${icepickLibVersion}"
annotationProcessor "frankiesardo:icepick-processor:${icepickLibVersion}"
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryLibVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryLibVersion"
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakCanaryLibVersion}"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryLibVersion}"
implementation "com.squareup.okhttp3:okhttp:$okHttpLibVersion"
debugImplementation "com.facebook.stetho:stetho-okhttp3:$stethoLibVersion"
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation "com.squareup.okhttp3:okhttp:${okHttpLibVersion}"
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoLibVersion}"
}

View File

@@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:name=".App"
@@ -238,4 +239,4 @@
android:name=".RouterActivity$FetcherService"
android:exported="false"/>
</application>
</manifest>
</manifest>

View File

@@ -5,6 +5,7 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -21,6 +22,7 @@ import org.acra.config.ConfigurationBuilder;
import org.acra.sender.ReportSenderFactory;
import org.schabi.newpipe.extractor.Downloader;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.utils.Localization;
import org.schabi.newpipe.report.AcraReportSenderFactory;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
@@ -65,7 +67,8 @@ public class App extends Application {
private RefWatcher refWatcher;
@SuppressWarnings("unchecked")
private static final Class<? extends ReportSenderFactory>[] reportSenderFactoryClasses = new Class[]{AcraReportSenderFactory.class};
private static final Class<? extends ReportSenderFactory>[]
reportSenderFactoryClasses = new Class[]{AcraReportSenderFactory.class};
@Override
protected void attachBaseContext(Context base) {
@@ -88,7 +91,8 @@ public class App extends Application {
// Initialize settings first because others inits can use its values
SettingsActivity.initSettings(this);
NewPipe.init(getDownloader());
NewPipe.init(getDownloader(),
org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(this));
StateSaver.init(this);
initNotificationChannel();
@@ -106,7 +110,7 @@ public class App extends Application {
// https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
public void accept(@NonNull Throwable throwable) {
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " +
"throwable = [" + throwable.getClass().getName() + "]");
@@ -180,7 +184,11 @@ public class App extends Application {
ACRA.init(this, acraConfig);
} catch (ACRAConfigurationException ace) {
ace.printStackTrace();
ErrorActivity.reportError(this, ace, null, null, ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
ErrorActivity.reportError(this,
ace,
null,
null,
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
"Could not initialize ACRA crash report", R.string.app_ui_crash));
}
}
@@ -200,7 +208,8 @@ public class App extends Application {
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
mChannel.setDescription(description);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(mChannel);
}

View File

@@ -12,14 +12,12 @@ import android.view.View;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.leakcanary.RefWatcher;
import org.schabi.newpipe.report.UserAction;
import icepick.Icepick;
import icepick.State;
public abstract class BaseFragment extends Fragment {
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
protected boolean DEBUG = MainActivity.DEBUG;
protected final boolean DEBUG = MainActivity.DEBUG;
protected AppCompatActivity activity;
public static final ImageLoader imageLoader = ImageLoader.getInstance();

View File

@@ -4,6 +4,7 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.utils.Localization;
import java.io.IOException;
import java.io.InputStream;
@@ -43,7 +44,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
private static Downloader instance;
private String mCookies;
private OkHttpClient client;
private final OkHttpClient client;
private Downloader(OkHttpClient.Builder builder) {
this.client = builder
@@ -103,13 +104,13 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
* but set the HTTP header field "Accept-Language" to the supplied string.
*
* @param siteUrl the URL of the text file to return the contents of
* @param language the language (usually a 2-character code) to set as the preferred language
* @param localization the language and country (usually a 2-character code) to set
* @return the contents of the specified text file
*/
@Override
public String download(String siteUrl, String language) throws IOException, ReCaptchaException {
public String download(String siteUrl, Localization localization) throws IOException, ReCaptchaException {
Map<String, String> requestProperties = new HashMap<>();
requestProperties.put("Accept-Language", language);
requestProperties.put("Accept-Language", localization.getLanguage());
return download(siteUrl, requestProperties);
}

View File

@@ -23,7 +23,6 @@ package org.schabi.newpipe;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -66,8 +65,6 @@ import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver;
import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.extractor.InfoItem.InfoType.PLAYLIST;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");

View File

@@ -85,7 +85,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
}
private class ReCaptchaWebViewClient extends WebViewClient {
private Activity context;
private final Activity context;
private String mCookies;
ReCaptchaWebViewClient(Activity ctx) {

View File

@@ -1,7 +1,6 @@
package org.schabi.newpipe;
import android.annotation.SuppressLint;
import android.app.FragmentManager;
import android.app.IntentService;
import android.content.Context;
import android.content.DialogInterface;
@@ -13,7 +12,6 @@ import android.preference.PreferenceManager;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@@ -38,7 +36,6 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -51,14 +48,12 @@ import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Observer;
import icepick.Icepick;
import icepick.State;
@@ -86,7 +81,7 @@ public class RouterActivity extends AppCompatActivity {
protected int selectedPreviously = -1;
protected String currentUrl;
protected CompositeDisposable disposables = new CompositeDisposable();
protected final CompositeDisposable disposables = new CompositeDisposable();
private boolean selectionIsDownload = false;
@@ -184,12 +179,16 @@ public class RouterActivity extends AppCompatActivity {
if (selectedChoiceKey.equals(alwaysAskKey)) {
final List<AdapterChoiceItem> choices = getChoicesForService(currentService, currentLinkType);
if (choices.size() == 1) {
handleChoice(choices.get(0).key);
} else if (choices.size() == 0) {
handleChoice(showInfoKey);
} else {
showDialog(choices);
switch (choices.size()) {
case 1:
handleChoice(choices.get(0).key);
break;
case 0:
handleChoice(showInfoKey);
break;
default:
showDialog(choices);
break;
}
} else if (selectedChoiceKey.equals(showInfoKey)) {
handleChoice(showInfoKey);

View File

@@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
@@ -17,7 +16,7 @@ import java.lang.ref.WeakReference;
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
WeakReference<Activity> weakReference;
final WeakReference<Activity> weakReference;
private License license;
public LicenseFragmentHelper(@Nullable Activity activity) {
@@ -78,18 +77,18 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
throw new NullPointerException("license is null");
}
String licenseContent = "";
StringBuilder licenseContent = new StringBuilder();
String webViewData;
try {
BufferedReader in = new BufferedReader(new InputStreamReader(context.getAssets().open(license.getFilename()), "UTF-8"));
String str;
while ((str = in.readLine()) != null) {
licenseContent += str;
licenseContent.append(str);
}
in.close();
// split the HTML file and insert the stylesheet into the HEAD of the file
String[] insert = licenseContent.split("</head>");
String[] insert = licenseContent.toString().split("</head>");
webViewData = insert[0] + "<style type=\"text/css\">"
+ getLicenseStylesheet(context) + "</style></head>"
+ insert[1];

View File

@@ -30,7 +30,7 @@ public interface BasicDAO<Entity> {
/* Deletes */
@Delete
int delete(final Entity entity);
void delete(final Entity entity);
@Delete
int delete(final Collection<Entity> entities);
@@ -42,5 +42,5 @@ public interface BasicDAO<Entity> {
int update(final Entity entity);
@Update
int update(final Collection<Entity> entities);
void update(final Collection<Entity> entities);
}

View File

@@ -4,7 +4,6 @@ import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.support.annotation.Nullable;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import java.util.List;

View File

@@ -5,7 +5,6 @@ import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.support.annotation.Nullable;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;

View File

@@ -2,7 +2,6 @@ package org.schabi.newpipe.database.playlist.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Transaction;
import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
@@ -12,7 +11,6 @@ import java.util.List;
import io.reactivex.Flowable;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
@Dao

View File

@@ -8,7 +8,6 @@ import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import java.util.List;

View File

@@ -5,8 +5,6 @@ import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import java.util.Date;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;

View File

@@ -6,7 +6,6 @@ import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.util.Constants;

View File

@@ -10,7 +10,6 @@ import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import java.util.ArrayList;
import java.util.List;
@@ -23,7 +22,6 @@ import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_SERVI
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
@Dao
public abstract class StreamDAO implements BasicDAO<StreamEntity> {

View File

@@ -28,11 +28,11 @@ public class DeleteDownloadManager {
private static final String KEY_STATE = "delete_manager_state";
private View mView;
private HashSet<String> mPendingMap;
private List<Disposable> mDisposableList;
private final View mView;
private final HashSet<String> mPendingMap;
private final List<Disposable> mDisposableList;
private DownloadManager mDownloadManager;
private PublishSubject<DownloadMission> publishSubject = PublishSubject.create();
private final PublishSubject<DownloadMission> publishSubject = PublishSubject.create();
DeleteDownloadManager(Activity activity) {
mPendingMap = new HashSet<>();

View File

@@ -55,7 +55,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
private StreamItemAdapter<AudioStream> audioStreamsAdapter;
private StreamItemAdapter<VideoStream> videoStreamsAdapter;
private CompositeDisposable disposables = new CompositeDisposable();
private final CompositeDisposable disposables = new CompositeDisposable();
private EditText nameEditText;
private Spinner streamsSpinner;

View File

@@ -32,7 +32,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import icepick.State;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import static org.schabi.newpipe.util.AnimationUtils.animateView;

View File

@@ -2,7 +2,6 @@ package org.schabi.newpipe.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

View File

@@ -3,9 +3,9 @@ package org.schabi.newpipe.fragments.detail;
import java.io.Serializable;
class StackItem implements Serializable {
private int serviceId;
private final int serviceId;
private String title;
private String url;
private final String url;
StackItem(int serviceId, String url, String title) {
this.serviceId = serviceId;

View File

@@ -33,12 +33,14 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@@ -64,19 +66,17 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.StreamItemAdapter;
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
@@ -87,6 +87,8 @@ import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.StreamItemAdapter;
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
@@ -154,6 +156,7 @@ public class VideoDetailFragment
private View videoTitleRoot;
private TextView videoTitleTextView;
@Nullable
private ImageView videoTitleToggleArrow;
private TextView videoCountView;
@@ -415,14 +418,16 @@ public class VideoDetailFragment
}
private void toggleTitleAndDescription() {
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
videoTitleTextView.setMaxLines(1);
videoDescriptionRootLayout.setVisibility(View.GONE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
} else {
videoTitleTextView.setMaxLines(10);
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
if (videoTitleToggleArrow != null) { //it is null for tablets
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
videoTitleTextView.setMaxLines(1);
videoDescriptionRootLayout.setVisibility(View.GONE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
} else {
videoTitleTextView.setMaxLines(10);
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
}
}
}
@@ -622,8 +627,11 @@ public class VideoDetailFragment
relatedStreamsView.addView(
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
relatedStreamsView.addView(getSeparatorView());
relatedStreamRootLayout.setVisibility(View.VISIBLE);
} else nextStreamTitle.setVisibility(View.GONE);
setRelatedStreamsVisibility(View.VISIBLE);
} else {
nextStreamTitle.setVisibility(View.GONE);
setRelatedStreamsVisibility(View.GONE);
}
if (info.getRelatedStreams() != null
&& !info.getRelatedStreams().isEmpty() && showRelatedStreams) {
@@ -639,13 +647,13 @@ public class VideoDetailFragment
}
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
relatedStreamRootLayout.setVisibility(View.VISIBLE);
setRelatedStreamsVisibility(View.VISIBLE);
relatedStreamExpandButton.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
} else {
if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
if (info.getNextVideo() == null) setRelatedStreamsVisibility(View.GONE);
relatedStreamExpandButton.setVisibility(View.GONE);
}
}
@@ -760,7 +768,7 @@ public class VideoDetailFragment
* Stack that contains the "navigation history".<br>
* The peek is the current video.
*/
protected LinkedList<StackItem> stack = new LinkedList<>();
protected final LinkedList<StackItem> stack = new LinkedList<>();
public void clearHistory() {
stack.clear();
@@ -1114,8 +1122,16 @@ public class VideoDetailFragment
animateView(videoTitleTextView, true, 0);
videoDescriptionRootLayout.setVisibility(View.GONE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
videoTitleToggleArrow.setVisibility(View.GONE);
if (videoTitleToggleArrow != null) { //phone
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
videoTitleToggleArrow.setVisibility(View.GONE);
} else { //tablet
final View related = (View) relatedStreamRootLayout.getParent();
//don`t need to hide it if related streams are disabled
if (related.getVisibility() == View.VISIBLE) {
related.setVisibility(View.INVISIBLE);
}
}
videoTitleRoot.setClickable(false);
imageLoader.cancelDisplayTask(thumbnailImageView);
@@ -1190,11 +1206,15 @@ public class VideoDetailFragment
detailDurationView.setVisibility(View.GONE);
}
videoTitleRoot.setClickable(true);
videoTitleToggleArrow.setVisibility(View.VISIBLE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
videoDescriptionView.setVisibility(View.GONE);
videoDescriptionRootLayout.setVisibility(View.GONE);
if (videoTitleToggleArrow != null) {
videoTitleRoot.setClickable(true);
videoTitleToggleArrow.setVisibility(View.VISIBLE);
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
videoDescriptionRootLayout.setVisibility(View.GONE);
} else {
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
}
if (!TextUtils.isEmpty(info.getUploadDate())) {
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
}
@@ -1242,6 +1262,11 @@ public class VideoDetailFragment
// Only auto play in the first open
autoPlayEnabled = false;
}
final ViewParent related = relatedStreamRootLayout.getParent();
if (related instanceof ScrollView) {
((ScrollView) related).scrollTo(0, 0);
}
}
@@ -1299,4 +1324,13 @@ public class VideoDetailFragment
showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema);
}
private void setRelatedStreamsVisibility(int visibility) {
final ViewParent parent = relatedStreamRootLayout.getParent();
if (parent instanceof ScrollView) {
((ScrollView) parent).setVisibility(visibility);
} else {
relatedStreamRootLayout.setVisibility(visibility);
}
}
}

View File

@@ -3,10 +3,15 @@ package org.schabi.newpipe.fragments.list;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -21,9 +26,9 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemDialog;
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.util.NavigationHelper;
@@ -36,7 +41,7 @@ import java.util.Queue;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implements ListViewContract<I, N>, StateSaver.WriteRead {
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implements ListViewContract<I, N>, StateSaver.WriteRead, SharedPreferences.OnSharedPreferenceChangeListener {
/*//////////////////////////////////////////////////////////////////////////
// Views
@@ -44,6 +49,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
protected InfoListAdapter infoListAdapter;
protected RecyclerView itemsList;
private int updateFlags = 0;
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
@@ -59,12 +67,31 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
PreferenceManager.getDefaultSharedPreferences(activity)
.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
StateSaver.onDestroy(savedState);
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onResume() {
super.onResume();
if (updateFlags != 0) {
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
final boolean useGrid = isGridLayout();
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
infoListAdapter.setGridItemVariants(useGrid);
infoListAdapter.notifyDataSetChanged();
}
updateFlags = 0;
}
}
/*//////////////////////////////////////////////////////////////////////////
@@ -119,13 +146,25 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
return new LinearLayoutManager(activity);
}
protected RecyclerView.LayoutManager getGridLayoutManager() {
final Resources resources = activity.getResources();
int width = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width);
width += (24 * resources.getDisplayMetrics().density);
final int spanCount = (int) Math.floor(resources.getDisplayMetrics().widthPixels / (double)width);
final GridLayoutManager lm = new GridLayoutManager(activity, spanCount);
lm.setSpanSizeLookup(infoListAdapter.getSpanSizeLookup(spanCount));
return lm;
}
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
final boolean useGrid = isGridLayout();
itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(getListLayoutManager());
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
infoListAdapter.setGridItemVariants(useGrid);
infoListAdapter.setFooter(getListFooter());
infoListAdapter.setHeader(getListHeader());
@@ -308,4 +347,22 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
public void handleNextItems(N result) {
isLoading.set(false);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(getString(R.string.list_view_mode_key))) {
updateFlags |= LIST_MODE_UPDATE_FLAG;
}
}
protected boolean isGridLayout() {
final String list_mode = PreferenceManager.getDefaultSharedPreferences(activity).getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value));
if ("auto".equals(list_mode)) {
final Configuration configuration = getResources().getConfiguration();
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
} else {
return "grid".equals(list_mode);
}
}
}

View File

@@ -8,9 +8,6 @@ import android.view.View;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.util.Constants;
import java.util.Queue;
@@ -19,7 +16,6 @@ import icepick.State;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public abstract class BaseListInfoFragment<I extends ListInfo>

View File

@@ -68,7 +68,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
private CompositeDisposable disposables = new CompositeDisposable();
private final CompositeDisposable disposables = new CompositeDisposable();
private Disposable subscribeButtonMonitor;
private SubscriptionService subscriptionService;
@@ -90,8 +90,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
private MenuItem menuRssButton;
private boolean mIsVisibleToUser = false;
public static ChannelFragment getInstance(int serviceId, String url, String name) {
ChannelFragment instance = new ChannelFragment();
instance.setInitialData(serviceId, url, name);
@@ -105,7 +103,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
mIsVisibleToUser = isVisibleToUser;
if(activity != null
&& useAsFrontPage
&& isVisibleToUser) {

View File

@@ -5,7 +5,6 @@ import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -19,8 +18,6 @@ import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
@@ -131,26 +128,16 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
@Override
public Single<KioskInfo> loadResult(boolean forceReload) {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getKioskInfo(serviceId,
url,
contentCountry,
forceReload);
}
@Override
public Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getMoreKioskItems(serviceId,
url,
currentNextPageUrl,
contentCountry);
currentNextPageUrl);
}
/*//////////////////////////////////////////////////////////////////////////

View File

@@ -20,7 +20,6 @@ import android.widget.TextView;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.schabi.newpipe.App;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
@@ -30,7 +29,6 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;

View File

@@ -122,12 +122,11 @@ public class SearchFragment
private String nextPageUrl;
private String contentCountry;
private boolean isSuggestionsEnabled = true;
private boolean isSearchHistoryEnabled = true;
private PublishSubject<String> suggestionPublisher = PublishSubject.create();
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
private Disposable searchDisposable;
private Disposable suggestionDisposable;
private CompositeDisposable disposables = new CompositeDisposable();
private final CompositeDisposable disposables = new CompositeDisposable();
private SuggestionListAdapter suggestionListAdapter;
private HistoryRecordManager historyRecordManager;
@@ -173,7 +172,7 @@ public class SearchFragment
suggestionListAdapter = new SuggestionListAdapter(activity);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
boolean isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
historyRecordManager = new HistoryRecordManager(context);
@@ -627,7 +626,7 @@ public class SearchFragment
}
final Observable<List<SuggestionItem>> network = ExtractorHelper
.suggestionsFor(serviceId, query, contentCountry)
.suggestionsFor(serviceId, query)
.toObservable()
.map(strings -> {
List<SuggestionItem> result = new ArrayList<>();
@@ -727,8 +726,7 @@ public class SearchFragment
searchDisposable = ExtractorHelper.searchFor(serviceId,
searchString,
Arrays.asList(contentFilter),
sortFilter,
contentCountry)
sortFilter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
@@ -746,8 +744,7 @@ public class SearchFragment
searchString,
asList(contentFilter),
sortFilter,
nextPageUrl,
contentCountry)
nextPageUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))

View File

@@ -45,7 +45,7 @@ public class InfoItemBuilder {
private static final String TAG = InfoItemBuilder.class.toString();
private final Context context;
private ImageLoader imageLoader = ImageLoader.getInstance();
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;

View File

@@ -5,7 +5,6 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

View File

@@ -1,6 +1,7 @@
package org.schabi.newpipe.info_list;
import android.app.Activity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
@@ -12,9 +13,12 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
@@ -52,14 +56,18 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final int MINI_STREAM_HOLDER_TYPE = 0x100;
private static final int STREAM_HOLDER_TYPE = 0x101;
private static final int GRID_STREAM_HOLDER_TYPE = 0x102;
private static final int MINI_CHANNEL_HOLDER_TYPE = 0x200;
private static final int CHANNEL_HOLDER_TYPE = 0x201;
private static final int GRID_CHANNEL_HOLDER_TYPE = 0x202;
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
private static final int GRID_PLAYLIST_HOLDER_TYPE = 0x302;
private final InfoItemBuilder infoItemBuilder;
private final ArrayList<InfoItem> infoItemList;
private boolean useMiniVariant = false;
private boolean useGridVariant = false;
private boolean showFooter = false;
private View header = null;
private View footer = null;
@@ -94,6 +102,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
this.useMiniVariant = useMiniVariant;
}
public void setGridItemVariants(boolean useGridVariant) {
this.useGridVariant = useGridVariant;
}
public void addInfoItemList(List<InfoItem> data) {
if (data != null) {
if (DEBUG) {
@@ -206,11 +218,11 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
final InfoItem item = infoItemList.get(position);
switch (item.getInfoType()) {
case STREAM:
return useMiniVariant ? MINI_STREAM_HOLDER_TYPE : STREAM_HOLDER_TYPE;
return useGridVariant ? GRID_STREAM_HOLDER_TYPE : useMiniVariant ? MINI_STREAM_HOLDER_TYPE : STREAM_HOLDER_TYPE;
case CHANNEL:
return useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
return useGridVariant ? GRID_CHANNEL_HOLDER_TYPE : useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
case PLAYLIST:
return useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
return useGridVariant ? GRID_PLAYLIST_HOLDER_TYPE : useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
default:
Log.e(TAG, "Trollolo");
return -1;
@@ -229,14 +241,20 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return new StreamMiniInfoItemHolder(infoItemBuilder, parent);
case STREAM_HOLDER_TYPE:
return new StreamInfoItemHolder(infoItemBuilder, parent);
case GRID_STREAM_HOLDER_TYPE:
return new StreamGridInfoItemHolder(infoItemBuilder, parent);
case MINI_CHANNEL_HOLDER_TYPE:
return new ChannelMiniInfoItemHolder(infoItemBuilder, parent);
case CHANNEL_HOLDER_TYPE:
return new ChannelInfoItemHolder(infoItemBuilder, parent);
case GRID_CHANNEL_HOLDER_TYPE:
return new ChannelGridInfoItemHolder(infoItemBuilder, parent);
case MINI_PLAYLIST_HOLDER_TYPE:
return new PlaylistMiniInfoItemHolder(infoItemBuilder, parent);
case PLAYLIST_HOLDER_TYPE:
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
case GRID_PLAYLIST_HOLDER_TYPE:
return new PlaylistGridInfoItemHolder(infoItemBuilder, parent);
default:
Log.e(TAG, "Trollolo");
return new FallbackViewHolder(new View(parent.getContext()));
@@ -257,4 +275,14 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
((HFHolder) holder).view = footer;
}
}
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
return new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
final int type = getItemViewType(position);
return type == HEADER_TYPE || type == FOOTER_TYPE ? spanCount : 1;
}
};
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.info_list.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.info_list.InfoItemBuilder;
public class ChannelGridInfoItemHolder extends ChannelMiniInfoItemHolder {
public ChannelGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_channel_grid_item, parent);
}
}

View File

@@ -47,6 +47,13 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
itemBuilder.getOnChannelSelectedListener().selected(item);
}
});
itemView.setOnLongClickListener(view -> {
if (itemBuilder.getOnChannelSelectedListener() != null) {
itemBuilder.getOnChannelSelectedListener().held(item);
}
return true;
});
}
protected String getDetailLine(final ChannelInfoItem item) {

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.info_list.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.info_list.InfoItemBuilder;
public class PlaylistGridInfoItemHolder extends PlaylistMiniInfoItemHolder {
public PlaylistGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.info_list.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.info_list.InfoItemBuilder;
public class StreamGridInfoItemHolder extends StreamMiniInfoItemHolder {
public StreamGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_stream_grid_item, parent);
}
}

View File

@@ -1,8 +1,13 @@
package org.schabi.newpipe.local;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -25,7 +30,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
* called and is memory efficient when in backstack.
* */
public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
implements ListViewContract<I, N> {
implements ListViewContract<I, N>, SharedPreferences.OnSharedPreferenceChangeListener {
/*//////////////////////////////////////////////////////////////////////////
// Views
@@ -36,6 +41,9 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
protected LocalItemListAdapter itemListAdapter;
protected RecyclerView itemsList;
private int updateFlags = 0;
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
/*//////////////////////////////////////////////////////////////////////////
// Lifecycle - Creation
@@ -45,6 +53,29 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
PreferenceManager.getDefaultSharedPreferences(activity)
.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onResume() {
super.onResume();
if (updateFlags != 0) {
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
final boolean useGrid = isGridLayout();
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
itemListAdapter.setGridItemVariants(useGrid);
itemListAdapter.notifyDataSetChanged();
}
updateFlags = 0;
}
}
/*//////////////////////////////////////////////////////////////////////////
@@ -59,6 +90,16 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
return activity.getLayoutInflater().inflate(R.layout.pignate_footer, itemsList, false);
}
protected RecyclerView.LayoutManager getGridLayoutManager() {
final Resources resources = activity.getResources();
int width = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width);
width += (24 * resources.getDisplayMetrics().density);
final int spanCount = (int) Math.floor(resources.getDisplayMetrics().widthPixels / (double)width);
final GridLayoutManager lm = new GridLayoutManager(activity, spanCount);
lm.setSpanSizeLookup(itemListAdapter.getSpanSizeLookup(spanCount));
return lm;
}
protected RecyclerView.LayoutManager getListLayoutManager() {
return new LinearLayoutManager(activity);
}
@@ -67,10 +108,13 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(getListLayoutManager());
itemListAdapter = new LocalItemListAdapter(activity);
final boolean useGrid = isGridLayout();
itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
itemListAdapter.setGridItemVariants(useGrid);
itemListAdapter.setHeader(headerRootView = getListHeader());
itemListAdapter.setFooter(footerRootView = getListFooter());
@@ -174,4 +218,22 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
resetFragment();
return super.onError(exception);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(getString(R.string.list_view_mode_key))) {
updateFlags |= LIST_MODE_UPDATE_FLAG;
}
}
protected boolean isGridLayout() {
final String list_mode = PreferenceManager.getDefaultSharedPreferences(activity).getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value));
if ("auto".equals(list_mode)) {
final Configuration configuration = getResources().getConfiguration();
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
} else {
return "grid".equals(list_mode);
}
}
}

View File

@@ -33,7 +33,7 @@ public class LocalItemBuilder {
private static final String TAG = LocalItemBuilder.class.toString();
private final Context context;
private ImageLoader imageLoader = ImageLoader.getInstance();
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnClickGesture<LocalItem> onSelectedListener;

View File

@@ -1,18 +1,21 @@
package org.schabi.newpipe.local;
import android.app.Activity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.local.HeaderFooterHolder;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.holder.LocalItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistGridItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistStreamGridItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistStreamItemHolder;
import org.schabi.newpipe.local.holder.LocalStatisticStreamGridItemHolder;
import org.schabi.newpipe.local.holder.LocalStatisticStreamItemHolder;
import org.schabi.newpipe.local.holder.RemotePlaylistGridItemHolder;
import org.schabi.newpipe.local.holder.RemotePlaylistItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.Localization;
@@ -52,14 +55,19 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
private static final int STREAM_STATISTICS_HOLDER_TYPE = 0x1000;
private static final int STREAM_PLAYLIST_HOLDER_TYPE = 0x1001;
private static final int STREAM_STATISTICS_GRID_HOLDER_TYPE = 0x1002;
private static final int STREAM_PLAYLIST_GRID_HOLDER_TYPE = 0x1004;
private static final int LOCAL_PLAYLIST_HOLDER_TYPE = 0x2000;
private static final int REMOTE_PLAYLIST_HOLDER_TYPE = 0x2001;
private static final int LOCAL_PLAYLIST_GRID_HOLDER_TYPE = 0x2002;
private static final int REMOTE_PLAYLIST_GRID_HOLDER_TYPE = 0x2004;
private final LocalItemBuilder localItemBuilder;
private final ArrayList<LocalItem> localItems;
private final DateFormat dateFormat;
private boolean showFooter = false;
private boolean useGridVariant = false;
private View header = null;
private View footer = null;
@@ -134,6 +142,10 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
notifyDataSetChanged();
}
public void setGridItemVariants(boolean useGridVariant) {
this.useGridVariant = useGridVariant;
}
public void setHeader(View header) {
boolean changed = header != this.header;
this.header = header;
@@ -195,11 +207,11 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
final LocalItem item = localItems.get(position);
switch (item.getLocalItemType()) {
case PLAYLIST_LOCAL_ITEM: return LOCAL_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_REMOTE_ITEM: return REMOTE_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_LOCAL_ITEM: return useGridVariant ? LOCAL_PLAYLIST_GRID_HOLDER_TYPE : LOCAL_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_REMOTE_ITEM: return useGridVariant ? REMOTE_PLAYLIST_GRID_HOLDER_TYPE : REMOTE_PLAYLIST_HOLDER_TYPE;
case PLAYLIST_STREAM_ITEM: return STREAM_PLAYLIST_HOLDER_TYPE;
case STATISTIC_STREAM_ITEM: return STREAM_STATISTICS_HOLDER_TYPE;
case PLAYLIST_STREAM_ITEM: return useGridVariant ? STREAM_PLAYLIST_GRID_HOLDER_TYPE : STREAM_PLAYLIST_HOLDER_TYPE;
case STATISTIC_STREAM_ITEM: return useGridVariant ? STREAM_STATISTICS_GRID_HOLDER_TYPE : STREAM_STATISTICS_HOLDER_TYPE;
default:
Log.e(TAG, "No holder type has been considered for item: [" +
item.getLocalItemType() + "]");
@@ -218,12 +230,20 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
return new HeaderFooterHolder(footer);
case LOCAL_PLAYLIST_HOLDER_TYPE:
return new LocalPlaylistItemHolder(localItemBuilder, parent);
case LOCAL_PLAYLIST_GRID_HOLDER_TYPE:
return new LocalPlaylistGridItemHolder(localItemBuilder, parent);
case REMOTE_PLAYLIST_HOLDER_TYPE:
return new RemotePlaylistItemHolder(localItemBuilder, parent);
case REMOTE_PLAYLIST_GRID_HOLDER_TYPE:
return new RemotePlaylistGridItemHolder(localItemBuilder, parent);
case STREAM_PLAYLIST_HOLDER_TYPE:
return new LocalPlaylistStreamItemHolder(localItemBuilder, parent);
case STREAM_PLAYLIST_GRID_HOLDER_TYPE:
return new LocalPlaylistStreamGridItemHolder(localItemBuilder, parent);
case STREAM_STATISTICS_HOLDER_TYPE:
return new LocalStatisticStreamItemHolder(localItemBuilder, parent);
case STREAM_STATISTICS_GRID_HOLDER_TYPE:
return new LocalStatisticStreamGridItemHolder(localItemBuilder, parent);
default:
Log.e(TAG, "No view type has been considered for holder: [" + type + "]");
return new FallbackViewHolder(new View(parent.getContext()));
@@ -247,4 +267,14 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
((HeaderFooterHolder) holder).view = footer;
}
}
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
return new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
final int type = getItemViewType(position);
return type == HEADER_TYPE || type == FOOTER_TYPE ? spanCount : 1;
}
};
}
}

View File

@@ -1,9 +1,11 @@
package org.schabi.newpipe.local.dialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.Window;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.util.StateSaver;
@@ -41,6 +43,18 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
StateSaver.onDestroy(savedState);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Dialog dialog = super.onCreateDialog(savedInstanceState);
//remove title
final Window window = dialog.getWindow();
if (window != null) {
window.requestFeature(Window.FEATURE_NO_TITLE);
}
return dialog;
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@@ -58,7 +72,7 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
@Override
@SuppressWarnings("unchecked")
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
public void readFrom(@NonNull Queue<Object> savedObjects) {
streamEntities = (List<StreamEntity>) savedObjects.poll();
}

View File

@@ -36,8 +36,6 @@ import io.reactivex.MaybeObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {

View File

@@ -1,7 +1,6 @@
package org.schabi.newpipe.local.history;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;

View File

@@ -45,7 +45,6 @@ import java.util.List;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.Scheduler;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;

View File

@@ -21,7 +21,6 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -57,7 +56,7 @@ public class StatisticsPlaylistFragment
/* Used for independent events */
private Subscription databaseSubscription;
private HistoryRecordManager recordManager;
private CompositeDisposable disposables = new CompositeDisposable();
private final CompositeDisposable disposables = new CompositeDisposable();
private enum StatisticSortMode {
LAST_PLAYED,

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.local.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.local.LocalItemBuilder;
public class LocalPlaylistGridItemHolder extends LocalPlaylistItemHolder {
public LocalPlaylistGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
}
}

View File

@@ -16,6 +16,10 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
super(infoItemBuilder, parent);
}
LocalPlaylistItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
}
@Override
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
if (!(localItem instanceof PlaylistMetadataEntry)) return;

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.local.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.local.LocalItemBuilder;
public class LocalPlaylistStreamGridItemHolder extends LocalPlaylistStreamItemHolder {
public LocalPlaylistStreamGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_stream_playlist_grid_item, parent); //TODO
}
}

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.local.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.local.LocalItemBuilder;
public class LocalStatisticStreamGridItemHolder extends LocalStatisticStreamItemHolder {
public LocalStatisticStreamGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_stream_grid_item, parent);
}
}

View File

@@ -1,5 +1,6 @@
package org.schabi.newpipe.local.holder;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.ViewGroup;
@@ -42,10 +43,15 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
public final TextView itemVideoTitleView;
public final TextView itemUploaderView;
public final TextView itemDurationView;
@Nullable
public final TextView itemAdditionalDetails;
public LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_stream_item, parent);
public LocalStatisticStreamItemHolder(LocalItemBuilder itemBuilder, ViewGroup parent) {
this(itemBuilder, R.layout.list_stream_item, parent);
}
LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView);
@@ -80,7 +86,9 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
itemDurationView.setVisibility(View.GONE);
}
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat));
if (itemAdditionalDetails != null) {
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat));
}
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,

View File

@@ -0,0 +1,13 @@
package org.schabi.newpipe.local.holder;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
import org.schabi.newpipe.local.LocalItemBuilder;
public class RemotePlaylistGridItemHolder extends RemotePlaylistItemHolder {
public RemotePlaylistGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
}
}

View File

@@ -16,6 +16,10 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
super(infoItemBuilder, parent);
}
RemotePlaylistItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
}
@Override
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
if (!(localItem instanceof PlaylistRemoteEntity)) return;

View File

@@ -459,7 +459,11 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
if (isGridLayout()) {
directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return new ItemTouchHelper.SimpleCallback(directions,
ItemTouchHelper.ACTION_STATE_IDLE) {
@Override
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,

View File

@@ -1,15 +1,22 @@
package org.schabi.newpipe.local.subscription;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -17,6 +24,7 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -40,10 +48,11 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
@@ -72,7 +81,7 @@ import static org.schabi.newpipe.local.subscription.services.SubscriptionsImport
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEntity>> {
public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEntity>> implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final int REQUEST_EXPORT_CODE = 666;
private static final int REQUEST_IMPORT_CODE = 667;
@@ -80,8 +89,10 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
@State
protected Parcelable itemsListState;
private InfoListAdapter infoListAdapter;
private int updateFlags = 0;
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
private View headerRootLayout;
private View whatsNewItemListHeader;
private View importExportListHeader;
@@ -100,6 +111,8 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
PreferenceManager.getDefaultSharedPreferences(activity)
.registerOnSharedPreferenceChangeListener(this);
}
@Override
@@ -127,6 +140,15 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
public void onResume() {
super.onResume();
setupBroadcastReceiver();
if (updateFlags != 0) {
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
final boolean useGrid = isGridLayout();
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
infoListAdapter.setGridItemVariants(useGrid);
infoListAdapter.notifyDataSetChanged();
}
updateFlags = 0;
}
}
@Override
@@ -153,9 +175,25 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
disposables = null;
subscriptionService = null;
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
protected RecyclerView.LayoutManager getListLayoutManager() {
return new LinearLayoutManager(activity);
}
protected RecyclerView.LayoutManager getGridLayoutManager() {
final Resources resources = activity.getResources();
int width = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width);
width += (24 * resources.getDisplayMetrics().density);
final int spanCount = (int) Math.floor(resources.getDisplayMetrics().widthPixels / (double)width);
final GridLayoutManager lm = new GridLayoutManager(activity, spanCount);
lm.setSpanSizeLookup(infoListAdapter.getSpanSizeLookup(spanCount));
return lm;
}
/*/////////////////////////////////////////////////////////////////////////
// Menu
/////////////////////////////////////////////////////////////////////////*/
@@ -287,16 +325,19 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
final boolean useGrid = isGridLayout();
infoListAdapter = new InfoListAdapter(getActivity());
itemsList = rootView.findViewById(R.id.items_list);
itemsList.setLayoutManager(new LinearLayoutManager(activity));
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
View headerRootLayout;
infoListAdapter.setHeader(headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, itemsList, false));
whatsNewItemListHeader = headerRootLayout.findViewById(R.id.whats_new);
importExportListHeader = headerRootLayout.findViewById(R.id.import_export);
importExportOptions = headerRootLayout.findViewById(R.id.import_export_options);
infoListAdapter.useMiniItemVariants(true);
infoListAdapter.setGridItemVariants(useGrid);
itemsList.setAdapter(infoListAdapter);
setupImportFromItems(headerRootLayout.findViewById(R.id.import_from_options));
@@ -320,7 +361,7 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
super.initListeners();
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
@Override
public void selected(ChannelInfoItem selectedItem) {
final FragmentManager fragmentManager = getFM();
NavigationHelper.openChannelFragment(fragmentManager,
@@ -328,6 +369,11 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
selectedItem.getUrl(),
selectedItem.getName());
}
public void held(ChannelInfoItem selectedItem) {
showLongTapDialog(selectedItem);
}
});
//noinspection ConstantConditions
@@ -338,6 +384,85 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
importExportListHeader.setOnClickListener(v -> importExportOptions.switchState());
}
private void showLongTapDialog(ChannelInfoItem selectedItem) {
final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
context.getResources().getString(R.string.share),
context.getResources().getString(R.string.unsubscribe)
};
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
switch (i) {
case 0:
shareChannel(selectedItem);
break;
case 1:
deleteChannel(selectedItem);
break;
default:
break;
}
};
final View bannerView = View.inflate(activity, R.layout.dialog_title, null);
bannerView.setSelected(true);
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
titleView.setText(selectedItem.getName());
TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
detailsView.setVisibility(View.GONE);
new AlertDialog.Builder(activity)
.setCustomTitle(bannerView)
.setItems(commands, actions)
.create()
.show();
}
private void shareChannel (ChannelInfoItem selectedItem) {
shareUrl(selectedItem.getName(), selectedItem.getUrl());
}
@SuppressLint("CheckResult")
private void deleteChannel (ChannelInfoItem selectedItem) {
subscriptionService.subscriptionTable()
.getSubscription(selectedItem.getServiceId(), selectedItem.getUrl())
.toObservable()
.observeOn(Schedulers.io())
.subscribe(getDeleteObserver());
Toast.makeText(activity, getString(R.string.channel_unsubscribed), Toast.LENGTH_SHORT).show();
}
private Observer<List<SubscriptionEntity>> getDeleteObserver(){
return new Observer<List<SubscriptionEntity>>() {
@Override
public void onSubscribe(Disposable d) {
disposables.add(d);
}
@Override
public void onNext(List<SubscriptionEntity> subscriptionEntities) {
subscriptionService.subscriptionTable().delete(subscriptionEntities);
}
@Override
public void onError(Throwable exception) {
SubscriptionFragment.this.onError(exception);
}
@Override
public void onComplete() { }
};
}
private void resetFragment() {
if (disposables != null) disposables.clear();
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
@@ -447,4 +572,22 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
R.string.general_error);
return true;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(getString(R.string.list_view_mode_key))) {
updateFlags |= LIST_MODE_UPDATE_FLAG;
}
}
protected boolean isGridLayout() {
final String list_mode = PreferenceManager.getDefaultSharedPreferences(activity).getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value));
if ("auto".equals(list_mode)) {
final Configuration configuration = getResources().getConfiguration();
return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
} else {
return "grid".equals(list_mode);
}
}
}

View File

@@ -55,10 +55,10 @@ public class SubscriptionService {
private static final int SUBSCRIPTION_DEBOUNCE_INTERVAL = 500;
private static final int SUBSCRIPTION_THREAD_POOL_SIZE = 4;
private AppDatabase db;
private Flowable<List<SubscriptionEntity>> subscription;
private final AppDatabase db;
private final Flowable<List<SubscriptionEntity>> subscription;
private Scheduler subscriptionScheduler;
private final Scheduler subscriptionScheduler;
private SubscriptionService(Context context) {
db = NewPipeDatabase.getInstance(context.getApplicationContext());
@@ -116,7 +116,7 @@ public class SubscriptionService {
public Completable updateChannelInfo(final ChannelInfo info) {
final Function<List<SubscriptionEntity>, CompletableSource> update = new Function<List<SubscriptionEntity>, CompletableSource>() {
@Override
public CompletableSource apply(@NonNull List<SubscriptionEntity> subscriptionEntities) throws Exception {
public CompletableSource apply(@NonNull List<SubscriptionEntity> subscriptionEntities) {
if (DEBUG) Log.d(TAG, "updateChannelInfo() called with: subscriptionEntities = [" + subscriptionEntities + "]");
if (subscriptionEntities.size() == 1) {
SubscriptionEntity subscription = subscriptionEntities.get(0);

View File

@@ -58,8 +58,8 @@ public abstract class BaseImportExportService extends Service {
protected NotificationCompat.Builder notificationBuilder;
protected SubscriptionService subscriptionService;
protected CompositeDisposable disposables = new CompositeDisposable();
protected PublishProcessor<String> notificationUpdater = PublishProcessor.create();
protected final CompositeDisposable disposables = new CompositeDisposable();
protected final PublishProcessor<String> notificationUpdater = PublishProcessor.create();
@Nullable
@Override
@@ -90,9 +90,9 @@ public abstract class BaseImportExportService extends Service {
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
protected AtomicInteger currentProgress = new AtomicInteger(-1);
protected AtomicInteger maxProgress = new AtomicInteger(-1);
protected ImportExportEventListener eventListener = new ImportExportEventListener() {
protected final AtomicInteger currentProgress = new AtomicInteger(-1);
protected final AtomicInteger maxProgress = new AtomicInteger(-1);
protected final ImportExportEventListener eventListener = new ImportExportEventListener() {
@Override
public void onSizeReceived(int size) {
maxProgress.set(size);
@@ -187,13 +187,13 @@ public abstract class BaseImportExportService extends Service {
protected Toast toast;
protected void showToast(@StringRes int message) {
showToast(getString(message), Toast.LENGTH_SHORT);
showToast(getString(message));
}
protected void showToast(String message, int duration) {
protected void showToast(String message) {
if (toast != null) toast.cancel();
toast = Toast.makeText(this, message, duration);
toast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
toast.show();
}

View File

@@ -144,12 +144,16 @@ public class SubscriptionsImportService extends BaseImportExportService {
showToast(R.string.import_ongoing);
Flowable<List<SubscriptionItem>> flowable = null;
if (currentMode == CHANNEL_URL_MODE) {
flowable = importFromChannelUrl();
} else if (currentMode == INPUT_STREAM_MODE) {
flowable = importFromInputStream();
} else if (currentMode == PREVIOUS_EXPORT_MODE) {
flowable = importFromPreviousExport();
switch (currentMode) {
case CHANNEL_URL_MODE:
flowable = importFromChannelUrl();
break;
case INPUT_STREAM_MODE:
flowable = importFromInputStream();
break;
case PREVIOUS_EXPORT_MODE:
flowable = importFromPreviousExport();
break;
}
if (flowable == null) {

View File

@@ -230,7 +230,8 @@ public abstract class BasePlayer implements
int sizeBeforeAppend = playQueue.size();
playQueue.append(queue.getStreams());
if (intent.getBooleanExtra(SELECT_ON_APPEND, false) &&
if ((intent.getBooleanExtra(SELECT_ON_APPEND, false) ||
getCurrentState() == STATE_COMPLETED) &&
queue.getStreams().size() > 0) {
playQueue.setIndex(sizeBeforeAppend);
}
@@ -1112,7 +1113,9 @@ public abstract class BasePlayer implements
@Player.RepeatMode
public int getRepeatMode() {
return simpleExoPlayer == null ? Player.REPEAT_MODE_OFF : simpleExoPlayer.getRepeatMode();
return simpleExoPlayer == null
? Player.REPEAT_MODE_OFF
: simpleExoPlayer.getRepeatMode();
}
public void setRepeatMode(@Player.RepeatMode final int repeatMode) {
@@ -1178,4 +1181,8 @@ public abstract class BasePlayer implements
if (DEBUG) Log.d(TAG, "Setting recovery, queue: " + queuePos + ", pos: " + windowPos);
playQueue.setRecovery(queuePos, windowPos);
}
public boolean gotDestroyed() {
return simpleExoPlayer == null;
}
}

View File

@@ -175,6 +175,10 @@ public final class MainVideoPlayer extends AppCompatActivity
setLandscape(lastOrientationWasLandscape);
}
final int lastResizeMode = defaultPreferences.getInt(
getString(R.string.last_resize_mode), AspectRatioFrameLayout.RESIZE_MODE_FIT);
playerImpl.setResizeMode(lastResizeMode);
// Upon going in or out of multiwindow mode, isInMultiWindow will always be false,
// since the first onResume needs to restore the player.
// Subsequent onResume calls while multiwindow mode remains the same and the player is
@@ -213,10 +217,9 @@ public final class MainVideoPlayer extends AppCompatActivity
if (playerImpl == null) return;
playerImpl.setRecovery();
playerState = new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
playerImpl.getPlaybackQuality(), playerImpl.getPlaybackSkipSilence(),
playerImpl.isPlaying());
if(!playerImpl.gotDestroyed()) {
playerState = createPlayerState();
}
StateSaver.tryToSave(isChangingConfigurations(), null, outState, this);
}
@@ -231,6 +234,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (!isBackPressed) {
playerImpl.minimize();
}
playerState = createPlayerState();
playerImpl.destroy();
isInMultiWindow = false;
@@ -241,6 +245,13 @@ public final class MainVideoPlayer extends AppCompatActivity
// State Saving
//////////////////////////////////////////////////////////////////////////*/
private PlayerState createPlayerState() {
return new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
playerImpl.getPlaybackQuality(), playerImpl.getPlaybackSkipSilence(),
playerImpl.isPlaying());
}
@Override
public String generateSuffix() {
return "." + UUID.randomUUID().toString() + ".player";
@@ -705,14 +716,27 @@ public final class MainVideoPlayer extends AppCompatActivity
@Override
protected int nextResizeMode(int currentResizeMode) {
final int newResizeMode;
switch (currentResizeMode) {
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
return AspectRatioFrameLayout.RESIZE_MODE_FILL;
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL;
break;
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
return AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
break;
default:
return AspectRatioFrameLayout.RESIZE_MODE_FIT;
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
break;
}
storeResizeMode(newResizeMode);
return newResizeMode;
}
private void storeResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode) {
defaultPreferences.edit()
.putInt(getString(R.string.last_resize_mode), resizeMode)
.apply();
}
@Override
@@ -989,12 +1013,14 @@ public final class MainVideoPlayer extends AppCompatActivity
private static final int MOVEMENT_THRESHOLD = 40;
private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
private final boolean isVolumeGestureEnabled = PlayerHelper.isVolumeGestureEnabled(getApplicationContext());
private final boolean isBrightnessGestureEnabled = PlayerHelper.isBrightnessGestureEnabled(getApplicationContext());
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
@Override
public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
if (!isPlayerGestureEnabled) return false;
if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) return false;
//noinspection PointlessBooleanExpression
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
@@ -1010,7 +1036,11 @@ public final class MainVideoPlayer extends AppCompatActivity
isMoving = true;
if (initialEvent.getX() > playerImpl.getRootView().getWidth() / 2) {
boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
@@ -1035,7 +1065,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
} else {
} else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();

View File

@@ -114,7 +114,6 @@ public final class PopupVideoPlayer extends Service {
private View closeOverlayView;
private FloatingActionButton closeOverlayButton;
private WindowManager.LayoutParams closeOverlayLayoutParams;
private int tossFlingVelocity;
@@ -248,7 +247,7 @@ public final class PopupVideoPlayer extends Service {
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
closeOverlayLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
layoutParamType,
flags,

View File

@@ -137,16 +137,16 @@ public abstract class VideoPlayer extends BasePlayer
private TextView captionTextView;
private ValueAnimator controlViewAnimator;
private Handler controlsVisibilityHandler = new Handler();
private final Handler controlsVisibilityHandler = new Handler();
boolean isSomePopupMenuVisible = false;
private int qualityPopupMenuGroupId = 69;
private final int qualityPopupMenuGroupId = 69;
private PopupMenu qualityPopupMenu;
private int playbackSpeedPopupMenuGroupId = 79;
private final int playbackSpeedPopupMenuGroupId = 79;
private PopupMenu playbackSpeedPopupMenu;
private int captionPopupMenuGroupId = 89;
private final int captionPopupMenuGroupId = 89;
private PopupMenu captionPopupMenu;
///////////////////////////////////////////////////////////////////////////
@@ -683,12 +683,17 @@ public abstract class VideoPlayer extends BasePlayer
if (getAspectRatioFrameLayout() != null) {
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
final int newResizeMode = nextResizeMode(currentResizeMode);
getAspectRatioFrameLayout().setResizeMode(newResizeMode);
getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode));
setResizeMode(newResizeMode);
}
}
protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
getAspectRatioFrameLayout().setResizeMode(resizeMode);
getResizeView().setText(PlayerHelper.resizeTypeOf(context, resizeMode));
}
protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode);
/*//////////////////////////////////////////////////////////////////////////
// SeekBar Listener
//////////////////////////////////////////////////////////////////////////*/

View File

@@ -116,7 +116,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
private void onAudioFocusGain() {
Log.d(TAG, "onAudioFocusGain() called");
player.setVolume(DUCK_AUDIO_TO);
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
animateAudio(DUCK_AUDIO_TO, 1f);
if (PlayerHelper.isResumeAfterAudioFocusGain(context)) {
player.setPlayWhenReady(true);
@@ -131,13 +131,13 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
private void onAudioFocusLossCanDuck() {
Log.d(TAG, "onAudioFocusLossCanDuck() called");
// Set the volume to 1/10 on ducking
animateAudio(player.getVolume(), DUCK_AUDIO_TO, DUCK_DURATION);
animateAudio(player.getVolume(), DUCK_AUDIO_TO);
}
private void animateAudio(final float from, final float to, int duration) {
private void animateAudio(final float from, final float to) {
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setFloatValues(from, to);
valueAnimator.setDuration(duration);
valueAnimator.setDuration(AudioReactor.DUCK_DURATION);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {

View File

@@ -4,12 +4,9 @@ import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
@@ -17,8 +14,6 @@ import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import org.schabi.newpipe.Downloader;
import java.io.File;
/* package-private */ class CacheFactory implements DataSource.Factory {

View File

@@ -66,25 +66,15 @@ public class PlaybackParameterDialog extends DialogFragment {
private double stepSize = DEFAULT_STEP;
@Nullable private SeekBar tempoSlider;
@Nullable private TextView tempoMinimumText;
@Nullable private TextView tempoMaximumText;
@Nullable private TextView tempoCurrentText;
@Nullable private TextView tempoStepDownText;
@Nullable private TextView tempoStepUpText;
@Nullable private SeekBar pitchSlider;
@Nullable private TextView pitchMinimumText;
@Nullable private TextView pitchMaximumText;
@Nullable private TextView pitchCurrentText;
@Nullable private TextView pitchStepDownText;
@Nullable private TextView pitchStepUpText;
@Nullable private TextView stepSizeOnePercentText;
@Nullable private TextView stepSizeFivePercentText;
@Nullable private TextView stepSizeTenPercentText;
@Nullable private TextView stepSizeTwentyFivePercentText;
@Nullable private TextView stepSizeOneHundredPercentText;
@Nullable private CheckBox unhookingCheckbox;
@Nullable private CheckBox skipSilenceCheckbox;
@@ -181,8 +171,8 @@ public class PlaybackParameterDialog extends DialogFragment {
private void setupTempoControl(@NonNull View rootView) {
tempoSlider = rootView.findViewById(R.id.tempoSeekbar);
tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText);
tempoStepUpText = rootView.findViewById(R.id.tempoStepUp);
tempoStepDownText = rootView.findViewById(R.id.tempoStepDown);
@@ -203,8 +193,8 @@ public class PlaybackParameterDialog extends DialogFragment {
private void setupPitchControl(@NonNull View rootView) {
pitchSlider = rootView.findViewById(R.id.pitchSeekbar);
pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText);
pitchStepDownText = rootView.findViewById(R.id.pitchStepDown);
pitchStepUpText = rootView.findViewById(R.id.pitchStepUp);
@@ -247,11 +237,11 @@ public class PlaybackParameterDialog extends DialogFragment {
}
private void setupStepSizeSelector(@NonNull final View rootView) {
stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
stepSizeTwentyFivePercentText = rootView.findViewById(R.id.stepSizeTwentyFivePercent);
stepSizeOneHundredPercentText = rootView.findViewById(R.id.stepSizeOneHundredPercent);
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
TextView stepSizeTwentyFivePercentText = rootView.findViewById(R.id.stepSizeTwentyFivePercent);
TextView stepSizeOneHundredPercentText = rootView.findViewById(R.id.stepSizeOneHundredPercent);
if (stepSizeOnePercentText != null) {
stepSizeOnePercentText.setText(getPercentString(STEP_ONE_PERCENT_VALUE));

View File

@@ -169,8 +169,12 @@ public class PlayerHelper {
return isResumeAfterAudioFocusGain(context, false);
}
public static boolean isPlayerGestureEnabled(@NonNull final Context context) {
return isPlayerGestureEnabled(context, true);
public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
return isVolumeGestureEnabled(context, true);
}
public static boolean isBrightnessGestureEnabled(@NonNull final Context context) {
return isBrightnessGestureEnabled(context, true);
}
public static boolean isUsingOldPlayer(@NonNull final Context context) {
@@ -203,7 +207,7 @@ public class PlayerHelper {
@NonNull
public static SeekParameters getSeekParameters(@NonNull final Context context) {
return isUsingInexactSeek(context, false) ?
return isUsingInexactSeek(context) ?
SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
}
@@ -306,8 +310,12 @@ public class PlayerHelper {
return getPreferences(context).getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), b);
}
private static boolean isPlayerGestureEnabled(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.player_gesture_controls_key), b);
private static boolean isVolumeGestureEnabled(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.volume_gesture_control_key), b);
}
private static boolean isBrightnessGestureEnabled(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.brightness_gesture_control_key), b);
}
private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) {
@@ -318,8 +326,8 @@ public class PlayerHelper {
return getPreferences(context).getBoolean(context.getString(R.string.popup_remember_size_pos_key), b);
}
private static boolean isUsingInexactSeek(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.use_inexact_seek_key), b);
private static boolean isUsingInexactSeek(@NonNull final Context context) {
return getPreferences(context).getBoolean(context.getString(R.string.use_inexact_seek_key), false);
}
private static boolean isAutoQueueEnabled(@NonNull final Context context, final boolean b) {

View File

@@ -79,7 +79,7 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
private void publishFloatingQueueWindow() {
if (callback.getQueueSize() == 0) {
mediaSession.setQueue(Collections.<MediaSessionCompat.QueueItem>emptyList());
mediaSession.setQueue(Collections.emptyList());
activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
return;
}

View File

@@ -8,7 +8,7 @@ import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
public class BasePlayerMediaSession implements MediaSessionCallback {
private BasePlayer player;
private final BasePlayer player;
public BasePlayerMediaSession(final BasePlayer player) {
this.player = player;

View File

@@ -4,7 +4,6 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
@@ -12,7 +11,6 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
/**
* This class allows irregular text language labels for use when selecting text captions and
@@ -55,7 +53,7 @@ public class CustomTrackSelector extends DefaultTrackSelector {
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
@Override
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
Parameters params) throws ExoPlaybackException {
Parameters params) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;

View File

@@ -335,7 +335,7 @@ public class MediaSourceManager {
private void loadImmediate() {
if (DEBUG) Log.d(TAG, "MediaSource - loadImmediate() called");
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue, WINDOW_SIZE);
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue);
if (itemsToLoad == null) return;
// Evict the previous items being loaded to free up memory, before start loading new ones
@@ -472,8 +472,7 @@ public class MediaSourceManager {
// Manager Helpers
//////////////////////////////////////////////////////////////////////////*/
@Nullable
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue,
final int windowSize) {
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue) {
// The current item has higher priority
final int currentIndex = playQueue.getIndex();
final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
@@ -482,8 +481,8 @@ public class MediaSourceManager {
// The rest are just for seamless playback
// Although timeline is not updated prior to the current index, these sources are still
// loaded into the cache for faster retrieval at a potentially later time.
final int leftBound = Math.max(0, currentIndex - windowSize);
final int rightLimit = currentIndex + windowSize + 1;
final int leftBound = Math.max(0, currentIndex - MediaSourceManager.WINDOW_SIZE);
final int rightLimit = currentIndex + MediaSourceManager.WINDOW_SIZE + 1;
final int rightBound = Math.min(playQueue.size(), rightLimit);
final Set<PlayQueueItem> neighbors = new ArraySet<>(
playQueue.getStreams().subList(leftBound,rightBound));

View File

@@ -8,8 +8,6 @@ import com.google.android.exoplayer2.source.MediaSource;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.util.List;
public interface PlaybackListener {
/**

View File

@@ -19,14 +19,14 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
boolean isInitial;
boolean isComplete;
int serviceId;
String baseUrl;
final int serviceId;
final String baseUrl;
String nextUrl;
transient Disposable fetchReactor;
AbstractInfoPlayQueue(final U item) {
this(item.getServiceId(), item.getUrl(), null, Collections.<StreamInfoItem>emptyList(), 0);
this(item.getServiceId(), item.getUrl(), null, Collections.emptyList(), 0);
}
AbstractInfoPlayQueue(final int serviceId,

View File

@@ -5,10 +5,8 @@ import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;

View File

@@ -6,8 +6,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
/**
* Created by Christian Schabesberger on 01.08.16.

View File

@@ -5,7 +5,6 @@ import android.support.annotation.NonNull;
import org.acra.collector.CrashReportData;
import org.acra.sender.ReportSender;
import org.acra.sender.ReportSenderException;
import org.schabi.newpipe.R;
/*
@@ -31,7 +30,7 @@ import org.schabi.newpipe.R;
public class AcraReportSender implements ReportSender {
@Override
public void send(@NonNull Context context, @NonNull CrashReportData report) throws ReportSenderException {
public void send(@NonNull Context context, @NonNull CrashReportData report) {
ErrorActivity.reportError(context, report,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,"none",
"App crash, UI failure", R.string.app_ui_crash));

View File

@@ -3,7 +3,6 @@ package org.schabi.newpipe.report;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
@@ -46,7 +45,6 @@ import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
/*
* Created by Christian Schabesberger on 24.10.15.
@@ -81,12 +79,7 @@ public class ErrorActivity extends AppCompatActivity {
private ErrorInfo errorInfo;
private Class returnActivity;
private String currentTimeStamp;
// views
private TextView errorView;
private EditText userCommentBox;
private Button reportButton;
private TextView infoView;
private TextView errorMessageView;
public static void reportUiError(final AppCompatActivity activity, final Throwable el) {
reportError(activity, el, activity.getClass(), null,
@@ -194,11 +187,11 @@ public class ErrorActivity extends AppCompatActivity {
actionBar.setDisplayShowTitleEnabled(true);
}
reportButton = findViewById(R.id.errorReportButton);
Button reportButton = findViewById(R.id.errorReportButton);
userCommentBox = findViewById(R.id.errorCommentBox);
errorView = findViewById(R.id.errorView);
infoView = findViewById(R.id.errorInfosView);
errorMessageView = findViewById(R.id.errorMessageView);
TextView errorView = findViewById(R.id.errorView);
TextView infoView = findViewById(R.id.errorInfosView);
TextView errorMessageView = findViewById(R.id.errorMessageView);
ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
returnActivity = ac.returnActivity;
@@ -281,15 +274,14 @@ public class ErrorActivity extends AppCompatActivity {
}
private String formErrorText(String[] el) {
String text = "";
StringBuilder text = new StringBuilder();
if (el != null) {
for (String e : el) {
text += "-------------------------------------\n"
+ e;
text.append("-------------------------------------\n").append(e);
}
}
text += "-------------------------------------";
return text;
text.append("-------------------------------------");
return text.toString();
}
/**

View File

@@ -6,7 +6,6 @@ import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v7.preference.Preference;
import android.util.Log;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.Constants;
@@ -49,7 +48,7 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment {
return super.onPreferenceTreeClick(preference);
}
private Preference.OnPreferenceChangeListener themePreferenceChange = new Preference.OnPreferenceChangeListener() {
private final Preference.OnPreferenceChangeListener themePreferenceChange = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
defaultPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, true).apply();

View File

@@ -13,7 +13,7 @@ import org.schabi.newpipe.MainActivity;
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
protected boolean DEBUG = MainActivity.DEBUG;
protected final boolean DEBUG = MainActivity.DEBUG;
protected SharedPreferences defaultPreferences;

View File

@@ -9,8 +9,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import android.widget.Toast;
@@ -20,11 +18,10 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.utils.Localization;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.ZipHelper;
import java.io.BufferedOutputStream;
@@ -47,7 +44,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
private static final int REQUEST_IMPORT_PATH = 8945;
private static final int REQUEST_EXPORT_PATH = 30945;
private String homeDir;
private File databasesDir;
private File newpipe_db;
private File newpipe_db_journal;
@@ -81,7 +77,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
homeDir = getActivity().getApplicationInfo().dataDir;
String homeDir = getActivity().getApplicationInfo().dataDir;
databasesDir = new File(homeDir + "/databases");
newpipe_db = new File(homeDir + "/databases/newpipe.db");
newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal");
@@ -112,6 +108,20 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
startActivityForResult(i, REQUEST_EXPORT_PATH);
return true;
});
Preference setPreferredLanguage = findPreference(getString(R.string.content_language_key));
setPreferredLanguage.setOnPreferenceChangeListener((Preference p, Object newLanguage) -> {
Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
NewPipe.setLocalization(new Localization(oldLocal.getCountry(), (String) newLanguage));
return true;
});
Preference setPreferredCountry = findPreference(getString(R.string.content_country_key));
setPreferredCountry.setOnPreferenceChangeListener((Preference p, Object newCountry) -> {
Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
NewPipe.setLocalization(new Localization((String) newCountry, oldLocal.getLanguage()));
return true;
});
}
@Override
@@ -193,7 +203,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
} finally {
try {
zipFile.close();
} catch (Exception e){}
} catch (Exception ignored){}
}
try {
@@ -254,17 +264,17 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
String key = entry.getKey();
if (v instanceof Boolean)
prefEdit.putBoolean(key, ((Boolean) v).booleanValue());
prefEdit.putBoolean(key, (Boolean) v);
else if (v instanceof Float)
prefEdit.putFloat(key, ((Float) v).floatValue());
prefEdit.putFloat(key, (Float) v);
else if (v instanceof Integer)
prefEdit.putInt(key, ((Integer) v).intValue());
prefEdit.putInt(key, (Integer) v);
else if (v instanceof Long)
prefEdit.putLong(key, ((Long) v).longValue());
prefEdit.putLong(key, (Long) v);
else if (v instanceof String)
prefEdit.putString(key, ((String) v));
}
prefEdit.commit();
prefEdit.apply();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -286,13 +296,12 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
protected void onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
}
}

View File

@@ -1,29 +1,20 @@
package org.schabi.newpipe.settings;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference;
import android.util.Log;
import android.widget.Toast;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.InfoCache;
import java.util.ArrayList;
import java.util.Collection;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.disposables.Disposables;
public class HistorySettingsFragment extends BasePreferenceFragment {
private String cacheWipeKey;

View File

@@ -51,9 +51,7 @@ import io.reactivex.schedulers.Schedulers;
*/
public class SelectChannelFragment extends DialogFragment {
private SelectChannelAdapter channelAdapter;
private SubscriptionService subscriptionService;
private ImageLoader imageLoader = ImageLoader.getInstance();
private final ImageLoader imageLoader = ImageLoader.getInstance();
private ProgressBar progressBar;
private TextView emptyView;
@@ -89,9 +87,9 @@ public class SelectChannelFragment extends DialogFragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
recyclerView = v.findViewById(R.id.items_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
channelAdapter = new SelectChannelAdapter();
SelectChannelAdapter channelAdapter = new SelectChannelAdapter();
recyclerView.setAdapter(channelAdapter);
progressBar = v.findViewById(R.id.progressBar);
@@ -101,7 +99,7 @@ public class SelectChannelFragment extends DialogFragment {
emptyView.setVisibility(View.GONE);
subscriptionService = SubscriptionService.getInstance(getContext());
SubscriptionService subscriptionService = SubscriptionService.getInstance(getContext());
subscriptionService.getSubscription().toObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -203,9 +201,9 @@ public class SelectChannelFragment extends DialogFragment {
thumbnailView = v.findViewById(R.id.itemThumbnailView);
titleView = v.findViewById(R.id.itemTitleView);
}
public View view;
public CircleImageView thumbnailView;
public TextView titleView;
public final View view;
public final CircleImageView thumbnailView;
public final TextView titleView;
}
}
@@ -213,14 +211,13 @@ public class SelectChannelFragment extends DialogFragment {
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
protected void onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
}

View File

@@ -75,7 +75,7 @@ public class SelectKioskFragment extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
recyclerView = v.findViewById(R.id.items_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
try {
selectKioskAdapter = new SelectKioskAdapter();
@@ -112,13 +112,13 @@ public class SelectKioskFragment extends DialogFragment {
public Entry (int i, int si, String ki, String kn){
icon = i; serviceId=si; kioskId=ki; kioskName = kn;
}
int icon;
int serviceId;
String kioskId;
String kioskName;
final int icon;
final int serviceId;
final String kioskId;
final String kioskName;
}
private List<Entry> kioskList = new Vector<>();
private final List<Entry> kioskList = new Vector<>();
public SelectKioskAdapter()
throws Exception {
@@ -157,9 +157,9 @@ public class SelectKioskFragment extends DialogFragment {
thumbnailView = v.findViewById(R.id.itemThumbnailView);
titleView = v.findViewById(R.id.itemTitleView);
}
public View view;
public ImageView thumbnailView;
public TextView titleView;
public final View view;
public final ImageView thumbnailView;
public final TextView titleView;
}
public void onBindViewHolder(SelectKioskItemHolder holder, final int position) {
@@ -179,13 +179,12 @@ public class SelectKioskFragment extends DialogFragment {
// Error
//////////////////////////////////////////////////////////////////////////*/
protected boolean onError(Throwable e) {
protected void onError(Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e,
activity.getClass(),
null,
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
"none", "", R.string.app_ui_crash));
return true;
}
}

View File

@@ -32,6 +32,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
@@ -67,42 +68,37 @@ public final class ExtractorHelper {
public static Single<SearchInfo> searchFor(final int serviceId,
final String searchString,
final List<String> contentFilter,
final String sortFilter,
final String contentCountry) {
final String sortFilter) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
SearchInfo.getInfo(NewPipe.getService(serviceId),
NewPipe.getService(serviceId)
.getSearchQHFactory()
.fromQuery(searchString, contentFilter, sortFilter),
contentCountry));
.fromQuery(searchString, contentFilter, sortFilter)));
}
public static Single<InfoItemsPage> getMoreSearchItems(final int serviceId,
final String searchString,
final List<String> contentFilter,
final String sortFilter,
final String pageUrl,
final String contentCountry) {
final String pageUrl) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
SearchInfo.getMoreItems(NewPipe.getService(serviceId),
NewPipe.getService(serviceId)
.getSearchQHFactory()
.fromQuery(searchString, contentFilter, sortFilter),
contentCountry,
pageUrl));
}
public static Single<List<String>> suggestionsFor(final int serviceId,
final String query,
final String contentCountry) {
final String query) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
NewPipe.getService(serviceId)
.getSuggestionExtractor()
.suggestionList(query, contentCountry));
.suggestionList(query));
}
public static Single<StreamInfo> getStreamInfo(final int serviceId,
@@ -147,19 +143,17 @@ public final class ExtractorHelper {
public static Single<KioskInfo> getKioskInfo(final int serviceId,
final String url,
final String contentCountry,
boolean forceLoad) {
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry)));
KioskInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<InfoItemsPage> getMoreKioskItems(final int serviceId,
final String url,
final String nextStreamsUrl,
final String contentCountry) {
final String nextStreamsUrl) {
return Single.fromCallable(() ->
KioskInfo.getMoreItems(NewPipe.getService(serviceId),
url, nextStreamsUrl, contentCountry));
url, nextStreamsUrl));
}
/*//////////////////////////////////////////////////////////////////////////
@@ -183,7 +177,7 @@ public final class ExtractorHelper {
cache.removeInfo(serviceId, url);
load = loadFromNetwork;
} else {
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url),
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url),
loadFromNetwork.toMaybe())
.firstElement() //Take the first valid
.toSingle();

View File

@@ -28,9 +28,6 @@ import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.extractor.Info;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
public final class InfoCache {
@@ -58,7 +55,7 @@ public final class InfoCache {
public Info getFromKey(int serviceId, @NonNull String url) {
if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
synchronized (lruCache) {
return getInfo(lruCache, keyOf(serviceId, url));
return getInfo(keyOf(serviceId, url));
}
}
@@ -89,7 +86,7 @@ public final class InfoCache {
public void trimCache() {
if (DEBUG) Log.d(TAG, "trimCache() called");
synchronized (lruCache) {
removeStaleCache(lruCache);
removeStaleCache();
lruCache.trimToSize(TRIM_CACHE_TO);
}
}
@@ -105,23 +102,22 @@ public final class InfoCache {
return serviceId + url;
}
private static void removeStaleCache(@NonNull final LruCache<String, CacheData> cache) {
for (Map.Entry<String, CacheData> entry : cache.snapshot().entrySet()) {
private static void removeStaleCache() {
for (Map.Entry<String, CacheData> entry : InfoCache.lruCache.snapshot().entrySet()) {
final CacheData data = entry.getValue();
if (data != null && data.isExpired()) {
cache.remove(entry.getKey());
InfoCache.lruCache.remove(entry.getKey());
}
}
}
@Nullable
private static Info getInfo(@NonNull final LruCache<String, CacheData> cache,
@NonNull final String key) {
final CacheData data = cache.get(key);
private static Info getInfo(@NonNull final String key) {
final CacheData data = InfoCache.lruCache.get(key);
if (data == null) return null;
if (data.isExpired()) {
cache.remove(key);
InfoCache.lruCache.remove(key);
return null;
}

View File

@@ -204,7 +204,7 @@ public final class ListHelper {
*/
private static void sortStreamList(List<VideoStream> videoStreams, final boolean ascendingOrder) {
Collections.sort(videoStreams, (o1, o2) -> {
int result = compareVideoStreamResolution(o1, o2, VIDEO_FORMAT_QUALITY_RANKING);
int result = compareVideoStreamResolution(o1, o2);
return result == 0 ? 0 : (ascendingOrder ? result : -result);
});
}
@@ -399,8 +399,7 @@ public final class ListHelper {
}
// Compares the quality of two video streams.
private static int compareVideoStreamResolution(VideoStream streamA, VideoStream streamB,
List<MediaFormat> formatRanking) {
private static int compareVideoStreamResolution(VideoStream streamA, VideoStream streamB) {
if (streamA == null) {
return -1;
}
@@ -414,7 +413,7 @@ public final class ListHelper {
}
// Same bitrate and format
return formatRanking.indexOf(streamA.getFormat()) - formatRanking.indexOf(streamB.getFormat());
return ListHelper.VIDEO_FORMAT_QUALITY_RANKING.indexOf(streamA.getFormat()) - ListHelper.VIDEO_FORMAT_QUALITY_RANKING.indexOf(streamB.getFormat());
}

View File

@@ -69,10 +69,23 @@ public class Localization {
return stringBuilder.toString();
}
public static org.schabi.newpipe.extractor.utils.Localization getPreferredExtractorLocal(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String languageCode = sp.getString(context.getString(R.string.content_language_key),
context.getString(R.string.default_language_value));
String countryCode = sp.getString(context.getString(R.string.content_country_key),
context.getString(R.string.default_country_value));
return new org.schabi.newpipe.extractor.utils.Localization(countryCode, languageCode);
}
public static Locale getPreferredLocale(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String languageCode = sp.getString(context.getString(R.string.search_language_key), context.getString(R.string.default_language_value));
String languageCode = sp.getString(context.getString(R.string.content_language_key),
context.getString(R.string.default_language_value));
try {
if (languageCode.length() == 2) {

View File

@@ -26,7 +26,6 @@ import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;

View File

@@ -21,7 +21,6 @@ package org.schabi.newpipe.util;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;

View File

@@ -31,7 +31,7 @@ import us.shandian.giga.util.Utility;
public class StreamItemAdapter<T extends Stream> extends BaseAdapter {
private final Context context;
private StreamSizeWrapper<T> streamsWrapper;
private final StreamSizeWrapper<T> streamsWrapper;
private final boolean showIconNoAudio;
public StreamItemAdapter(Context context, StreamSizeWrapper<T> streamsWrapper, boolean showIconNoAudio) {
@@ -124,7 +124,7 @@ public class StreamItemAdapter<T extends Stream> extends BaseAdapter {
public static class StreamSizeWrapper<T extends Stream> implements Serializable {
private static final StreamSizeWrapper<Stream> EMPTY = new StreamSizeWrapper<>(Collections.emptyList());
private final List<T> streamsList;
private long[] streamSizes;
private final long[] streamSizes;
public StreamSizeWrapper(List<T> streamsList) {
this.streamsList = streamsList;

View File

@@ -56,7 +56,6 @@ public class ZipHelper {
/**
* This will extract data from Zipfiles.
* Caution this will override the original file.
* @param inZip The ZipOutputStream where the data is stored in
* @param file The path of the file on the disk where the data should be extracted to.
* @param name The path of the file inside the zip.
* @return will return true if the file was found within the zip file

View File

@@ -81,7 +81,7 @@ public class CollapsibleView extends LinearLayout {
private int targetHeight = -1;
private ValueAnimator currentAnimator;
private List<StateListener> listeners = new ArrayList<>();
private final List<StateListener> listeners = new ArrayList<>();
/**
* This method recalculates the height of this view so it <b>must</b> be called when

View File

@@ -123,7 +123,7 @@ public class DownloadManagerImpl implements DownloadManager {
Collections.sort(missions, new Comparator<DownloadMission>() {
@Override
public int compare(DownloadMission o1, DownloadMission o2) {
return Long.valueOf(o1.timestamp).compareTo(o2.timestamp);
return Long.compare(o1.timestamp, o2.timestamp);
}
});
}

View File

@@ -67,8 +67,8 @@ public class DownloadMission implements Serializable {
public long done;
public int threadCount = 3;
public int finishCount;
private List<Long> threadPositions = new ArrayList<Long>();
public final Map<Long, Boolean> blockState = new HashMap<Long, Boolean>();
private final List<Long> threadPositions = new ArrayList<>();
public final Map<Long, Boolean> blockState = new HashMap<>();
public boolean running;
public boolean finished;
public boolean fallback;
@@ -77,7 +77,7 @@ public class DownloadMission implements Serializable {
public transient boolean recovered;
private transient ArrayList<WeakReference<MissionListener>> mListeners = new ArrayList<WeakReference<MissionListener>>();
private transient ArrayList<WeakReference<MissionListener>> mListeners = new ArrayList<>();
private transient boolean mWritingToFile;
private static final int NO_IDENTIFIER = -1;
@@ -232,7 +232,7 @@ public class DownloadMission implements Serializable {
public synchronized void addListener(MissionListener listener) {
Handler handler = new Handler(Looper.getMainLooper());
MissionListener.handlerStore.put(listener, handler);
mListeners.add(new WeakReference<MissionListener>(listener));
mListeners.add(new WeakReference<>(listener));
}
public synchronized void removeListener(MissionListener listener) {

View File

@@ -92,7 +92,7 @@ public class DownloadRunnable implements Runnable {
// A server may be ignoring the range request
if (conn.getResponseCode() != 206) {
mMission.errCode = DownloadMission.ERROR_SERVER_UNSUPPORTED;
notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED);
notifyError();
if (DEBUG) {
Log.e(TAG, mId + ":Unsupported " + conn.getResponseCode());
@@ -161,9 +161,9 @@ public class DownloadRunnable implements Runnable {
}
}
private void notifyError(final int err) {
private void notifyError() {
synchronized (mMission) {
mMission.notifyError(err);
mMission.notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED);
mMission.pause();
}
}

View File

@@ -56,7 +56,7 @@ public class DownloadManagerService extends Service {
private DownloadDataSource mDataSource;
private MissionListener missionListener = new MissionListener();
private final MissionListener missionListener = new MissionListener();
private void notifyMediaScanner(DownloadMission mission) {

View File

@@ -306,12 +306,12 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
public DownloadMission mission;
public int position;
public TextView status;
public ImageView icon;
public TextView name;
public TextView size;
public View bkg;
public ImageView menu;
public final TextView status;
public final ImageView icon;
public final TextView name;
public final TextView size;
public final View bkg;
public final ImageView menu;
public ProgressDrawable progress;
public MissionObserver observer;
@@ -332,8 +332,8 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
}
static class MissionObserver implements DownloadMission.MissionListener {
private MissionAdapter mAdapter;
private ViewHolder mHolder;
private final MissionAdapter mAdapter;
private final ViewHolder mHolder;
public MissionObserver(MissionAdapter adapter, ViewHolder holder) {
mAdapter = adapter;
@@ -365,7 +365,7 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
private static class ChecksumTask extends AsyncTask<String, Void, String> {
ProgressDialog prog;
WeakReference<Activity> weakReference;
final WeakReference<Activity> weakReference;
ChecksumTask(@NonNull Activity activity) {
weakReference = new WeakReference<>(activity);

View File

@@ -12,7 +12,8 @@ import android.support.v4.content.ContextCompat;
public class ProgressDrawable extends Drawable {
private float mProgress;
private int mBackgroundColor, mForegroundColor;
private final int mBackgroundColor;
private final int mForegroundColor;
public ProgressDrawable(Context context, @ColorRes int background, @ColorRes int foreground) {
this(ContextCompat.getColor(context, background), ContextCompat.getColor(context, foreground));

View File

@@ -16,6 +16,8 @@ import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -44,7 +46,7 @@ public abstract class MissionsFragment extends Fragment {
private DeleteDownloadManager mDeleteDownloadManager;
private Disposable mDeleteDisposable;
private ServiceConnection mConnection = new ServiceConnection() {
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
@@ -144,17 +146,21 @@ public abstract class MissionsFragment extends Fragment {
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
public void onPrepareOptionsMenu(Menu menu) {
mSwitch = menu.findItem(R.id.switch_mode);
super.onPrepareOptionsMenu(menu);
}
/*switch (item.getItemId()) {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.switch_mode:
mLinear = !mLinear;
updateList();
return true;
default:
return super.onOptionsItemSelected(item);
}*/
}
}
public void notifyChange() {

View File

@@ -11,9 +11,7 @@ import android.widget.Toast;
import org.schabi.newpipe.R;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -198,7 +196,7 @@ public class Utility {
while ((len = i.read(buf)) != -1) {
md.update(buf, 0, len);
}
} catch (IOException e) {
} catch (IOException ignored) {
}

View File

@@ -0,0 +1,581 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center">
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
android:id="@+id/aspectRatioLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_gravity="center">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
<View
android:id="@+id/surfaceForeground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"/>
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
<com.google.android.exoplayer2.ui.SubtitleView
android:id="@+id/subtitleView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_gravity="center"/>
<ImageView
android:id="@+id/endScreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:visibility="gone"
tools:background="@android:color/white"
tools:ignore="ContentDescription"
tools:visibility="visible"/>
<RelativeLayout
android:id="@+id/playQueuePanel"
android:layout_width="380dp"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:visibility="invisible"
android:background="?attr/queue_background_color"
tools:visibility="visible">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/playQueueControl">
<ImageButton
android:id="@+id/playQueueClose"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="40dp"
android:layout_marginEnd="40dp"
android:padding="10dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:tint="?attr/colorAccent"
android:src="@drawable/ic_close_white_24dp"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription"/>
<ImageButton
android:id="@+id/repeatButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="40dp"
android:layout_marginStart="40dp"
android:padding="10dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:tint="?attr/colorAccent"
android:src="@drawable/exo_controls_repeat_off"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
<ImageButton
android:id="@+id/shuffleButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeatButton"
android:padding="10dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:tint="?attr/colorAccent"
android:src="@drawable/ic_shuffle_white_24dp"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/playQueue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/playQueueControl"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/play_queue_item"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/playbackControlRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/video_overlay_color"
android:visibility="gone"
tools:visibility="visible">
<RelativeLayout
android:id="@+id/playbackWindowRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<RelativeLayout
android:id="@+id/topControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="@drawable/player_top_controls_bg"
android:gravity="top"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
tools:ignore="RtlHardcoded">
<LinearLayout
android:id="@+id/metadataView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/qualityTextView"
android:gravity="top"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="15sp"
android:textStyle="bold"
android:clickable="true"
android:focusable="true"
tools:ignore="RtlHardcoded"
tools:text="The Video Title LONG very LONG"/>
<TextView
android:id="@+id/channelTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="12sp"
android:clickable="true"
android:focusable="true"
tools:text="The Video Artist LONG very LONG very Long"/>
</LinearLayout>
<TextView
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/playbackSpeed"
android:gravity="center"
android:minWidth="50dp"
android:text="720p"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded"/>
<TextView
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/queueButton"
android:gravity="center"
android:minHeight="35dp"
android:minWidth="40dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RtlHardcoded,RtlSymmetry"
tools:text="1x" />
<ImageButton
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/moreOptionsButton"
android:clickable="true"
android:focusable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/list"
android:background="?attr/selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
<ImageButton
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="2dp"
android:padding="5dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:src="@drawable/ic_expand_more_white_24dp"
android:background="?attr/selectableItemBackgroundBorderless"
tools:ignore="ContentDescription,RtlHardcoded"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/secondaryControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/topControls"
android:gravity="top"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
<TextView
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_alignParentLeft="true"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded"
tools:text="FIT"/>
<TextView
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_toLeftOf="@id/switchBackground"
android:layout_toRightOf="@id/resizeTextView"
android:gravity="center|left"
android:minHeight="35dp"
android:minWidth="40dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English" />
<ImageButton
android:id="@+id/toggleOrientation"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="2dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="true"
android:focusable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_screen_rotation_white"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/toggle_orientation"
tools:ignore="RtlHardcoded"/>
<ImageButton
android:id="@+id/switchPopup"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_toLeftOf="@id/toggleOrientation"
android:layout_centerVertical="true"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:src="@drawable/ic_fullscreen_exit_white"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/switch_to_popup"
tools:ignore="RtlHardcoded"/>
<ImageButton
android:id="@+id/switchBackground"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_toLeftOf="@id/switchPopup"
android:layout_centerVertical="true"
android:clickable="true"
android:focusable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_headset_white_24dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/switch_to_background"
tools:ignore="RtlHardcoded"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/bottomControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/player_controls_bg"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<TextView
android:id="@+id/playbackCurrentTime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minHeight="40dp"
android:text="-:--:--"
android:textColor="@android:color/white"
tools:ignore="HardcodedText"
tools:text="1:06:29"/>
<android.support.v7.widget.AppCompatSeekBar
android:id="@+id/playbackSeekBar"
style="@style/Widget.AppCompat.SeekBar"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingBottom="4dp"
android:paddingTop="8dp"
tools:progress="25"
tools:secondaryProgress="50"/>
<TextView
android:id="@+id/playbackEndTime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="-:--:--"
android:textColor="@android:color/white"
tools:ignore="HardcodedText"
tools:text="1:23:49"/>
<TextView
android:id="@+id/playbackLiveSync"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:gravity="center"
android:text="@string/duration_live_button"
android:textAllCaps="true"
android:textColor="@android:color/white"
android:maxLength="4"
android:visibility="gone"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
</LinearLayout>
</RelativeLayout>
<ImageButton
android:id="@+id/playPauseButton"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY"
android:src="@drawable/ic_pause_white"
tools:ignore="ContentDescription"/>
<ImageButton
android:id="@+id/playPreviousButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="30dp"
android:layout_marginEnd="30dp"
android:layout_centerInParent="true"
android:layout_toLeftOf="@id/playPauseButton"
android:layout_toStartOf="@id/playPauseButton"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY"
android:src="@drawable/exo_controls_previous"
tools:ignore="ContentDescription"/>
<ImageButton
android:id="@+id/playNextButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="30dp"
android:layout_marginStart="30dp"
android:layout_centerInParent="true"
android:layout_toRightOf="@id/playPauseButton"
android:layout_toEndOf="@id/playPauseButton"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY"
android:src="@drawable/exo_controls_next"
tools:ignore="ContentDescription"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/controlAnimationView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/background_oval_black_transparent"
android:visibility="gone"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_action_av_fast_rewind"
tools:visibility="visible" />
</LinearLayout>
<RelativeLayout
android:id="@+id/loading_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
tools:visibility="gone">
<ProgressBar
android:id="@+id/progressBarLoadingPanel"
style="?android:attr/progressBarStyleLargeInverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_gravity="center"
android:layout_toEndOf="@+id/loading_panel"
android:layout_toRightOf="@+id/loading_panel"
tools:ignore="RtlHardcoded">
<RelativeLayout
android:id="@+id/volumeRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/background_oval_black_transparent"
android:visibility="gone"
tools:visibility="visible">
<ProgressBar
android:id="@+id/volumeProgressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="128dp"
android:layout_height="128dp"
android:indeterminate="false"
android:progressDrawable="@drawable/progress_circular_white" />
<ImageView
android:id="@+id/volumeImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_volume_up_white_72dp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/brightnessRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/background_oval_black_transparent"
android:visibility="gone"
tools:visibility="visible">
<ProgressBar
android:id="@+id/brightnessProgressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="128dp"
android:layout_height="128dp"
android:indeterminate="false"
android:progressDrawable="@drawable/progress_circular_white" />
<ImageView
android:id="@+id/brightnessImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_brightness_high_white_72dp" />
</RelativeLayout>
<TextView
android:id="@+id/currentDisplaySeek"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="58dp"
android:background="#64000000"
android:paddingBottom="10dp"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:paddingTop="10dp"
android:textColor="@android:color/white"
android:textSize="26sp"
android:textStyle="bold"
android:visibility="gone"
tools:ignore="RtlHardcoded"
tools:text="1:06:29"
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>

Some files were not shown because too many files have changed in this diff Show More