1
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-09-20 11:20:52 +02:00

Compare commits

...

518 Commits

Author SHA1 Message Date
Tobias Groza
b2a5ff5f9d Merge pull request #3669 from TeamNewPipe/release_0.19.4
Release 0.19.4
2020-05-29 19:13:09 +02:00
Stypox
f47ef2b5ea Add 0.19.4 (940) fastlane changelog 2020-05-29 18:55:01 +02:00
Stypox
bd7ec3b692 Bump to 0.19.4 (940) 2020-05-29 18:55:01 +02:00
TobiGr
52895e7b6b Increase JVM memory to fix release build 2020-05-29 18:55:01 +02:00
Stypox
a6a82c6477 Regression: fix icon size in main player 2020-05-29 15:32:44 +02:00
Tobias Groza
af66ed94b2 Merge pull request #3662 from B0pol/localisation-fixes
Localisation fixes (Fix crashes, lint)
2020-05-29 08:02:19 +02:00
bopol
583f1476d6 oops 2020-05-28 23:32:44 +02:00
bopol
b42bef32fd remove totally untranslated languages 2020-05-28 23:21:28 +02:00
bopol
8bb85ccf19 other translation linting stuff 2020-05-28 23:14:57 +02:00
bopol
3d88c2a5fa fix crash in hindi and pa languages 2020-05-28 22:59:14 +02:00
bopol
e350acaf08 remove unused plural string «comments»
on top of being unused, there were MANY problems for some languages: %s missing, only «one» quantity is translated…
2020-05-28 22:49:41 +02:00
bopol
172f70bef9 fix crash in polish, lint: remove translated translatable=false string 2020-05-28 22:22:29 +02:00
Tobias Groza
9d25c0bf8a Merge pull request #3509 from wb9688/upgrade-dependencies
Upgrade some dependencies
2020-05-28 22:07:04 +02:00
TobiGr
75b377aab3 Updatethe extractor version 2020-05-28 21:56:54 +02:00
TobiGr
3706f30b44 Merge remote-tracking branch 'Weblate/dev' into dev 2020-05-28 21:46:45 +02:00
wb9688
a9697a61ad Fix viewing licenses 2020-05-28 11:39:17 +02:00
wb9688
e16a2d7cb6 Upgrade jsoup 2020-05-28 11:39:17 +02:00
Arnis Jaundzeikars
f106e2945b Added translation using Weblate (Latvian) 2020-05-27 18:06:40 +02:00
pjammo
1ad7deddb1 Translated using Weblate (Italian)
Currently translated at 99.6% (575 of 577 strings)
2020-05-26 09:52:46 +02:00
wb9688
7b81e98581 Upgrade ACRA 2020-05-25 11:03:07 +02:00
wb9688
0cae58ce8e Upgrade LeakCanary 2020-05-25 11:03:07 +02:00
wb9688
7231150115 Upgrade some dependencies 2020-05-22 15:40:28 +02:00
Hosted Weblate
071986a4c9 Merge branch 'origin/dev' into Weblate. 2020-05-22 11:41:39 +02:00
Rahul Bali
39e7d43f10 Translated using Weblate (Hindi)
Currently translated at 82.4% (476 of 577 strings)
2020-05-22 11:41:37 +02:00
Yaron Shahrabani
aa1b17ae66 Translated using Weblate (Hebrew)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:37 +02:00
Anonymous
92bae88355 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.8% (172 of 577 strings)
2020-05-22 11:41:36 +02:00
Jeff Huang
067eaf363e Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:36 +02:00
Samuel Carvalho de Araújo
00efc266d9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:36 +02:00
Oğuz Ersen
0b014185e3 Translated using Weblate (Turkish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:36 +02:00
zmni
3eee7378de Translated using Weblate (Indonesian)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:36 +02:00
zeritti
c31428f6bc Translated using Weblate (Czech)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:35 +02:00
B0pol
163e561cf9 Translated using Weblate (French)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:35 +02:00
JoC
a32ded2829 Translated using Weblate (Spanish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-22 11:41:35 +02:00
nautilusx
a5b7517fbd Translated using Weblate (German)
Currently translated at 99.8% (576 of 577 strings)
2020-05-22 11:41:34 +02:00
Tobias Groza
176d57b35a Merge pull request #3271 from Stypox/icons
Use vector drawables instead of PNGs for material icons
2020-05-21 19:32:43 +02:00
Stypox
927a1d58e2 Use drop down/up instead of expand icons in drawer
As per the material guidelines
2020-05-21 15:39:36 +02:00
Stypox
bbd0df08d3 Add shadow behind play icon in video detail fragment 2020-05-21 15:39:36 +02:00
Stypox
9e57195e14 Fix checkstyle issues
Also replace all tabs with 4 spaces
2020-05-21 15:39:36 +02:00
Stypox
05ab54c30d Fix invisible fullscreen button in popup player on API 19 2020-05-21 15:39:36 +02:00
Stypox
e3e2028153 Use AppCompatResources instead of ContextCompat 2020-05-21 15:39:36 +02:00
Stypox
883bcc735d Fix pause used instead of play in paused popup player when seeking
Also use `setBackgroundResource` to automatically obtain PNG drawables (from exoplayer)
2020-05-21 15:39:36 +02:00
Stypox
158727e2f2 Replace hardcoded white drawable with themed one 2020-05-21 15:39:36 +02:00
Stypox
899f69d120 Fix additional empty title on tab selection fragments in API 19 2020-05-21 15:39:36 +02:00
Stypox
b575046c05 Fix choice dialogs on API 19 by manually getting drawable 2020-05-21 15:39:36 +02:00
Stypox
b5c60d2be2 Update AndroidX to fix icon crashes in preferences on API 19
Also remove legacy libraries
Use `androidx.preference:preference` instead of `androidx.legacy:legacy-preference-v14` and remove `androidx.legacy:legacy-support-v4
2020-05-21 15:39:36 +02:00
Stypox
631dfee763 Readd ic_close and ic_replay PNGs: needed in notifications
The other icons used in notifications are taken from exoplayer's ones: `@drawable/exo_controls_*`
2020-05-21 15:39:36 +02:00
Stypox
d7f610113e Fix background player queue crashing on opening 2020-05-21 15:39:36 +02:00
Stypox
e0e4f6db2b Fix MainFragment tab icons did not follow theme color 2020-05-21 15:39:36 +02:00
Stypox
c27a26c0aa Rename ic_hot in ic_kiosk_hot and improve getKioskIcon() 2020-05-21 15:39:36 +02:00
Stypox
3dcd2468a2 Use app:srcCompat and derivatives intead of android: ones
To fix crashes on API 19
2020-05-21 15:39:36 +02:00
Stypox
ea43b28f74 Use vector drawables instead of PNGs for material icons
For all manually-created images PNG have been kept.
- rename all icon attrs to have a `ic_` prefix
- always use `_24dp` icons, because there is no real difference, since they are vector drawables
- always use the original name found on material.io for icon drawables, as to not create confusion and possibly duplicates. Icon names can still be different from real drawable names, though I have made some of them compliant to this or maybe more meaningul.
- remove duplicate `getIconByAttr()` in ThemeHelper (use `resolveResourceIdFromAttr()`
- use standard icons for `expand_more` and `expand_less` instead of triangles
- use `play_button_outline` instead of custom PNG as play button in VideoDetailFragment (questionable, as there is no shadow anymore)
2020-05-21 15:39:35 +02:00
bopol
a3e2a085b6 Merge pull request #3501 from B0pol/openInBrowser
Open in browser button now really opens in browser
2020-05-21 09:24:57 +02:00
Anonymous
635d51b60d Translated using Weblate (Hindi)
Currently translated at 82.4% (476 of 577 strings)
2020-05-20 12:31:02 +02:00
Rahul Bali
95eb1c0d95 Translated using Weblate (Hindi)
Currently translated at 82.4% (476 of 577 strings)
2020-05-20 12:31:01 +02:00
Rahul Bali
8aca43a7e6 Translated using Weblate (Hindi)
Currently translated at 81.9% (473 of 577 strings)
2020-05-20 12:25:58 +02:00
Anonymous
f6afe59788 Translated using Weblate (Hindi)
Currently translated at 81.9% (473 of 577 strings)
2020-05-20 12:25:57 +02:00
bopol
8e13161f64 fix checkstyle 2020-05-19 21:57:46 +02:00
bopol
97437b8af3 apply @stypox suggestions 2020-05-19 21:52:30 +02:00
bopol
9a938093e2 Open in browser button now really opens in browser 2020-05-19 21:51:47 +02:00
Hosted Weblate
3edcc9f9fd Merge branch 'origin/dev' into Weblate. 2020-05-19 17:02:04 +02:00
Oymate
55db408720 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (171 of 577 strings)
2020-05-19 17:02:04 +02:00
Samuel Carvalho de Araújo
caef874814 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-19 17:02:04 +02:00
Anonymous
1622639eca Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (171 of 577 strings)
2020-05-19 17:02:00 +02:00
Oymate
4df89f4217 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (171 of 577 strings)
2020-05-19 17:02:00 +02:00
Tobias Groza
079b98ed3f Merge pull request #3618 from Stypox/long-press-strings
Improve long-press menu strings
2020-05-19 08:38:00 +02:00
Stypox
a0526d2c9c Improve long-press menu strings 2020-05-19 08:24:04 +02:00
Stypox
169b1cbd32 Merge pull request #3613 from wb9688/fix-download-dialog-freeze
Fix download dialog freeze
2020-05-18 14:11:17 +02:00
wb9688
8968081e77 Remove not needed Checkstyle stuff 2020-05-18 13:40:01 +02:00
wb9688
93ba7510e1 Fix ListHelper ANR 2020-05-18 13:40:01 +02:00
Hosted Weblate
579bb743bb Merge branch 'origin/dev' into Weblate. 2020-05-18 13:17:56 +02:00
Rai Tsa
9e5e9ea612 Translated using Weblate (Finnish)
Currently translated at 58.0% (335 of 577 strings)
2020-05-18 13:17:54 +02:00
Thien Bui
2241a13cba Translated using Weblate (Vietnamese)
Currently translated at 99.8% (576 of 577 strings)
2020-05-18 13:17:54 +02:00
Isak Holmström
9c1fb0cb92 Translated using Weblate (Swedish)
Currently translated at 89.4% (516 of 577 strings)
2020-05-18 13:17:52 +02:00
Anonymous
4904514257 Translated using Weblate (Swedish)
Currently translated at 89.4% (516 of 577 strings)
2020-05-18 13:17:52 +02:00
Samuel Carvalho de Araújo
6d829c26a1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-18 13:17:52 +02:00
Stypox
c05467fb92 Merge pull request #3513 from Stypox/exoplayer
Update to ExoPlayer 2.11.4
2020-05-17 22:02:19 +02:00
Anonymous
d47f7f3348 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-17 00:52:28 +02:00
Samuel Carvalho de Araújo
5931a84651 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-16 04:41:32 +02:00
zeritti
5771783d11 Translated using Weblate (Czech)
Currently translated at 100.0% (577 of 577 strings)
2020-05-16 04:41:32 +02:00
Hosted Weblate
aae07a60bd Merge branch 'origin/dev' into Weblate. 2020-05-14 11:38:10 +02:00
MohammedSR Vevo
462d418ee0 Translated using Weblate (Kurdish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-14 11:38:08 +02:00
Isak Holmström
ce63c2e1db Translated using Weblate (Swedish)
Currently translated at 89.4% (516 of 577 strings)
2020-05-14 11:38:07 +02:00
Isak Holmström
52baf8cbe5 Translated using Weblate (Swedish)
Currently translated at 89.4% (516 of 577 strings)
2020-05-14 11:38:07 +02:00
ssantos
1779b9ee1a Translated using Weblate (Portuguese)
Currently translated at 100.0% (577 of 577 strings)
2020-05-14 11:38:06 +02:00
B0pol
eae169236c Merge pull request #3581 from B0pol/gitignore
Add vscode / eclipse files to gitignore
2020-05-13 18:11:51 +00:00
bopol
ce0efba0d2 gitignore update 2020-05-13 19:54:02 +02:00
Tobias Groza
87c7ac3970 Merge pull request #3580 from wb9688/fix-email
Fix sending e-mail from crash reporter
2020-05-13 17:10:22 +02:00
bopol
0f8d196a52 Add vscode / eclipse files to gitignore 2020-05-13 11:07:02 +02:00
Stypox
6dc7dab154 Merge pull request #3565 from B0pol/retry-button-color
Change retry & subscribe buttons background color based on service color
2020-05-13 11:01:40 +02:00
wb9688
dd4cb23005 Fix sending e-mail from crash reporter 2020-05-13 09:42:08 +02:00
ButterflyOfFire
0589017f8c Translated using Weblate (Arabic)
Currently translated at 100.0% (577 of 577 strings)
2020-05-12 15:41:32 +02:00
bopol
375e18bec8 subscribe button now match service's main color 2020-05-11 19:29:34 +02:00
WaldiS
b9de74f183 Translated using Weblate (Polish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-11 08:54:43 +02:00
Oğuz Ersen
08ca69507f Translated using Weblate (Turkish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-11 08:54:42 +02:00
JoC
65ca982342 Translated using Weblate (Spanish)
Currently translated at 100.0% (577 of 577 strings)
2020-05-11 08:54:42 +02:00
Igor Nedoboy
658281a92c Translated using Weblate (Russian)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 22:59:48 +02:00
Igor Nedoboy
a959f61367 Translated using Weblate (Russian)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 22:50:30 +02:00
Yaron Shahrabani
8e61f744ec Translated using Weblate (Hebrew)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:56 +02:00
Jeff Huang
73d3e52e29 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:55 +02:00
Xiang Xu
49a134845c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:55 +02:00
Samuel Carvalho de Araújo
29807f3d39 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:55 +02:00
WaldiS
29b79b7725 Translated using Weblate (Polish)
Currently translated at 99.8% (576 of 577 strings)
2020-05-10 14:34:54 +02:00
zmni
1cdb10a040 Translated using Weblate (Indonesian)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:54 +02:00
AioiLight
5f7851df72 Translated using Weblate (Japanese)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:54 +02:00
winqooq
3d9bc05d7a Translated using Weblate (Russian)
Currently translated at 99.4% (574 of 577 strings)
2020-05-10 14:34:53 +02:00
B0pol
c127428c59 Translated using Weblate (French)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:53 +02:00
nautilusx
7966d8403a Translated using Weblate (German)
Currently translated at 100.0% (577 of 577 strings)
2020-05-10 14:34:53 +02:00
bopol
80cc8a8e02 color retry button based on service color 2020-05-10 10:54:12 +02:00
Igor Nedoboy
ee4e205fef Translated using Weblate (Russian)
Currently translated at 99.4% (574 of 577 strings)
2020-05-10 02:07:05 +02:00
Hosted Weblate
ea443dc80c Merge branch 'origin/dev' into Weblate. 2020-05-09 16:13:01 +02:00
Senthil Kumar G
283645513d Translated using Weblate (Tamil)
Currently translated at 35.8% (206 of 574 strings)
2020-05-09 16:12:57 +02:00
Anonymous
81b99382b8 Translated using Weblate (Italian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-09 16:12:57 +02:00
random r
ab74465e6c Translated using Weblate (Italian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-09 16:12:57 +02:00
Tobias Groza
b3eadb557b Merge pull request #3337 from AioiLight/blocking-gesture-when-touch-from-navbar
Block the gesture when touch it from NavigationBar or StatusBar.
2020-05-09 10:43:15 +02:00
AioiLight
0abd2bcba6 Clean up code
Follow Checkstyle

Move to PlayerGestureListener from VideoPlayerImpl

Update app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java

Co-authored-by: wb9688 <46277131+wb9688@users.noreply.github.com>
2020-05-09 10:11:46 +02:00
Tobias Groza
9cf76a918e Merge pull request #3430 from Royosef/DisplayParentChannelDetails
Display parent channel details
2020-05-08 23:29:28 +02:00
wb9688
ae437b1510 Bump NewPipeExtractor 2020-05-08 18:07:52 +02:00
wb9688
1096ec1c09 Adjust sub-channel thumbnail size 2020-05-08 15:51:21 +02:00
wb9688
235394d96c Don't show sub-channel thumbnail by default 2020-05-08 15:51:21 +02:00
Anonymous
d25e1d801c Translated using Weblate (Italian)
Currently translated at 99.6% (572 of 574 strings)
2020-05-08 12:35:52 +02:00
random r
2dca5ab966 Translated using Weblate (Italian)
Currently translated at 99.6% (572 of 574 strings)
2020-05-08 12:35:52 +02:00
caltaojihun
89ab57b1c1 Translated using Weblate (Vietnamese)
Currently translated at 94.4% (542 of 574 strings)
2020-05-08 09:56:46 +02:00
caltaojihun
dc66e6a4bf Translated using Weblate (Vietnamese)
Currently translated at 79.7% (458 of 574 strings)
2020-05-08 06:49:55 +02:00
Hosted Weblate
5c2f2fd882 Merge branch 'origin/dev' into Weblate. 2020-05-07 23:24:06 +02:00
MohammedSR Vevo
5c3ddefbf9 Translated using Weblate (Kurdish)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 23:24:04 +02:00
thami simo
a8d3f45ea1 Translated using Weblate (Arabic)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 23:24:03 +02:00
ssantos
cc2c41ddc8 Translated using Weblate (Portuguese)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 23:24:03 +02:00
wb9688
b990f30a09 Merge pull request #3545 from Stypox/kore
Fix Kodi button showing up with unsupported services
2020-05-07 21:44:09 +02:00
Stypox
5c711322d4 In player hide kodi button if service unsupported 2020-05-07 21:11:34 +02:00
Roy Yosef
b7d4a4f604 Navigate to parent(uploader) channel from the uploader section on long click 2020-05-07 20:40:17 +02:00
Roy Yosef
cc8874b687 Fix PR review
Make all of the uploader section on stream page navigate to the channel page
Extract hard coded strings
Remove redundant spaces
Fix open streams from a channel
Rename "ParentChannel" to "SubChannel"
Config royosef:NewPipeExtractor in app/build.gradle
2020-05-07 20:40:17 +02:00
Roy Yosef
2d0bc05488 Add sub-channel details to channel fragment 2020-05-07 20:39:32 +02:00
Roy Yosef
1429774487 Add sub-channel details to video detail fragment 2020-05-07 20:39:32 +02:00
wb9688
2060312dc1 Merge pull request #3466 from B0pol/soundCloudComments
adapt CommentsInfoItemExtractorRefactoring
2020-05-07 16:06:15 +02:00
bopol
8b6728480f bump extractor version 2020-05-07 15:46:41 +02:00
Anxhelo Lushka
cecafdee29 Translated using Weblate (Albanian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:28 +02:00
Senthil Kumar G
05f2af25af Translated using Weblate (Tamil)
Currently translated at 35.7% (205 of 574 strings)
2020-05-07 13:58:27 +02:00
Yaron Shahrabani
e3d826f6c4 Translated using Weblate (Hebrew)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:27 +02:00
Jeff Huang
02430bed90 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:27 +02:00
Samuel Carvalho de Araújo
3f7005ed9a Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:26 +02:00
WaldiS
586ee75833 Translated using Weblate (Polish)
Currently translated at 99.8% (573 of 574 strings)
2020-05-07 13:58:26 +02:00
Emin Tufan Çetin
1d903f11a8 Translated using Weblate (Turkish)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:25 +02:00
Muhammad Mauli Mubassari
578159b95c Translated using Weblate (Indonesian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:25 +02:00
zeritti
5c95587284 Translated using Weblate (Czech)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:25 +02:00
Marian Hanzel
f7e9227ad2 Translated using Weblate (Slovak)
Currently translated at 94.0% (540 of 574 strings)
2020-05-07 13:58:24 +02:00
AioiLight
c11a4d6867 Translated using Weblate (Japanese)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:23 +02:00
Anonymous
6c2b0448a4 Translated using Weblate (Dutch)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:23 +02:00
Terry Louwers
bd0eb8cccf Translated using Weblate (Dutch)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:23 +02:00
nautilusx
09bb043952 Translated using Weblate (German)
Currently translated at 100.0% (574 of 574 strings)
2020-05-07 13:58:22 +02:00
Stypox
9ca6cfd637 Fix Kodi button showing up in unsupported services 2020-05-06 20:55:53 +02:00
Igor Nedoboy
3869a66fcc Translated using Weblate (Russian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-06 13:33:14 +02:00
bopol
d1c94f5120 adapt CommentsInfoItemExtractorRefactoring 2020-05-05 15:03:59 +02:00
Igor Nedoboy
c55e9941ec Translated using Weblate (Russian)
Currently translated at 100.0% (574 of 574 strings)
2020-05-05 08:21:44 +02:00
Hosted Weblate
fa9a419d73 Merge branch 'origin/dev' into Weblate. 2020-05-04 17:49:25 +02:00
Software In Interlingua
ab4e0da6b4 Translated using Weblate (Interlingua)
Currently translated at 39.7% (228 of 573 strings)
2020-05-04 17:49:22 +02:00
Igor Nedoboy
073572681e Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-05-04 17:49:21 +02:00
wb9688
b630f269c4 Merge pull request #3511 from wb9688/ktlint
Ktlint
2020-05-04 15:13:07 +02:00
wb9688
40b1cd82b1 Merge pull request #2727 from vnagel/ageRestrictedContent
Restricted mode setting for youtube
2020-05-04 15:05:11 +02:00
Tobias Groza
abcbdef63b Merge pull request #3502 from wb9688/allow-translation
Allow time ago debug setting translation
2020-05-03 23:25:54 +02:00
Tobias Groza
dc8d1b0993 Merge pull request #3478 from TeamNewPipe/release_0.19.3
Release 0.19.3
2020-05-03 21:22:44 +02:00
Hosted Weblate
56d53d8805 Merge branch 'origin/dev' into Weblate. 2020-05-03 15:40:40 +02:00
Oymate
7433fe049c Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (170 of 573 strings)
2020-05-03 15:40:40 +02:00
postsorino
bb2be49d3b Translated using Weblate (Greek)
Currently translated at 85.1% (488 of 573 strings)
2020-05-03 15:40:40 +02:00
Bruno Guerreiro
cd1b578e84 Translated using Weblate (Portuguese)
Currently translated at 100.0% (573 of 573 strings)
2020-05-03 15:40:40 +02:00
winqooq
c3df9b4105 Translated using Weblate (Russian)
Currently translated at 99.4% (570 of 573 strings)
2020-05-03 15:40:37 +02:00
TobiGr
243f3e21ec Release 0.19.3 (930) 2020-05-03 14:13:21 +02:00
TobiGr
375291380c Add changelog 2020-05-03 14:13:21 +02:00
TobiGr
d221194454 Merge remote-tracking branch 'Weblate/dev' into dev 2020-05-03 14:12:59 +02:00
TobiGr
6d94a54387 Update extractor to fix NPE in YouTube Muic search 2020-05-03 14:12:22 +02:00
Anonymous
910bde88c7 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (170 of 573 strings)
2020-05-02 16:35:50 +02:00
Oymate
72916544ce Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.6% (170 of 573 strings)
2020-05-02 16:35:50 +02:00
Anonymous
a01975dfce Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.4% (169 of 573 strings)
2020-05-02 16:35:29 +02:00
Oymate
10708801ae Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.4% (169 of 573 strings)
2020-05-02 16:35:28 +02:00
Anonymous
ac096fb4e7 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.3% (168 of 573 strings)
2020-05-02 16:33:50 +02:00
Oymate
620c1397ba Translated using Weblate (Bengali (Bangladesh))
Currently translated at 29.3% (168 of 573 strings)
2020-05-02 16:33:50 +02:00
Anonymous
5b2f2f34f6 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.7% (165 of 573 strings)
2020-05-02 16:33:04 +02:00
Hosted Weblate
ae3861a29d Merge branch 'origin/dev' into Weblate. 2020-05-02 16:27:27 +02:00
Oymate
93e2145254 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.6% (164 of 573 strings)
2020-05-02 16:27:27 +02:00
pjammo
2b6290d275 Translated using Weblate (Italian)
Currently translated at 99.6% (571 of 573 strings)
2020-05-02 16:27:26 +02:00
Anonymous
f81af7acb3 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.6% (164 of 573 strings)
2020-05-02 16:27:23 +02:00
Oymate
f0170247a4 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.6% (164 of 573 strings)
2020-05-02 16:27:23 +02:00
TobiGr
3430874d11 Merge remote-tracking branch 'Weblate/dev' into dev 2020-05-02 16:21:56 +02:00
Tobias Groza
cb5e7532ab Merge pull request #3480 from wb9688/update-nanojson
Use our nanojson fork
2020-05-02 16:17:29 +02:00
Anonymous
5b928d679c Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.2% (162 of 573 strings)
2020-05-02 16:17:14 +02:00
Oymate
697b9694e5 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 28.2% (162 of 573 strings)
2020-05-02 16:17:13 +02:00
wb9688
81c3e7e7f6 Use our nanojson fork 2020-05-02 16:03:15 +02:00
NITHIN
0517bba8ca Translated using Weblate (Malayalam)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:09 +02:00
MohammedSR Vevo
83c7244fe6 Translated using Weblate (Kurdish)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:09 +02:00
ssantos
68fd129042 Translated using Weblate (Portuguese)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:08 +02:00
pjammo
b697e8a616 Translated using Weblate (Italian)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:08 +02:00
B0pol
2b281fbde9 Translated using Weblate (French)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:07 +02:00
JoC
de8c4018c4 Translated using Weblate (Spanish)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:07 +02:00
Jeannette
9e8af96bbf Translated using Weblate (German)
Currently translated at 100.0% (573 of 573 strings)
2020-05-02 12:31:07 +02:00
wb9688
b0415a5289 Auto-format using Ktlint 2020-05-01 20:13:21 +02:00
wb9688
ff7344438b Optimize imports 2020-05-01 20:13:01 +02:00
wb9688
f5f8e5d279 Add Ktlint 2020-05-01 20:09:52 +02:00
Stypox
b4ddc8f96c Update to ExoPlayer 2.11.4 2020-05-01 15:03:54 +02:00
Theophine Savio Theodore
e556c8ee15 Translated using Weblate (Malayalam)
Currently translated at 100.0% (573 of 573 strings)
2020-04-30 02:16:11 +02:00
Anxhelo Lushka
2f9a0b3376 Translated using Weblate (Albanian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-30 02:16:06 +02:00
Isak Holmström
828f07b401 Translated using Weblate (Swedish)
Currently translated at 85.8% (492 of 573 strings)
2020-04-30 02:16:06 +02:00
Isak Holmström
36921b3426 Translated using Weblate (Swedish)
Currently translated at 85.8% (492 of 573 strings)
2020-04-30 02:16:06 +02:00
Edoardo Regni
3988c6491c Translated using Weblate (Dutch)
Currently translated at 100.0% (573 of 573 strings)
2020-04-30 02:16:05 +02:00
Igor Nedoboy
2cf558ec05 Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-29 21:53:56 +02:00
Anonymous
6fbadbdd94 Translated using Weblate (Dutch)
Currently translated at 100.0% (573 of 573 strings)
2020-04-29 16:06:40 +02:00
Edoardo Regni
faa1d7effb Translated using Weblate (Dutch)
Currently translated at 100.0% (573 of 573 strings)
2020-04-29 16:06:40 +02:00
Anonymous
fe73a708d4 Translated using Weblate (Dutch)
Currently translated at 100.0% (573 of 573 strings)
2020-04-29 16:00:05 +02:00
Edoardo Regni
a5ca262faa Translated using Weblate (Dutch)
Currently translated at 100.0% (573 of 573 strings)
2020-04-29 16:00:05 +02:00
wb9688
8ebb1e29fa Allow time ago debug setting translation 2020-04-29 14:47:06 +02:00
Igor Nedoboy
1b44dc9522 Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-28 21:43:06 +02:00
Theophine Savio Theodore
a66d468dc2 Translated using Weblate (Malayalam)
Currently translated at 81.5% (467 of 573 strings)
2020-04-28 05:27:35 +02:00
Igor Nedoboy
ca8beafc2d Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-27 19:08:53 +02:00
Igor Nedoboy
639c589a4a Translated using Weblate (Russian)
Currently translated at 99.3% (569 of 573 strings)
2020-04-27 18:53:59 +02:00
Hosted Weblate
cd66836218 Merge branch 'origin/dev' into Weblate. 2020-04-27 16:26:09 +02:00
Rex_sa
98662baa26 Translated using Weblate (Arabic)
Currently translated at 100.0% (573 of 573 strings)
2020-04-27 16:26:09 +02:00
Theophine Savio Theodore
004e5794e3 Added translation using Weblate (Malayalam) 2020-04-27 16:26:05 +02:00
Tobias Groza
f4f4f062cf Merge pull request #3495 from Stypox/fix-rotation
Fix rotation
2020-04-27 09:18:08 +02:00
Stypox
d8d9c7e171 Fix crashes on rotation by checking for null 2020-04-27 09:01:24 +02:00
Hosted Weblate
ceff82732e Merge branch 'origin/dev' into Weblate. 2020-04-26 20:43:27 +02:00
Anxhelo Lushka
d94b1708a9 Translated using Weblate (Albanian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:27 +02:00
MohammedSR Vevo
46e1f16012 Translated using Weblate (Kurdish)
Currently translated at 99.8% (572 of 573 strings)
2020-04-26 20:43:27 +02:00
Milo Ivir
bbd014d409 Translated using Weblate (Croatian)
Currently translated at 88.1% (505 of 573 strings)
2020-04-26 20:43:26 +02:00
Jeff Huang
d553ee7c60 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:26 +02:00
WaldiS
2df6ab240d Translated using Weblate (Polish)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:26 +02:00
Emin Tufan Çetin
8a2b9dfd6a Translated using Weblate (Turkish)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:26 +02:00
Иван
1f7892d7a9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:25 +02:00
vkhomenk
d11c537bea Translated using Weblate (Ukrainian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:25 +02:00
winqooq
2d4d237009 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:25 +02:00
zeritti
daeee6b616 Translated using Weblate (Czech)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:24 +02:00
StarFang208
eacb0b13b2 Translated using Weblate (Italian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:23 +02:00
Igor Nedoboy
dc5748059a Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:23 +02:00
JoC
96d75f4bcb Translated using Weblate (Spanish)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:23 +02:00
winqooq
19bfdf3f9f Translated using Weblate (Russian)
Currently translated at 100.0% (573 of 573 strings)
2020-04-26 20:43:20 +02:00
Tobias Groza
4ea273b297 Merge pull request #3483 from B0pol/tv
Better detection of TV devices
2020-04-26 12:55:13 +02:00
Vincent Nagel
72c9845174 removed unnecessary method call 2020-04-25 21:39:53 -05:00
bopol
77597b329e store isTv value to prevent calculating it again and again 2020-04-26 00:36:45 +02:00
bopol
f62f00b4ad Fix crash on Android 4.4 and surely other sdk versions 2020-04-25 23:38:34 +02:00
bopol
00262b4a49 Better detection of TV devices
Some devices were not detected as TV even though they are
2020-04-25 12:04:44 +02:00
Hosted Weblate
de6cabe408 Merge branch 'origin/dev' into Weblate. 2020-04-25 02:11:39 +02:00
Mitosagi
d65552b59f Translated using Weblate (Japanese)
Currently translated at 100.0% (573 of 573 strings)
2020-04-25 02:11:37 +02:00
Florian
3755f48bce Translated using Weblate (French)
Currently translated at 100.0% (573 of 573 strings)
2020-04-25 02:11:36 +02:00
Anonymous
8fe75d2015 Translated using Weblate (French)
Currently translated at 100.0% (573 of 573 strings)
2020-04-25 02:11:36 +02:00
TobiGr
b0c0249ce6 Merge remote-tracking branch 'Weblate/dev' into dev 2020-04-24 18:27:25 +02:00
Lucas Araujo
17685f3d86 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (573 of 573 strings)
2020-04-24 17:04:09 +02:00
Anonymous
30f1c71569 Translated using Weblate (Indonesian)
Currently translated at 99.8% (572 of 573 strings)
2020-04-24 17:04:09 +02:00
zmni
137afba1b6 Translated using Weblate (Indonesian)
Currently translated at 99.8% (572 of 573 strings)
2020-04-24 17:04:09 +02:00
AioiLight
b27de5cac1 Translated using Weblate (Japanese)
Currently translated at 100.0% (573 of 573 strings)
2020-04-24 17:04:08 +02:00
nautilusx
8d43ae9805 Translated using Weblate (German)
Currently translated at 100.0% (573 of 573 strings)
2020-04-24 17:04:08 +02:00
Yaron Shahrabani
3cebb028f4 Translated using Weblate (Hebrew)
Currently translated at 100.0% (573 of 573 strings)
2020-04-24 11:39:27 +02:00
Hosted Weblate
28ab9d3515 Merge branch 'origin/dev' into Weblate. 2020-04-24 11:19:02 +02:00
Mladen Pejaković
f7739309e8 Translated using Weblate (Serbian)
Currently translated at 42.1% (240 of 569 strings)
2020-04-24 11:19:00 +02:00
Stypox
2db0d63c97 Merge pull request #3065 from GradyClark/dev
Added the ability to remove all watched videos from a local playlist
2020-04-23 23:52:28 +02:00
Stypox
437b86d1a7 Use centralized CompositeDisposable instead of custom Disposable
Also do not show any dialog if the user is aready removing watched videos in a local playlist
2020-04-23 23:35:00 +02:00
TobiGr
5ba1df52e0 Add Achinese (ACE) to the language selector 2020-04-23 23:24:52 +02:00
TobiGr
04ab753b26 Merge pull request Android TV support #2806
Closes #2806
2020-04-23 22:33:20 +02:00
TobiGr
bc4a598a55 Merge remote-tracking branch 'Weblate/dev' into dev 2020-04-23 21:11:50 +02:00
TobiGr
651cdec9b5 Fix button ripples in VideoDetailFragment 2020-04-22 22:35:41 +02:00
Hosted Weblate
346f9fbacd Merge branch 'origin/dev' into Weblate. 2020-04-21 22:05:03 +02:00
Anxhelo Lushka
0f493ae808 Translated using Weblate (Albanian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-21 22:05:03 +02:00
Igor Nedoboy
a07f143759 Translated using Weblate (Russian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-21 22:05:00 +02:00
Stypox
0ec22c7a6e Fix pause button is not focused on player control activation 2020-04-21 09:25:09 +02:00
Grady Clark
73611004a0 Code cleanup, and best practices 2020-04-21 01:57:23 -05:00
Grady Clark
776ddddc83 fixed naming and formatting issues 2020-04-21 01:03:42 -05:00
Vincent Nagel
f60cce54ea rename setting to "YouTube restricted mode" 2020-04-20 21:47:32 -05:00
Vincent Nagel
63087a4311 renamed to "restricted mode" 2020-04-20 21:46:40 -05:00
Vincent Nagel
5a193d50f6 remove duplicate line 2020-04-20 21:45:32 -05:00
Vincent Nagel
08a6e999b9 fix checkstyle errors 2020-04-20 21:45:32 -05:00
Vincent Nagel
e33cdca1ef added logging when context null in onPrefTreeClick 2020-04-20 21:45:32 -05:00
Vincent Nagel
9ede7a3c42 setupTabs() if ageRestrictedContent pref changed 2020-04-20 21:45:32 -05:00
Vincent Nagel
430d4e1ccd ageRestrictedContent cookie only sent for youtube
Now the age restricted content cookie is only sent when sending a
request to youtube. There's no need to remove the cookie when the
service changes because whether to add the cookie is determined by
looking at the url the request is being sent to.
2020-04-20 21:45:32 -05:00
Vincent Nagel
de4d6037d3 ageRestrictedContent first draft
Cookie updated whenever ageRestrictedContent setting is changed or
service is changed. Right now there is only a cookie for youtube, but
cookies for other services could be added in the future.

Problems with this approach: Even when the service is set to youtube,
the downloader doesn't only request youtube urls e.g. it also sends
reqeusts to i.ytimg.com, suggestqueries.google.com, and yt3.ggpht.com.
The ageRestrictedContent cookie is not normally sent when sending
requests to these other urls, so doing so might have unknown effects.
2020-04-20 21:45:32 -05:00
Tobias Groza
fc1fc6842b Merge pull request #3464 from wb9688/checkstyle-debug-only
Run Checkstyle only on debug builds
2020-04-20 20:22:12 +02:00
wb9688
0649b297f6 Run Checkstyle only on debug builds 2020-04-20 17:01:36 +02:00
Hosted Weblate
9a470b9d41 Merge branch 'origin/dev' into Weblate. 2020-04-20 14:46:28 +02:00
MohammedSR Vevo
47d1ab356d Translated using Weblate (Kurdish)
Currently translated at 99.8% (568 of 569 strings)
2020-04-20 14:46:27 +02:00
WaldiS
1ea5787486 Translated using Weblate (Polish)
Currently translated at 100.0% (569 of 569 strings)
2020-04-20 14:46:27 +02:00
thami simo
1d4695c109 Translated using Weblate (Arabic)
Currently translated at 100.0% (569 of 569 strings)
2020-04-20 14:46:27 +02:00
Gontzal Manuel Pujana Onaindia
b673f9dd7f Translated using Weblate (Basque)
Currently translated at 100.0% (569 of 569 strings)
2020-04-20 14:46:27 +02:00
Bruno Guerreiro
a1dd03472f Translated using Weblate (Portuguese)
Currently translated at 100.0% (569 of 569 strings)
2020-04-20 14:46:26 +02:00
Anxhelo Lushka
497e545024 Translated using Weblate (Albanian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-20 14:46:22 +02:00
wb9688
6892fdb70b Merge pull request #3463 from B0pol/json
use nanojson instead of org.json
2020-04-20 14:02:36 +02:00
wb9688
aa1cc32d17 Open comment author on TV at long press 2020-04-20 13:37:35 +02:00
bopol
b22398ae6c use nanojson instead of org.json 2020-04-20 11:02:45 +02:00
Stypox
e6eddaff73 Merge pull request #3460 from wb9688/force-utf-8
Force UTF-8 encoding for Gradle
2020-04-20 10:18:56 +02:00
Tobias Groza
cd53518897 Merge pull request #3345 from mitosagi/error-with-bookmarks
Fix repeated exceptions in Bookmarked Playlists
2020-04-19 22:00:31 +02:00
wb9688
8e9b1b7213 Merge pull request #3414 from Stypox/recaptcha
Fix ReCaptcha Activity for another type of recaptcha page
2020-04-19 19:49:01 +02:00
wb9688
7a88fae2e2 Force UTF-8 encoding for Gradle 2020-04-19 19:33:46 +02:00
Tobias Groza
f066da23c5 Merge pull request #3456 from Stypox/enqueue-channel
Enqueue on long click on background/popup in channel
2020-04-19 11:41:12 +02:00
Stypox
34aa3d3e00 Enqueue on long click on background/popup in channel 2020-04-19 10:34:07 +02:00
Hosted Weblate
715119fd45 Merge branch 'origin/dev' into Weblate. 2020-04-16 21:55:01 +02:00
Allan Nordhøy
bde34fc4c4 Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.6% (516 of 569 strings)
2020-04-16 21:55:00 +02:00
MohammedSR Vevo
07b4aa89d4 Translated using Weblate (Kurdish)
Currently translated at 99.4% (566 of 569 strings)
2020-04-16 21:54:59 +02:00
Isak Holmström
d60351114c Translated using Weblate (Swedish)
Currently translated at 83.1% (473 of 569 strings)
2020-04-16 21:54:59 +02:00
Yaron Shahrabani
c932a70bef Translated using Weblate (Hebrew)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:58 +02:00
Jeff Huang
4641d7ee8c Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:58 +02:00
Xiang Xu
d4b3ee50f2 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:58 +02:00
Samuel Carvalho de Araújo
5392daa3ff Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:57 +02:00
Mostafa Ahangarha
a70e366fb4 Translated using Weblate (Persian)
Currently translated at 85.2% (485 of 569 strings)
2020-04-16 21:54:56 +02:00
Oğuz Ersen
dff14268db Translated using Weblate (Turkish)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:55 +02:00
zmni
5517e157ad Translated using Weblate (Indonesian)
Currently translated at 98.9% (563 of 569 strings)
2020-04-16 21:54:54 +02:00
anonymous
bdf4ffc36b Translated using Weblate (Arabic)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:54 +02:00
Vojtěch Šamla
71455c63c1 Translated using Weblate (Czech)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:54 +02:00
Aaron Feng
b1ae2b1a41 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 30.0% (171 of 569 strings)
2020-04-16 21:54:53 +02:00
Jeannette L
8a31732ce2 Translated using Weblate (Italian)
Currently translated at 99.8% (568 of 569 strings)
2020-04-16 21:54:53 +02:00
AioiLight
e79aed7792 Translated using Weblate (Japanese)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:52 +02:00
B0pol
973fc08f2d Translated using Weblate (French)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:52 +02:00
JoC
00211e1fb2 Translated using Weblate (Spanish)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:52 +02:00
C. Rüdinger
ce7286a72a Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)
2020-04-16 21:54:51 +02:00
Grady Clark
db335d5cec Removed redundant code
reorganized code
2020-04-16 12:58:16 -05:00
Stypox
ee5ce0c809 Save and restore cookies to/from preferences
So that the user does not have to solve a recaptcha every time he opens the app
2020-04-15 13:30:27 +02:00
Stypox
b8efef7c7a Remove duplicate check if cookies are already present 2020-04-15 13:30:27 +02:00
Stypox
e2cbf40957 Fix recaptcha activity for another type of recaptcha page
Try to get cookies from pages even when they start loading, because non-html pages like ones with `pbj=1` never stop loading.
Try to extract the cookie directly from the redirection url, by looking at the field "google_abuse=".
Add `GOOGLE_ABUSE_EXEMPTION=` to the youtube recaptcha cookies.
2020-04-15 13:30:27 +02:00
Stypox
d7d45fb8e2 Merge pull request #3415 from TeamNewPipe/fix/f-droid_build
Fix F-Droid build
2020-04-15 10:32:44 +02:00
Grady Clark
1d0c3de65f Merge branch 'dev' of https://github.com/TeamNewPipe/NewPipe into dev 2020-04-14 13:24:57 -05:00
Grady Clark
fe1646caa0 Changed "Remove Watched":
- Will now execute on the io thread
- Added confirmation dialog
  - Warning the user, and asking if they also want to remove partially watched videos
2020-04-14 13:15:07 -05:00
nautilusx
72710f075b Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)
2020-04-14 18:37:12 +02:00
Jeannette L
c7c01aedc2 Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)
2020-04-14 18:37:12 +02:00
C. Rüdinger
c2e2e76fd8 Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)
2020-04-14 18:37:11 +02:00
anonymous
f30a87e4e2 Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)
2020-04-14 18:37:11 +02:00
Igor Nedoboy
7a84cfd510 Translated using Weblate (Russian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-14 10:43:22 +02:00
Jeannette L
7a5a773b07 Translated using Weblate (German)
Currently translated at 99.6% (567 of 569 strings)
2020-04-13 02:46:08 +02:00
Jeannette L
cf1488f6ce Translated using Weblate (German)
Currently translated at 99.6% (567 of 569 strings)
2020-04-13 02:43:01 +02:00
ce4
b02badba0c Translated using Weblate (German)
Currently translated at 98.7% (562 of 569 strings)
2020-04-13 02:40:54 +02:00
Jeannette L
772d84ea5a Translated using Weblate (German)
Currently translated at 99.6% (567 of 569 strings)
2020-04-13 02:40:30 +02:00
random r
ddaa66f080 Translated using Weblate (Italian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-13 02:34:48 +02:00
Igor Nedoboy
8fd75833f0 Translated using Weblate (Russian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-12 22:07:15 +02:00
Igor Nedoboy
1967d60813 Translated using Weblate (Russian)
Currently translated at 100.0% (569 of 569 strings)
2020-04-12 21:59:31 +02:00
Hosted Weblate
f38f265cf7 Merge branch 'origin/dev' into Weblate. 2020-04-12 16:45:50 +02:00
Isak Holmström
79f37ffee0 Translated using Weblate (Swedish)
Currently translated at 83.5% (468 of 560 strings)
2020-04-12 16:45:48 +02:00
Isak Holmström
d4b2a3c696 Translated using Weblate (Swedish)
Currently translated at 83.5% (468 of 560 strings)
2020-04-12 16:45:47 +02:00
Samuel Carvalho de Araújo
39ec365821 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:46 +02:00
Tolstovka
bc423c471d Translated using Weblate (Ukrainian)
Currently translated at 93.3% (523 of 560 strings)
2020-04-12 16:45:44 +02:00
thami simo
a790f43566 Translated using Weblate (Arabic)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:43 +02:00
Gontzal Manuel Pujana Onaindia
9fbdc950d2 Translated using Weblate (Basque)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:41 +02:00
random r
8319963cbb Translated using Weblate (Italian)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:39 +02:00
Mitosagi
4341219497 Translated using Weblate (Japanese)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:39 +02:00
Igor Nedoboy
835504270d Translated using Weblate (Russian)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:38 +02:00
C. Rüdinger
daed42d208 Translated using Weblate (German)
Currently translated at 100.0% (560 of 560 strings)
2020-04-12 16:45:38 +02:00
Alexander--
850f51a156 When drawer opens, always place focus at it's start 2020-04-12 09:39:32 +06:59
TobiGr
d37b195708 Fix F-Droid build
Fixes the behaviour described in https://github.com/TeamNewPipe/NewPipe/pull/3265#issuecomment-612102349
2020-04-11 22:18:04 +02:00
Alexander--
54ceb85ebe Don't break navigation if player Views other than controls are focused 2020-04-11 16:04:38 +06:59
Alexander--
ef7a5bc753 Make channel info button focusable 2020-04-11 16:04:29 +06:59
wb9688
b7ef60eedd Merge pull request #3410 from wb9688/fix-restricted
Show error when video has age limit and setting is disabled
2020-04-11 09:44:25 +02:00
wb9688
70ede70ea8 Hide tabs when a video is age restricted 2020-04-11 09:30:12 +02:00
Alexander--
d1d942f3fd Fix Checkstyle violations in MediaSourceManager 2020-04-11 09:51:50 +06:59
Alexander--
53b3bda909 Comply with Checkstyle rules 2020-04-11 09:02:22 +06:59
Alexander--
ac5571a363 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-04-11 08:30:40 +06:59
Alexander--
c42f5eca87 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-04-11 08:24:05 +06:59
Tobias Groza
9cb6816b3c Merge pull request #3294 from mauriciocolli/fix-network-issues-detection
Fix detection of network related exceptions
2020-04-10 23:10:34 +02:00
Stypox
feab633e60 Merge pull request #3075 from harshlele/better-popup-resizing
Better popup resizing with pinch gestures
2020-04-10 22:26:59 +02:00
Stypox
a50e430cd9 Fix checkstyle issues and improve code formatting
Also calculate differently the moved distance of a pointer: use euclidean and not manhattan geometry
2020-04-10 22:12:45 +02:00
Harshal Lele
46918ee907 formatting changes 2020-04-10 22:10:32 +02:00
Harshal Lele
fe1889653e made formatting changes 2020-04-10 22:10:32 +02:00
Harshal Lele
9487b5367d changed popup resizing 2020-04-10 22:10:32 +02:00
Tobias Groza
6b47df75a7 Merge pull request #3412 from mauriciocolli/improve-drawer-title-size-handling
Improve size handling of the drawer header title
2020-04-10 22:04:53 +02:00
wb9688
bd9b2d54aa Merge pull request #3240 from wb9688/yt-music-search
YouTube Music search stuff
2020-04-10 19:04:49 +02:00
Mauricio Colli
506d1dc1f2 Improve size handling of the drawer header title
Some devices, specially with custom fonts that changed the font width,
weren't being correctly adjusted before.
2020-04-10 10:31:28 -03:00
wb9688
90f9819cbd Show error when video has age limit and setting is disabled 2020-04-10 15:29:48 +02:00
wb9688
9bbd03c14e Bump NewPipeExtractor version 2020-04-10 10:37:03 +02:00
wb9688
2852815e1a Use suggested layout for search filters 2020-04-10 10:35:54 +02:00
wb9688
41a100613f Add ability to translate YouTube Music search options 2020-04-10 10:35:54 +02:00
Stypox
63e489f134 Use ITEM_COUNT_UNKNOWN 2020-04-10 10:35:54 +02:00
Stypox
914d3c4a66 Use "mini" stream count alternatives for info items
Note: more_than_100_videos_mini and infinite_videos_mini are untranslatable
2020-04-10 10:35:54 +02:00
Stypox
2b47a1b06a Also use localizeStreamCount() in local items 2020-04-10 10:35:54 +02:00
Stypox
625419a7db Detect ITEM_COUNT_* in localizeStreamCount()
ITEM_COUNT_INFINITE and ITEM_COUNT_MORE_THAN_100.
Use localizeStreamCount in PlaylistFragment and PlaylistItemHolder
2020-04-10 10:35:54 +02:00
Stypox
2710d9de5b Add support for INFINITE_ and MORE_THAN_100_ITEMS in playlists 2020-04-10 10:35:53 +02:00
wb9688
e51314b104 Merge pull request #3300 from B0pol/content_not_supported
handle ContentNotSupportedException
2020-04-10 10:33:34 +02:00
bopol
4c128d837c handle ContentNotSupportedException for Channel Fragment (when an user has no video tab) 2020-04-10 09:12:29 +02:00
bopol
c392804f47 handle ContentNotSupportedException in ExtractorHelper.handleGeneralException() 2020-04-09 23:58:01 +02:00
bopol
cc7a25d9ce handle ContentNotSupportedException in BaseStateFragment
thus not supported soundcloud streams (e.g. hls streams) don't crash
anyore
2020-04-09 23:58:01 +02:00
wb9688
36b2bea25f Merge pull request #3395 from kapodamy/checkstyle-warnings
remove some warnings issued by checkstyle
2020-04-09 21:08:53 +02:00
Mauricio Colli
913796ff0f Use exception utils in network error detection throughout the app 2020-04-09 13:22:24 -03:00
Mauricio Colli
a1b9892c77 Move exception utils to a separate class and add tests for it 2020-04-09 13:22:18 -03:00
wb9688
03de4b29ea Suppress remaining Checkstyle errors 2020-04-09 17:24:43 +02:00
Hosted Weblate
35a706f745 Merge branch 'origin/dev' into Weblate. 2020-04-09 08:58:43 +02:00
Tobias Groza
65cd9751d8 Merge pull request #3288 from XiangRongLin/save-playback
Save and restore playback parameters into/from preferences
2020-04-08 21:38:53 +02:00
kapodamy
ff9a1ebb1b checkstyle
* drop unused methods
* split blobs
* make no final parameters
2020-04-08 12:08:01 -03:00
Hosted Weblate
b5df000e9d Merge branch 'origin/dev' into Weblate. 2020-04-08 14:09:42 +02:00
Claudio Maradonna
655522a3e5 Translated using Weblate (Italian)
Currently translated at 99.6% (558 of 560 strings)
2020-04-08 14:09:40 +02:00
wb9688
e4a4af34c5 Merge pull request #3276 from lnjX/fix/the-the-typo
ThemeHelper: Fix 'the the' typo
2020-04-07 09:25:00 +02:00
wb9688
b047e562ca Merge branch 'dev' into fix/the-the-typo 2020-04-07 09:17:10 +02:00
Tobias Groza
1600233c48 Merge pull request #3374 from mauriciocolli/fix-sort-button-visibility
Fix visibility of group sort button in the subscriptions fragment
2020-04-07 09:15:59 +02:00
Hosted Weblate
55c8bcd0e3 Merge branch 'origin/dev' into Weblate. 2020-04-07 05:23:56 +02:00
Software In Interlingua
2d0dadbd34 Translated using Weblate (Interlingua)
Currently translated at 35.5% (199 of 560 strings)
2020-04-07 05:23:54 +02:00
Tajnymag
49879bc9db Translated using Weblate (Czech)
Currently translated at 100.0% (560 of 560 strings)
2020-04-07 05:23:53 +02:00
Tobias Groza
2c453c7691 Merge pull request #3357 from opusforlife2/improve-bug-report-template
Made the bug report template less daunting
2020-04-06 21:51:07 +02:00
Tobias Groza
5166c22ce9 Fix webalte badge and link in readme
Update releases badge URL to point to releases instead of GitHub repo page
See WeblateOrg/weblate#3668
2020-04-06 21:01:40 +02:00
Mauricio Colli
225b9e1b15 Fix visibility of group sort button in the subscriptions fragment 2020-04-05 16:57:28 -03:00
ssantos
7a9d2c9a74 Translated using Weblate (Portuguese)
Currently translated at 100.0% (560 of 560 strings)
2020-04-05 19:41:29 +02:00
Xiang Rong Lin
3855e488cb Save and restore playback parameters into/from preferences
Playback parameters are speed, pitch and skip silence.
Remove parameters being passed on as intent to the player, since the parameters can be restored from the preferences instead.

# Conflicts:
#	app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
2020-04-05 17:46:49 +02:00
Hosted Weblate
ce75747887 Merge branch 'origin/dev' into Weblate. 2020-04-05 17:08:38 +02:00
Bruno Arruda
c462766cb8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (559 of 560 strings)
2020-04-05 17:08:38 +02:00
anonymous
bb905b70df Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (559 of 560 strings)
2020-04-05 17:08:35 +02:00
wb9688
5c8b9f6b4c Merge pull request #3370 from mauriciocolli/avoid-upload-date-update
Avoid unnecessary changes to the upload date of saved streams
2020-04-05 16:36:39 +02:00
Mauricio Colli
c726639484 Avoid unnecessary changes to the upload date of saved streams
The upload date was being updated regardless if the new one had more
precision or not, this caused items on the feed to jump around when the
user opened one of them.

This changes it to only update when the existent upload date is null or
the new one has a higher precision (i.e. is not an approximation).
2020-04-05 10:57:54 -03:00
Mahyuddin
100c7b8360 Translated using Weblate (Acehnese)
Currently translated at 7.3% (41 of 560 strings)
2020-04-05 11:34:48 +02:00
WaldiS
5502df89bb Translated using Weblate (Polish)
Currently translated at 100.0% (560 of 560 strings)
2020-04-05 11:34:47 +02:00
mitosagi
4491b66872 Make null sortable 2020-04-05 17:26:00 +09:00
Mahyuddin
9bc24728b4 Added translation using Weblate (Acehnese) 2020-04-05 09:47:16 +02:00
Hosted Weblate
a3a00ea052 Merge branch 'origin/dev' into Weblate. 2020-04-05 04:25:04 +02:00
Allan Nordhøy
1b1534add5 Translated using Weblate (Norwegian Bokmål)
Currently translated at 89.6% (502 of 560 strings)
2020-04-05 04:25:01 +02:00
Enol P
a54c8d4f55 Translated using Weblate (Asturian)
Currently translated at 51.9% (291 of 560 strings)
2020-04-05 04:25:01 +02:00
JoC
0cddd15203 Translated using Weblate (Spanish)
Currently translated at 100.0% (560 of 560 strings)
2020-04-05 04:25:00 +02:00
Tobias Groza
5653d443d9 Merge pull request #3344 from wb9688/checkfornewappversiontask-downloaderimpl
Use DownloaderImpl in CheckForNewAppVersionTask
2020-04-04 20:11:39 +02:00
wb9688
a5a497c4ea Clean up CheckForNewAppVersionTask 2020-04-04 19:34:13 +02:00
Hosted Weblate
d60feb466c Merge branch 'origin/dev' into Weblate. 2020-04-04 17:31:08 +02:00
Hemanta Sharma
a435167619 Translated using Weblate (Nepali)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 17:31:05 +02:00
Allan Nordhøy
99c823c763 Translated using Weblate (Norwegian Bokmål)
Currently translated at 89.1% (499 of 560 strings)
2020-04-04 17:31:04 +02:00
Jeff Huang
aebed13a40 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 17:31:03 +02:00
AioiLight
1347bdd545 Translated using Weblate (Japanese)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 17:31:03 +02:00
AioiLight
562754c0b9 Merge branch 'dev' into blocking-gesture-when-touch-from-navbar 2020-04-04 23:52:06 +09:00
Tobias Groza
ec52e144e8 Merge pull request #3356 from B0pol/contributing.md
update contributing.md
2020-04-04 15:02:57 +02:00
Hosted Weblate
3e383a9f57 Merge branch 'origin/dev' into Weblate. 2020-04-04 14:23:24 +02:00
Hemanta Sharma
3a2444db0d Translated using Weblate (Nepali)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 14:23:21 +02:00
zeritti
14d01ae358 Translated using Weblate (Czech)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 14:23:19 +02:00
Éfrit
1f4b147ddd Translated using Weblate (French)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 14:23:19 +02:00
opusforlife2
12405f4059 Made the bug report template less daunting
The biggest problem was that the reporter needed to delete a lot of text to be able to give a clean report. Now most of that is comments.
2020-04-04 11:22:00 +00:00
B0pol
8d6965713c Update .github/CONTRIBUTING.md
Co-Authored-By: Tobias Groza <TobiGr@users.noreply.github.com>
2020-04-04 12:37:51 +02:00
bopol
fe2858bc75 update contributing.md 2020-04-04 12:14:32 +02:00
Tobias Groza
99dd6ae6aa Merge pull request #3349 from B0pol/update_changelog_0.19.2
mention view count added in 0.19.2 in changelog
2020-04-04 11:18:19 +02:00
Hosted Weblate
cb7ed4079f Merge branch 'origin/dev' into Weblate. 2020-04-04 09:17:37 +02:00
anonymous
89fbc055f4 Translated using Weblate (Nepali)
Currently translated at 99.8% (559 of 560 strings)
2020-04-04 09:17:35 +02:00
Hemanta Sharma
df12b838ad Translated using Weblate (Nepali)
Currently translated at 99.8% (559 of 560 strings)
2020-04-04 09:17:35 +02:00
Allan Nordhøy
055fa19c9b Translated using Weblate (Nepali)
Currently translated at 99.8% (559 of 560 strings)
2020-04-04 09:17:34 +02:00
Allan Nordhøy
d1b661506e Translated using Weblate (Norwegian Bokmål)
Currently translated at 88.9% (498 of 560 strings)
2020-04-04 09:17:33 +02:00
anonymous
180ddcceaa Translated using Weblate (Estonian)
Currently translated at 73.5% (412 of 560 strings)
2020-04-04 09:17:33 +02:00
Allan Nordhøy
512fad207b Translated using Weblate (Punjabi)
Currently translated at 80.3% (450 of 560 strings)
2020-04-04 09:17:33 +02:00
Allan Nordhøy
82d514d857 Translated using Weblate (Kurdish)
Currently translated at 99.4% (557 of 560 strings)
2020-04-04 09:17:32 +02:00
Allan Nordhøy
037fac7cd4 Translated using Weblate (Tamil)
Currently translated at 36.4% (204 of 560 strings)
2020-04-04 09:17:32 +02:00
Allan Nordhøy
ebad85664d Translated using Weblate (Telugu)
Currently translated at 24.4% (137 of 560 strings)
2020-04-04 09:17:32 +02:00
Allan Nordhøy
4b626c39fe Translated using Weblate (Persian)
Currently translated at 81.6% (457 of 560 strings)
2020-04-04 09:17:32 +02:00
Oğuz Ersen
81c539f150 Translated using Weblate (Turkish)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 09:17:31 +02:00
Emin Tufan Çetin
0e74d82777 Translated using Weblate (Turkish)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 09:17:31 +02:00
Allan Nordhøy
5ea34a3c07 Translated using Weblate (Slovak)
Currently translated at 93.9% (526 of 560 strings)
2020-04-04 09:17:31 +02:00
Igor Nedoboy
4f8c5c3c0a Translated using Weblate (Russian)
Currently translated at 100.0% (560 of 560 strings)
2020-04-04 09:17:30 +02:00
opusforlife2
37e45e0984 Translated using Weblate (English)
Currently translated at 99.8% (559 of 560 strings)
2020-04-04 09:17:30 +02:00
bopol
5683ad6666 mention view count added in 0.19.2 in changelog 2020-04-03 23:34:16 +02:00
Stypox
92ca1e6e09 Check if already running before removing watched 2020-04-03 20:41:21 +02:00
Stypox
6571fdbaa2 Fix checkstyle errors 2020-04-03 20:13:56 +02:00
Stypox
9c3f138b8e Use binary search to remove watched items from playlists 2020-04-03 19:51:29 +02:00
developer
0ac2865b74 Optimised 'removeWatchedStreams'
Removed merge mistake
Reordered code
Refactored 'removeWatchedWorker' to 'removeWatchedDisposable'
2020-04-03 19:50:12 +02:00
Grady Clark
98fc88dec6 Simplified the removal of watched videos, into the function removeWatchedStreams
Replaced unnecessary nested class.
Fixed formating issues
2020-04-03 19:49:41 +02:00
Grady Clark
8cab790030 - Will now use ReactiveX instead of AsyncTask, when removing watched videos.
- Removed redundant file 'local_playlist_control'
- Fixed grammer issue
2020-04-03 19:49:41 +02:00
Grady Clark
954399b255 Moved the 'Remove Watched' button to the three dot menu button. 2020-04-03 19:49:01 +02:00
Grady Clark
66c95f901d Added the ability to remove all watched videos from local playlists
Changes:
 - local_playlist_control.xml
   * A copy of playlist_control.xml
   * To hold the 'Remove Watched Videos' buttton

 - local_playlist_header.xml
   * Changed the include layout	to now include local_playlist_control.xml

 - strings.xml
   * added string 'remove_watched' with value 'Remove Watched'

 - LocalPlaylistFragment.java
   * Added the functionality to remove watched videos,
      to the 'Remove Watched Videos' button in local_playlist_control.xml.
      In the background via AsyncTask.
      This will also change the playlist's thumbnail, if the thumbnail video is removed.

Tested on:
 - Pixel
2020-04-03 19:47:31 +02:00
Tobias Groza
8265922d68 Merge pull request #3286 from opusforlife2/Update-Issue-and-PR-templates
Update Feature Request and PR templates
2020-04-03 19:04:04 +02:00
Tobias Groza
2403184845 Merge pull request #3282 from wb9688/checkstyle
Check code style with Checkstyle
2020-04-03 17:10:07 +02:00
wb9688
15a53d299d Revert some more changes 2020-04-03 15:48:38 +02:00
Hosted Weblate
24a1a5d680 Merge branch 'origin/dev' into Weblate. 2020-04-03 14:43:36 +02:00
Vojtěch Šamla
c1cfff1502 Translated using Weblate (Czech)
Currently translated at 100.0% (560 of 560 strings)
2020-04-03 14:43:33 +02:00
Igor Nedoboy
1ed387dd54 Translated using Weblate (Russian)
Currently translated at 100.0% (560 of 560 strings)
2020-04-03 04:39:52 +02:00
Igor Nedoboy
9c795895ba Translated using Weblate (Russian)
Currently translated at 100.0% (560 of 560 strings)
2020-04-03 02:13:55 +02:00
Alexander--
3c193dca58 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-04-03 06:56:52 +06:59
Hosted Weblate
ce2a8fbfab Merge branch 'origin/dev' into Weblate. 2020-04-03 00:39:15 +02:00
Igor Nedoboy
4bbcf44351 Translated using Weblate (Russian)
Currently translated at 99.2% (556 of 560 strings)
2020-04-03 00:39:12 +02:00
AioiLight
d9c6f7acb6 Block the gesture when touch it from NavigationBar or StatusBar. 2020-04-03 05:11:36 +09:00
wb9688
41061d0289 Use DownloaderImpl in CheckForNewAppVersionTask 2020-04-02 20:13:05 +02:00
wb9688
fed9197d23 Disable TodoComment in checkstyle.xml 2020-04-02 19:43:38 +02:00
wb9688
282d3dbf8c Disable MissingSwitchDefault in checkstyle.xml 2020-04-02 16:48:58 +02:00
wb9688
b6c6dc7282 Use Checkstyle for org.schabi.newpipe.streams as well 2020-04-02 16:48:57 +02:00
wb9688
55480c8290 Disable VisibilityModifier in checkstyle.xml 2020-04-02 15:57:50 +02:00
wb9688
63bcc04eff Move things back to its original place 2020-04-02 15:57:50 +02:00
wb9688
fda5405e48 Improve code style to be more consistent 2020-04-02 15:57:50 +02:00
wb9688
819e52cab3 Check code style with Checkstyle 2020-04-02 15:57:50 +02:00
Alexander--
6a84f433ea Merge remote-tracking branch 'newpipe/dev' into rebase 2020-03-30 16:54:51 +06:59
opusforlife2
713bf58c44 Add reminder to link Issues/PRs 2020-03-28 11:49:46 +00:00
opusforlife2
a7af21958f Make feature request template easier to fill out 2020-03-28 10:54:20 +00:00
opusforlife2
8fed3df681 Update PULL_REQUEST_TEMPLATE.md
Minor modifications
2020-03-28 09:58:43 +00:00
Linus Jahn
edff3c35f2 ThemeHelper: Fix 'the the' typo 2020-03-26 01:50:32 +01:00
Alexander--
3a611adc11 Prevent NavigationMenuView from gobbling up focus 2020-03-15 12:04:49 +06:59
Alexander--
381b491845 Prevent foocus from escaping open navigation drawer
When contents of NewPipe navigation drawer change, NavigationMenuView
(which is actually a RecyclerView) removes and re-adds all its adapter
children, which leads to temporary loss of focus on currently focused drawer
child. This situation was not anticipated by developers of original
support library DrawerLayout: while NavigationMenuView itself is able
to keep focus from escaping via onRequestFocusInDescendants(),
the implementation of that method in DrawerLayout does not pass focus
to previously focused View. In fact it does not pass focus correctly at all
because the AOSP implementation of that method does not call addFocusables()
and simply focuses the first available VISIBLE View, without regard
to state of drawers.
2020-03-15 09:37:29 +06:59
Alexander--
6aca344bf7 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-03-15 09:08:01 +06:59
Alexander--
512046e300 Fix navigating to action bar buttons on API 28
Keyboard focus clusters prevent that from working, so
we simply remove all focus clusters.

While they are generally a good idea, focus clusters were created
with Chrome OS and it's keyboard-driven interface in mind - there is no
documented way to move focus between clusters using only IR remote.
As such, there are no negative consequences to disabling them on Android TV.
2020-03-14 14:47:02 +06:59
Alexander--
9cb3cf250c Intercept ActivityNotFoundException for ACTION_MANAGE_OVERLAY_PERMISSION 2020-03-12 05:32:20 +06:59
Alexander--
1cc5a67d82 Fix focus getting stuck by cycling within the same list item 2020-03-12 05:29:37 +06:59
Alexander--
fa6823599a Merge remote-tracking branch 'newpipe/dev' into rebase 2020-03-12 04:48:37 +06:59
Alexander--
6a3a72eb06 NewPipeRecyclerView should allow scrolling down by default 2020-02-26 06:40:46 +06:59
Alexander--
56544802e8 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-02-26 05:56:09 +06:59
Alexander--
5bd0c701c7 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-02-11 08:01:05 +06:59
Alexander--
50a2771d87 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-02-07 07:39:40 +06:59
Alexander--
e6df041613 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-02-06 02:44:08 +06:59
Alexander--
caa1de8aff Rename FireTvUtils to AndroidTvUtils and isFireTv() to isTV()
Because those methods are no longer exclusive to Amazon devices
2020-01-29 03:16:33 +06:59
Alexander--
fac13fb8cb Merge remote-tracking branch 'newpipe/dev' into rebase 2020-01-29 03:10:16 +06:59
Alexander--
55d2637214 Merge remote-tracking branch 'newpipe/dev' into rebase 2020-01-01 12:55:05 +06:59
Alexander--
8c9015b57b Remove commented code 2019-12-10 21:21:35 +06:59
Alexander--
a0cb96abff Merge remote-tracking branch 'newpipe/dev' into rebase 2019-12-10 21:20:26 +06:59
Alexander--
3f51114129 Improve usability of settings on TV devices
* Add focus overlay to SettingsActivity
* Make screen "Contents of Main Page" navigable from remote
2019-12-01 12:43:38 +06:59
Alexander--
29136d633a Intercept ActivityNotFoundException for ACTION_CAPTIONING_SETTINGS 2019-12-01 12:43:38 +06:59
Alexander--
20bff1389e Disable touchScreenBlocksFocus on AppBarLayout
For some inexplicable reason this attribute got
enabled by default on Android 9, which effectively
prevents details screen from working
2019-12-01 12:41:11 +06:59
Alexander--
106e538d08 Excpicitly disable touchscreen requirement 2019-12-01 12:41:11 +06:59
Alexander--
dc7ae3917e Leanback launcher support 2019-12-01 12:41:11 +06:59
Alexander--
c0fb96a911 Release seekbar on any confirmation key, not just DPAD_CENTER 2019-12-01 12:41:11 +06:59
Alexander--
a1e02f7704 Default to landscape orientation for Android TV 2019-12-01 12:41:11 +06:59
Alexander--
436c75ca6c Make comment pic explicitly non-focusable 2019-12-01 12:41:11 +06:59
Alexander--
7d75950624 Disable srolling down comment list while comments are loading
Prevents comment list from losing focus to some outside View
when user tries to scroll down after reaching "end"
2019-12-01 12:41:11 +06:59
Alexander--
5f051a9766 More fixes to comment focus handling 2019-12-01 12:41:11 +06:59
Alexander--
5716cf8cb2 Add hints for focus transition from description 2019-12-01 12:41:11 +06:59
Alexander--
7bb5cacb0d Special MovementMethod for video description
Video descriptions can be very long. Some of them are
basically walls of text with couple of lines at top or bottom.
They are also not scrolled within TextView itself, - instead
NewPipe expects user to scroll their containing ViewGroup.
This renders all builtin MovementMethod implementations useless.

This commit adds a new MovementMethod, that uses requestRectangleOnScreen
to intelligently re-position the TextView within it's scrollable container.
2019-12-01 12:41:11 +06:59
Alexander--
9801cf50e3 Save/restore focused item 2019-12-01 12:41:11 +06:59
Alexander--
b5558a8b78 Remove FixedGridLayoutManager 2019-12-01 12:41:11 +06:59
Alexander--
a7c31e6bcc RecyclerView scroll fixes
* Move all focus-related work arouns to NewPipeRecyclerView
* Try to pass focus within closer parents first
* Do small arrow scroll if there are not more focusables in move direction
2019-12-01 12:41:11 +06:59
Alexander
6e76610f30 Eliminate bunch of ExoPlayer warnings 2019-12-01 12:41:11 +06:59
Alexander
6da2b399e8 Allow comment links (if any) to gain focus 2019-12-01 12:41:11 +06:59
Alexander
79c962fc88 More robust focus search in SuperScrollLayoutManager
FocusFinder has glitches when some of target Views have different size.
Fortunately LayoutManager can redefine focus search strategy to override
the default behavior.
2019-12-01 12:41:11 +06:59
Alexander
28fb864ed0 Focus video view thumbnail after it is loaded 2019-12-01 12:41:11 +06:59
Alexander
d23227d427 Implement global focus highlight 2019-12-01 12:41:11 +06:59
Alexander
eb6d26b6a4 Focus drawer when it opens
It is still buggy because of NavigationView (why the hell
is NavigationMenuView marked as focusable?) but at least initial
opening works as intended
2019-12-01 12:41:10 +06:59
Alexander
a8a28294d3 Support for seeking videos in directional navigation mode 2019-12-01 12:41:10 +06:59
Alexander
7db1ba40eb Do not allow focus to escape from open DrawerLayout
Upstream DrawerLayout does override addFocusables, but
incorrectly checks for isDrawerOpen instread of isDrawerVisible
2019-12-01 12:41:10 +06:59
Alexander
d8bd8d87ec Make player screen controls into buttons
Buttons are more likely to have "correct" styling and are
focusable/clickable out of box
2019-12-01 12:41:10 +06:59
Alexander
d29e0aa1a7 Improve usability of MainVideoActivity with directional navigation
* Hide player controls when back is pressed (only on TV devices)
* Do not hide control after click unless in touch mode
* Show player controls on dpad usage
* Notably increase control hide timeout when not in touch mode
2019-12-01 12:41:10 +06:59
Alexander
644ad110c0 Make description focusable, so TV users can scroll it 2019-12-01 12:41:10 +06:59
Alexander
6791de5fc0 Do not discriminate against non-Amazon TV boxes 2019-12-01 12:41:10 +06:59
Alexander
1bb96ef405 When child of CoordinatorLayout wants focus, show it!
The same logic is present in RecyclerView, ScrollView etc.
Android really should default to this behavior for all Views
with isScrollContainer = true
2019-12-01 12:41:10 +06:59
Alexander
7dc4ccf144 MainPlayer: make title and subtitle non-focusable
Focus isn't needed for marquee, only selection
2019-12-01 12:41:10 +06:59
Alexander
2b39438eba Fix scrolling in main screen grid
GridLayoutManager is buggy - https://issuetracker.google.com/issues/37067220:
it randomly loses or incorrectly assigns focus when being scrolled via
direction-based navigation. This commit reimplements onFocusSearchFailed()
on top of scrollBy() to work around that problem.

Ordinary touch-based navigation should not be affected.
2019-12-01 12:41:10 +06:59
Alexander
8952e2b0cd Close DrawerLayout on back button press 2019-12-01 12:41:10 +06:59
Alexander
4806ac62ee Correctly move focus from toolbar search bar to dropdown
We don't hide MainFragment when search is show, so FocusFinder
sometimes gives focus to (obscured) main content
2019-12-01 12:41:10 +06:59
Alexander
eaa1179572 Fix scrolling comments list
AppBarLayout mostly gets it, but we still need to uphold our own part -
expanding it back after focus returns to it
2019-12-01 12:41:10 +06:59
1143 changed files with 22475 additions and 14188 deletions

View File

@@ -12,57 +12,53 @@ add a comment to it. You'll see exactly what is sent, the system is 100% transpa
## Issue reporting/feature requests ## Issue reporting/feature requests
* Search the [existing issues](https://github.com/TeamNewPipe/NewPipe/issues) first to make sure your issue/feature * Search the [existing issues](https://github.com/TeamNewPipe/NewPipe/issues) first to make sure your issue/feature
hasn't been reported/requested before hasn't been reported/requested before.
* Check whether your issue/feature is already fixed/implemented * Check whether your issue/feature is already fixed/implemented.
* Check if the issue still exists in the latest release/beta version * Check if the issue still exists in the latest release/beta version.
* If you are an Android/Java developer, you are always welcome to fix/implement an issue/a feature yourself. PRs welcome! * If you are an Android/Java developer, you are always welcome to fix an issue or implement a feature yourself. PRs welcome!
* We use English for development. Issues in other languages will be closed and ignored. * We use English for development. Issues in other languages will be closed and ignored.
* Please only add *one* issue at a time. Do not put multiple issues into one thread. * Please only add *one* issue at a time. Do not put multiple issues into one thread.
* When reporting a bug please give us a context, and a description how to reproduce it. * Follow the template! Issues or feature requests not matching the template might be closed.
* Issues that only contain a generated bug report, but no description might be closed.
## Bug Fixing ## Bug Fixing
* If you want to help NewPipe to become free of bugs (this is our utopic goal for NewPipe), you can send us an email to * If you want to help NewPipe to become free of bugs (this is our utopic goal for NewPipe), you can send us an email to
tnp@newpipe.schabi.org to let me know that you intend to help. We'll send you further instructions. You may, on request, <a href="mailto:tnp@newpipe.schabi.org">tnp@newpipe.schabi.org</a> to let us know that you intend to help. We'll send you further instructions. You may, on request,
register at our [Sentry](https://sentry.schabi.org) instance (see section "Crash reporting" for more information. register at our [Sentry](https://sentry.schabi.org) instance (see section "Crash reporting" for more information).
## Translation ## Translation
* NewPipe can be translated via [Weblate](https://hosted.weblate.org/projects/newpipe/strings/). You can log in there * NewPipe is translated via [Weblate](https://hosted.weblate.org/projects/newpipe/strings/). You can log in there
with your GitHub account. with your GitHub account.
* If the language you want to translate is not on Weblate, you can add it: see [How to add a new language](https://github.com/TeamNewPipe/NewPipe/wiki/How-to-add-a-new-language-to-NewPipe) in the wiki.
## Code contribution ## Code contribution
* Stick to NewPipe's style conventions (well, just look the other code and then do it the same way :)) * Stick to NewPipe's style conventions: follow [checkStyle](https://github.com/checkstyle/checkstyle). It will run each time you build the project.
* Do not bring non-free software (e.g., binary blobs) into the project. Also, make sure you do not introduce Google * Do not bring non-free software (e.g. binary blobs) into the project. Also, make sure you do not introduce Google
libraries. libraries.
* Stick to [F-Droid contribution guidelines](https://f-droid.org/wiki/page/Inclusion_Policy) * Stick to [F-Droid contribution guidelines](https://f-droid.org/wiki/page/Inclusion_Policy).
* Make changes on a separate branch, not on the master branch. This is commonly known as *feature branch workflow*. You * Make changes on a separate branch with a meaningful name, not on the master neither dev branch. This is commonly known as *feature branch workflow*. You
may then send your changes as a pull request on GitHub. Patches to the email address mentioned in this document might may then send your changes as a pull request (PR) on GitHub.
not be considered, GitHub is the primary platform. (This only affects you if you are a member of TeamNewPipe)
* When submitting changes, you confirm that your code is licensed under the terms of the * When submitting changes, you confirm that your code is licensed under the terms of the
[GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html). [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html).
* Please test (compile and run) your code before you submit changes! Ideally, provide test feedback in the PR * Please test (compile and run) your code before you submit changes! Ideally, provide test feedback in the PR
description. Untested code will **not** be merged! description. Untested code will **not** be merged!
* Try to figure out yourself why builds on our CI fail. * Try to figure out yourself why builds on our CI fail.
* Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job, * Make sure your PR is up-to-date with the rest of the code. Often, a simple click on "Update branch" will do the job,
but if not, you are asked to merge the master branch manually and resolve the problems on your own. That will make the but if not, you are asked to rebase the dev branch manually and resolve the problems on your own. You can find help [on the wiki](https://github.com/TeamNewPipe/NewPipe/wiki/How-to-merge-a-PR). That will make the
maintainers' jobs way easier. maintainers' jobs way easier.
* Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for * Please show intention to maintain your features and code after you contributed it. Unmaintained code is a hassle for
the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again the core developers, and just adds work. If you do not intend to maintain features you contributed, please think again
about submission, or clearly state that in the description of your PR. about submission, or clearly state that in the description of your PR.
* Respond yourselves if someone requests changes or otherwise raises issues about your PRs. * Respond yourselves if someone requests changes or otherwise raises issues about your PRs.
* Check if your contributions align with the [fdroid inclusion guidelines](https://f-droid.org/en/docs/Inclusion_Policy/).
* Check if your submission can be build with the current fdroid build server setup.
* Send PR that only cover one specific issue/solution/bug. Do not send PRs that are huge and consists of multiple * Send PR that only cover one specific issue/solution/bug. Do not send PRs that are huge and consists of multiple
independent solutions. independent solutions.
## Communication ## Communication
* WE DO NOW HAVE A MAILING LIST: [newpipe@list.schabi.org](https://list.schabi.org/cgi-bin/mailman/listinfo/newpipe).
* There is an IRC channel on Freenode which is regularly visited by the core team and other developers: * There is an IRC channel on Freenode which is regularly visited by the core team and other developers:
[#newpipe](irc:irc.freenode.net/newpipe). [Click here for Webchat](https://webchat.freenode.net/?channels=newpipe)! [#newpipe](irc:irc.freenode.net/newpipe). [Click here for Webchat](https://webchat.freenode.net/?channels=newpipe)!
* If you want to get in touch with the core team or one of our other contributors you can send an email to * If you want to get in touch with the core team or one of our other contributors you can send an email to
tnp(at)schabi.org. Please do not send issue reports, they will be ignored and remain unanswered! Use the GitHub issue <a href="mailto:tnp@newpipe.schabi.org">tnp@newpipe.schabi.org</a>. Please do not send issue reports, they will be ignored and remain unanswered! Use the GitHub issue
tracker described above! tracker described above!
* Feel free to post suggestions, changes, ideas etc. on GitHub, IRC or the mailing list! * Feel free to post suggestions, changes, ideas etc. on GitHub or IRC!

View File

@@ -7,38 +7,40 @@ assignees: ''
--- ---
<!-- <!--
Oh no, a bug! It happens. Thanks for reporting an issue with NewPipe. Oh no, a bug! It happens. Thanks for reporting an issue with NewPipe. If this is your first bug report, read the following information before proceeding:
Use this template to notify us if you found a bug. Please note, we only support the latest version of NewPipe. In order to check your app version, open the left drawer and click on "About". If you don't have the latest version, upgrade to it and reproduce the problem before opening the issue. The release page (https://github.com/TeamNewPipe/NewPipe/releases/latest) is where you can get it.
To make it easier for us to help you please enter detailed information below.
Please note, we only support the latest version of NewPipe and the master branch. Make sure you have that version installed. If you don't, upgrade & reproduce the problem before opening the issue. The release page (https://github.com/TeamNewPipe/NewPipe/releases/latest) is the go-to place to get this version. In order to check your app version, open the left drawer and click on "About".
P.S.: Our contribution guidelines might be a nice document to read before you fill out the report :) You can find it at https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md P.S.: Our contribution guidelines might be a nice document to read before you fill out the report :) You can find it at https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md
-->
### Version
<!-- Which version are you using? -->
-
To make it easier for us to help you please enter detailed information in the template we have provided below. If a section isn't relevant, just delete it, though it would be helpful to still provide as much detail as possible.
-->
<!-- The comments between these brackets won't show up in the submitted issue (as you can see in the preview). -->
### Version
<!-- Which version are you using? Hopefully the latest! We just told you that above! -->
-
### Steps to reproduce the bug ### Steps to reproduce the bug
<!-- If you can't reproduce it, please try to give as many details as possible on how you think you got to the bug. --> <!--
Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Press on '....' 2. Press on '....'
3. Swipe down to '....' 3. Swipe down to '....'
-->
<!-- If you can't cause the bug to show up again reliably (and hence don't have a proper set of steps to give us), please still try to give as many details as possible on how you think you encountered the bug. -->
### Expected behavior ### Expected behavior
Tell us what you expected to happen. <!-- Tell us what you expect to happen. -->
### Actual behaviour ### Actual behaviour
Tell us what happens instead. <!-- Tell us what happens instead. -->
### Screenshots/Screen records ### Screenshots/Screen recordings
If applicable, add screenshots or a screen recording to help explain your problem. GitHub should support uploading them directly in the issue field. If your file is too big, feel free to paste a link from an image/video hoster here instead. <!-- If applicable, add screenshots or a screen recording to help explain your problem. GitHub supports uploading them directly in the issue text box. If your file is too big for Github to accept, feel free to paste a link from an image/video hoster here instead. -->
### Logs ### Logs
If your bug includes a crash, please head over to the [incredible bugreport to markdown converter](https://teamnewpipe.github.io/CrashReportToMarkdown/). Copy the result. Paste it here: <!-- If your bug includes a crash (where you're shown the Error Report page with a bunch of info), copy it to the clipboard (there is a share button for this), head over to our bug report to markdown converter at https://teamnewpipe.github.io/CrashReportToMarkdown/ and paste it. Copy the converted text (it is MUCH easier to read this way) from there and paste it here: -->
<!-- That's right, here! --> <!-- That's right, here! -->

View File

@@ -7,22 +7,33 @@ assignees: ''
--- ---
<!-- Hey. Our contribution guidelines (https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) might be an appropriate <!-- Hey. Our contribution guidelines (https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md) might be an appropriate
document to read before you fill out the request :) --> document to read before you fill out the request :) -->
#### Is your feature request related to a problem? Please describe it
A clear and concise description of what the problem is.
Example: *I want to do X, but there is no way to do it.*
#### Describe the solution you'd like <!-- The comments between these brackets won't show up in the submitted issue (as you can see in the preview). -->
A clear and concise description of what you want to happen.
#### Describe the feature you want
<!-- A clear and concise description of what you want to happen. PLEASE MAKE SURE it is one feature ONLY. You should open separate issues for separate feature requests, because those issues will be used to track their status.
Example: *I think it would be nice if you add feature Y which makes X possible.* Example: *I think it would be nice if you add feature Y which makes X possible.*
#### (Optional) Describe alternatives you've considered Optionally, also describe alternatives you've considered.
A clear and concise description of any alternative solutions or features you've considered. Example: *Z is also a good alternative. Not as good as Y, but at least...* or *I considered Z, but that didn't turn out to be a good idea because...* -->
Example: *I considered Z, but that didn't turn out to be a good idea because...*
<!-- Write below this -->
#### Is your feature request related to a problem? Please describe it
<!-- A clear and concise description of what the problem is. Maybe the developers could brainstorm and come up with a better solution to your problem. If they exist, link to related Issues and/or PRs for developers to keep track easier.
Example: *I want to do X, but there is no way to do it.* -->
<!-- Write below this -->
#### Additional context #### Additional context
Add any other context or screenshots about the feature request here. <!-- Add any other context, like screenshots, about the feature request here.
Example: *Here's a photo of my cat!* Example: *Here's a photo of my cat!* -->
<!-- Write below this -->
#### How will you/everyone benefit from this feature? #### How will you/everyone benefit from this feature?
Convince us! How does it change your NewPipe experience and/or your life? <!-- Convince us! How does it change your NewPipe experience and/or your life?
The better this paragraph is, the more likely a developer will think about working on it. The better this paragraph is, the more likely a developer will think about working on it.
Example: *This feature will help us colonize the galaxy! -->
<!-- Write below this -->

View File

@@ -1,10 +1,12 @@
<!-- Hey there. Thank you so much for improving NewPipe. Please take a moment to fill out the following suggestion on how to structure this PR description. Having roughly the same layout helps everyone considerably :)--> <!-- Hey there. Thank you so much for improving NewPipe. Please take a moment to fill out the following suggestion on how to structure this PR description. Having roughly the same layout helps everyone considerably :)-->
#### What is it? #### What is it?
- [ ] Bug fix - [ ] Bug fix (user facing)
- [ ] Feature - [ ] Feature (user facing)
- [ ] Code base improvement (dev facing)
- [ ] Meta improvement to the project (dev facing)
#### Long description of the changes in your PR #### Description of the changes in your PR
<!-- While bullet points are the norm in this section, feel free to write a text instead if you can't fit it in a list --> <!-- While bullet points are the norm in this section, feel free to write a text instead if you can't fit it in a list -->
- record videos - record videos
- create clones - create clones

8
.gitignore vendored
View File

@@ -10,3 +10,11 @@
*~ *~
.weblate .weblate
*.class *.class
# vscode / eclipse files
*.classpath
*.project
*.settings
bin/
.vscode/
*.code-workspace

View File

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

View File

@@ -4,10 +4,10 @@
<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://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"> <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://github.com/TeamNewPipe/NewPipe/releases" 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://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://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="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="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://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
</p> </p>

View File

@@ -2,18 +2,19 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'checkstyle'
android { android {
compileSdkVersion 28 compileSdkVersion 29
buildToolsVersion '28.0.3' buildToolsVersion '29.0.3'
defaultConfig { defaultConfig {
applicationId "org.schabi.newpipe" applicationId "org.schabi.newpipe"
resValue "string", "app_name", "NewPipe" resValue "string", "app_name", "NewPipe"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 28 targetSdkVersion 29
versionCode 920 versionCode 940
versionName "0.19.2" versionName "0.19.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@@ -26,12 +27,6 @@ android {
} }
buildTypes { buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug { debug {
multiDexEnabled true multiDexEnabled true
debuggable true debuggable true
@@ -49,6 +44,16 @@ android {
archivesBaseName = 'NewPipe_' + normalizedWorkingBranch archivesBaseName = 'NewPipe_' + normalizedWorkingBranch
} }
} }
// Keep the release build type at the end of the list to override 'archivesBaseName' of
// debug build. This seems to be a Gradle bug, therefore
// TODO: update Gradle version
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
archivesBaseName = 'app'
}
} }
lintOptions { lintOptions {
@@ -61,6 +66,7 @@ android {
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
encoding 'utf-8'
} }
// Required and used only by groupie // Required and used only by groupie
@@ -74,81 +80,133 @@ android {
} }
ext { ext {
androidxLibVersion = '1.0.0' icepickVersion = '3.2.0'
exoPlayerLibVersion = '2.10.8' checkstyleVersion = '8.32'
roomDbLibVersion = '2.1.0' stethoVersion = '1.5.1'
leakCanaryLibVersion = '1.5.4' //1.6.1 leakCanaryVersion = '2.2'
okHttpLibVersion = '3.12.6' exoPlayerVersion = '2.11.4'
icepickLibVersion = '3.2.0' androidxLifecycleVersion = '2.2.0'
stethoLibVersion = '1.5.0' androidxRoomVersion = '2.2.5'
markwonVersion = '4.2.1' groupieVersion = '2.8.0'
markwonVersion = '4.3.1'
}
checkstyle {
configFile rootProject.file('checkstyle.xml')
ignoreFailures false
showViolations true
toolVersion = checkstyleVersion
}
task runCheckstyle(type: Checkstyle) {
source 'src'
include '**/*.java'
exclude '**/gen/**'
exclude '**/R.java'
exclude '**/BuildConfig.java'
exclude 'main/java/us/shandian/giga/**'
// empty classpath
classpath = files()
showViolations true
reports {
xml.enabled true
html.enabled true
}
}
configurations {
ktlint
}
task runKtlint(type: JavaExec) {
main = "com.pinterest.ktlint.Main"
classpath = configurations.ktlint
args "src/**/*.kt"
}
task formatKtlint(type: JavaExec) {
main = "com.pinterest.ktlint.Main"
classpath = configurations.ktlint
args "-F", "src/**/*.kt"
}
afterEvaluate {
preDebugBuild.dependsOn runCheckstyle, runKtlint
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
androidTestImplementation 'androidx.test.ext:junit:1.1.1' implementation "frankiesardo:icepick:${icepickVersion}"
androidTestImplementation "android.arch.persistence.room:testing:1.1.1" kapt "frankiesardo:icepick-processor:${icepickVersion}"
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
debugImplementation "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
ktlint "com.pinterest:ktlint:0.35.0"
debugImplementation "com.facebook.stetho:stetho:${stethoVersion}"
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}"
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
implementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}"
debugImplementation "androidx.multidex:multidex:2.0.1"
testImplementation 'junit:junit:4.13'
testImplementation 'org.mockito:mockito-core:3.3.3'
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0", {
exclude module: 'support-annotations' exclude module: 'support-annotations'
}) }
implementation 'com.github.TeamNewPipe:NewPipeExtractor:69e0624e3' implementation 'com.github.TeamNewPipe:NewPipeExtractor:98055a3c3c17f2543a63d375a44c1d1f557fa76e'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.23.0'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "androidx.legacy:legacy-support-v4:${androidxLibVersion}" implementation "org.jsoup:jsoup:1.13.1"
implementation "com.google.android.material:material:${androidxLibVersion}"
implementation "androidx.recyclerview:recyclerview:${androidxLibVersion}"
implementation "androidx.legacy:legacy-preference-v14:${androidxLibVersion}"
implementation "androidx.cardview:cardview:${androidxLibVersion}"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.xwray:groupie:2.7.0' implementation "com.squareup.okhttp3:okhttp:3.12.11"
implementation 'com.xwray:groupie-kotlin-android-extensions:2.7.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.0.0' implementation "com.google.android.exoplayer:exoplayer:${exoPlayerVersion}"
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.0.0' implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
// Originally in NewPipeExtractor implementation "com.google.android.material:material:1.1.0"
implementation 'com.grack:nanojson:1.1'
implementation 'org.jsoup:jsoup:1.9.2'
implementation 'ch.acra:acra:4.9.2' //4.11 implementation "androidx.appcompat:appcompat:1.1.0"
implementation "androidx.preference:preference:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
implementation 'de.hdodenhof:circleimageview:2.2.0' implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
implementation 'com.nononsenseapps:filepicker:4.2.1' implementation "androidx.lifecycle:lifecycle-extensions:${androidxLifecycleVersion}"
implementation "com.google.android.exoplayer:exoplayer:${exoPlayerLibVersion}" implementation "androidx.room:room-runtime:${androidxRoomVersion}"
implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerLibVersion}" implementation "androidx.room:room-rxjava2:${androidxRoomVersion}"
kapt "androidx.room:room-compiler:${androidxRoomVersion}"
debugImplementation "com.facebook.stetho:stetho:${stethoLibVersion}" implementation "com.xwray:groupie:${groupieVersion}"
debugImplementation "com.facebook.stetho:stetho-urlconnection:${stethoLibVersion}" implementation "com.xwray:groupie-kotlin-android-extensions:${groupieVersion}"
debugImplementation 'androidx.multidex:multidex:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.2' implementation "de.hdodenhof:circleimageview:3.1.0"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation "com.nostra13.universalimageloader:universal-image-loader:1.9.5"
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.3.Final'
implementation "androidx.room:room-runtime:${roomDbLibVersion}"
implementation "androidx.room:room-rxjava2:${roomDbLibVersion}"
kapt "androidx.room:room-compiler:${roomDbLibVersion}"
implementation "frankiesardo:icepick:${icepickLibVersion}"
kapt "frankiesardo:icepick-processor:${icepickLibVersion}"
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 "io.noties.markwon:core:${markwonVersion}" implementation "io.noties.markwon:core:${markwonVersion}"
implementation "io.noties.markwon:linkify:${markwonVersion}" implementation "io.noties.markwon:linkify:${markwonVersion}"
implementation "com.nononsenseapps:filepicker:4.2.1"
implementation "ch.acra:acra-core:5.5.0"
implementation "io.reactivex.rxjava2:rxjava:2.2.19"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
implementation "com.jakewharton.rxbinding2:rxbinding:2.2.0"
implementation "org.ocpsoft.prettytime:prettytime:4.0.5.Final"
} }
static String getGitWorkingBranch() { static String getGitWorkingBranch() {
@@ -165,4 +223,4 @@ static String getGitWorkingBranch() {
// git was not found // git was not found
return "" return ""
} }
} }

View File

@@ -30,8 +30,9 @@ class AppDatabaseTest {
private const val DEFAULT_SECOND_URL = "https://www.youtube.com/watch?v=ncQU6iBn5Fc" private const val DEFAULT_SECOND_URL = "https://www.youtube.com/watch?v=ncQU6iBn5Fc"
} }
@get:Rule val testHelper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), @get:Rule
AppDatabase::class.java.canonicalName, FrameworkSQLiteOpenHelperFactory()); val testHelper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java.canonicalName, FrameworkSQLiteOpenHelperFactory())
@Test @Test
fun migrateDatabaseFrom2to3() { fun migrateDatabaseFrom2to3() {
@@ -72,7 +73,7 @@ class AppDatabaseTest {
} }
testHelper.runMigrationsAndValidate(AppDatabase.DATABASE_NAME, Migrations.DB_VER_3, testHelper.runMigrationsAndValidate(AppDatabase.DATABASE_NAME, Migrations.DB_VER_3,
true, Migrations.MIGRATION_2_3); true, Migrations.MIGRATION_2_3)
val migratedDatabaseV3 = getMigratedDatabase() val migratedDatabaseV3 = getMigratedDatabase()
val listFromDB = migratedDatabaseV3.streamDAO().all.blockingFirst() val listFromDB = migratedDatabaseV3.streamDAO().all.blockingFirst()
@@ -115,4 +116,4 @@ class AppDatabaseTest {
testHelper.closeWhenFinished(database) testHelper.closeWhenFinished(database)
return database return database
} }
} }

View File

@@ -1,8 +1,9 @@
package org.schabi.newpipe.report; package org.schabi.newpipe.report;
import android.os.Parcel; import android.os.Parcel;
import androidx.test.filters.LargeTest;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -12,15 +13,16 @@ import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
* Instrumented tests for {@link ErrorInfo} * Instrumented tests for {@link ErrorInfo}.
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@LargeTest @LargeTest
public class ErrorInfoTest { public class ErrorInfoTest {
@Test @Test
public void errorInfo_testParcelable() { public void errorInfoTestParcelable() {
ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request", R.string.general_error); ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request",
R.string.general_error);
// Obtain a Parcel object and write the parcelable object to it: // Obtain a Parcel object and write the parcelable object to it:
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
info.writeToParcel(parcel, 0); info.writeToParcel(parcel, 0);
@@ -34,4 +36,4 @@ public class ErrorInfoTest {
parcel.recycle(); parcel.recycle();
} }
} }

View File

@@ -1,104 +0,0 @@
package org.schabi.newpipe;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.multidex.MultiDex;
import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.squareup.leakcanary.AndroidHeapDumper;
import com.squareup.leakcanary.DefaultLeakDirectoryProvider;
import com.squareup.leakcanary.HeapDumper;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.LeakDirectoryProvider;
import com.squareup.leakcanary.RefWatcher;
import org.schabi.newpipe.extractor.downloader.Downloader;
import java.io.File;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
public class DebugApp extends App {
private static final String TAG = DebugApp.class.toString();
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
initStetho();
}
@Override
protected Downloader getDownloader() {
return DownloaderImpl.init(new OkHttpClient.Builder()
.addNetworkInterceptor(new StethoInterceptor()));
}
private void initStetho() {
// Create an InitializerBuilder
Stetho.InitializerBuilder initializerBuilder =
Stetho.newInitializerBuilder(this);
// Enable Chrome DevTools
initializerBuilder.enableWebKitInspector(
Stetho.defaultInspectorModulesProvider(this)
);
// Enable command line interface
initializerBuilder.enableDumpapp(
Stetho.defaultDumperPluginsProvider(getApplicationContext())
);
// Use the InitializerBuilder to generate an Initializer
Stetho.Initializer initializer = initializerBuilder.build();
// Initialize Stetho with the Initializer
Stetho.initialize(initializer);
}
@Override
protected boolean isDisposedRxExceptionsReported() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.allow_disposed_exceptions_key), false);
}
@Override
protected RefWatcher installLeakCanary() {
return LeakCanary.refWatcher(this)
.heapDumper(new ToggleableHeapDumper(this))
// give each object 10 seconds to be gc'ed, before leak canary gets nosy on it
.watchDelay(10, TimeUnit.SECONDS)
.buildAndInstall();
}
public static class ToggleableHeapDumper implements HeapDumper {
private final HeapDumper dumper;
private final SharedPreferences preferences;
private final String dumpingAllowanceKey;
ToggleableHeapDumper(@NonNull final Context context) {
LeakDirectoryProvider leakDirectoryProvider = new DefaultLeakDirectoryProvider(context);
this.dumper = new AndroidHeapDumper(context, leakDirectoryProvider);
this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
this.dumpingAllowanceKey = context.getString(R.string.allow_heap_dumping_key);
}
private boolean isDumpingAllowed() {
return preferences.getBoolean(dumpingAllowanceKey, false);
}
@Override
public File dumpHeap() {
return isDumpingAllowed() ? dumper.dumpHeap() : HeapDumper.RETRY_LATER;
}
}
}

View File

@@ -0,0 +1,59 @@
package org.schabi.newpipe
import android.content.Context
import androidx.multidex.MultiDex
import androidx.preference.PreferenceManager
import com.facebook.stetho.Stetho
import com.facebook.stetho.okhttp3.StethoInterceptor
import leakcanary.AppWatcher
import leakcanary.LeakCanary
import okhttp3.OkHttpClient
import org.schabi.newpipe.extractor.downloader.Downloader
class DebugApp : App() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
override fun onCreate() {
super.onCreate()
initStetho()
// Give each object 10 seconds to be GC'ed, before LeakCanary gets nosy on it
AppWatcher.config = AppWatcher.config.copy(watchDurationMillis = 10000)
LeakCanary.config = LeakCanary.config.copy(dumpHeap = PreferenceManager
.getDefaultSharedPreferences(this).getBoolean(getString(
R.string.allow_heap_dumping_key), false))
}
override fun getDownloader(): Downloader {
val downloader = DownloaderImpl.init(OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor()))
setCookiesToDownloader(downloader)
return downloader
}
private fun initStetho() {
// Create an InitializerBuilder
val initializerBuilder = Stetho.newInitializerBuilder(this)
// Enable Chrome DevTools
initializerBuilder.enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this))
// Enable command line interface
initializerBuilder.enableDumpapp(
Stetho.defaultDumperPluginsProvider(applicationContext))
// Use the InitializerBuilder to generate an Initializer
val initializer = initializerBuilder.build()
// Initialize Stetho with the Initializer
Stetho.initialize(initializer)
}
override fun isDisposedRxExceptionsReported(): Boolean {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(getString(R.string.allow_disposed_exceptions_key), false)
}
}

View File

@@ -11,7 +11,10 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<application <application
android:banner="@mipmap/newpipe_tv_banner"
android:name=".App" android:name=".App"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
@@ -26,6 +29,7 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>

View File

@@ -38,12 +38,15 @@ import java.util.ArrayList;
* This is a copy from {@link androidx.fragment.app.FragmentStatePagerAdapter}. * This is a copy from {@link androidx.fragment.app.FragmentStatePagerAdapter}.
* <p> * <p>
* It includes a workaround to fix the menu visibility when the adapter is restored. * It includes a workaround to fix the menu visibility when the adapter is restored.
* </p>
* <p> * <p>
* When restoring the state of this adapter, all the fragments' menu visibility were set to false, * When restoring the state of this adapter, all the fragments' menu visibility were set to false,
* effectively disabling the menu from the user until he switched pages or another event that triggered the * effectively disabling the menu from the user until he switched pages or another event
* menu to be visible again happened. * that triggered the menu to be visible again happened.
* </p>
* <p> * <p>
* <br><b>Check out the changes in:</b> * <b>Check out the changes in:</b>
* </p>
* <ul> * <ul>
* <li>{@link #saveState()}</li> * <li>{@link #saveState()}</li>
* <li>{@link #restoreState(Parcelable, ClassLoader)}</li> * <li>{@link #restoreState(Parcelable, ClassLoader)}</li>
@@ -88,8 +91,8 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
private Fragment mCurrentPrimaryItem = null; private Fragment mCurrentPrimaryItem = null;
/** /**
* Constructor for {@link FragmentStatePagerAdapterMenuWorkaround} that sets the fragment manager for the * Constructor for {@link FragmentStatePagerAdapterMenuWorkaround}
* adapter. This is the equivalent of calling * that sets the fragment manager for the adapter. This is the equivalent of calling
* {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} and passing in * {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} and passing in
* {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}. * {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}.
* *
@@ -101,7 +104,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
* {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT}
*/ */
@Deprecated @Deprecated
public FragmentStatePagerAdapterMenuWorkaround(@NonNull FragmentManager fm) { public FragmentStatePagerAdapterMenuWorkaround(@NonNull final FragmentManager fm) {
this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT); this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
} }
@@ -117,20 +120,21 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
* @param fm fragment manager that will interact with this adapter * @param fm fragment manager that will interact with this adapter
* @param behavior determines if only current fragments are in a resumed state * @param behavior determines if only current fragments are in a resumed state
*/ */
public FragmentStatePagerAdapterMenuWorkaround(@NonNull FragmentManager fm, public FragmentStatePagerAdapterMenuWorkaround(@NonNull final FragmentManager fm,
@Behavior int behavior) { @Behavior final int behavior) {
mFragmentManager = fm; mFragmentManager = fm;
mBehavior = behavior; mBehavior = behavior;
} }
/** /**
* Return the Fragment associated with a specified position. * @param position the position of the item you want
* @return the {@link Fragment} associated with a specified position
*/ */
@NonNull @NonNull
public abstract Fragment getItem(int position); public abstract Fragment getItem(int position);
@Override @Override
public void startUpdate(@NonNull ViewGroup container) { public void startUpdate(@NonNull final ViewGroup container) {
if (container.getId() == View.NO_ID) { if (container.getId() == View.NO_ID) {
throw new IllegalStateException("ViewPager with adapter " + this throw new IllegalStateException("ViewPager with adapter " + this
+ " requires a view id"); + " requires a view id");
@@ -140,7 +144,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@NonNull @NonNull
@Override @Override
public Object instantiateItem(@NonNull ViewGroup container, int position) { public Object instantiateItem(@NonNull final ViewGroup container, final int position) {
// If we already have this item instantiated, there is nothing // If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager // to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already // from its saved state, where the fragment manager has already
@@ -157,7 +161,9 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
} }
Fragment fragment = getItem(position); Fragment fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); if (DEBUG) {
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
}
if (mSavedState.size() > position) { if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position); Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) { if (fss != null) {
@@ -183,14 +189,17 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
} }
@Override @Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { public void destroyItem(@NonNull final ViewGroup container, final int position,
@NonNull final Object object) {
Fragment fragment = (Fragment) object; Fragment fragment = (Fragment) object;
if (mCurTransaction == null) { if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction(); mCurTransaction = mFragmentManager.beginTransaction();
} }
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object if (DEBUG) {
+ " v=" + ((Fragment)object).getView()); Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment) object).getView());
}
while (mSavedState.size() <= position) { while (mSavedState.size() <= position) {
mSavedState.add(null); mSavedState.add(null);
} }
@@ -206,8 +215,9 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
@Override @Override
@SuppressWarnings({"ReferenceEquality", "deprecation"}) @SuppressWarnings({"ReferenceEquality", "deprecation"})
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
Fragment fragment = (Fragment)object; @NonNull final Object object) {
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) { if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) { if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false); mCurrentPrimaryItem.setMenuVisibility(false);
@@ -235,7 +245,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
} }
@Override @Override
public void finishUpdate(@NonNull ViewGroup container) { public void finishUpdate(@NonNull final ViewGroup container) {
if (mCurTransaction != null) { if (mCurTransaction != null) {
mCurTransaction.commitNowAllowingStateLoss(); mCurTransaction.commitNowAllowingStateLoss();
mCurTransaction = null; mCurTransaction = null;
@@ -243,12 +253,12 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
} }
@Override @Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { public boolean isViewFromObject(@NonNull final View view, @NonNull final Object object) {
return ((Fragment)object).getView() == view; return ((Fragment) object).getView() == view;
} }
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
private final String SELECTED_FRAGMENT = "selected_fragment"; private final String selectedFragment = "selected_fragment";
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@Override @Override
@@ -261,7 +271,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
mSavedState.toArray(fss); mSavedState.toArray(fss);
state.putParcelableArray("states", fss); state.putParcelableArray("states", fss);
} }
for (int i=0; i<mFragments.size(); i++) { for (int i = 0; i < mFragments.size(); i++) {
Fragment f = mFragments.get(i); Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) { if (f != null && f.isAdded()) {
if (state == null) { if (state == null) {
@@ -273,7 +283,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Check if it's the same fragment instance // Check if it's the same fragment instance
if (f == mCurrentPrimaryItem) { if (f == mCurrentPrimaryItem) {
state.putString(SELECTED_FRAGMENT, key); state.putString(selectedFragment, key);
} }
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
} }
@@ -282,16 +292,16 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
} }
@Override @Override
public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) { public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) {
if (state != null) { if (state != null) {
Bundle bundle = (Bundle)state; Bundle bundle = (Bundle) state;
bundle.setClassLoader(loader); bundle.setClassLoader(loader);
Parcelable[] fss = bundle.getParcelableArray("states"); Parcelable[] fss = bundle.getParcelableArray("states");
mSavedState.clear(); mSavedState.clear();
mFragments.clear(); mFragments.clear();
if (fss != null) { if (fss != null) {
for (int i=0; i<fss.length; i++) { for (int i = 0; i < fss.length; i++) {
mSavedState.add((Fragment.SavedState)fss[i]); mSavedState.add((Fragment.SavedState) fss[i]);
} }
} }
Iterable<String> keys = bundle.keySet(); Iterable<String> keys = bundle.keySet();
@@ -304,7 +314,8 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
mFragments.add(null); mFragments.add(null);
} }
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
final boolean wasSelected = bundle.getString(SELECTED_FRAGMENT, "").equals(key); final boolean wasSelected = bundle.getString(selectedFragment, "")
.equals(key);
f.setMenuVisibility(wasSelected); f.setMenuVisibility(wasSelected);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
mFragments.set(index, f); mFragments.set(index, f);

View File

@@ -1,24 +1,60 @@
package com.google.android.material.appbar; package com.google.android.material.appbar;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.OverScroller; import android.widget.OverScroller;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import java.lang.reflect.Field; import java.lang.reflect.Field;
// check this https://stackoverflow.com/questions/56849221/recyclerview-fling-causes-laggy-while-appbarlayout-is-scrolling/57997489#57997489 // See https://stackoverflow.com/questions/56849221#57997489
public final class FlingBehavior extends AppBarLayout.Behavior { public final class FlingBehavior extends AppBarLayout.Behavior {
private final Rect focusScrollRect = new Rect();
public FlingBehavior(Context context, AttributeSet attrs) { public FlingBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
@Override @Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) { public boolean onRequestChildRectangleOnScreen(
@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final AppBarLayout child,
@NonNull final Rect rectangle, final boolean immediate) {
focusScrollRect.set(rectangle);
coordinatorLayout.offsetDescendantRectToMyCoords(child, focusScrollRect);
int height = coordinatorLayout.getHeight();
if (focusScrollRect.top <= 0 && focusScrollRect.bottom >= height) {
// the child is too big to fit inside ourselves completely, ignore request
return false;
}
int dy;
if (focusScrollRect.bottom > height) {
dy = focusScrollRect.top;
} else if (focusScrollRect.top < 0) {
// scrolling up
dy = -(height - focusScrollRect.bottom);
} else {
// nothing to do
return false;
}
int consumed = scroll(coordinatorLayout, child, dy, getMaxDragOffset(child), 0);
return consumed == dy;
}
public boolean onInterceptTouchEvent(final CoordinatorLayout parent, final AppBarLayout child,
final MotionEvent ev) {
switch (ev.getActionMasked()) { switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
// remove reference to old nested scrolling child // remove reference to old nested scrolling child
@@ -35,7 +71,8 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
@Nullable @Nullable
private OverScroller getScrollerField() { private OverScroller getScrollerField() {
try { try {
Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass().getSuperclass(); Class<?> headerBehaviorType = this.getClass()
.getSuperclass().getSuperclass().getSuperclass();
if (headerBehaviorType != null) { if (headerBehaviorType != null) {
Field field = headerBehaviorType.getDeclaredField("scroller"); Field field = headerBehaviorType.getDeclaredField("scroller");
field.setAccessible(true); field.setAccessible(true);
@@ -62,12 +99,14 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
return null; return null;
} }
private void resetNestedScrollingChild(){ private void resetNestedScrollingChild() {
Field field = getLastNestedScrollingChildRefField(); Field field = getLastNestedScrollingChildRefField();
if(field != null){ if (field != null) {
try { try {
Object value = field.get(this); Object value = field.get(this);
if(value != null) field.set(this, null); if (value != null) {
field.set(this, null);
}
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
// ? // ?
} }
@@ -76,7 +115,8 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
private void stopAppBarLayoutFling() { private void stopAppBarLayoutFling() {
OverScroller scroller = getScrollerField(); OverScroller scroller = getScrollerField();
if (scroller != null) scroller.forceFinished(true); if (scroller != null) {
scroller.forceFinished(true);
}
} }
}
}

View File

@@ -23,17 +23,25 @@ package org.schabi.newpipe;
/** /**
* Singleton: * Singleton:
* Used to send data between certain Activity/Services within the same process. * Used to send data between certain Activity/Services within the same process.
* This can be considered as an ugly hack inside the Android universe. **/ * This can be considered as an ugly hack inside the Android universe.
**/
public class ActivityCommunicator { public class ActivityCommunicator {
private static ActivityCommunicator activityCommunicator; private static ActivityCommunicator activityCommunicator;
private volatile Class returnActivity;
public static ActivityCommunicator getCommunicator() { public static ActivityCommunicator getCommunicator() {
if(activityCommunicator == null) { if (activityCommunicator == null) {
activityCommunicator = new ActivityCommunicator(); activityCommunicator = new ActivityCommunicator();
} }
return activityCommunicator; return activityCommunicator;
} }
public volatile Class returnActivity; public Class getReturnActivity() {
return returnActivity;
}
public void setReturnActivity(final Class returnActivity) {
this.returnActivity = returnActivity;
}
} }

View File

@@ -5,21 +5,20 @@ import android.app.Application;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import androidx.annotation.Nullable; import androidx.preference.PreferenceManager;
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache; import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import org.acra.ACRA; import org.acra.ACRA;
import org.acra.config.ACRAConfiguration;
import org.acra.config.ACRAConfigurationException; import org.acra.config.ACRAConfigurationException;
import org.acra.config.ConfigurationBuilder; import org.acra.config.CoreConfiguration;
import org.acra.config.CoreConfigurationBuilder;
import org.acra.sender.ReportSenderFactory; import org.acra.sender.ReportSenderFactory;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Downloader;
@@ -27,7 +26,7 @@ import org.schabi.newpipe.report.AcraReportSenderFactory;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.settings.SettingsActivity; import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver; import org.schabi.newpipe.util.StateSaver;
@@ -66,15 +65,17 @@ import io.reactivex.plugins.RxJavaPlugins;
public class App extends Application { public class App extends Application {
protected static final String TAG = App.class.toString(); protected static final String TAG = App.class.toString();
private RefWatcher refWatcher;
private static App app;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static final Class<? extends ReportSenderFactory>[] private static final Class<? extends ReportSenderFactory>[]
reportSenderFactoryClasses = new Class[]{AcraReportSenderFactory.class}; REPORT_SENDER_FACTORY_CLASSES = new Class[]{AcraReportSenderFactory.class};
private static App app;
public static App getApp() {
return app;
}
@Override @Override
protected void attachBaseContext(Context base) { protected void attachBaseContext(final Context base) {
super.attachBaseContext(base); super.attachBaseContext(base);
initACRA(); initACRA();
@@ -84,13 +85,6 @@ public class App extends Application {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
refWatcher = installLeakCanary();
app = this; app = this;
// Initialize settings first because others inits can use its values // Initialize settings first because others inits can use its values
@@ -116,31 +110,47 @@ public class App extends Application {
} }
protected Downloader getDownloader() { protected Downloader getDownloader() {
return DownloaderImpl.init(null); DownloaderImpl downloader = DownloaderImpl.init(null);
setCookiesToDownloader(downloader);
return downloader;
}
protected void setCookiesToDownloader(final DownloaderImpl downloader) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
getApplicationContext());
final String key = getApplicationContext().getString(R.string.recaptcha_cookies_key);
downloader.setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, prefs.getString(key, ""));
downloader.updateYoutubeRestrictedModeCookies(getApplicationContext());
} }
private void configureRxJavaErrorHandler() { private void configureRxJavaErrorHandler() {
// https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling // https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() { RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override @Override
public void accept(@NonNull Throwable throwable) { public void accept(@NonNull final Throwable throwable) {
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " + Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : "
"throwable = [" + throwable.getClass().getName() + "]"); + "throwable = [" + throwable.getClass().getName() + "]");
final Throwable actualThrowable;
if (throwable instanceof UndeliverableException) { if (throwable instanceof UndeliverableException) {
// As UndeliverableException is a wrapper, get the cause of it to get the "real" exception // As UndeliverableException is a wrapper,
throwable = throwable.getCause(); // get the cause of it to get the "real" exception
actualThrowable = throwable.getCause();
} else {
actualThrowable = throwable;
} }
final List<Throwable> errors; final List<Throwable> errors;
if (throwable instanceof CompositeException) { if (actualThrowable instanceof CompositeException) {
errors = ((CompositeException) throwable).getExceptions(); errors = ((CompositeException) actualThrowable).getExceptions();
} else { } else {
errors = Collections.singletonList(throwable); errors = Collections.singletonList(actualThrowable);
} }
for (final Throwable error : errors) { for (final Throwable error : errors) {
if (isThrowableIgnored(error)) return; if (isThrowableIgnored(error)) {
return;
}
if (isThrowableCritical(error)) { if (isThrowableCritical(error)) {
reportException(error); reportException(error);
return; return;
@@ -150,22 +160,24 @@ public class App extends Application {
// Out-of-lifecycle exceptions should only be reported if a debug user wishes so, // Out-of-lifecycle exceptions should only be reported if a debug user wishes so,
// When exception is not reported, log it // When exception is not reported, log it
if (isDisposedRxExceptionsReported()) { if (isDisposedRxExceptionsReported()) {
reportException(throwable); reportException(actualThrowable);
} else { } else {
Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", throwable); Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", actualThrowable);
} }
} }
private boolean isThrowableIgnored(@NonNull final Throwable throwable) { private boolean isThrowableIgnored(@NonNull final Throwable throwable) {
// Don't crash the application over a simple network problem // Don't crash the application over a simple network problem
return ExtractorHelper.hasAssignableCauseThrowable(throwable, return ExceptionUtils.hasAssignableCause(throwable,
IOException.class, SocketException.class, // network api cancellation // network api cancellation
InterruptedException.class, InterruptedIOException.class); // blocking code disposed IOException.class, SocketException.class,
// blocking code disposed
InterruptedException.class, InterruptedIOException.class);
} }
private boolean isThrowableCritical(@NonNull final Throwable throwable) { private boolean isThrowableCritical(@NonNull final Throwable throwable) {
// Though these exceptions cannot be ignored // Though these exceptions cannot be ignored
return ExtractorHelper.hasAssignableCauseThrowable(throwable, return ExceptionUtils.hasAssignableCause(throwable,
NullPointerException.class, IllegalArgumentException.class, // bug in app NullPointerException.class, IllegalArgumentException.class, // bug in app
OnErrorNotImplementedException.class, MissingBackpressureException.class, OnErrorNotImplementedException.class, MissingBackpressureException.class,
IllegalStateException.class); // bug in operator IllegalStateException.class); // bug in operator
@@ -190,8 +202,8 @@ public class App extends Application {
private void initACRA() { private void initACRA() {
try { try {
final ACRAConfiguration acraConfig = new ConfigurationBuilder(this) final CoreConfiguration acraConfig = new CoreConfigurationBuilder(this)
.setReportSenderFactoryClasses(reportSenderFactoryClasses) .setReportSenderFactoryClasses(REPORT_SENDER_FACTORY_CLASSES)
.setBuildConfigClass(BuildConfig.class) .setBuildConfigClass(BuildConfig.class)
.build(); .build();
ACRA.init(this, acraConfig); ACRA.init(this, acraConfig);
@@ -202,7 +214,7 @@ public class App extends Application {
null, null,
null, null,
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
"Could not initialize ACRA crash report", R.string.app_ui_crash)); "Could not initialize ACRA crash report", R.string.app_ui_crash));
} }
} }
@@ -230,11 +242,11 @@ public class App extends Application {
/** /**
* Set up notification channel for app update. * Set up notification channel for app update.
*
* @param importance * @param importance
*/ */
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
private void setUpUpdateNotificationChannel(int importance) { private void setUpUpdateNotificationChannel(final int importance) {
final String appUpdateId final String appUpdateId
= getString(R.string.app_update_notification_channel_id); = getString(R.string.app_update_notification_channel_id);
final CharSequence appUpdateName final CharSequence appUpdateName
@@ -251,21 +263,7 @@ public class App extends Application {
appUpdateNotificationManager.createNotificationChannel(appUpdateChannel); appUpdateNotificationManager.createNotificationChannel(appUpdateChannel);
} }
@Nullable
public static RefWatcher getRefWatcher(Context context) {
final App application = (App) context.getApplicationContext();
return application.refWatcher;
}
protected RefWatcher installLeakCanary() {
return RefWatcher.DISABLED;
}
protected boolean isDisposedRxExceptionsReported() { protected boolean isDisposedRxExceptionsReported() {
return false; return false;
} }
public static App getApp() {
return app;
}
} }

View File

@@ -2,32 +2,31 @@ package org.schabi.newpipe;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.leakcanary.RefWatcher;
import icepick.Icepick; import icepick.Icepick;
import icepick.State; import icepick.State;
import leakcanary.AppWatcher;
public abstract class BaseFragment extends Fragment { public abstract class BaseFragment extends Fragment {
public static final ImageLoader IMAGE_LOADER = ImageLoader.getInstance();
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()); protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
protected final boolean DEBUG = MainActivity.DEBUG; protected final boolean DEBUG = MainActivity.DEBUG;
protected AppCompatActivity activity; protected AppCompatActivity activity;
public static final ImageLoader imageLoader = ImageLoader.getInstance(); //These values are used for controlling fragments when they are part of the frontpage
//These values are used for controlling framgents when they are part of the frontpage
@State @State
protected boolean useAsFrontPage = false; protected boolean useAsFrontPage = false;
protected boolean mIsVisibleToUser = false; private boolean mIsVisibleToUser = false;
public void useAsFrontPage(boolean value) { public void useAsFrontPage(final boolean value) {
useAsFrontPage = value; useAsFrontPage = value;
} }
@@ -36,7 +35,7 @@ public abstract class BaseFragment extends Fragment {
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
public void onAttach(Context context) { public void onAttach(final Context context) {
super.onAttach(context); super.onAttach(context);
activity = (AppCompatActivity) context; activity = (AppCompatActivity) context;
} }
@@ -48,43 +47,49 @@ public abstract class BaseFragment extends Fragment {
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); if (DEBUG) {
Log.d(TAG, "onCreate() called with: "
+ "savedInstanceState = [" + savedInstanceState + "]");
}
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState);
if (savedInstanceState != null) onRestoreInstanceState(savedInstanceState); if (savedInstanceState != null) {
onRestoreInstanceState(savedInstanceState);
}
} }
@Override @Override
public void onViewCreated(View rootView, Bundle savedInstanceState) { public void onViewCreated(final View rootView, final Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState); super.onViewCreated(rootView, savedInstanceState);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onViewCreated() called with: rootView = [" + rootView + "], savedInstanceState = [" + savedInstanceState + "]"); Log.d(TAG, "onViewCreated() called with: "
+ "rootView = [" + rootView + "], "
+ "savedInstanceState = [" + savedInstanceState + "]");
} }
initViews(rootView, savedInstanceState); initViews(rootView, savedInstanceState);
initListeners(); initListeners();
} }
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState); Icepick.saveInstanceState(this, outState);
} }
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
RefWatcher refWatcher = App.getRefWatcher(getActivity()); AppWatcher.INSTANCE.getObjectWatcher().watch(this);
if (refWatcher != null) refWatcher.watch(this);
} }
@Override @Override
public void setUserVisibleHint(boolean isVisibleToUser) { public void setUserVisibleHint(final boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser); super.setUserVisibleHint(isVisibleToUser);
mIsVisibleToUser = isVisibleToUser; mIsVisibleToUser = isVisibleToUser;
} }
@@ -93,7 +98,7 @@ public abstract class BaseFragment extends Fragment {
// Init // Init
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
protected void initViews(View rootView, Bundle savedInstanceState) { protected void initViews(final View rootView, final Bundle savedInstanceState) {
} }
protected void initListeners() { protected void initListeners() {
@@ -103,10 +108,12 @@ public abstract class BaseFragment extends Fragment {
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
public void setTitle(String title) { public void setTitle(final String title) {
if (DEBUG) Log.d(TAG, "setTitle() called with: title = [" + title + "]"); if (DEBUG) {
if((!useAsFrontPage || mIsVisibleToUser) Log.d(TAG, "setTitle() called with: title = [" + title + "]");
&& (activity != null && activity.getSupportActionBar() != null)) { }
if ((!useAsFrontPage || mIsVisibleToUser)
&& (activity != null && activity.getSupportActionBar() != null)) {
activity.getSupportActionBar().setDisplayShowTitleEnabled(true); activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
activity.getSupportActionBar().setTitle(title); activity.getSupportActionBar().setTitle(title);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
package org.schabi.newpipe; package org.schabi.newpipe;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@@ -27,9 +26,20 @@ import android.os.Bundle;
public class ExitActivity extends Activity { public class ExitActivity extends Activity {
public static void exitAndRemoveFromRecentApps(final Activity activity) {
Intent intent = new Intent(activity, ExitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.startActivity(intent);
}
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 21) { if (Build.VERSION.SDK_INT >= 21) {
@@ -40,15 +50,4 @@ public class ExitActivity extends Activity {
System.exit(0); System.exit(0);
} }
public static void exitAndRemoveFromRecentApps(Activity activity) {
Intent intent = new Intent(activity, ExitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.startActivity(intent);
}
} }

View File

@@ -18,7 +18,7 @@ public class ImageDownloader extends BaseImageDownloader {
private final SharedPreferences preferences; private final SharedPreferences preferences;
private final String downloadThumbnailKey; private final String downloadThumbnailKey;
public ImageDownloader(Context context) { public ImageDownloader(final Context context) {
super(context); super(context);
this.resources = context.getResources(); this.resources = context.getResources();
this.preferences = PreferenceManager.getDefaultSharedPreferences(context); this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
@@ -31,7 +31,7 @@ public class ImageDownloader extends BaseImageDownloader {
@SuppressLint("ResourceType") @SuppressLint("ResourceType")
@Override @Override
public InputStream getStream(String imageUri, Object extra) throws IOException { public InputStream getStream(final String imageUri, final Object extra) throws IOException {
if (isDownloadingThumbnail()) { if (isDownloadingThumbnail()) {
return super.getStream(imageUri, extra); return super.getStream(imageUri, extra);
} else { } else {
@@ -39,7 +39,8 @@ public class ImageDownloader extends BaseImageDownloader {
} }
} }
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException { protected InputStream getStreamFromNetwork(final String imageUri, final Object extra)
throws IOException {
final DownloaderImpl downloader = (DownloaderImpl) NewPipe.getDownloader(); final DownloaderImpl downloader = (DownloaderImpl) NewPipe.getDownloader();
return downloader.stream(imageUri); return downloader.stream(imageUri);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -13,14 +13,13 @@ import static org.schabi.newpipe.database.Migrations.MIGRATION_1_2;
import static org.schabi.newpipe.database.Migrations.MIGRATION_2_3; import static org.schabi.newpipe.database.Migrations.MIGRATION_2_3;
public final class NewPipeDatabase { public final class NewPipeDatabase {
private static volatile AppDatabase databaseInstance; private static volatile AppDatabase databaseInstance;
private NewPipeDatabase() { private NewPipeDatabase() {
//no instance //no instance
} }
private static AppDatabase getDatabase(Context context) { private static AppDatabase getDatabase(final Context context) {
return Room return Room
.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME) .databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3) .addMigrations(MIGRATION_1_2, MIGRATION_2_3)
@@ -28,13 +27,14 @@ public final class NewPipeDatabase {
} }
@NonNull @NonNull
public static AppDatabase getInstance(@NonNull Context context) { public static AppDatabase getInstance(@NonNull final Context context) {
AppDatabase result = databaseInstance; AppDatabase result = databaseInstance;
if (result == null) { if (result == null) {
synchronized (NewPipeDatabase.class) { synchronized (NewPipeDatabase.class) {
result = databaseInstance; result = databaseInstance;
if (result == null) { if (result == null) {
databaseInstance = (result = getDatabase(context)); databaseInstance = getDatabase(context);
result = databaseInstance;
} }
} }
} }

View File

@@ -1,4 +1,3 @@
package org.schabi.newpipe; package org.schabi.newpipe;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@@ -26,17 +25,18 @@ import android.os.Bundle;
*/ */
public class PanicResponderActivity extends Activity { public class PanicResponderActivity extends Activity {
public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER"; public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER";
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Intent intent = getIntent(); Intent intent = getIntent();
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) { if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
// TODO explicitly clear the search results once they are restored when the app restarts // TODO: Explicitly clear the search results
// or if the app reloads the current video after being killed, that should be cleared also // once they are restored when the app restarts
// or if the app reloads the current video after being killed,
// that should be cleared also
ExitActivity.exitAndRemoveFromRecentApps(this); ExitActivity.exitAndRemoveFromRecentApps(this);
} }

View File

@@ -1,24 +1,31 @@
package org.schabi.newpipe; package org.schabi.newpipe;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.core.app.NavUtils;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.NavUtils;
import androidx.preference.PreferenceManager;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import androidx.annotation.NonNull; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/* /*
* Created by beneth <bmauduit@beneth.fr> on 06.12.16. * Created by beneth <bmauduit@beneth.fr> on 06.12.16.
@@ -44,12 +51,13 @@ public class ReCaptchaActivity extends AppCompatActivity {
public static final String RECAPTCHA_URL_EXTRA = "recaptcha_url_extra"; public static final String RECAPTCHA_URL_EXTRA = "recaptcha_url_extra";
public static final String TAG = ReCaptchaActivity.class.toString(); public static final String TAG = ReCaptchaActivity.class.toString();
public static final String YT_URL = "https://www.youtube.com"; public static final String YT_URL = "https://www.youtube.com";
public static final String RECAPTCHA_COOKIES_KEY = "recaptcha_cookies";
private WebView webView; private WebView webView;
private String foundCookies = ""; private String foundCookies = "";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
ThemeHelper.setTheme(this); ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recaptcha); setContentView(R.layout.activity_recaptcha);
@@ -72,10 +80,33 @@ public class ReCaptchaActivity extends AppCompatActivity {
webSettings.setJavaScriptEnabled(true); webSettings.setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() { webView.setWebViewClient(new WebViewClient() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override @Override
public void onPageFinished(WebView view, String url) { public boolean shouldOverrideUrlLoading(final WebView view,
final WebResourceRequest request) {
String url = request.getUrl().toString();
if (MainActivity.DEBUG) {
Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
}
handleCookiesFromUrl(url);
return false;
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
if (MainActivity.DEBUG) {
Log.d(TAG, "shouldOverrideUrlLoading: url=" + url);
}
handleCookiesFromUrl(url);
return false;
}
@Override
public void onPageFinished(final WebView view, final String url) {
super.onPageFinished(view, url); super.onPageFinished(view, url);
handleCookies(url); handleCookiesFromUrl(url);
} }
}); });
@@ -84,7 +115,8 @@ public class ReCaptchaActivity extends AppCompatActivity {
webView.clearHistory(); webView.clearHistory();
android.webkit.CookieManager cookieManager = CookieManager.getInstance(); android.webkit.CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(aBoolean -> {}); cookieManager.removeAllCookies(aBoolean -> {
});
} else { } else {
cookieManager.removeAllCookie(); cookieManager.removeAllCookie();
} }
@@ -93,7 +125,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.menu_recaptcha, menu); getMenuInflater().inflate(R.menu.menu_recaptcha, menu);
ActionBar actionBar = getSupportActionBar(); ActionBar actionBar = getSupportActionBar();
@@ -112,7 +144,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
int id = item.getItemId(); int id = item.getItemId();
switch (id) { switch (id) {
case R.id.menu_item_done: case R.id.menu_item_done:
@@ -124,10 +156,20 @@ public class ReCaptchaActivity extends AppCompatActivity {
} }
private void saveCookiesAndFinish() { private void saveCookiesAndFinish() {
handleCookies(webView.getUrl()); // try to get cookies of unclosed page handleCookiesFromUrl(webView.getUrl()); // try to get cookies of unclosed page
if (MainActivity.DEBUG) {
Log.d(TAG, "saveCookiesAndFinish: foundCookies=" + foundCookies);
}
if (!foundCookies.isEmpty()) { if (!foundCookies.isEmpty()) {
// save cookies to preferences
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
getApplicationContext());
final String key = getApplicationContext().getString(R.string.recaptcha_cookies_key);
prefs.edit().putString(key, foundCookies).apply();
// give cookies to Downloader class // give cookies to Downloader class
DownloaderImpl.getInstance().setCookies(foundCookies); DownloaderImpl.getInstance().setCookie(RECAPTCHA_COOKIES_KEY, foundCookies);
setResult(RESULT_OK); setResult(RESULT_OK);
} }
@@ -137,24 +179,60 @@ public class ReCaptchaActivity extends AppCompatActivity {
} }
private void handleCookiesFromUrl(@Nullable final String url) {
if (MainActivity.DEBUG) {
Log.d(TAG, "handleCookiesFromUrl: url=" + (url == null ? "null" : url));
}
if (url == null) {
return;
}
private void handleCookies(String url) {
String cookies = CookieManager.getInstance().getCookie(url); String cookies = CookieManager.getInstance().getCookie(url);
if (MainActivity.DEBUG) Log.d(TAG, "handleCookies: url=" + url + "; cookies=" + (cookies == null ? "null" : cookies)); handleCookies(cookies);
if (cookies == null) return;
addYoutubeCookies(cookies); // sometimes cookies are inside the url
// add other methods to extract cookies here int abuseStart = url.indexOf("google_abuse=");
if (abuseStart != -1) {
int abuseEnd = url.indexOf("+path");
try {
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
abuseCookie = URLDecoder.decode(abuseCookie, "UTF-8");
handleCookies(abuseCookie);
} catch (UnsupportedEncodingException | StringIndexOutOfBoundsException e) {
if (MainActivity.DEBUG) {
e.printStackTrace();
Log.d(TAG, "handleCookiesFromUrl: invalid google abuse starting at "
+ abuseStart + " and ending at " + abuseEnd + " for url " + url);
}
}
}
} }
private void addYoutubeCookies(@NonNull String cookies) { private void handleCookies(@Nullable final String cookies) {
if (cookies.contains("s_gl=") || cookies.contains("goojf=") || cookies.contains("VISITOR_INFO1_LIVE=")) { if (MainActivity.DEBUG) {
Log.d(TAG, "handleCookies: cookies=" + (cookies == null ? "null" : cookies));
}
if (cookies == null) {
return;
}
addYoutubeCookies(cookies);
// add here methods to extract cookies for other services
}
private void addYoutubeCookies(@NonNull final String cookies) {
if (cookies.contains("s_gl=") || cookies.contains("goojf=")
|| cookies.contains("VISITOR_INFO1_LIVE=")
|| cookies.contains("GOOGLE_ABUSE_EXEMPTION=")) {
// youtube seems to also need the other cookies: // youtube seems to also need the other cookies:
addCookie(cookies); addCookie(cookies);
} }
} }
private void addCookie(String cookie) { private void addCookie(final String cookie) {
if (foundCookies.contains(cookie)) { if (foundCookies.contains(cookie)) {
return; return;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -4,21 +4,22 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import com.google.android.material.tabs.TabLayout; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter; import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import com.google.android.material.tabs.TabLayout;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@@ -27,26 +28,41 @@ import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class AboutActivity extends AppCompatActivity { public class AboutActivity extends AppCompatActivity {
/** /**
* List of all software components * List of all software components.
*/ */
private static final SoftwareComponent[] SOFTWARE_COMPONENTS = new SoftwareComponent[]{ private static final SoftwareComponent[] SOFTWARE_COMPONENTS = new SoftwareComponent[]{
new SoftwareComponent("Giga Get", "2014 - 2015", "Peter Cai", "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL2), new SoftwareComponent("Giga Get", "2014 - 2015", "Peter Cai",
new SoftwareComponent("NewPipe Extractor", "2017 - 2020", "Christian Schabesberger", "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3), "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL2),
new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley", "https://github.com/jhy/jsoup", StandardLicenses.MIT), new SoftwareComponent("NewPipe Extractor", "2017 - 2020", "Christian Schabesberger",
new SoftwareComponent("Rhino", "2015", "Mozilla", "https://www.mozilla.org/rhino/", StandardLicenses.MPL2), "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3),
new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", "http://www.acra.ch", StandardLicenses.APACHE2), new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley",
new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich", "https://github.com/nostra13/Android-Universal-Image-Loader", StandardLicenses.APACHE2), "https://github.com/jhy/jsoup", StandardLicenses.MIT),
new SoftwareComponent("CircleImageView", "2014 - 2020", "Henning Dodenhof", "https://github.com/hdodenhof/CircleImageView", StandardLicenses.APACHE2), new SoftwareComponent("Rhino", "2015", "Mozilla",
new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam", "https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2), "https://www.mozilla.org/rhino/", StandardLicenses.MPL2),
new SoftwareComponent("ExoPlayer", "2014 - 2020", "Google Inc", "https://github.com/google/ExoPlayer", StandardLicenses.APACHE2), new SoftwareComponent("ACRA", "2013", "Kevin Gaudin",
new SoftwareComponent("RxAndroid", "2015 - 2018", "The RxAndroid authors", "https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2), "http://www.acra.ch", StandardLicenses.APACHE2),
new SoftwareComponent("RxJava", "2016 - 2020", "RxJava Contributors", "https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2), new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich",
new SoftwareComponent("RxBinding", "2015 - 2018", "Jake Wharton", "https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2), "https://github.com/nostra13/Android-Universal-Image-Loader",
new SoftwareComponent("PrettyTime", "2012 - 2020", "Lincoln Baxter, III", "https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2), StandardLicenses.APACHE2),
new SoftwareComponent("Markwon", "2017 - 2020", "Noties", "https://github.com/noties/Markwon", StandardLicenses.APACHE2), new SoftwareComponent("CircleImageView", "2014 - 2020", "Henning Dodenhof",
new SoftwareComponent("Groupie", "2016", "Lisa Wray", "https://github.com/lisawray/groupie", StandardLicenses.MIT) "https://github.com/hdodenhof/CircleImageView", StandardLicenses.APACHE2),
new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam",
"https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2),
new SoftwareComponent("ExoPlayer", "2014 - 2020", "Google Inc",
"https://github.com/google/ExoPlayer", StandardLicenses.APACHE2),
new SoftwareComponent("RxAndroid", "2015 - 2018", "The RxAndroid authors",
"https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2),
new SoftwareComponent("RxJava", "2016 - 2020", "RxJava Contributors",
"https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2),
new SoftwareComponent("RxBinding", "2015 - 2018", "Jake Wharton",
"https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2),
new SoftwareComponent("PrettyTime", "2012 - 2020", "Lincoln Baxter, III",
"https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2),
new SoftwareComponent("Markwon", "2017 - 2020", "Noties",
"https://github.com/noties/Markwon", StandardLicenses.APACHE2),
new SoftwareComponent("Groupie", "2016", "Lisa Wray",
"https://github.com/lisawray/groupie", StandardLicenses.MIT)
}; };
/** /**
@@ -65,7 +81,7 @@ public class AboutActivity extends AppCompatActivity {
private ViewPager mViewPager; private ViewPager mViewPager;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this); assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this); ThemeHelper.setTheme(this);
@@ -88,10 +104,8 @@ public class AboutActivity extends AppCompatActivity {
tabLayout.setupWithViewPager(mViewPager); tabLayout.setupWithViewPager(mViewPager);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
int id = item.getItemId(); int id = item.getItemId();
switch (id) { switch (id) {
@@ -107,21 +121,20 @@ public class AboutActivity extends AppCompatActivity {
* A placeholder fragment containing a simple view. * A placeholder fragment containing a simple view.
*/ */
public static class AboutFragment extends Fragment { public static class AboutFragment extends Fragment {
public AboutFragment() { }
public AboutFragment() {
}
/** /**
* Returns a new instance of this fragment for the given section * Created a new instance of this fragment for the given section number.
* number. *
* @return New instance of {@link AboutFragment}
*/ */
public static AboutFragment newInstance() { public static AboutFragment newInstance() {
return new AboutFragment(); return new AboutFragment();
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) { final Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_about, container, false); View rootView = inflater.inflate(R.layout.fragment_about, container, false);
Context context = this.getContext(); Context context = this.getContext();
@@ -129,40 +142,42 @@ public class AboutActivity extends AppCompatActivity {
version.setText(BuildConfig.VERSION_NAME); version.setText(BuildConfig.VERSION_NAME);
View githubLink = rootView.findViewById(R.id.github_link); View githubLink = rootView.findViewById(R.id.github_link);
githubLink.setOnClickListener(nv -> openWebsite(context.getString(R.string.github_url), context)); githubLink.setOnClickListener(nv ->
openWebsite(context.getString(R.string.github_url), context));
View donationLink = rootView.findViewById(R.id.donation_link); View donationLink = rootView.findViewById(R.id.donation_link);
donationLink.setOnClickListener(v -> openWebsite(context.getString(R.string.donation_url), context)); donationLink.setOnClickListener(v ->
openWebsite(context.getString(R.string.donation_url), context));
View websiteLink = rootView.findViewById(R.id.website_link); View websiteLink = rootView.findViewById(R.id.website_link);
websiteLink.setOnClickListener(nv -> openWebsite(context.getString(R.string.website_url), context)); websiteLink.setOnClickListener(nv ->
openWebsite(context.getString(R.string.website_url), context));
View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link); View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
privacyPolicyLink.setOnClickListener(v -> openWebsite(context.getString(R.string.privacy_policy_url), context)); privacyPolicyLink.setOnClickListener(v ->
openWebsite(context.getString(R.string.privacy_policy_url), context));
return rootView; return rootView;
} }
private void openWebsite(String url, Context context) { private void openWebsite(final String url, final Context context) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(intent); context.startActivity(intent);
} }
} }
/** /**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages. * one of the sections/tabs/pages.
*/ */
public class SectionsPagerAdapter extends FragmentPagerAdapter { public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(final FragmentManager fm) {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm); super(fm);
} }
@Override @Override
public Fragment getItem(int position) { public Fragment getItem(final int position) {
switch (position) { switch (position) {
case 0: case 0:
return AboutFragment.newInstance(); return AboutFragment.newInstance();
@@ -179,7 +194,7 @@ public class AboutActivity extends AppCompatActivity {
} }
@Override @Override
public CharSequence getPageTitle(int position) { public CharSequence getPageTitle(final int position) {
switch (position) { switch (position) {
case 0: case 0:
return getString(R.string.tab_about); return getString(R.string.tab_about);

View File

@@ -5,18 +5,17 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
/** /**
* A software license * Class for storing information about a software license.
*/ */
public class License implements Parcelable { public class License implements Parcelable {
public static final Creator<License> CREATOR = new Creator<License>() { public static final Creator<License> CREATOR = new Creator<License>() {
@Override @Override
public License createFromParcel(Parcel source) { public License createFromParcel(final Parcel source) {
return new License(source); return new License(source);
} }
@Override @Override
public License[] newArray(int size) { public License[] newArray(final int size) {
return new License[size]; return new License[size];
} }
}; };
@@ -24,16 +23,22 @@ public class License implements Parcelable {
private final String name; private final String name;
private String filename; private String filename;
public License(String name, String abbreviation, String filename) { public License(final String name, final String abbreviation, final String filename) {
if(name == null) throw new NullPointerException("name is null"); if (name == null) {
if(abbreviation == null) throw new NullPointerException("abbreviation is null"); throw new NullPointerException("name is null");
if(filename == null) throw new NullPointerException("filename is null"); }
if (abbreviation == null) {
throw new NullPointerException("abbreviation is null");
}
if (filename == null) {
throw new NullPointerException("filename is null");
}
this.name = name; this.name = name;
this.filename = filename; this.filename = filename;
this.abbreviation = abbreviation; this.abbreviation = abbreviation;
} }
protected License(Parcel in) { protected License(final Parcel in) {
this.filename = in.readString(); this.filename = in.readString();
this.abbreviation = in.readString(); this.abbreviation = in.readString();
this.name = in.readString(); this.name = in.readString();
@@ -50,7 +55,7 @@ public class License implements Parcelable {
public String getAbbreviation() { public String getAbbreviation() {
return abbreviation; return abbreviation;
} }
public String getFilename() { public String getFilename() {
return filename; return filename;
} }
@@ -61,7 +66,7 @@ public class License implements Parcelable {
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(this.filename); dest.writeString(this.filename);
dest.writeString(this.abbreviation); dest.writeString(this.abbreviation);
dest.writeString(this.name); dest.writeString(this.name);

View File

@@ -2,29 +2,33 @@ package org.schabi.newpipe.about;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import android.view.*;
import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ShareUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
/** /**
* Fragment containing the software licenses * Fragment containing the software licenses.
*/ */
public class LicenseFragment extends Fragment { public class LicenseFragment extends Fragment {
private static final String ARG_COMPONENTS = "components"; private static final String ARG_COMPONENTS = "components";
private SoftwareComponent[] softwareComponents; private SoftwareComponent[] softwareComponents;
private SoftwareComponent mComponentForContextMenu; private SoftwareComponent componentForContextMenu;
public static LicenseFragment newInstance(SoftwareComponent[] softwareComponents) { public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
if(softwareComponents == null) { if (softwareComponents == null) {
throw new NullPointerException("softwareComponents is null"); throw new NullPointerException("softwareComponents is null");
} }
LicenseFragment fragment = new LicenseFragment(); LicenseFragment fragment = new LicenseFragment();
@@ -35,57 +39,50 @@ public class LicenseFragment extends Fragment {
} }
/** /**
* Shows a popup containing the license * Shows a popup containing the license.
*
* @param context the context to use * @param context the context to use
* @param license the license to show * @param license the license to show
*/ */
public static void showLicense(Context context, License license) { private static void showLicense(final Context context, final License license) {
new LicenseFragmentHelper((Activity) context).execute(license); new LicenseFragmentHelper((Activity) context).execute(license);
} }
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
softwareComponents = (SoftwareComponent[]) getArguments().getParcelableArray(ARG_COMPONENTS); softwareComponents = (SoftwareComponent[]) getArguments()
.getParcelableArray(ARG_COMPONENTS);
// Sort components by name // Sort components by name
Arrays.sort(softwareComponents, new Comparator<SoftwareComponent>() { Arrays.sort(softwareComponents, (o1, o2) -> o1.getName().compareTo(o2.getName()));
@Override
public int compare(SoftwareComponent o1, SoftwareComponent o2) {
return o1.getName().compareTo(o2.getName());
}
});
} }
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
View rootView = inflater.inflate(R.layout.fragment_licenses, container, false); @Nullable final Bundle savedInstanceState) {
ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components); final View rootView = inflater.inflate(R.layout.fragment_licenses, container, false);
final ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
View licenseLink = rootView.findViewById(R.id.app_read_license); final View licenseLink = rootView.findViewById(R.id.app_read_license);
licenseLink.setOnClickListener(new OnReadFullLicenseClickListener()); licenseLink.setOnClickListener(v ->
showLicense(getActivity(), StandardLicenses.GPL3));
for (final SoftwareComponent component : softwareComponents) { for (final SoftwareComponent component : softwareComponents) {
View componentView = inflater.inflate(R.layout.item_software_component, container, false); final View componentView = inflater
TextView softwareName = componentView.findViewById(R.id.name); .inflate(R.layout.item_software_component, container, false);
TextView copyright = componentView.findViewById(R.id.copyright); final TextView softwareName = componentView.findViewById(R.id.name);
final TextView copyright = componentView.findViewById(R.id.copyright);
softwareName.setText(component.getName()); softwareName.setText(component.getName());
copyright.setText(getContext().getString(R.string.copyright, copyright.setText(getString(R.string.copyright,
component.getYears(), component.getYears(),
component.getCopyrightOwner(), component.getCopyrightOwner(),
component.getLicense().getAbbreviation())); component.getLicense().getAbbreviation()));
componentView.setTag(component); componentView.setTag(component);
componentView.setOnClickListener(new View.OnClickListener() { componentView.setOnClickListener(v ->
@Override showLicense(getActivity(), component.getLicense()));
public void onClick(View v) {
Context context = v.getContext();
if (context != null) {
showLicense(context, component.getLicense());
}
}
});
softwareComponentsView.addView(componentView); softwareComponentsView.addView(componentView);
registerForContextMenu(componentView); registerForContextMenu(componentView);
} }
@@ -93,41 +90,30 @@ public class LicenseFragment extends Fragment {
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu(final ContextMenu menu, final View v,
MenuInflater inflater = getActivity().getMenuInflater(); final ContextMenu.ContextMenuInfo menuInfo) {
SoftwareComponent component = (SoftwareComponent) v.getTag(); final MenuInflater inflater = getActivity().getMenuInflater();
final SoftwareComponent component = (SoftwareComponent) v.getTag();
menu.setHeaderTitle(component.getName()); menu.setHeaderTitle(component.getName());
inflater.inflate(R.menu.software_component, menu); inflater.inflate(R.menu.software_component, menu);
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
mComponentForContextMenu = (SoftwareComponent) v.getTag(); componentForContextMenu = (SoftwareComponent) v.getTag();
} }
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(final MenuItem item) {
// item.getMenuInfo() is null so we use the tag of the view // item.getMenuInfo() is null so we use the tag of the view
final SoftwareComponent component = mComponentForContextMenu; final SoftwareComponent component = componentForContextMenu;
if (component == null) { if (component == null) {
return false; return false;
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_website: case R.id.action_website:
openWebsite(component.getLink()); ShareUtils.openUrlInBrowser(getActivity(), component.getLink());
return true; return true;
case R.id.action_show_license: case R.id.action_show_license:
showLicense(getContext(), component.getLicense()); showLicense(getActivity(), component.getLicense());
} }
return false; return false;
} }
private void openWebsite(String componentLink) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(componentLink));
startActivity(browserIntent);
}
private static class OnReadFullLicenseClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
LicenseFragment.showLicense(v.getContext(), StandardLicenses.GPL3);
}
}
} }

View File

@@ -2,33 +2,95 @@ package org.schabi.newpipe.about;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Base64;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import android.webkit.WebView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> { public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
private final WeakReference<Activity> weakReference;
final WeakReference<Activity> weakReference;
private License license; private License license;
public LicenseFragmentHelper(@Nullable Activity activity) { public LicenseFragmentHelper(@Nullable final Activity activity) {
weakReference = new WeakReference<>(activity); weakReference = new WeakReference<>(activity);
} }
/**
* @param context the context to use
* @param license the license
* @return String which contains a HTML formatted license page
* styled according to the context's theme
*/
private static String getFormattedLicense(@NonNull final Context context,
@NonNull final License license) {
final StringBuilder licenseContent = new StringBuilder();
final String webViewData;
try {
final BufferedReader in = new BufferedReader(new InputStreamReader(
context.getAssets().open(license.getFilename()), StandardCharsets.UTF_8));
String str;
while ((str = in.readLine()) != null) {
licenseContent.append(str);
}
in.close();
// split the HTML file and insert the stylesheet into the HEAD of the file
webViewData = licenseContent.toString().replace("</head>",
"<style>" + getLicenseStylesheet(context) + "</style></head>");
} catch (IOException e) {
throw new IllegalArgumentException(
"Could not get license file: " + license.getFilename(), e);
}
return webViewData;
}
/**
* @param context
* @return String which is a CSS stylesheet according to the context's theme
*/
private static String getLicenseStylesheet(final Context context) {
final boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
return "body{padding:12px 15px;margin:0;"
+ "background:#" + getHexRGBColor(context, isLightTheme
? R.color.light_license_background_color
: R.color.dark_license_background_color) + ";"
+ "color:#" + getHexRGBColor(context, isLightTheme
? R.color.light_license_text_color
: R.color.dark_license_text_color) + "}"
+ "a[href]{color:#" + getHexRGBColor(context, isLightTheme
? R.color.light_youtube_primary_color
: R.color.dark_youtube_primary_color) + "}"
+ "pre{white-space:pre-wrap}";
}
/**
* Cast R.color to a hexadecimal color value.
*
* @param context the context to use
* @param color the color number from R.color
* @return a six characters long String with hexadecimal RGB values
*/
private static String getHexRGBColor(final Context context, final int color) {
return context.getResources().getString(color).substring(3);
}
@Nullable @Nullable
private Activity getActivity() { private Activity getActivity() {
Activity activity = weakReference.get(); final Activity activity = weakReference.get();
if (activity != null && activity.isFinishing()) { if (activity != null && activity.isFinishing()) {
return null; return null;
@@ -38,99 +100,29 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
} }
@Override @Override
protected Integer doInBackground(Object... objects) { protected Integer doInBackground(final Object... objects) {
license = (License) objects[0]; license = (License) objects[0];
return 1; return 1;
} }
@Override @Override
protected void onPostExecute(Integer result) { protected void onPostExecute(final Integer result) {
Activity activity = getActivity(); final Activity activity = getActivity();
if (activity == null) { if (activity == null) {
return; return;
} }
String webViewData = getFormattedLicense(activity, license); final String webViewData = Base64.encodeToString(getFormattedLicense(activity, license)
AlertDialog.Builder alert = new AlertDialog.Builder(activity); .getBytes(StandardCharsets.UTF_8), Base64.NO_PADDING);
final WebView webView = new WebView(activity);
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64");
final AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle(license.getName()); alert.setTitle(license.getName());
alert.setView(webView);
WebView wv = new WebView(activity); assureCorrectAppLanguage(activity);
wv.loadData(webViewData, "text/html; charset=UTF-8", null); alert.setNegativeButton(activity.getString(R.string.finish),
(dialog, which) -> dialog.dismiss());
alert.setView(wv);
assureCorrectAppLanguage(activity.getApplicationContext());
alert.setNegativeButton(getFinishString(activity), (dialog, which) -> dialog.dismiss());
alert.show(); alert.show();
} }
private static String getFinishString(Activity activity) {
return activity.getApplicationContext().getResources().getString(R.string.finish);
}
/**
* @param context the context to use
* @param license the license
* @return String which contains a HTML formatted license page styled according to the context's theme
*/
public static String getFormattedLicense(Context context, License license) {
if(context == null) {
throw new NullPointerException("context is null");
}
if(license == null) {
throw new NullPointerException("license is null");
}
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.append(str);
}
in.close();
// split the HTML file and insert the stylesheet into the HEAD of the file
String[] insert = licenseContent.toString().split("</head>");
webViewData = insert[0] + "<style type=\"text/css\">"
+ getLicenseStylesheet(context) + "</style></head>"
+ insert[1];
} catch (Exception e) {
throw new NullPointerException("could not get license file:" + getLicenseStylesheet(context));
}
return webViewData;
}
/**
*
* @param context
* @return String which is a CSS stylesheet according to the context's theme
*/
public static String getLicenseStylesheet(Context context) {
boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
return "body{padding:12px 15px;margin:0;background:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_license_background_color
: R.color.dark_license_background_color)
+ ";color:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_license_text_color
: R.color.dark_license_text_color) + ";}"
+ "a[href]{color:#"
+ getHexRGBColor(context, isLightTheme
? R.color.light_youtube_primary_color
: R.color.dark_youtube_primary_color) + ";}"
+ "pre{white-space: pre-wrap;}";
}
/**
* Cast R.color to a hexadecimal color value
* @param context the context to use
* @param color the color number from R.color
* @return a six characters long String with hexadecimal RGB values
*/
public static String getHexRGBColor(Context context, int color) {
return context.getResources().getString(color).substring(3);
}
} }

View File

@@ -4,19 +4,44 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
public class SoftwareComponent implements Parcelable { public class SoftwareComponent implements Parcelable {
public static final Creator<SoftwareComponent> CREATOR = new Creator<SoftwareComponent>() { public static final Creator<SoftwareComponent> CREATOR = new Creator<SoftwareComponent>() {
@Override @Override
public SoftwareComponent createFromParcel(Parcel source) { public SoftwareComponent createFromParcel(final Parcel source) {
return new SoftwareComponent(source); return new SoftwareComponent(source);
} }
@Override @Override
public SoftwareComponent[] newArray(int size) { public SoftwareComponent[] newArray(final int size) {
return new SoftwareComponent[size]; return new SoftwareComponent[size];
} }
}; };
private final License license;
private final String name;
private final String years;
private final String copyrightOwner;
private final String link;
private final String version;
public SoftwareComponent(final String name, final String years, final String copyrightOwner,
final String link, final License license) {
this.name = name;
this.years = years;
this.copyrightOwner = copyrightOwner;
this.link = link;
this.license = license;
this.version = null;
}
protected SoftwareComponent(final Parcel in) {
this.name = in.readString();
this.license = in.readParcelable(License.class.getClassLoader());
this.copyrightOwner = in.readString();
this.link = in.readString();
this.years = in.readString();
this.version = in.readString();
}
public String getName() { public String getName() {
return name; return name;
} }
@@ -37,31 +62,6 @@ public class SoftwareComponent implements Parcelable {
return version; return version;
} }
private final License license;
private final String name;
private final String years;
private final String copyrightOwner;
private final String link;
private final String version;
public SoftwareComponent(String name, String years, String copyrightOwner, String link, License license) {
this.name = name;
this.years = years;
this.copyrightOwner = copyrightOwner;
this.link = link;
this.license = license;
this.version = null;
}
protected SoftwareComponent(Parcel in) {
this.name = in.readString();
this.license = in.readParcelable(License.class.getClassLoader());
this.copyrightOwner = in.readString();
this.link = in.readString();
this.years = in.readString();
this.version = in.readString();
}
public License getLicense() { public License getLicense() {
return license; return license;
} }
@@ -72,7 +72,7 @@ public class SoftwareComponent implements Parcelable {
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(name); dest.writeString(name);
dest.writeParcelable(license, flags); dest.writeParcelable(license, flags);
dest.writeString(copyrightOwner); dest.writeString(copyrightOwner);

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