Compare commits

...

220 Commits

Author SHA1 Message Date
Christian Schabesberger
3bb95ad44c add changelog for version v0.13.4 2018-05-25 18:38:07 +02:00
Christian Schabesberger
0a6572c282 roll back to more stable version of newpipe extractor 2018-05-25 18:29:30 +02:00
Christian Schabesberger
3937067be1 move on to version 0.13.4 2018-05-25 09:45:22 +02:00
Christian Schabesberger
48e4eb44f2 remove unused imports 2018-05-25 09:43:28 +02:00
TobiGr
c78cc6f2fd Add dialog to accept privacy policy before sending crash report
Add link to privacy policy in about fragment
Replace some onClickListeners with Lamdas
2018-05-25 09:29:14 +02:00
Bogdan Khomutsky
73a71e0f5c Translated using Weblate (Russian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-25 08:22:43 +02:00
SINUS (সাইনাস)
93605774f0 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 40.0% (146 of 365 strings)
2018-05-24 18:34:46 +02:00
Daria Szatan
2834e5d78f Translated using Weblate (Polish)
Currently translated at 100.0% (365 of 365 strings)
2018-05-23 19:53:07 +02:00
Allan Nordhøy
dd467b4d63 Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.1% (351 of 365 strings)
2018-05-22 11:40:49 +02:00
SN
1fa541776b Translated using Weblate (Hindi)
Currently translated at 80.0% (292 of 365 strings)
2018-05-22 08:37:59 +02:00
Weblate
f6f67c7b0a Merge branch 'dev' into weblate-merge-tmp 2018-05-21 06:37:51 +02:00
lartial
9b3f19c19b Translated using Weblate (Indonesian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-21 06:37:49 +02:00
Christian Schabesberger
f4a9ec15e8 Merge pull request #1407 from DafabHoid/dev
Downloader: Fix crash on loading unfinished downloads from .giga files
2018-05-19 16:19:33 +02:00
Osoitz
006c4ecb02 Translated using Weblate (Basque)
Currently translated at 100.0% (365 of 365 strings)
2018-05-19 10:34:39 +02:00
Nishargo Nigar
1c752b0e18 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 34.2% (125 of 365 strings)
2018-05-19 08:34:45 +02:00
AB
f84aff63e3 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-18 19:06:33 +02:00
DafabHoid
ae8121b680 Utility: Buffer the output to files when serializing 2018-05-18 18:23:32 +02:00
DafabHoid
882fbf9275 Fix crash on loading not yet finished downloads from .giga files 2018-05-18 18:18:37 +02:00
Dual Natan
0a1743251e Translated using Weblate (Macedonian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-18 11:49:10 +02:00
Osoitz
3403a127c1 Translated using Weblate (Basque)
Currently translated at 100.0% (365 of 365 strings)
2018-05-18 10:24:13 +02:00
Robson Cassiano
9c5ca9f09d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (365 of 365 strings)
2018-05-17 16:40:02 +02:00
David Adrião
73eea5608a Translated using Weblate (Portuguese)
Currently translated at 86.3% (315 of 365 strings)
2018-05-17 13:40:38 +02:00
Osoitz
f48aeb91f4 Translated using Weblate (Basque)
Currently translated at 98.9% (361 of 365 strings)
2018-05-17 11:34:34 +02:00
Robson Cassiano
0bda964ece Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (365 of 365 strings)
2018-05-16 16:21:22 +02:00
Ale-Ma
14f5d54b50 Translated using Weblate (Italian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-16 00:13:39 +02:00
Freddy Morán Jr
105ac2f6ff Translated using Weblate (Spanish)
Currently translated at 99.4% (363 of 365 strings)
2018-05-15 20:43:45 +02:00
HashikDonthineni
160560f1fd Translated using Weblate (Telugu)
Currently translated at 35.3% (129 of 365 strings)
2018-05-15 17:42:23 +02:00
ditokp
deeb667d6f Translated using Weblate (Indonesian)
Currently translated at 100.0% (365 of 365 strings)
2018-05-15 13:48:13 +02:00
Ali Demirtas
78123ff6f5 Translated using Weblate (Turkish)
Currently translated at 100.0% (365 of 365 strings)
2018-05-14 21:09:52 +02:00
anonymous
9b1fdff22f Translated using Weblate (Romanian)
Currently translated at 82.7% (302 of 365 strings)
2018-05-14 19:46:37 +02:00
Ciprian
0275502796 Translated using Weblate (Romanian)
Currently translated at 82.7% (302 of 365 strings)
2018-05-14 19:46:32 +02:00
Weblate
8af475e319 Merge branch 'dev' into weblate-merge-tmp 2018-05-14 13:34:29 +02:00
Allan Nordhøy
2202c8f09e Translated using Weblate (Norwegian Bokmål)
Currently translated at 95.8% (350 of 365 strings)
2018-05-14 13:34:28 +02:00
ScratchBuild
adf309d3a8 Translated using Weblate (Japanese)
Currently translated at 77.5% (283 of 365 strings)
2018-05-14 13:34:26 +02:00
Marc Riera
3071314586 Translated using Weblate (Catalan)
Currently translated at 100.0% (365 of 365 strings)
2018-05-14 13:34:24 +02:00
thami simo
88e1df840d Translated using Weblate (Arabic)
Currently translated at 100.0% (365 of 365 strings)
2018-05-14 13:34:21 +02:00
Christian Schabesberger
23c1b66f6c add note to contribution description 2018-05-14 13:24:35 +02:00
ezjerry liao
b0318a1cce Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (365 of 365 strings)
2018-05-14 11:52:01 +02:00
Nathan Follens
c130a66e4d Translated using Weblate (Flemish)
Currently translated at 100.0% (365 of 365 strings)
2018-05-13 18:44:26 +02:00
ssantos
3386ba6d1b Translated using Weblate (German)
Currently translated at 100.0% (365 of 365 strings)
2018-05-13 16:41:08 +02:00
Marc Riera
9275569fa6 Translated using Weblate (Catalan)
Currently translated at 100.0% (365 of 365 strings)
2018-05-13 13:50:07 +02:00
Heimen Stoffels
2b23dfd0a6 Translated using Weblate (Dutch)
Currently translated at 100.0% (365 of 365 strings)
2018-05-13 13:46:49 +02:00
thami simo
2a13d9990e Translated using Weblate (Arabic)
Currently translated at 100.0% (365 of 365 strings)
2018-05-13 12:37:46 +02:00
Weblate
c9669b51c6 Merge branch 'dev' into weblate-merge-tmp 2018-05-13 11:34:46 +02:00
Osoitz
486c180b3c Translated using Weblate (Basque)
Currently translated at 98.9% (360 of 364 strings)
2018-05-13 11:34:43 +02:00
Christian Schabesberger
9eb5bf9b87 Merge pull request #1375 from acrosca/code_inspection
Code inspection
2018-05-12 14:21:37 +02:00
Christian Schabesberger
953a89f3a1 Merge branch 'settingsExport' of https://github.com/Somethingweirdhere/NewPipe into test 2018-05-12 13:34:05 +02:00
Christian Schabesberger
d638fa1434 use commit from newpipeextractor master 2018-05-11 18:00:28 +02:00
Christian Schabesberger
e6d700288c fix afiliate parse link failure 2018-05-11 18:00:28 +02:00
Christian Schabesberger
371f14cdc9 make compartible to yoututbe service restructure 2018-05-11 18:00:28 +02:00
Christian Schabesberger
0733ae2404 make compatible with encosing urlidhandler commit 2018-05-11 18:00:28 +02:00
ButterflyOfFire
b1731ebd49 Translated using Weblate (French)
Currently translated at 99.1% (361 of 364 strings)
2018-05-11 17:37:14 +02:00
Somethingweirdhere
342b3191ac Changed to lambda convention 2018-05-11 17:17:07 +02:00
zmni
cd39445245 Translated using Weblate (Indonesian)
Currently translated at 91.2% (332 of 364 strings)
2018-05-11 16:39:32 +02:00
Freddy Morán Jr
92eac67367 Translated using Weblate (Spanish)
Currently translated at 97.2% (354 of 364 strings)
2018-05-10 19:41:12 +02:00
Edwar Tikhonov
0e31a0c704 Translated using Weblate (Russian)
Currently translated at 100.0% (364 of 364 strings)
2018-05-10 11:42:55 +02:00
gensitu
d60c117a70 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (364 of 364 strings)
2018-05-10 11:36:24 +02:00
thami simo
69ccad5998 Translated using Weblate (Arabic)
Currently translated at 100.0% (364 of 364 strings)
2018-05-10 11:34:28 +02:00
Edwar Tikhonov
b6d22320e6 Translated using Weblate (Russian)
Currently translated at 100.0% (364 of 364 strings)
2018-05-09 11:12:45 +02:00
Weblate
d3bf948dba Merge remote-tracking branch 'origin/dev' into dev 2018-05-09 09:50:28 +02:00
ditokp
5de3d96b31 Translated using Weblate (Indonesian)
Currently translated at 85.7% (312 of 364 strings)
2018-05-09 09:50:28 +02:00
Florian
d30dd64322 Translated using Weblate (French)
Currently translated at 99.1% (361 of 364 strings)
2018-05-09 09:50:27 +02:00
thami simo
386df10a5a Translated using Weblate (Arabic)
Currently translated at 100.0% (364 of 364 strings)
2018-05-09 09:50:25 +02:00
Christian Schabesberger
af147de547 upgrade gradle 2018-05-08 20:56:11 +02:00
anonymous
23cd0e5a5e Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 17:30:05 +02:00
anonymous
c5a566657c Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:21:31 +02:00
Alexander Sparzt
ce2018c864 Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:21:26 +02:00
anonymous
472ab46af2 Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:18:30 +02:00
Alexander Sparzt
7f87d45bb5 Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:18:25 +02:00
anonymous
e9f7ab18bb Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:16:29 +02:00
Alexander Sparzt
fba83a8afe Translated using Weblate (French)
Currently translated at 98.3% (358 of 364 strings)
2018-05-08 16:16:24 +02:00
nailyk
05089abddc Translated using Weblate (French)
Currently translated at 96.4% (351 of 364 strings)
2018-05-08 14:43:20 +02:00
Prabjot Singh
ccd70aac51 Translated using Weblate (Punjabi)
Currently translated at 5.2% (19 of 364 strings)
2018-05-08 07:41:59 +02:00
nailyk
5df8445d04 Translated using Weblate (French)
Currently translated at 96.1% (350 of 364 strings)

Peut-être existe des traductions existantes mais je ne les aies pas trouvées.
2018-05-07 18:17:34 +02:00
nailyk
8c43674fa4 Translated using Weblate (French)
Currently translated at 95.8% (349 of 364 strings)
2018-05-07 18:14:23 +02:00
Florent Peterschmitt
f162316a6b Translated using Weblate (French)
Currently translated at 94.5% (344 of 364 strings)
2018-05-07 14:37:09 +02:00
Andrea Troiano
670596ed88 Translated using Weblate (Italian)
Currently translated at 100.0% (364 of 364 strings)
2018-05-07 10:08:51 +02:00
Prabjot Singh
6b3eb716c4 Added translation using Weblate (Punjabi) 2018-05-07 06:39:45 +02:00
Emin Tufan Çetin
6a5180d94c Translated using Weblate (Turkish)
Currently translated at 100.0% (364 of 364 strings)
2018-05-06 17:16:30 +02:00
Florent Peterschmitt
83faaedfcc Translated using Weblate (French)
Currently translated at 93.4% (340 of 364 strings)
2018-05-06 13:54:09 +02:00
Florian
d98d790a7a Translated using Weblate (French)
Currently translated at 93.4% (340 of 364 strings)
2018-05-06 13:54:02 +02:00
Florian
36b5833a3a Translated using Weblate (French)
Currently translated at 93.4% (340 of 364 strings)
2018-05-06 13:51:12 +02:00
anonymous
5e86781a79 Translated using Weblate (French)
Currently translated at 89.5% (326 of 364 strings)
2018-05-06 13:27:25 +02:00
Florian
6a780504b4 Translated using Weblate (French)
Currently translated at 89.5% (326 of 364 strings)
2018-05-06 13:27:20 +02:00
Weblate
a0d8212136 Merge remote-tracking branch 'origin/dev' into dev 2018-05-06 13:01:58 +02:00
Marian Hanzel
0e1e6a9d62 Translated using Weblate (Slovak)
Currently translated at 95.8% (349 of 364 strings)
2018-05-06 13:01:58 +02:00
thami simo
812282a332 Translated using Weblate (Arabic)
Currently translated at 89.5% (326 of 364 strings)
2018-05-06 13:01:56 +02:00
r2308145
a8a4c9e97f Translated using Weblate (Czech)
Currently translated at 100.0% (364 of 364 strings)
2018-05-06 13:01:53 +02:00
Andrei.Rosca
24c293e335 fix context leaks 2018-05-06 10:50:02 +02:00
Andrei.Rosca
0a596df497 default ViewHolder 2018-05-06 10:14:24 +02:00
Andrei.Rosca
3d66c6572b prevent infinite loop 2018-05-06 10:08:56 +02:00
Andrei.Rosca
f45769cbb2 Reduce overdraw 2018-05-05 10:26:35 +02:00
Weblate
ef51f93c6f Merge remote-tracking branch 'origin/dev' into dev 2018-05-05 09:02:21 +02:00
ssantos
35af68f148 Translated using Weblate (German)
Currently translated at 100.0% (364 of 364 strings)
2018-05-05 09:02:19 +02:00
Christian Schabesberger
ff21430b43 move on to v0.13.3
also:
- reduce snack bar error visibility time
- fix metadata error
2018-05-04 16:21:36 +02:00
Weblate
fcb67f5119 Merge remote-tracking branch 'origin/dev' into dev 2018-05-04 09:40:15 +02:00
AB
0a41fbd185 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (364 of 364 strings)
2018-05-04 09:40:14 +02:00
Oleh Ilnytskyi
d32aaf488f Translated using Weblate (Russian)
Currently translated at 89.8% (327 of 364 strings)
2018-05-04 09:40:13 +02:00
Tobias Groza
1254798013 Translated using Weblate (German)
Currently translated at 92.5% (337 of 364 strings)
2018-05-04 09:40:12 +02:00
Heimen Stoffels
c72d2a2308 Translated using Weblate (Dutch)
Currently translated at 100.0% (364 of 364 strings)
2018-05-04 09:40:11 +02:00
Marc Riera
703181655b Translated using Weblate (Catalan)
Currently translated at 100.0% (364 of 364 strings)
2018-05-04 09:40:10 +02:00
Allan Nordhøy
da4a1c5bf0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 94.5% (344 of 364 strings)
2018-05-04 09:40:06 +02:00
Christian Schabesberger
1130bd502e Merge pull request #1342 from Somethingweirdhere/popupplayerdont
PopUpPlayer now also has a Play and Pause button
2018-05-03 17:25:11 +02:00
AB
27ea4ee679 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 14:36:57 +02:00
Heimen Stoffels
56e3b66d06 Translated using Weblate (Dutch)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 11:36:33 +02:00
Nathan Follens
7d4768e151 Translated using Weblate (Dutch)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 11:36:28 +02:00
Marc Riera
7ec1011610 Translated using Weblate (Catalan)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 11:18:20 +02:00
Nathan Follens
e1bbd2055c Translated using Weblate (Flemish)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 08:58:01 +02:00
Nathan Follens
8a19547d9f Translated using Weblate (Dutch)
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 08:47:28 +02:00
Jeff Huang
6e6922dab8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (364 of 364 strings)
2018-05-03 02:27:38 +02:00
Weblate
e009ade922 Merge remote-tracking branch 'origin/dev' into dev 2018-05-02 23:38:15 +02:00
Freddy Morán Jr
90e15bcab9 Translated using Weblate (Spanish)
Currently translated at 99.7% (362 of 363 strings)
2018-05-02 23:38:15 +02:00
Allan Nordhøy
2a040cea4b Translated using Weblate (Norwegian Bokmål)
Currently translated at 94.4% (343 of 363 strings)
2018-05-02 23:38:14 +02:00
Yoav
72f2a7f8db Translated using Weblate (Hebrew)
Currently translated at 86.7% (315 of 363 strings)
2018-05-02 23:38:11 +02:00
Somethingweirdhere
8a8022afe6 Now the play/pause button also has the correct scale! 2018-05-02 22:08:14 +02:00
Christian Schabesberger
b692bec310 Merge pull request #1350 from comradekingu/patch-6
Spelling: Rework new strings
2018-05-02 21:03:20 +02:00
Andrea Troiano
536c01c70d Translated using Weblate (Italian)
Currently translated at 100.0% (363 of 363 strings)
2018-05-02 10:15:53 +02:00
Allan Nordhøy
ec8e14e977 reverted the other "History & Cache" 2018-05-02 09:18:04 +02:00
Allan Nordhøy
85b34f8809 New desc, "& Cache" reverted 2018-05-02 09:16:53 +02:00
Lukas Wiedemann
22951a56a5 Translated using Weblate (German)
Currently translated at 100.0% (363 of 363 strings)
2018-05-01 23:37:09 +02:00
r2308145
46ad84b101 Translated using Weblate (Czech)
Currently translated at 100.0% (363 of 363 strings)
2018-05-01 22:58:31 +02:00
Marc Riera
5efb77e520 Translated using Weblate (Catalan)
Currently translated at 100.0% (363 of 363 strings)
2018-05-01 18:34:55 +02:00
Lukas Wiedemann
76903102b8 Translated using Weblate (German)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 23:26:35 +02:00
Nathan Follens
c8e26b429c Translated using Weblate (Flemish)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 21:49:04 +02:00
Marc Riera
55c1310f74 Translated using Weblate (Catalan)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 17:32:00 +02:00
Heimen Stoffels
b8278d91e0 Translated using Weblate (Dutch)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 16:58:57 +02:00
Marian Hanzel
b032502148 Translated using Weblate (Slovak)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 16:42:39 +02:00
Jeff Huang
bec1a4dd1a Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 16:22:48 +02:00
AB
4dfb9e7977 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (363 of 363 strings)
2018-04-30 15:06:19 +02:00
Weblate
2bfa165cdc Merge remote-tracking branch 'origin/dev' into dev 2018-04-30 14:42:49 +02:00
AB
658666276d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (354 of 354 strings)
2018-04-30 14:42:44 +02:00
Christian Schabesberger
62f91b9084 Merge pull request #1356 from DafabHoid/doubletap-playpause
Double-tap the middle of the player screen to pause the video
2018-04-29 17:16:09 +02:00
Christian Schabesberger
719140ab78 resolve conflict 2018-04-29 17:13:45 +02:00
Christian Schabesberger
0471fd8145 add clear orphans 2018-04-29 17:06:54 +02:00
Christian Schabesberger
a079a0c901 fix requested changes part 1 2018-04-29 13:15:52 +02:00
Christian Schabesberger
ac2fa74c8f merge chagnes with dev 2018-04-29 13:01:37 +02:00
Christian Schabesberger
4c10ef65f5 add delete while history
add delete whole history
2018-04-29 12:51:57 +02:00
Christian Schabesberger
cfa697fab2 make history ui more consistent 2018-04-29 12:51:57 +02:00
Christian Schabesberger
a09b9d3e4d made items actually deltable 2018-04-29 12:51:57 +02:00
Christian Schabesberger
c470909f19 add delete options for StatisticPlaylistFragment 2018-04-29 12:51:57 +02:00
Christian Schabesberger
5e59cfcf9d remove HistoryInfoItem again
blub
2018-04-29 12:51:57 +02:00
Christian Schabesberger
a099fe35d2 reorder playqueue/localPlaylist classes 2018-04-29 12:51:57 +02:00
Christian Schabesberger
bcfd8a2450 rename playlist to player.playqueue 2018-04-29 12:49:52 +02:00
Christian Schabesberger
8ed9d71e14 put local foo into local foo folder 2018-04-29 12:47:12 +02:00
Christian Schabesberger
004c2fa55a Project restructure for history part 1
- add HistoryInfoItem (deriving from StreamInfoItem)
  in order to add a special options menu for the list items
- delete HistoryActivity and everything that belongs to its UI (not the
  manager tho)
- put everything that is local into local. (subscriptions still missing)
2018-04-29 12:47:12 +02:00
DafabHoid
3dd63d03cb Double-tap the middle of the player screen to pause the video 2018-04-29 11:23:21 +02:00
AB
cceedab864 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (354 of 354 strings)
2018-04-29 10:34:40 +02:00
Andrei.Rosca
b494b2ea39 Remove GSON lib 2018-04-29 01:06:34 +02:00
Rubix
0b29cf086b Translated using Weblate (Romanian)
Currently translated at 86.7% (307 of 354 strings)
2018-04-27 21:40:56 +02:00
r2308145
11d33097f7 Translated using Weblate (Czech)
Currently translated at 100.0% (354 of 354 strings)
2018-04-27 11:35:54 +02:00
ButterflyOfFire
3ae61645de Translated using Weblate (Arabic)
Currently translated at 87.8% (311 of 354 strings)
2018-04-26 15:34:21 +02:00
Weblate
4711befffa Merge remote-tracking branch 'origin/dev' into dev 2018-04-25 02:40:49 +02:00
Robson Cassiano
5673d53a20 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (354 of 354 strings)
2018-04-25 02:40:47 +02:00
Christian Schabesberger
90ca4a5e92 Merge pull request #1346 from naXa777/dev
Fix #1345 Gradle build fails
2018-04-24 22:03:36 +02:00
Allan Nordhøy
ad252956ab Translated using Weblate (Norwegian Bokmål)
Currently translated at 94.3% (334 of 354 strings)
2018-04-24 21:39:29 +02:00
Marian Hanzel
1b2c091c39 Translated using Weblate (Slovak)
Currently translated at 100.0% (354 of 354 strings)
2018-04-24 09:40:59 +02:00
anonymous
9031bc0c7b Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (353 of 354 strings)
2018-04-24 02:28:17 +02:00
anonymous
1d85e0ea63 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (353 of 354 strings)
2018-04-24 02:27:25 +02:00
Robson Cassiano
458774aadb Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (353 of 354 strings)
2018-04-24 02:27:20 +02:00
ButterflyOfFire
ae89f7bea3 Translated using Weblate (Arabic)
Currently translated at 83.8% (297 of 354 strings)
2018-04-23 23:34:19 +02:00
Allan Nordhøy
fd77b8552b Rework new strings 2018-04-23 22:07:27 +02:00
Marian Hanzel
bae9f5e844 Translated using Weblate (Slovak)
Currently translated at 100.0% (354 of 354 strings)
2018-04-23 08:05:45 +02:00
Paul
e3f3d90b68 Translated using Weblate (Russian)
Currently translated at 99.1% (351 of 354 strings)
2018-04-22 19:41:32 +02:00
naXa!
7f3bd8aec2 Fix #1345 Gradle build fails with "error: unescaped apostrophe in string" 2018-04-22 14:31:59 +03:00
CaptainCrumble
4501203a7a Translated using Weblate (Portuguese)
Currently translated at 93.2% (330 of 354 strings)
2018-04-22 01:40:38 +02:00
Somethingweirdhere
06292bceb2 PopUpPlayer now has a play and pause button. Tapping now doesnt pause or unpause the video and instead shows this button. 2018-04-22 00:16:07 +02:00
Somethingweirdhere
f94f14ab65 Added settings export 2018-04-21 21:11:52 +02:00
AB
7145c68e03 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (354 of 354 strings)
2018-04-21 19:11:00 +02:00
wellinkstein
bac3825c87 Translated using Weblate (French)
Currently translated at 100.0% (354 of 354 strings)
2018-04-21 15:37:08 +02:00
Dante
fc1d283414 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (354 of 354 strings)
2018-04-21 09:35:29 +02:00
anonymous
c0652daa97 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (354 of 354 strings)
2018-04-21 09:35:24 +02:00
Q. A
553903bd9d Translated using Weblate (Albanian)
Currently translated at 12.7% (45 of 354 strings)
2018-04-21 09:34:14 +02:00
Freddy Morán Jr
a43ec25b7e Translated using Weblate (Spanish)
Currently translated at 99.7% (353 of 354 strings)
2018-04-20 16:42:38 +02:00
wellinkstein
bb2a66fd02 Translated using Weblate (French)
Currently translated at 100.0% (354 of 354 strings)
2018-04-20 14:41:22 +02:00
Ale-Ma
71ac830bfa Translated using Weblate (Italian)
Currently translated at 100.0% (354 of 354 strings)
2018-04-20 12:15:48 +02:00
r2308145
82bce80c62 Translated using Weblate (Czech)
Currently translated at 100.0% (354 of 354 strings)
2018-04-20 11:48:04 +02:00
Dante
67ddf78e18 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (354 of 354 strings)
2018-04-20 09:25:12 +02:00
Marc Riera
8285df0f3f Translated using Weblate (Catalan)
Currently translated at 99.1% (351 of 354 strings)
2018-04-19 22:35:00 +02:00
Somethingweirdhere
bdb45295b9 Merge pull request #2 from TeamNewPipe/dev
d
2018-04-19 15:30:12 +02:00
Emin Tufan Çetin
f330ee8f8d Translated using Weblate (Turkish)
Currently translated at 100.0% (354 of 354 strings)
2018-04-19 10:51:45 +02:00
Joseph Kim
7331e4a7f2 Translated using Weblate (Korean)
Currently translated at 100.0% (354 of 354 strings)
2018-04-19 04:40:40 +02:00
Jeff Huang
51252d3b61 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (354 of 354 strings)
2018-04-19 01:33:35 +02:00
Somethingweirdhere
dcdb2c323e Added settings export 2018-04-19 01:31:25 +02:00
Q. A
c4ac901c67 Added translation using Weblate (Albanian) 2018-04-18 23:38:25 +02:00
Tobias Groza
a7ce072ca2 Translated using Weblate (German)
Currently translated at 100.0% (354 of 354 strings)
2018-04-18 23:34:48 +02:00
Nathan Follens
a9b427b877 Translated using Weblate (Flemish)
Currently translated at 100.0% (354 of 354 strings)
2018-04-18 22:37:17 +02:00
Nathan Follens
67a9f3a4ad Added translation using Weblate (Flemish) 2018-04-18 22:12:00 +02:00
Nathan Follens
1a4905f36a Translated using Weblate (Dutch)
Currently translated at 100.0% (354 of 354 strings)
2018-04-18 21:57:15 +02:00
Weblate
cbb1fde7b0 Merge remote-tracking branch 'origin/dev' into dev 2018-04-18 21:41:20 +02:00
DafabHoid
b86bd019a7 Translated using Weblate (German)
Currently translated at 100.0% (353 of 353 strings)
2018-04-18 21:41:20 +02:00
anonymous
6a0bada9d2 Translated using Weblate (Polish)
Currently translated at 100.0% (353 of 353 strings)
2018-04-18 21:41:18 +02:00
Christian Schabesberger
a708278cf0 Merge pull request #1327 from Somethingweirdhere/dev
Fixed crash when trying to open a downloaded file without a player
2018-04-18 20:35:44 +02:00
Mauricio Colli
119462cbc9 Fix RouterActivity choice selection
- Improve behavior when external player is enabled
- Fixes #1324
2018-04-18 11:44:46 -03:00
Tobias Groza
0324a4928c Translated using Weblate (German)
Currently translated at 100.0% (353 of 353 strings)
2018-04-18 12:00:09 +02:00
syed muzammil
895a2a56b5 Translated using Weblate (Urdu)
Currently translated at 2.5% (9 of 353 strings)
2018-04-18 01:41:26 +02:00
Somethingweirdhere
d9e616beee Fixed crash when trying to open a downloaded file without a player 2018-04-17 22:26:24 +02:00
horyzont
aa5d5d2b6d Translated using Weblate (Polish)
Currently translated at 100.0% (353 of 353 strings)
2018-04-17 21:20:47 +02:00
Somethingweirdhere
85dc555358 Fixed crash when trying to open a downloaded file without a player 2018-04-17 19:47:17 +02:00
Somethingweirdhere
15b4a7d055 Fixed crash when trying to open a downloaded file without a player 2018-04-17 19:19:12 +02:00
Andrea Troiano
696c94050d Translated using Weblate (Italian)
Currently translated at 100.0% (353 of 353 strings)
2018-04-17 09:38:03 +02:00
DafabHoid
b222614c4a Translated using Weblate (German)
Currently translated at 100.0% (353 of 353 strings)
2018-04-16 22:58:47 +02:00
Emin Tufan Çetin
edff694bf3 Translated using Weblate (Turkish)
Currently translated at 100.0% (353 of 353 strings)
2018-04-16 22:42:33 +02:00
Jeff Huang
be430a6ac0 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (353 of 353 strings)
2018-04-16 13:03:02 +02:00
AB
937d40c5f7 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (353 of 353 strings)
2018-04-16 11:42:15 +02:00
Rubix
d3979676ab Translated using Weblate (Romanian)
Currently translated at 84.1% (297 of 353 strings)
2018-04-16 10:40:03 +02:00
Emin Tufan Çetin
6716262a28 Translated using Weblate (Turkish)
Currently translated at 100.0% (353 of 353 strings)
2018-04-15 22:11:00 +02:00
r2308145
06d8bafce6 Translated using Weblate (Czech)
Currently translated at 100.0% (353 of 353 strings)
2018-04-15 19:35:47 +02:00
Anton Shestakov
f814755908 Translated using Weblate (Russian)
Currently translated at 98.8% (349 of 353 strings)
2018-04-15 16:39:47 +02:00
AB
f355fd2551 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (353 of 353 strings)
2018-04-15 10:40:28 +02:00
Andrea Troiano
ea84c62d76 Translated using Weblate (Italian)
Currently translated at 100.0% (353 of 353 strings)
2018-04-14 21:24:40 +02:00
r2308145
acda71cebb Translated using Weblate (Czech)
Currently translated at 100.0% (353 of 353 strings)
2018-04-14 19:05:22 +02:00
Heimen Stoffels
67dcd2e5c6 Translated using Weblate (Dutch)
Currently translated at 100.0% (353 of 353 strings)
2018-04-14 17:42:09 +02:00
Marc Riera
c996644613 Translated using Weblate (Catalan)
Currently translated at 100.0% (353 of 353 strings)
2018-04-14 16:00:44 +02:00
M1ck
171c3e492d Translated using Weblate (French)
Currently translated at 100.0% (353 of 353 strings)
2018-04-14 12:53:15 +02:00
Weblate
8834195cc6 Merge remote-tracking branch 'origin/dev' into dev 2018-04-14 11:39:08 +02:00
M1ck
ed57e72fa1 Translated using Weblate (French)
Currently translated at 96.9% (344 of 355 strings)
2018-04-14 11:39:07 +02:00
Dar Mackani
7e84c3e167 Translated using Weblate (Esperanto)
Currently translated at 18.3% (65 of 355 strings)
2018-04-14 11:39:07 +02:00
gensitu
4adc33471b Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (355 of 355 strings)
2018-04-14 11:39:06 +02:00
gensitu
31d07cc1e2 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (355 of 355 strings)
2018-04-14 11:39:05 +02:00
Andrea Troiano
a349a66d5a Translated using Weblate (Italian)
Currently translated at 100.0% (355 of 355 strings)
2018-04-14 11:38:59 +02:00
154 changed files with 3380 additions and 2266 deletions

View File

@@ -28,7 +28,7 @@ Do not report crashes in the GitHub issue tracker. NewPipe has an automated cras
* 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 (well, just look the other code and then do it the same way :))
* Do not bring non-free software (e.g., binary blobs) into the project. Also, make sure you do not introduce Google libraries. * Do not bring non-free software (e.g., binary blobs) into the project. Also, make sure you do not introduce Google 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 may then send your changes as a pull request on GitHub. Patches to the email address mentioned in this document might not be considered, GitHub is the primary platform. * Make changes on a separate branch, not on the master 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 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 [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html). * 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).
* 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! * Please test (compile and run) your code before you submit changes! Ideally, provide test feedback in the PR description. Untested code will **not** be merged!
* Try to figure out yourself why builds on our CI fail. * Try to figure out yourself why builds on our CI fail.

View File

@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe" applicationId "org.schabi.newpipe"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 27 targetSdkVersion 27
versionCode 61 versionCode 63
versionName "0.13.2" versionName "0.13.4"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@@ -41,7 +41,7 @@ android {
} }
ext { ext {
supportLibVersion = '27.1.0' supportLibVersion = '27.1.1'
exoPlayerLibVersion = '2.7.3' exoPlayerLibVersion = '2.7.3'
roomDbLibVersion = '1.0.0' roomDbLibVersion = '1.0.0'
leakCanaryLibVersion = '1.5.4' leakCanaryLibVersion = '1.5.4'
@@ -54,8 +54,7 @@ dependencies {
exclude module: 'support-annotations' exclude module: 'support-annotations'
} }
implementation 'com.github.TeamNewPipe:NewPipeExtractor:77a74b8' implementation 'com.github.TeamNewPipe:NewPipeExtractor:bf1c771'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19' testImplementation 'org.mockito:mockito-core:1.10.19'
@@ -66,7 +65,6 @@ dependencies {
implementation "com.android.support:recyclerview-v7:$supportLibVersion" implementation "com.android.support:recyclerview-v7:$supportLibVersion"
implementation "com.android.support:preference-v14:$supportLibVersion" implementation "com.android.support:preference-v14:$supportLibVersion"
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'ch.acra:acra:4.9.2' implementation 'ch.acra:acra:4.9.2'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

View File

@@ -80,8 +80,8 @@
android:name=".history.HistoryActivity" android:name=".history.HistoryActivity"
android:label="@string/title_activity_history"/> android:label="@string/title_activity_history"/>
<service android:name=".subscription.services.SubscriptionsImportService"/> <service android:name=".local.subscription.services.SubscriptionsImportService"/>
<service android:name=".subscription.services.SubscriptionsExportService"/> <service android:name=".local.subscription.services.SubscriptionsExportService"/>
<activity <activity
android:name=".PanicResponderActivity" android:name=".PanicResponderActivity"

View File

@@ -151,7 +151,8 @@ public class MainActivity extends AppCompatActivity {
settings.setOnClickListener(view -> NavigationHelper.openSettings(this)); settings.setOnClickListener(view -> NavigationHelper.openSettings(this));
downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this)); downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this));
history.setOnClickListener(view -> NavigationHelper.openHistory(this)); history.setOnClickListener(view ->
NavigationHelper.openStatisticFragment(getSupportFragmentManager()));
} }
private void setupDrawerHeader() { private void setupDrawerHeader() {
@@ -327,16 +328,16 @@ public class MainActivity extends AppCompatActivity {
case android.R.id.home: case android.R.id.home:
onHomeButtonPressed(); onHomeButtonPressed();
return true; return true;
case R.id.action_settings:
NavigationHelper.openSettings(this);
return true;
case R.id.action_show_downloads: case R.id.action_show_downloads:
return NavigationHelper.openDownloads(this); return NavigationHelper.openDownloads(this);
case R.id.action_history:
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
return true;
case R.id.action_about: case R.id.action_about:
NavigationHelper.openAbout(this); NavigationHelper.openAbout(this);
return true; return true;
case R.id.action_history: case R.id.action_settings:
NavigationHelper.openHistory(this); NavigationHelper.openSettings(this);
return true; return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@@ -32,10 +32,10 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.ChannelPlayQueue; import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@@ -59,7 +59,8 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer; import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.*; import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr; import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
/** /**
@@ -67,13 +68,10 @@ import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
*/ */
public class RouterActivity extends AppCompatActivity { public class RouterActivity extends AppCompatActivity {
@State @State protected int currentServiceId = -1;
protected int currentServiceId = -1;
private StreamingService currentService; private StreamingService currentService;
@State @State protected LinkType currentLinkType;
protected LinkType currentLinkType; @State protected int selectedRadioPosition = -1;
@State
protected int selectedRadioPosition = -1;
protected int selectedPreviously = -1; protected int selectedPreviously = -1;
protected String currentUrl; protected String currentUrl;
@@ -94,8 +92,7 @@ public class RouterActivity extends AppCompatActivity {
} }
setTheme(ThemeHelper.isLightThemeSelected(this) setTheme(ThemeHelper.isLightThemeSelected(this)
? R.style.RouterActivityThemeLight ? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
: R.style.RouterActivityThemeDark);
} }
@Override @Override
@@ -162,49 +159,65 @@ public class RouterActivity extends AppCompatActivity {
protected void onSuccess() { protected void onSuccess() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false); final String selectedChoiceKey = preferences.getString(getString(R.string.preferred_open_action_key), getString(R.string.preferred_open_action_default));
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
if ((isExtAudioEnabled || isExtVideoEnabled) && currentLinkType != LinkType.STREAM) {
Toast.makeText(this, R.string.external_player_unsupported_link_type, Toast.LENGTH_LONG).show();
finish();
return;
}
final String playerChoiceKey = preferences.getString(getString(R.string.preferred_open_action_key), getString(R.string.preferred_open_action_default));
final String showInfoKey = getString(R.string.show_info_key);
final String videoPlayerKey = getString(R.string.video_player_key); final String videoPlayerKey = getString(R.string.video_player_key);
final String backgroundPlayerKey = getString(R.string.background_player_key); final String backgroundPlayerKey = getString(R.string.background_player_key);
final String popupPlayerKey = getString(R.string.popup_player_key); final String popupPlayerKey = getString(R.string.popup_player_key);
final String alwaysAskKey = getString(R.string.always_ask_open_action_key); final String alwaysAskKey = getString(R.string.always_ask_open_action_key);
if (selectedChoiceKey.equals(alwaysAskKey)) {
final List<AdapterChoiceItem> choices = getChoicesForService(currentService, currentLinkType);
if (choices.size() == 1) {
handleChoice(choices.get(0).key);
} else if (choices.size() == 0) {
handleChoice(showInfoKey);
} else {
showDialog(choices);
}
} else if (selectedChoiceKey.equals(showInfoKey)) {
handleChoice(showInfoKey);
} else {
final boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
final boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
final boolean isVideoPlayerSelected = selectedChoiceKey.equals(videoPlayerKey) || selectedChoiceKey.equals(popupPlayerKey);
final boolean isAudioPlayerSelected = selectedChoiceKey.equals(backgroundPlayerKey);
if (currentLinkType != LinkType.STREAM) {
if (isExtAudioEnabled && isAudioPlayerSelected || isExtVideoEnabled && isVideoPlayerSelected) {
Toast.makeText(this, R.string.external_player_unsupported_link_type, Toast.LENGTH_LONG).show();
handleChoice(showInfoKey);
return;
}
}
final List<StreamingService.ServiceInfo.MediaCapability> capabilities = currentService.getServiceInfo().getMediaCapabilities(); final List<StreamingService.ServiceInfo.MediaCapability> capabilities = currentService.getServiceInfo().getMediaCapabilities();
boolean serviceSupportsPlayer = false; boolean serviceSupportsChoice = false;
if (playerChoiceKey.equals(videoPlayerKey) || playerChoiceKey.equals(popupPlayerKey)) { if (isVideoPlayerSelected) {
serviceSupportsPlayer = capabilities.contains(VIDEO); serviceSupportsChoice = capabilities.contains(VIDEO);
} else if (playerChoiceKey.equals(backgroundPlayerKey)) { } else if (selectedChoiceKey.equals(backgroundPlayerKey)) {
serviceSupportsPlayer = capabilities.contains(AUDIO); serviceSupportsChoice = capabilities.contains(AUDIO);
} }
if (playerChoiceKey.equals(alwaysAskKey) || !serviceSupportsPlayer) { if (serviceSupportsChoice) {
showDialog(); handleChoice(selectedChoiceKey);
} else { } else {
handleChoice(playerChoiceKey); handleChoice(showInfoKey);
}
} }
} }
private void showDialog() { private void showDialog(final List<AdapterChoiceItem> choices) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final ContextThemeWrapper themeWrapperContext = new ContextThemeWrapper(this, final Context themeWrapperContext = getThemeWrapperContext();
ThemeHelper.isLightThemeSelected(this) ? R.style.LightTheme : R.style.DarkTheme);
final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext); final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext);
final LinearLayout rootLayout = (LinearLayout) inflater.inflate(R.layout.preferred_player_dialog_view, null, false); final LinearLayout rootLayout = (LinearLayout) inflater.inflate(R.layout.preferred_player_dialog_view, null, false);
final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list); final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
final List<AdapterChoiceItem> choices = getChoicesForService(themeWrapperContext, currentService);
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> { final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
final int indexOfChild = radioGroup.indexOfChild( final int indexOfChild = radioGroup.indexOfChild(
radioGroup.findViewById(radioGroup.getCheckedRadioButtonId())); radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
@@ -278,21 +291,27 @@ public class RouterActivity extends AppCompatActivity {
alertDialog.show(); alertDialog.show();
} }
private List<AdapterChoiceItem> getChoicesForService(Context context, StreamingService service) { private List<AdapterChoiceItem> getChoicesForService(StreamingService service, LinkType linkType) {
final Context context = getThemeWrapperContext();
final List<AdapterChoiceItem> returnList = new ArrayList<>(); final List<AdapterChoiceItem> returnList = new ArrayList<>();
final List<StreamingService.ServiceInfo.MediaCapability> capabilities = service.getServiceInfo().getMediaCapabilities(); final List<StreamingService.ServiceInfo.MediaCapability> capabilities = service.getServiceInfo().getMediaCapabilities();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key), getString(R.string.show_info), returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key), getString(R.string.show_info),
resolveResourceIdFromAttr(context, R.attr.info))); resolveResourceIdFromAttr(context, R.attr.info)));
if (capabilities.contains(VIDEO)) { if (capabilities.contains(VIDEO) && !(isExtVideoEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.video_player_key), getString(R.string.video_player), returnList.add(new AdapterChoiceItem(getString(R.string.video_player_key), getString(R.string.video_player),
resolveResourceIdFromAttr(context, R.attr.play))); resolveResourceIdFromAttr(context, R.attr.play)));
returnList.add(new AdapterChoiceItem(getString(R.string.popup_player_key), getString(R.string.popup_player), returnList.add(new AdapterChoiceItem(getString(R.string.popup_player_key), getString(R.string.popup_player),
resolveResourceIdFromAttr(context, R.attr.popup))); resolveResourceIdFromAttr(context, R.attr.popup)));
} }
if (capabilities.contains(AUDIO)) { if (capabilities.contains(AUDIO) && !(isExtAudioEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.background_player_key), getString(R.string.background_player), returnList.add(new AdapterChoiceItem(getString(R.string.background_player_key), getString(R.string.background_player),
resolveResourceIdFromAttr(context, R.attr.audio))); resolveResourceIdFromAttr(context, R.attr.audio)));
} }
@@ -300,6 +319,11 @@ public class RouterActivity extends AppCompatActivity {
return returnList; return returnList;
} }
private Context getThemeWrapperContext() {
return new ContextThemeWrapper(this,
ThemeHelper.isLightThemeSelected(this) ? R.style.LightTheme : R.style.DarkTheme);
}
private void setDialogButtonsState(AlertDialog dialog, boolean state) { private void setDialogButtonsState(AlertDialog dialog, boolean state) {
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE); final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
@@ -309,15 +333,15 @@ public class RouterActivity extends AppCompatActivity {
positiveButton.setEnabled(state); positiveButton.setEnabled(state);
} }
private void handleChoice(final String playerChoiceKey) { private void handleChoice(final String selectedChoiceKey) {
final List<String> validChoicesList = Arrays.asList(getResources().getStringArray(R.array.preferred_open_action_values_list)); final List<String> validChoicesList = Arrays.asList(getResources().getStringArray(R.array.preferred_open_action_values_list));
if (validChoicesList.contains(playerChoiceKey)) { if (validChoicesList.contains(selectedChoiceKey)) {
PreferenceManager.getDefaultSharedPreferences(this).edit() PreferenceManager.getDefaultSharedPreferences(this).edit()
.putString(getString(R.string.preferred_open_action_last_selected_key), playerChoiceKey) .putString(getString(R.string.preferred_open_action_last_selected_key), selectedChoiceKey)
.apply(); .apply();
} }
if (playerChoiceKey.equals(getString(R.string.popup_player_key)) && !PermissionHelper.isPopupEnabled(this)) { if (selectedChoiceKey.equals(getString(R.string.popup_player_key)) && !PermissionHelper.isPopupEnabled(this)) {
PermissionHelper.showPopupEnablementToast(this); PermissionHelper.showPopupEnablementToast(this);
finish(); finish();
return; return;
@@ -325,7 +349,7 @@ public class RouterActivity extends AppCompatActivity {
// stop and bypass FetcherService if InfoScreen was selected since // stop and bypass FetcherService if InfoScreen was selected since
// StreamDetailFragment can fetch data itself // StreamDetailFragment can fetch data itself
if (playerChoiceKey.equals(getString(R.string.show_info_key))) { if (selectedChoiceKey.equals(getString(R.string.show_info_key))) {
disposables.add(Observable disposables.add(Observable
.fromCallable(() -> NavigationHelper.getIntentByLink(this, currentUrl)) .fromCallable(() -> NavigationHelper.getIntentByLink(this, currentUrl))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@@ -342,7 +366,7 @@ public class RouterActivity extends AppCompatActivity {
} }
final Intent intent = new Intent(this, FetcherService.class); final Intent intent = new Intent(this, FetcherService.class);
final Choice choice = new Choice(currentService.getServiceId(), currentLinkType, currentUrl, playerChoiceKey); final Choice choice = new Choice(currentService.getServiceId(), currentLinkType, currentUrl, selectedChoiceKey);
intent.putExtra(FetcherService.KEY_CHOICE, choice); intent.putExtra(FetcherService.KEY_CHOICE, choice);
startService(intent); startService(intent);

View File

@@ -32,7 +32,6 @@ public class AboutActivity extends AppCompatActivity {
new SoftwareComponent("Giga Get", "2014", "Peter Cai", "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL2), new SoftwareComponent("Giga Get", "2014", "Peter Cai", "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL2),
new SoftwareComponent("NewPipe Extractor", "2017", "Christian Schabesberger", "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3), new SoftwareComponent("NewPipe Extractor", "2017", "Christian Schabesberger", "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3),
new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley", "https://github.com/jhy/jsoup", StandardLicenses.MIT), new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley", "https://github.com/jhy/jsoup", StandardLicenses.MIT),
new SoftwareComponent("Google Gson", "2008", "Google Inc", "https://github.com/google/gson", StandardLicenses.APACHE2),
new SoftwareComponent("Rhino", "2015", "Mozilla", "https://www.mozilla.org/rhino/", StandardLicenses.MPL2), new SoftwareComponent("Rhino", "2015", "Mozilla", "https://www.mozilla.org/rhino/", StandardLicenses.MPL2),
new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", "http://www.acra.ch", StandardLicenses.APACHE2), new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", "http://www.acra.ch", StandardLicenses.APACHE2),
new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich", "https://github.com/nostra13/Android-Universal-Image-Loader", StandardLicenses.APACHE2), new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich", "https://github.com/nostra13/Android-Universal-Image-Loader", StandardLicenses.APACHE2),
@@ -129,47 +128,31 @@ public class AboutActivity extends AppCompatActivity {
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { 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();
TextView version = rootView.findViewById(R.id.app_version); TextView version = rootView.findViewById(R.id.app_version);
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(new OnGithubLinkClickListener()); 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(new OnDonationLinkClickListener()); 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(new OnWebsiteLinkClickListener()); websiteLink.setOnClickListener(nv -> openWebsite(context.getString(R.string.website_url), context));
View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
privacyPolicyLink.setOnClickListener(v -> openWebsite(context.getString(R.string.privacy_policy_url), context));
return rootView; return rootView;
} }
private static class OnGithubLinkClickListener implements View.OnClickListener { private void openWebsite(String url, Context context) {
@Override Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.github_url)));
context.startActivity(intent); context.startActivity(intent);
} }
}
private static class OnDonationLinkClickListener implements View.OnClickListener {
@Override
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.donation_url)));
context.startActivity(intent);
}
}
private static class OnWebsiteLinkClickListener implements View.OnClickListener {
@Override
public void onClick(final View view) {
final Context context = view.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.website_url)));
context.startActivity(intent);
}
}
} }

View File

@@ -1,5 +1,6 @@
package org.schabi.newpipe.about; package org.schabi.newpipe.about;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
@@ -39,7 +40,7 @@ public class LicenseFragment extends Fragment {
* @param license the license to show * @param license the license to show
*/ */
public static void showLicense(Context context, License license) { public static void showLicense(Context context, License license) {
new LicenseFragmentHelper().execute(context, license); new LicenseFragmentHelper((Activity) context).execute(license);
} }
@Override @Override

View File

@@ -1,8 +1,11 @@
package org.schabi.newpipe.about; package org.schabi.newpipe.about;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.webkit.WebView; import android.webkit.WebView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@@ -10,26 +13,46 @@ import org.schabi.newpipe.util.ThemeHelper;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> { public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
private Context context; WeakReference<Activity> weakReference;
private License license; private License license;
public LicenseFragmentHelper(@Nullable Activity activity) {
weakReference = new WeakReference<>(activity);
}
@Nullable
private Activity getActivity() {
Activity activity = weakReference.get();
if (activity != null && activity.isFinishing()) {
return null;
} else {
return activity;
}
}
@Override @Override
protected Integer doInBackground(Object... objects) { protected Integer doInBackground(Object... objects) {
context = (Context) objects[0]; license = (License) objects[0];
license = (License) objects[1];
return 1; return 1;
} }
@Override @Override
protected void onPostExecute(Integer result) { protected void onPostExecute(Integer result) {
String webViewData = getFormattedLicense(context, license); Activity activity = getActivity();
AlertDialog.Builder alert = new AlertDialog.Builder(context); if (activity == null) {
return;
}
String webViewData = getFormattedLicense(activity, license);
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle(license.getName()); alert.setTitle(license.getName());
WebView wv = new WebView(context); WebView wv = new WebView(activity);
wv.loadData(webViewData, "text/html; charset=UTF-8", null); wv.loadData(webViewData, "text/html; charset=UTF-8", null);
alert.setView(wv); alert.setView(wv);

View File

@@ -9,7 +9,7 @@ import android.arch.persistence.room.PrimaryKey;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import java.io.Serializable; import java.io.Serializable;

View File

@@ -239,7 +239,8 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
if (rootView == null && getView() != null) rootView = getView(); if (rootView == null && getView() != null) rootView = getView();
if (rootView == null) return; if (rootView == null) return;
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId)); ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView,
ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View File

@@ -27,10 +27,10 @@ import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.kiosk.KioskList; import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.feed.FeedFragment; import org.schabi.newpipe.local.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment; import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.local.bookmark.BookmarkFragment; import org.schabi.newpipe.local.bookmark.BookmarkFragment;
import org.schabi.newpipe.fragments.subscription.SubscriptionFragment; import org.schabi.newpipe.local.subscription.SubscriptionFragment;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.KioskTranslator;

View File

@@ -64,15 +64,15 @@ import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.util.StreamItemAdapter; import org.schabi.newpipe.util.StreamItemAdapter;
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper; import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;

View File

@@ -20,10 +20,10 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.StateSaver; import org.schabi.newpipe.util.StateSaver;
@@ -140,9 +140,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() { infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() {
@Override @Override
public void selected(StreamInfoItem selectedItem) { public void selected(StreamInfoItem selectedItem) {
onItemSelected(selectedItem); onStreamSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
} }
@Override @Override
@@ -178,6 +176,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
}); });
} }
private void onStreamSelected(StreamInfoItem selectedItem) {
onItemSelected(selectedItem);
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
}
protected void onScrollToBottom() { protected void onScrollToBottom() {
if (hasMoreItems() && !isLoading.get()) { if (hasMoreItems() && !isLoading.get()) {
loadMoreItems(); loadMoreItems();
@@ -216,6 +220,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
new InfoItemDialog(getActivity(), item, commands, actions).show(); new InfoItemDialog(getActivity(), item, commands, actions).show();
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Menu // Menu
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@@ -32,17 +32,15 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.ChannelPlayQueue; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.subscription.SubscriptionService; import org.schabi.newpipe.local.subscription.SubscriptionService;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;

View File

@@ -77,8 +77,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
UrlIdHandler kioskTypeUrlIdHandler = service.getKioskList() UrlIdHandler kioskTypeUrlIdHandler = service.getKioskList()
.getUrlIdHandlerByType(kioskId); .getUrlIdHandlerByType(kioskId);
instance.setInitialData(serviceId, instance.setInitialData(serviceId,
kioskTypeUrlIdHandler.getUrl(kioskId), kioskTypeUrlIdHandler.getUrl(kioskId), kioskId);
kioskId);
instance.kioskId = kioskId; instance.kioskId = kioskId;
return instance; return instance;
} }

View File

@@ -27,14 +27,13 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.fragments.local.RemotePlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;

View File

@@ -41,7 +41,7 @@ import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult; import org.schabi.newpipe.extractor.search.SearchResult;
import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
@@ -544,7 +544,7 @@ public class SearchFragment
howManyDeleted -> suggestionPublisher howManyDeleted -> suggestionPublisher
.onNext(searchEditText.getText().toString()), .onNext(searchEditText.getText().toString()),
throwable -> showSnackBarError(throwable, throwable -> showSnackBarError(throwable,
UserAction.SOMETHING_ELSE, "none", UserAction.DELETE_FROM_HISTORY, "none",
"Deleting item failed", R.string.general_error) "Deleting item failed", R.string.general_error)
); );
disposables.add(onDelete); disposables.add(onDelete);

View File

@@ -63,24 +63,15 @@ public class SuggestionListAdapter extends RecyclerView.Adapter<SuggestionListAd
public void onBindViewHolder(SuggestionItemHolder holder, int position) { public void onBindViewHolder(SuggestionItemHolder holder, int position) {
final SuggestionItem currentItem = getItem(position); final SuggestionItem currentItem = getItem(position);
holder.updateFrom(currentItem); holder.updateFrom(currentItem);
holder.queryView.setOnClickListener(new View.OnClickListener() { holder.queryView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
if (listener != null) listener.onSuggestionItemSelected(currentItem); if (listener != null) listener.onSuggestionItemSelected(currentItem);
}
}); });
holder.queryView.setOnLongClickListener(new View.OnLongClickListener() { holder.queryView.setOnLongClickListener(v -> {
@Override
public boolean onLongClick(View v) {
if (listener != null) listener.onSuggestionItemLongClick(currentItem); if (listener != null) listener.onSuggestionItemLongClick(currentItem);
return true; return true;
}
}); });
holder.insertView.setOnClickListener(new View.OnClickListener() { holder.insertView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
if (listener != null) listener.onSuggestionItemInserted(currentItem); if (listener != null) listener.onSuggestionItemInserted(currentItem);
}
}); });
} }

View File

@@ -1,21 +0,0 @@
package org.schabi.newpipe.fragments.local.bookmark;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import java.util.Collections;
import java.util.List;
public final class LastPlayedFragment extends StatisticsPlaylistFragment {
@Override
protected String getName() {
return getString(R.string.title_last_played);
}
@Override
protected List<StreamStatisticsEntry> processResult(List<StreamStatisticsEntry> results) {
Collections.sort(results, (left, right) ->
right.latestAccessDate.compareTo(left.latestAccessDate));
return results;
}
}

View File

@@ -1,22 +0,0 @@
package org.schabi.newpipe.fragments.local.bookmark;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import java.util.Collections;
import java.util.List;
public final class MostPlayedFragment extends StatisticsPlaylistFragment {
@Override
protected String getName() {
return getString(R.string.title_most_played);
}
@Override
protected List<StreamStatisticsEntry> processResult(List<StreamStatisticsEntry> results) {
Collections.sort(results, (left, right) ->
((Long) right.watchCount).compareTo(left.watchCount));
return results;
}
}

View File

@@ -1,141 +0,0 @@
package org.schabi.newpipe.history;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import com.jakewharton.rxbinding2.view.RxView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ThemeHelper;
import io.reactivex.android.schedulers.AndroidSchedulers;
public class HistoryActivity extends AppCompatActivity {
private static final String TAG = "HistoryActivity";
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
setContentView(R.layout.activity_history);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.title_activity_history);
}
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
final FloatingActionButton fab = findViewById(R.id.fab);
RxView.clicks(fab)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ignored -> {
int currentItem = mViewPager.getCurrentItem();
HistoryFragment fragment = (HistoryFragment) mSectionsPagerAdapter
.instantiateItem(mViewPager, currentItem);
fragment.onHistoryCleared();
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_history, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.action_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment;
switch (position) {
case 0:
fragment = SearchHistoryFragment.newInstance();
break;
case 1:
fragment = WatchHistoryFragment.newInstance();
break;
default:
throw new IllegalArgumentException("position: " + position);
}
return fragment;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.title_history_search);
case 1:
return getString(R.string.title_history_view);
}
throw new IllegalArgumentException("position: " + position);
}
@Override
public int getCount() {
// Show 3 total pages.
return 2;
}
}
}

View File

@@ -1,286 +0,0 @@
package org.schabi.newpipe.history;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.annotation.CallSuper;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import icepick.State;
import io.reactivex.Flowable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
public abstract class HistoryFragment<E> extends BaseFragment
implements HistoryEntryAdapter.OnHistoryItemClickListener<E> {
private SharedPreferences mSharedPreferences;
private String mHistoryIsEnabledKey;
private boolean mHistoryIsEnabled;
private HistoryIsEnabledChangeListener mHistoryIsEnabledChangeListener;
private View mDisabledView;
private View mEmptyHistoryView;
@State
Parcelable mRecyclerViewState;
private RecyclerView mRecyclerView;
private HistoryEntryAdapter<E, ? extends RecyclerView.ViewHolder> mHistoryAdapter;
private Subscription historySubscription;
protected HistoryRecordManager historyRecordManager;
protected CompositeDisposable disposables;
@StringRes
abstract int getEnabledConfigKey();
@CallSuper
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHistoryIsEnabledKey = getString(getEnabledConfigKey());
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
// Read history enabled from preferences
mHistoryIsEnabled = isHistoryEnabled();
// Register history enabled listener
mSharedPreferences.registerOnSharedPreferenceChangeListener(mHistoryIsEnabledChangeListener);
historyRecordManager = new HistoryRecordManager(getContext());
disposables = new CompositeDisposable();
}
@NonNull
protected abstract HistoryEntryAdapter<E, ? extends RecyclerView.ViewHolder> createAdapter();
protected abstract Single<List<Long>> insert(final Collection<E> entries);
protected abstract Single<Integer> delete(final Collection<E> entries);
@NonNull
protected abstract Flowable<List<E>> getAll();
@Override
public void onResume() {
super.onResume();
getAll().observeOn(AndroidSchedulers.mainThread()).subscribe(getHistorySubscriber());
final boolean newEnabled = isHistoryEnabled();
if (newEnabled != mHistoryIsEnabled) {
onHistoryIsEnabledChanged(newEnabled);
}
}
@NonNull
private Subscriber<List<E>> getHistorySubscriber() {
return new Subscriber<List<E>>() {
@Override
public void onSubscribe(Subscription s) {
if (historySubscription != null) historySubscription.cancel();
historySubscription = s;
historySubscription.request(1);
}
@Override
public void onNext(List<E> entries) {
if (!entries.isEmpty()) {
mHistoryAdapter.setEntries(entries);
animateView(mEmptyHistoryView, false, 200);
if (mRecyclerViewState != null) {
mRecyclerView.getLayoutManager().onRestoreInstanceState(mRecyclerViewState);
mRecyclerViewState = null;
}
} else {
mHistoryAdapter.clear();
showEmptyHistory();
}
if (historySubscription != null) historySubscription.request(1);
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
};
}
private boolean isHistoryEnabled() {
return mSharedPreferences.getBoolean(mHistoryIsEnabledKey, false);
}
/**
* Called when the history is cleared to update the views
*/
@MainThread
public void onHistoryCleared() {
if (getContext() == null) return;
new AlertDialog.Builder(getContext())
.setTitle(R.string.delete_all)
.setMessage(R.string.delete_all_history_prompt)
.setCancelable(true)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.delete_all, (dialog, i) -> clearHistory())
.show();
}
protected void makeSnackbar(@StringRes final int text) {
if (getActivity() == null) return;
View view = getActivity().findViewById(R.id.main_content);
if (view == null) view = mRecyclerView.getRootView();
Snackbar.make(view, text, Snackbar.LENGTH_LONG).show();
}
private void clearHistory() {
final Collection<E> itemsToDelete = new ArrayList<>(mHistoryAdapter.getItems());
final Disposable deletion = delete(itemsToDelete)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> Log.d(TAG, "Clear history deleted [" +
itemsToDelete.size() + "] items."),
error -> Log.e(TAG, "Clear history delete step failed", error)
);
final Disposable cleanUp = historyRecordManager.removeOrphanedRecords()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> Log.d(TAG, "Clear history deleted orphaned stream records"),
error -> Log.e(TAG, "Clear history remove orphaned records failed", error)
);
disposables.addAll(deletion, cleanUp);
makeSnackbar(R.string.history_cleared);
mHistoryAdapter.clear();
showEmptyHistory();
}
private void showEmptyHistory() {
if (mHistoryIsEnabled) {
animateView(mEmptyHistoryView, true, 200);
}
}
@Nullable
@CallSuper
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_history, container, false);
mRecyclerView = rootView.findViewById(R.id.history_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext(),
LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mHistoryAdapter = createAdapter();
mHistoryAdapter.setOnHistoryItemClickListener(this);
mRecyclerView.setAdapter(mHistoryAdapter);
mDisabledView = rootView.findViewById(R.id.history_disabled_view);
mEmptyHistoryView = rootView.findViewById(R.id.history_empty);
if (mHistoryIsEnabled) {
mRecyclerView.setVisibility(View.VISIBLE);
} else {
mRecyclerView.setVisibility(View.GONE);
mDisabledView.setVisibility(View.VISIBLE);
}
return rootView;
}
@CallSuper
@Override
public void onDestroy() {
super.onDestroy();
if (disposables != null) disposables.dispose();
if (historySubscription != null) historySubscription.cancel();
mSharedPreferences.unregisterOnSharedPreferenceChangeListener(mHistoryIsEnabledChangeListener);
mSharedPreferences = null;
mHistoryIsEnabledChangeListener = null;
mHistoryIsEnabledKey = null;
historySubscription = null;
disposables = null;
}
@Override
public void onPause() {
super.onPause();
mRecyclerViewState = mRecyclerView.getLayoutManager().onSaveInstanceState();
}
/**
* Called when history enabled flag is changed.
*
* @param historyIsEnabled the new value
*/
@CallSuper
public void onHistoryIsEnabledChanged(boolean historyIsEnabled) {
mHistoryIsEnabled = historyIsEnabled;
if (historyIsEnabled) {
animateView(mRecyclerView, true, 300);
animateView(mDisabledView, false, 300);
if (mHistoryAdapter.isEmpty()) {
animateView(mEmptyHistoryView, true, 300);
}
} else {
animateView(mRecyclerView, false, 300);
animateView(mDisabledView, true, 300);
animateView(mEmptyHistoryView, false, 300);
}
}
private class HistoryIsEnabledChangeListener
implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(mHistoryIsEnabledKey)) {
boolean enabled = sharedPreferences.getBoolean(key, false);
if (mHistoryIsEnabled != enabled) {
onHistoryIsEnabledChanged(enabled);
}
}
}
}
}

View File

@@ -1,145 +0,0 @@
package org.schabi.newpipe.history;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import io.reactivex.Flowable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
public class SearchHistoryFragment extends HistoryFragment<SearchHistoryEntry> {
@NonNull
public static SearchHistoryFragment newInstance() {
return new SearchHistoryFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@NonNull
@Override
protected SearchHistoryAdapter createAdapter() {
return new SearchHistoryAdapter(getContext());
}
@Override
protected Single<List<Long>> insert(Collection<SearchHistoryEntry> entries) {
return historyRecordManager.insertSearches(entries);
}
@Override
protected Single<Integer> delete(Collection<SearchHistoryEntry> entries) {
return historyRecordManager.deleteSearches(entries);
}
@NonNull
@Override
protected Flowable<List<SearchHistoryEntry>> getAll() {
return historyRecordManager.getSearchHistory();
}
@StringRes
@Override
int getEnabledConfigKey() {
return R.string.enable_search_history_key;
}
@Override
public void onHistoryItemClick(final SearchHistoryEntry historyItem) {
NavigationHelper.openSearch(getContext(), historyItem.getServiceId(),
historyItem.getSearch());
}
@Override
public void onHistoryItemLongClick(final SearchHistoryEntry item) {
if (activity == null) return;
new AlertDialog.Builder(activity)
.setTitle(item.getSearch())
.setMessage(R.string.delete_item_search_history)
.setCancelable(true)
.setNeutralButton(R.string.cancel, null)
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
final Disposable onDelete = historyRecordManager
.deleteSearches(Collections.singleton(item))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {/*successful*/},
error -> Log.e(TAG, "Search history Delete One failed:", error)
);
disposables.add(onDelete);
makeSnackbar(R.string.item_deleted);
})
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
final Disposable onDeleteAll = historyRecordManager
.deleteSearchHistory(item.getSearch())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {/*successful*/},
error -> Log.e(TAG, "Search history Delete All failed:", error)
);
disposables.add(onDeleteAll);
makeSnackbar(R.string.item_deleted);
})
.show();
}
private static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView search;
private final TextView info;
public ViewHolder(View itemView) {
super(itemView);
search = itemView.findViewById(R.id.search);
info = itemView.findViewById(R.id.info);
}
}
protected class SearchHistoryAdapter extends HistoryEntryAdapter<SearchHistoryEntry, ViewHolder> {
SearchHistoryAdapter(Context context) {
super(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View rootView = inflater.inflate(R.layout.item_search_history, parent, false);
return new ViewHolder(rootView);
}
@Override
void onBindViewHolder(ViewHolder holder, SearchHistoryEntry entry, int position) {
holder.search.setText(entry.getSearch());
final String info = Localization.concatenateStrings(
getFormattedDate(entry.getCreationDate()),
NewPipe.getNameOfService(entry.getServiceId()));
holder.info.setText(info);
}
}
}

View File

@@ -1,171 +0,0 @@
package org.schabi.newpipe.history;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import io.reactivex.Flowable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
public class WatchHistoryFragment extends HistoryFragment<StreamHistoryEntry> {
@NonNull
public static WatchHistoryFragment newInstance() {
return new WatchHistoryFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@StringRes
@Override
int getEnabledConfigKey() {
return R.string.enable_watch_history_key;
}
@NonNull
@Override
protected StreamHistoryAdapter createAdapter() {
return new StreamHistoryAdapter(getContext());
}
@Override
protected Single<List<Long>> insert(Collection<StreamHistoryEntry> entries) {
return historyRecordManager.insertStreamHistory(entries);
}
@Override
protected Single<Integer> delete(Collection<StreamHistoryEntry> entries) {
return historyRecordManager.deleteStreamHistory(entries);
}
@NonNull
@Override
protected Flowable<List<StreamHistoryEntry>> getAll() {
return historyRecordManager.getStreamHistory();
}
@Override
public void onHistoryItemClick(StreamHistoryEntry historyItem) {
NavigationHelper.openVideoDetail(getContext(), historyItem.serviceId, historyItem.url,
historyItem.title);
}
@Override
public void onHistoryItemLongClick(StreamHistoryEntry item) {
new AlertDialog.Builder(activity)
.setTitle(item.title)
.setMessage(R.string.delete_stream_history_prompt)
.setCancelable(true)
.setNeutralButton(R.string.cancel, null)
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
final Disposable onDelete = historyRecordManager
.deleteStreamHistory(Collections.singleton(item))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {/*successful*/},
error -> Log.e(TAG, "Watch history Delete One failed:", error)
);
disposables.add(onDelete);
makeSnackbar(R.string.item_deleted);
})
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
final Disposable onDeleteAll = historyRecordManager
.deleteStreamHistory(item.streamId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ignored -> {/*successful*/},
error -> Log.e(TAG, "Watch history Delete All failed:", error)
);
disposables.add(onDeleteAll);
makeSnackbar(R.string.item_deleted);
})
.show();
}
private static class StreamHistoryAdapter extends HistoryEntryAdapter<StreamHistoryEntry, ViewHolder> {
StreamHistoryAdapter(Context context) {
super(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.list_stream_item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onViewRecycled(ViewHolder holder) {
holder.itemView.setOnClickListener(null);
ImageLoader.getInstance()
.cancelDisplayTask(holder.thumbnailView);
}
@Override
void onBindViewHolder(ViewHolder holder, StreamHistoryEntry entry, int position) {
final String formattedDate = getFormattedDate(entry.accessDate);
final String info;
if (entry.repeatCount > 1) {
info = Localization.concatenateStrings(formattedDate,
getFormattedViewString(entry.repeatCount));
} else {
info = formattedDate;
}
holder.info.setText(info);
holder.streamTitle.setText(entry.title);
holder.uploader.setText(entry.uploader);
holder.duration.setText(Localization.getDurationString(entry.duration));
ImageLoader.getInstance().displayImage(entry.thumbnailUrl, holder.thumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
}
}
private static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView info;
private final TextView streamTitle;
private final ImageView thumbnailView;
private final TextView uploader;
private final TextView duration;
public ViewHolder(View itemView) {
super(itemView);
thumbnailView = itemView.findViewById(R.id.itemThumbnailView);
info = itemView.findViewById(R.id.itemAdditionalDetails);
streamTitle = itemView.findViewById(R.id.itemVideoTitleView);
uploader = itemView.findViewById(R.id.itemUploaderView);
duration = itemView.findViewById(R.id.itemDurationView);
}
}
}

View File

@@ -17,6 +17,7 @@ import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder; import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import java.util.ArrayList; import java.util.ArrayList;
@@ -238,7 +239,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return new PlaylistInfoItemHolder(infoItemBuilder, parent); return new PlaylistInfoItemHolder(infoItemBuilder, parent);
default: default:
Log.e(TAG, "Trollolo"); Log.e(TAG, "Trollolo");
return null; return new FallbackViewHolder(new View(parent.getContext()));
} }
} }

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.bookmark; package org.schabi.newpipe.local;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@@ -13,7 +13,6 @@ import android.view.View;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.list.ListViewContract; import org.schabi.newpipe.fragments.list.ListViewContract;
import org.schabi.newpipe.fragments.local.LocalItemListAdapter;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local; package org.schabi.newpipe.local;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local; package org.schabi.newpipe.local;
import android.content.Context; import android.content.Context;
import android.widget.ImageView; import android.widget.ImageView;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local; package org.schabi.newpipe.local;
import android.app.Activity; import android.app.Activity;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@@ -7,11 +7,14 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.fragments.local.holder.LocalItemHolder; import org.schabi.newpipe.local.HeaderFooterHolder;
import org.schabi.newpipe.fragments.local.holder.LocalPlaylistItemHolder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.fragments.local.holder.LocalPlaylistStreamItemHolder; import org.schabi.newpipe.local.holder.LocalItemHolder;
import org.schabi.newpipe.fragments.local.holder.LocalStatisticStreamItemHolder; import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
import org.schabi.newpipe.fragments.local.holder.RemotePlaylistItemHolder; import org.schabi.newpipe.local.holder.LocalPlaylistStreamItemHolder;
import org.schabi.newpipe.local.holder.LocalStatisticStreamItemHolder;
import org.schabi.newpipe.local.holder.RemotePlaylistItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
@@ -223,7 +226,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
return new LocalStatisticStreamItemHolder(localItemBuilder, parent); return new LocalStatisticStreamItemHolder(localItemBuilder, parent);
default: default:
Log.e(TAG, "No view type has been considered for holder: [" + type + "]"); Log.e(TAG, "No view type has been considered for holder: [" + type + "]");
return null; return new FallbackViewHolder(new View(parent.getContext()));
} }
} }

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.bookmark; package org.schabi.newpipe.local.bookmark;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.os.Bundle; import android.os.Bundle;
@@ -19,8 +19,9 @@ import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.fragments.local.LocalPlaylistManager; import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.fragments.local.RemotePlaylistManager; import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
@@ -38,9 +39,6 @@ import io.reactivex.disposables.CompositeDisposable;
public final class BookmarkFragment public final class BookmarkFragment
extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> { extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
private View lastPlayedButton;
private View mostPlayedButton;
@State @State
protected Parcelable itemsListState; protected Parcelable itemsListState;
@@ -94,15 +92,6 @@ public final class BookmarkFragment
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
} }
@Override
protected View getListHeader() {
final View headerRootLayout = activity.getLayoutInflater()
.inflate(R.layout.bookmark_header, itemsList, false);
lastPlayedButton = headerRootLayout.findViewById(R.id.lastPlayed);
mostPlayedButton = headerRootLayout.findViewById(R.id.mostPlayed);
return headerRootLayout;
}
@Override @Override
protected void initListeners() { protected void initListeners() {
super.initListeners(); super.initListeners();
@@ -136,18 +125,6 @@ public final class BookmarkFragment
} }
} }
}); });
lastPlayedButton.setOnClickListener(view -> {
if (getParentFragment() != null) {
NavigationHelper.openLastPlayedFragment(getParentFragment().getFragmentManager());
}
});
mostPlayedButton.setOnClickListener(view -> {
if (getParentFragment() != null) {
NavigationHelper.openMostPlayedFragment(getParentFragment().getFragmentManager());
}
});
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@@ -180,8 +157,6 @@ public final class BookmarkFragment
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
if (mostPlayedButton != null) mostPlayedButton.setOnClickListener(null);
if (lastPlayedButton != null) lastPlayedButton.setOnClickListener(null);
if (disposables != null) disposables.clear(); if (disposables != null) disposables.clear();
if (databaseSubscription != null) databaseSubscription.cancel(); if (databaseSubscription != null) databaseSubscription.cancel();

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.dialog; package org.schabi.newpipe.local.dialog;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Bundle; import android.os.Bundle;
@@ -18,9 +18,9 @@ import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.local.LocalItemListAdapter; import org.schabi.newpipe.local.LocalItemListAdapter;
import org.schabi.newpipe.fragments.local.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.dialog; package org.schabi.newpipe.local.dialog;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@@ -12,7 +12,7 @@ import android.widget.Toast;
import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.fragments.local.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.dialog; package org.schabi.newpipe.local.dialog;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.list.feed; package org.schabi.newpipe.local.feed;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@@ -22,7 +22,7 @@ import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.subscription.SubscriptionService; import org.schabi.newpipe.local.subscription.SubscriptionService;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.history; package org.schabi.newpipe.local.history;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.history; package org.schabi.newpipe.local.history;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;

View File

@@ -1,4 +1,22 @@
package org.schabi.newpipe.history; package org.schabi.newpipe.local.history;
/*
* Copyright (C) Mauricio Colli 2018
* HistoryRecordManager.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@@ -27,6 +45,7 @@ import java.util.List;
import io.reactivex.Flowable; import io.reactivex.Flowable;
import io.reactivex.Maybe; import io.reactivex.Maybe;
import io.reactivex.Scheduler;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@@ -80,6 +99,11 @@ public class HistoryRecordManager {
.subscribeOn(Schedulers.io()); .subscribeOn(Schedulers.io());
} }
public Single<Integer> deleteWholeStreamHistory() {
return Single.fromCallable(() -> streamHistoryTable.deleteAll())
.subscribeOn(Schedulers.io());
}
public Flowable<List<StreamHistoryEntry>> getStreamHistory() { public Flowable<List<StreamHistoryEntry>> getStreamHistory() {
return streamHistoryTable.getHistory().subscribeOn(Schedulers.io()); return streamHistoryTable.getHistory().subscribeOn(Schedulers.io());
} }
@@ -114,20 +138,6 @@ public class HistoryRecordManager {
// Search History // Search History
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
public Single<List<Long>> insertSearches(final Collection<SearchHistoryEntry> entries) {
return Single.fromCallable(() -> searchHistoryTable.insertAll(entries))
.subscribeOn(Schedulers.io());
}
public Single<Integer> deleteSearches(final Collection<SearchHistoryEntry> entries) {
return Single.fromCallable(() -> searchHistoryTable.delete(entries))
.subscribeOn(Schedulers.io());
}
public Flowable<List<SearchHistoryEntry>> getSearchHistory() {
return searchHistoryTable.getAll();
}
public Maybe<Long> onSearched(final int serviceId, final String search) { public Maybe<Long> onSearched(final int serviceId, final String search) {
if (!isSearchHistoryEnabled()) return Maybe.empty(); if (!isSearchHistoryEnabled()) return Maybe.empty();
@@ -150,6 +160,11 @@ public class HistoryRecordManager {
.subscribeOn(Schedulers.io()); .subscribeOn(Schedulers.io());
} }
public Single<Integer> deleteWholeSearchHistory() {
return Single.fromCallable(() -> searchHistoryTable.deleteAll())
.subscribeOn(Schedulers.io());
}
public Flowable<List<SearchHistoryEntry>> getRelatedSearches(final String query, public Flowable<List<SearchHistoryEntry>> getRelatedSearches(final String query,
final int similarQueryLimit, final int similarQueryLimit,
final int uniqueQueryLimit) { final int uniqueQueryLimit) {

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.bookmark; package org.schabi.newpipe.local.history;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@@ -7,9 +7,13 @@ import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription; import org.reactivestreams.Subscription;
@@ -17,13 +21,14 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry; import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.history.HistoryRecordManager; import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.ThemeHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -31,13 +36,19 @@ import java.util.List;
import icepick.State; import icepick.State;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
public abstract class StatisticsPlaylistFragment public class StatisticsPlaylistFragment
extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> { extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> {
private View headerPlayAllButton; private View headerPlayAllButton;
private View headerPopupButton; private View headerPopupButton;
private View headerBackgroundButton; private View headerBackgroundButton;
private View playlistCtrl;
private View sortButton;
private ImageView sortButtonIcon;
private TextView sortButtonText;
@State @State
protected Parcelable itemsListState; protected Parcelable itemsListState;
@@ -45,14 +56,28 @@ public abstract class StatisticsPlaylistFragment
/* Used for independent events */ /* Used for independent events */
private Subscription databaseSubscription; private Subscription databaseSubscription;
private HistoryRecordManager recordManager; private HistoryRecordManager recordManager;
private CompositeDisposable disposables = new CompositeDisposable();
/////////////////////////////////////////////////////////////////////////// private enum StatisticSortMode {
// Abstracts LAST_PLAYED,
/////////////////////////////////////////////////////////////////////////// MOST_PLAYED,
}
protected abstract String getName(); StatisticSortMode sortMode = StatisticSortMode.LAST_PLAYED;
protected abstract List<StreamStatisticsEntry> processResult(final List<StreamStatisticsEntry> results); protected List<StreamStatisticsEntry> processResult(final List<StreamStatisticsEntry> results) {
switch (sortMode) {
case LAST_PLAYED:
Collections.sort(results, (left, right) ->
right.latestAccessDate.compareTo(left.latestAccessDate));
return results;
case MOST_PLAYED:
Collections.sort(results, (left, right) ->
((Long) right.watchCount).compareTo(left.watchCount));
return results;
default: return null;
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Creation // Fragment LifeCycle - Creation
@@ -78,16 +103,20 @@ public abstract class StatisticsPlaylistFragment
@Override @Override
protected void initViews(View rootView, Bundle savedInstanceState) { protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
setTitle(getName()); setTitle(getString(R.string.title_last_played));
} }
@Override @Override
protected View getListHeader() { protected View getListHeader() {
final View headerRootLayout = activity.getLayoutInflater().inflate(R.layout.playlist_control, final View headerRootLayout = activity.getLayoutInflater().inflate(R.layout.statistic_playlist_control,
itemsList, false); itemsList, false);
playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control);
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button); headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button); headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button); headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
sortButton = headerRootLayout.findViewById(R.id.sortButton);
sortButtonIcon = headerRootLayout.findViewById(R.id.sortButtonIcon);
sortButtonText = headerRootLayout.findViewById(R.id.sortButtonText);
return headerRootLayout; return headerRootLayout;
} }
@@ -193,6 +222,8 @@ public abstract class StatisticsPlaylistFragment
super.handleResult(result); super.handleResult(result);
if (itemListAdapter == null) return; if (itemListAdapter == null) return;
playlistCtrl.setVisibility(View.VISIBLE);
itemListAdapter.clearStreamItemList(); itemListAdapter.clearStreamItemList();
if (result.isEmpty()) { if (result.isEmpty()) {
@@ -212,6 +243,7 @@ public abstract class StatisticsPlaylistFragment
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue())); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
headerBackgroundButton.setOnClickListener(view -> headerBackgroundButton.setOnClickListener(view ->
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue())); NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
sortButton.setOnClickListener(view -> toggleSortMode());
hideLoading(); hideLoading();
} }
@@ -238,6 +270,21 @@ public abstract class StatisticsPlaylistFragment
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
private void toggleSortMode() {
if(sortMode == StatisticSortMode.LAST_PLAYED) {
sortMode = StatisticSortMode.MOST_PLAYED;
setTitle(getString(R.string.title_most_played));
sortButtonIcon.setImageResource(ThemeHelper.getIconByAttr(R.attr.history, getContext()));
sortButtonText.setText(R.string.title_last_played);
} else {
sortMode = StatisticSortMode.LAST_PLAYED;
setTitle(getString(R.string.title_last_played));
sortButtonIcon.setImageResource(ThemeHelper.getIconByAttr(R.attr.filter, getContext()));
sortButtonText.setText(R.string.title_most_played);
}
startLoading(true);
}
private void showStreamDialog(final StreamStatisticsEntry item) { private void showStreamDialog(final StreamStatisticsEntry item) {
final Context context = getContext(); final Context context = getContext();
final Activity activity = getActivity(); final Activity activity = getActivity();
@@ -250,6 +297,7 @@ public abstract class StatisticsPlaylistFragment
context.getResources().getString(R.string.start_here_on_main), context.getResources().getString(R.string.start_here_on_main),
context.getResources().getString(R.string.start_here_on_background), context.getResources().getString(R.string.start_here_on_background),
context.getResources().getString(R.string.start_here_on_popup), context.getResources().getString(R.string.start_here_on_popup),
context.getResources().getString(R.string.delete),
}; };
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> { final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
@@ -270,6 +318,9 @@ public abstract class StatisticsPlaylistFragment
case 4: case 4:
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index)); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break; break;
case 5:
deleteEntry(index);
break;
default: default:
break; break;
} }
@@ -278,6 +329,32 @@ public abstract class StatisticsPlaylistFragment
new InfoItemDialog(getActivity(), infoItem, commands, actions).show(); new InfoItemDialog(getActivity(), infoItem, commands, actions).show();
} }
private void deleteEntry(final int index) {
final LocalItem infoItem = itemListAdapter.getItemsList()
.get(index);
if(infoItem instanceof StreamStatisticsEntry) {
final StreamStatisticsEntry entry = (StreamStatisticsEntry) infoItem;
final Disposable onDelete = recordManager.deleteStreamHistory(entry.streamId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
howManyDelted -> {
if(getView() != null) {
Snackbar.make(getView(), R.string.one_item_deleted,
Snackbar.LENGTH_SHORT).show();
} else {
Toast.makeText(getContext(),
R.string.one_item_deleted,
Toast.LENGTH_SHORT).show();
}
},
throwable -> showSnackBarError(throwable,
UserAction.DELETE_FROM_HISTORY, "none",
"Deleting item failed", R.string.general_error));
disposables.add(onDelete);
}
}
private PlayQueue getPlayQueue() { private PlayQueue getPlayQueue() {
return getPlayQueue(0); return getPlayQueue(0);
} }

View File

@@ -1,11 +1,11 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import java.text.DateFormat; import java.text.DateFormat;

View File

@@ -1,11 +1,11 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import java.text.DateFormat; import java.text.DateFormat;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -11,7 +11,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.view.View; import android.view.View;
@@ -10,7 +10,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry; import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
@@ -6,7 +6,7 @@ import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import java.text.DateFormat; import java.text.DateFormat;

View File

@@ -1,11 +1,11 @@
package org.schabi.newpipe.fragments.local.holder; package org.schabi.newpipe.local.holder;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.fragments.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local.bookmark; package org.schabi.newpipe.local.playlist;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@@ -26,10 +26,10 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.local.LocalPlaylistManager; import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@@ -173,7 +173,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
@Override @Override
public void held(LocalItem selectedItem) { public void held(LocalItem selectedItem) {
if (selectedItem instanceof PlaylistStreamEntry) { if (selectedItem instanceof PlaylistStreamEntry) {
showStreamDialog((PlaylistStreamEntry) selectedItem); showStreamItemDialog((PlaylistStreamEntry) selectedItem);
} }
} }
@@ -506,7 +506,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
protected void showStreamDialog(final PlaylistStreamEntry item) { protected void showStreamItemDialog(final PlaylistStreamEntry item) {
final Context context = getContext(); final Context context = getContext();
final Activity activity = getActivity(); final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return; if (context == null || context.getResources() == null || getActivity() == null) return;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local; package org.schabi.newpipe.local.playlist;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.local; package org.schabi.newpipe.local.playlist;
import org.schabi.newpipe.database.AppDatabase; import org.schabi.newpipe.database.AppDatabase;
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO; import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
@@ -13,11 +13,9 @@ import io.reactivex.schedulers.Schedulers;
public class RemotePlaylistManager { public class RemotePlaylistManager {
private final AppDatabase database;
private final PlaylistRemoteDAO playlistRemoteTable; private final PlaylistRemoteDAO playlistRemoteTable;
public RemotePlaylistManager(final AppDatabase db) { public RemotePlaylistManager(final AppDatabase db) {
database = db;
playlistRemoteTable = db.playlistRemoteDAO(); playlistRemoteTable = db.playlistRemoteDAO();
} }

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.subscription; package org.schabi.newpipe.local.subscription;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.subscription; package org.schabi.newpipe.local.subscription;
public interface ImportExportEventListener { public interface ImportExportEventListener {
/** /**

View File

@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.schabi.newpipe.subscription; package org.schabi.newpipe.local.subscription;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.subscription; package org.schabi.newpipe.local.subscription;
import android.app.Activity; import android.app.Activity;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -39,9 +39,8 @@ import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.subscription.SubscriptionService; import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
import org.schabi.newpipe.subscription.services.SubscriptionsExportService; import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
import org.schabi.newpipe.subscription.services.SubscriptionsImportService;
import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
@@ -53,7 +52,6 @@ import java.io.File;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -65,9 +63,9 @@ import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_MODE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_VALUE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE;
import static org.schabi.newpipe.util.AnimationUtils.animateRotation; import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.subscription; package org.schabi.newpipe.local.subscription;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.fragments.subscription; package org.schabi.newpipe.local.subscription;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
@@ -26,7 +26,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
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.subscription.services.SubscriptionsImportService; import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ServiceHelper;
@@ -37,10 +37,10 @@ import java.util.List;
import icepick.State; import icepick.State;
import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL; import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.INPUT_STREAM_MODE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.INPUT_STREAM_MODE;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_MODE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE;
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_VALUE; import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE;
public class SubscriptionsImportFragment extends BaseFragment { public class SubscriptionsImportFragment extends BaseFragment {
private static final int REQUEST_IMPORT_FILE_CODE = 666; private static final int REQUEST_IMPORT_FILE_CODE = 666;

View File

@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.schabi.newpipe.subscription.services; package org.schabi.newpipe.local.subscription.services;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
@@ -36,8 +36,8 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
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.subscription.ImportExportEventListener; import org.schabi.newpipe.local.subscription.ImportExportEventListener;
import org.schabi.newpipe.subscription.SubscriptionService; import org.schabi.newpipe.local.subscription.SubscriptionService;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;

View File

@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.schabi.newpipe.subscription.services; package org.schabi.newpipe.local.subscription.services;
import android.content.Intent; import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
@@ -29,7 +29,7 @@ import org.reactivestreams.Subscription;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.subscription.SubscriptionItem; import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
import org.schabi.newpipe.subscription.ImportExportJsonHelper; import org.schabi.newpipe.local.subscription.ImportExportJsonHelper;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -49,7 +49,7 @@ public class SubscriptionsExportService extends BaseImportExportService {
/** /**
* A {@link LocalBroadcastManager local broadcast} will be made with this action when the export is successfully completed. * A {@link LocalBroadcastManager local broadcast} will be made with this action when the export is successfully completed.
*/ */
public static final String EXPORT_COMPLETE_ACTION = "org.schabi.newpipe.subscription.services.SubscriptionsExportService.EXPORT_COMPLETE"; public static final String EXPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.EXPORT_COMPLETE";
private Subscription subscription; private Subscription subscription;
private File outFile; private File outFile;

View File

@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.schabi.newpipe.subscription.services; package org.schabi.newpipe.local.subscription.services;
import android.content.Intent; import android.content.Intent;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@@ -33,7 +33,7 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.subscription.SubscriptionItem; import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
import org.schabi.newpipe.subscription.ImportExportJsonHelper; import org.schabi.newpipe.local.subscription.ImportExportJsonHelper;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
@@ -64,7 +64,7 @@ public class SubscriptionsImportService extends BaseImportExportService {
/** /**
* A {@link LocalBroadcastManager local broadcast} will be made with this action when the import is successfully completed. * A {@link LocalBroadcastManager local broadcast} will be made with this action when the import is successfully completed.
*/ */
public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.subscription.services.SubscriptionsImportService.IMPORT_COMPLETE"; public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.IMPORT_COMPLETE";
private Subscription subscription; private Subscription subscription;
private int currentMode; private int currentMode;

View File

@@ -48,7 +48,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.event.PlayerEventListener; import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.LockManager; import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;

View File

@@ -58,7 +58,7 @@ import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.helper.AudioReactor; import org.schabi.newpipe.player.helper.AudioReactor;
import org.schabi.newpipe.player.helper.LoadController; import org.schabi.newpipe.player.helper.LoadController;
import org.schabi.newpipe.player.helper.MediaSessionManager; import org.schabi.newpipe.player.helper.MediaSessionManager;
@@ -69,9 +69,9 @@ import org.schabi.newpipe.player.playback.BasePlayerMediaSession;
import org.schabi.newpipe.player.playback.CustomTrackSelector; import org.schabi.newpipe.player.playback.CustomTrackSelector;
import org.schabi.newpipe.player.playback.MediaSourceManager; import org.schabi.newpipe.player.playback.MediaSourceManager;
import org.schabi.newpipe.player.playback.PlaybackListener; import org.schabi.newpipe.player.playback.PlaybackListener;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.SerializedCache; import org.schabi.newpipe.util.SerializedCache;
import java.io.IOException; import java.io.IOException;

View File

@@ -25,6 +25,7 @@ import android.content.SharedPreferences;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
@@ -62,10 +63,10 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.player.helper.PlaybackParameterDialog; import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.playlist.PlayQueueItemBuilder; import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
import org.schabi.newpipe.playlist.PlayQueueItemHolder; import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
import org.schabi.newpipe.playlist.PlayQueueItemTouchCallback; import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@@ -114,6 +115,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(this); defaultPreferences = PreferenceManager.getDefaultSharedPreferences(this);
ThemeHelper.setTheme(this); ThemeHelper.setTheme(this);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) getWindow().setStatusBarColor(Color.BLACK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) getWindow().setStatusBarColor(Color.BLACK);
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
@@ -847,10 +849,12 @@ public final class MainVideoPlayer extends AppCompatActivity
if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY()); if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
if (!playerImpl.isPlaying()) return false; if (!playerImpl.isPlaying()) return false;
if (e.getX() > playerImpl.getRootView().getWidth() / 2) { if (e.getX() > playerImpl.getRootView().getWidth() * 2 / 3) {
playerImpl.onFastForward(); playerImpl.onFastForward();
} else { } else if (e.getX() < playerImpl.getRootView().getWidth() / 3) {
playerImpl.onFastRewind(); playerImpl.onFastRewind();
} else {
playerImpl.getPlayPauseButton().performClick();
} }
return true; return true;

View File

@@ -2,17 +2,12 @@ package org.schabi.newpipe.player;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log;
import com.google.gson.Gson; import org.schabi.newpipe.player.playqueue.PlayQueue;
import com.google.gson.JsonSyntaxException;
import org.schabi.newpipe.playlist.PlayQueue;
import java.io.Serializable; import java.io.Serializable;
public class PlayerState implements Serializable { public class PlayerState implements Serializable {
private final static String TAG = "PlayerState";
@NonNull private final PlayQueue playQueue; @NonNull private final PlayQueue playQueue;
private final int repeatMode; private final int repeatMode;
@@ -41,21 +36,6 @@ public class PlayerState implements Serializable {
// Serdes // Serdes
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Nullable
public static PlayerState fromJson(@NonNull final String json) {
try {
return new Gson().fromJson(json, PlayerState.class);
} catch (JsonSyntaxException error) {
Log.e(TAG, "Failed to deserialize PlayerState from json=[" + json + "]", error);
return null;
}
}
@NonNull
public String toJson() {
return new Gson().toJson(this);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Getters // Getters
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@@ -44,6 +44,7 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.SeekBar; import android.widget.SeekBar;
@@ -64,7 +65,7 @@ import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.LockManager; import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
@@ -370,6 +371,7 @@ public final class PopupVideoPlayer extends Service {
protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener { protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener {
private TextView resizingIndicator; private TextView resizingIndicator;
private ImageButton fullScreenButton; private ImageButton fullScreenButton;
private ImageView videoPlayPause;
private View extraOptionsView; private View extraOptionsView;
@@ -391,6 +393,8 @@ public final class PopupVideoPlayer extends Service {
resizingIndicator = rootView.findViewById(R.id.resizing_indicator); resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
fullScreenButton = rootView.findViewById(R.id.fullScreenButton); fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked()); fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
videoPlayPause = rootView.findViewById(R.id.videoPlayPause);
videoPlayPause.setOnClickListener(this::onPlayPauseButtonPressed);
extraOptionsView = rootView.findViewById(R.id.extraOptionsView); extraOptionsView = rootView.findViewById(R.id.extraOptionsView);
rootView.addOnLayoutChangeListener(this); rootView.addOnLayoutChangeListener(this);
@@ -406,6 +410,10 @@ public final class PopupVideoPlayer extends Service {
view.setStyle(captionStyle); view.setStyle(captionStyle);
} }
private void onPlayPauseButtonPressed(View ib) {
onPlayPause();
}
@Override @Override
public void onLayoutChange(final View view, int left, int top, int right, int bottom, public void onLayoutChange(final View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) { int oldLeft, int oldTop, int oldRight, int oldBottom) {
@@ -651,6 +659,7 @@ public final class PopupVideoPlayer extends Service {
public void onPlaying() { public void onPlaying() {
super.onPlaying(); super.onPlaying();
updateNotification(R.drawable.ic_pause_white); updateNotification(R.drawable.ic_pause_white);
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
lockManager.acquireWifiAndCpu(); lockManager.acquireWifiAndCpu();
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
@@ -666,13 +675,14 @@ public final class PopupVideoPlayer extends Service {
public void onPaused() { public void onPaused() {
super.onPaused(); super.onPaused();
updateNotification(R.drawable.ic_play_arrow_white); updateNotification(R.drawable.ic_play_arrow_white);
showAndAnimateControl(R.drawable.ic_play_arrow_white, false); videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white);
lockManager.releaseWifiAndCpu(); lockManager.releaseWifiAndCpu();
} }
@Override @Override
public void onPausedSeek() { public void onPausedSeek() {
super.onPausedSeek(); super.onPausedSeek();
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
updateNotification(R.drawable.ic_play_arrow_white); updateNotification(R.drawable.ic_play_arrow_white);
} }
@@ -680,10 +690,27 @@ public final class PopupVideoPlayer extends Service {
public void onCompleted() { public void onCompleted() {
super.onCompleted(); super.onCompleted();
updateNotification(R.drawable.ic_replay_white); updateNotification(R.drawable.ic_replay_white);
showAndAnimateControl(R.drawable.ic_replay_white, false); videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white);
lockManager.releaseWifiAndCpu(); lockManager.releaseWifiAndCpu();
} }
@Override
public void showControlsThenHide() {
videoPlayPause.setVisibility(View.VISIBLE);
super.showControlsThenHide();
}
public void showControls(long duration) {
videoPlayPause.setVisibility(View.VISIBLE);
super.showControls(duration);
}
public void hideControls(final long duration, long delay) {
super.hideControlsAndButton(duration, delay, videoPlayPause);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@@ -717,6 +744,8 @@ public final class PopupVideoPlayer extends Service {
Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY()); Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
if (playerImpl == null || !playerImpl.isPlaying()) return false; if (playerImpl == null || !playerImpl.isPlaying()) return false;
playerImpl.hideControls(0, 0);
if (e.getX() > popupWidth / 2) { if (e.getX() > popupWidth / 2) {
playerImpl.onFastForward(); playerImpl.onFastForward();
} else { } else {
@@ -730,7 +759,12 @@ public final class PopupVideoPlayer extends Service {
public boolean onSingleTapConfirmed(MotionEvent e) { public boolean onSingleTapConfirmed(MotionEvent e) {
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]"); if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
if (playerImpl == null || playerImpl.getPlayer() == null) return false; if (playerImpl == null || playerImpl.getPlayer() == null) return false;
playerImpl.onPlayPause(); if (playerImpl.isControlsVisible()) {
playerImpl.hideControls(100, 100);
} else {
playerImpl.showControlsThenHide();
}
return true; return true;
} }

View File

@@ -29,14 +29,14 @@ import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.player.event.PlayerEventListener; import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.PlaybackParameterDialog; import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
import org.schabi.newpipe.playlist.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.playlist.PlayQueueItemBuilder; import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
import org.schabi.newpipe.playlist.PlayQueueItemHolder; import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
import org.schabi.newpipe.playlist.PlayQueueItemTouchCallback; import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;

View File

@@ -68,7 +68,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
@@ -887,6 +887,19 @@ public abstract class VideoPlayer extends BasePlayer
() -> animateView(controlsRoot, false, duration), delay); () -> animateView(controlsRoot, false, duration), delay);
} }
public void hideControlsAndButton(final long duration, long delay, View button) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
controlsVisibilityHandler.removeCallbacksAndMessages(null);
controlsVisibilityHandler.postDelayed(hideControlsAndButtonHandler(duration, button), delay);
}
private Runnable hideControlsAndButtonHandler(long duration, View videoPlayPause)
{
return () -> {
videoPlayPause.setVisibility(View.INVISIBLE);
animateView(controlsRoot, false,duration);
};
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Getters and Setters // Getters and Setters
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@@ -24,9 +24,9 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.SubtitlesFormat; import org.schabi.newpipe.extractor.stream.SubtitlesFormat;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;

View File

@@ -7,7 +7,7 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.io.IOException; import java.io.IOException;

View File

@@ -7,7 +7,7 @@ import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.io.IOException; import java.io.IOException;

View File

@@ -4,7 +4,7 @@ import android.support.annotation.NonNull;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
public interface ManagedMediaSource extends MediaSource { public interface ManagedMediaSource extends MediaSource {
/** /**

View File

@@ -6,7 +6,7 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.io.IOException; import java.io.IOException;

View File

@@ -5,7 +5,7 @@ import android.support.v4.media.MediaDescriptionCompat;
import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.BasePlayer;
import org.schabi.newpipe.player.mediasession.MediaSessionCallback; import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
public class BasePlayerMediaSession implements MediaSessionCallback { public class BasePlayerMediaSession implements MediaSessionCallback {
private BasePlayer player; private BasePlayer player;

View File

@@ -16,12 +16,12 @@ import org.schabi.newpipe.player.mediasource.LoadedMediaSource;
import org.schabi.newpipe.player.mediasource.ManagedMediaSource; import org.schabi.newpipe.player.mediasource.ManagedMediaSource;
import org.schabi.newpipe.player.mediasource.ManagedMediaSourcePlaylist; import org.schabi.newpipe.player.mediasource.ManagedMediaSourcePlaylist;
import org.schabi.newpipe.player.mediasource.PlaceholderMediaSource; import org.schabi.newpipe.player.mediasource.PlaceholderMediaSource;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.playlist.events.MoveEvent; import org.schabi.newpipe.player.playqueue.events.MoveEvent;
import org.schabi.newpipe.playlist.events.PlayQueueEvent; import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent;
import org.schabi.newpipe.playlist.events.RemoveEvent; import org.schabi.newpipe.player.playqueue.events.RemoveEvent;
import org.schabi.newpipe.playlist.events.ReorderEvent; import org.schabi.newpipe.player.playqueue.events.ReorderEvent;
import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ServiceHelper;
import java.util.ArrayList; import java.util.ArrayList;
@@ -45,7 +45,7 @@ import io.reactivex.subjects.PublishSubject;
import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException; import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException;
import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException; import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException;
import static org.schabi.newpipe.playlist.PlayQueue.DEBUG; import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG;
public class MediaSourceManager { public class MediaSourceManager {
@NonNull private final String TAG = "MediaSourceManager@" + hashCode(); @NonNull private final String TAG = "MediaSourceManager@" + hashCode();

View File

@@ -6,7 +6,7 @@ import android.support.annotation.Nullable;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.util.Log; import android.util.Log;

View File

@@ -1,6 +1,6 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@@ -6,15 +6,15 @@ import android.util.Log;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription; import org.reactivestreams.Subscription;
import org.schabi.newpipe.playlist.events.AppendEvent; import org.schabi.newpipe.player.playqueue.events.AppendEvent;
import org.schabi.newpipe.playlist.events.ErrorEvent; import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
import org.schabi.newpipe.playlist.events.InitEvent; import org.schabi.newpipe.player.playqueue.events.InitEvent;
import org.schabi.newpipe.playlist.events.MoveEvent; import org.schabi.newpipe.player.playqueue.events.MoveEvent;
import org.schabi.newpipe.playlist.events.PlayQueueEvent; import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent;
import org.schabi.newpipe.playlist.events.RecoveryEvent; import org.schabi.newpipe.player.playqueue.events.RecoveryEvent;
import org.schabi.newpipe.playlist.events.RemoveEvent; import org.schabi.newpipe.player.playqueue.events.RemoveEvent;
import org.schabi.newpipe.playlist.events.ReorderEvent; import org.schabi.newpipe.player.playqueue.events.ReorderEvent;
import org.schabi.newpipe.playlist.events.SelectEvent; import org.schabi.newpipe.player.playqueue.events.SelectEvent;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.content.Context; import android.content.Context;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@@ -8,12 +8,13 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.playlist.events.AppendEvent; import org.schabi.newpipe.player.playqueue.events.AppendEvent;
import org.schabi.newpipe.playlist.events.ErrorEvent; import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
import org.schabi.newpipe.playlist.events.MoveEvent; import org.schabi.newpipe.player.playqueue.events.MoveEvent;
import org.schabi.newpipe.playlist.events.PlayQueueEvent; import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent;
import org.schabi.newpipe.playlist.events.RemoveEvent; import org.schabi.newpipe.player.playqueue.events.RemoveEvent;
import org.schabi.newpipe.playlist.events.SelectEvent; import org.schabi.newpipe.player.playqueue.events.SelectEvent;
import org.schabi.newpipe.util.FallbackViewHolder;
import java.util.List; import java.util.List;
@@ -188,7 +189,7 @@ public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
return new PlayQueueItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.play_queue_item, parent, false)); return new PlayQueueItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.play_queue_item, parent, false));
default: default:
Log.e(TAG, "Attempting to create view holder with undefined type: " + type); Log.e(TAG, "Attempting to create view holder with undefined type: " + type);
return null; return new FallbackViewHolder(new View(parent.getContext()));
} }
} }

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;

View File

@@ -1,6 +1,5 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist; package org.schabi.newpipe.player.playqueue;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class AppendEvent implements PlayQueueEvent { public class AppendEvent implements PlayQueueEvent {

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class ErrorEvent implements PlayQueueEvent { public class ErrorEvent implements PlayQueueEvent {

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class InitEvent implements PlayQueueEvent { public class InitEvent implements PlayQueueEvent {
@Override @Override

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class MoveEvent implements PlayQueueEvent { public class MoveEvent implements PlayQueueEvent {
final private int fromIndex; final private int fromIndex;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
import java.io.Serializable; import java.io.Serializable;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public enum PlayQueueEventType { public enum PlayQueueEventType {
INIT, INIT,

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class RecoveryEvent implements PlayQueueEvent { public class RecoveryEvent implements PlayQueueEvent {

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class RemoveEvent implements PlayQueueEvent { public class RemoveEvent implements PlayQueueEvent {

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class ReorderEvent implements PlayQueueEvent { public class ReorderEvent implements PlayQueueEvent {
private final int fromSelectedIndex; private final int fromSelectedIndex;

View File

@@ -1,4 +1,4 @@
package org.schabi.newpipe.playlist.events; package org.schabi.newpipe.player.playqueue.events;
public class SelectEvent implements PlayQueueEvent { public class SelectEvent implements PlayQueueEvent {

View File

@@ -1,7 +1,9 @@
package org.schabi.newpipe.report; package org.schabi.newpipe.report;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
@@ -33,10 +35,8 @@ import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.schabi.newpipe.ActivityCommunicator; import org.schabi.newpipe.ActivityCommunicator;
import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -44,9 +44,9 @@ import java.io.StringWriter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
/* /*
* Created by Christian Schabesberger on 24.10.15. * Created by Christian Schabesberger on 24.10.15.
@@ -96,7 +96,7 @@ public class ErrorActivity extends AppCompatActivity {
public static void reportError(final Context context, final List<Throwable> el, public static void reportError(final Context context, final List<Throwable> el,
final Class returnActivity, View rootView, final ErrorInfo errorInfo) { final Class returnActivity, View rootView, final ErrorInfo errorInfo) {
if (rootView != null) { if (rootView != null) {
Snackbar.make(rootView, R.string.error_snackbar_message, 15 * 1000) Snackbar.make(rootView, R.string.error_snackbar_message, 3 * 1000)
.setActionTextColor(Color.YELLOW) .setActionTextColor(Color.YELLOW)
.setAction(R.string.error_snackbar_action, v -> .setAction(R.string.error_snackbar_action, v ->
startErrorActivity(returnActivity, context, errorInfo, el)).show(); startErrorActivity(returnActivity, context, errorInfo, el)).show();
@@ -210,12 +210,31 @@ public class ErrorActivity extends AppCompatActivity {
currentTimeStamp = getCurrentTimeStamp(); currentTimeStamp = getCurrentTimeStamp();
reportButton.setOnClickListener((View v) -> { reportButton.setOnClickListener((View v) -> {
Context context = this;
new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.privacy_policy_title)
.setMessage(R.string.start_accept_privacy_policy)
.setCancelable(false)
.setNeutralButton(R.string.read_privacy_policy, (dialog, which) -> {
Intent webIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(context.getString(R.string.privacy_policy_url))
);
context.startActivity(webIntent);
})
.setPositiveButton(R.string.accept, (dialog, which) -> {
Intent i = new Intent(Intent.ACTION_SENDTO); Intent i = new Intent(Intent.ACTION_SENDTO);
i.setData(Uri.parse("mailto:" + ERROR_EMAIL_ADDRESS)) i.setData(Uri.parse("mailto:" + ERROR_EMAIL_ADDRESS))
.putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT) .putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT)
.putExtra(Intent.EXTRA_TEXT, buildJson()); .putExtra(Intent.EXTRA_TEXT, buildJson());
startActivity(Intent.createChooser(i, "Send Email")); startActivity(Intent.createChooser(i, "Send Email"));
})
.setNegativeButton(R.string.decline, (dialog, which) -> {
// do nothing
})
.show();
}); });
// normal bugreport // normal bugreport

View File

@@ -14,7 +14,8 @@ public enum UserAction {
REQUESTED_STREAM("requested stream"), REQUESTED_STREAM("requested stream"),
REQUESTED_CHANNEL("requested channel"), REQUESTED_CHANNEL("requested channel"),
REQUESTED_PLAYLIST("requested playlist"), REQUESTED_PLAYLIST("requested playlist"),
REQUESTED_KIOSK("requested kiosk"); REQUESTED_KIOSK("requested kiosk"),
DELETE_FROM_HISTORY("delete from history");
private final String message; private final String message;

View File

@@ -4,7 +4,9 @@ import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.preference.ListPreference; import android.support.v7.preference.ListPreference;
@@ -30,15 +32,21 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import static android.content.Context.MODE_PRIVATE;
public class ContentSettingsFragment extends BasePreferenceFragment { public class ContentSettingsFragment extends BasePreferenceFragment {
private static final int REQUEST_IMPORT_PATH = 8945; private static final int REQUEST_IMPORT_PATH = 8945;
@@ -48,6 +56,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
private File databasesDir; private File databasesDir;
private File newpipe_db; private File newpipe_db;
private File newpipe_db_journal; private File newpipe_db_journal;
private File newpipe_settings;
private String thumbnailLoadToggleKey; private String thumbnailLoadToggleKey;
@@ -79,6 +88,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
databasesDir = new File(homeDir + "/databases"); databasesDir = new File(homeDir + "/databases");
newpipe_db = new File(homeDir + "/databases/newpipe.db"); newpipe_db = new File(homeDir + "/databases/newpipe.db");
newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal"); newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal");
newpipe_settings = new File(homeDir + "/databases/newpipe.settings");
newpipe_settings.delete();
addPreferencesFromResource(R.xml.content_settings); addPreferencesFromResource(R.xml.content_settings);
@@ -197,6 +208,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
new FileOutputStream(path))); new FileOutputStream(path)));
ZipHelper.addFileToZip(outZip, newpipe_db.getPath(), "newpipe.db"); ZipHelper.addFileToZip(outZip, newpipe_db.getPath(), "newpipe.db");
ZipHelper.addFileToZip(outZip, newpipe_db_journal.getPath(), "newpipe.db-journal"); ZipHelper.addFileToZip(outZip, newpipe_db_journal.getPath(), "newpipe.db-journal");
saveSharedPreferencesToFile(newpipe_settings);
ZipHelper.addFileToZip(outZip, newpipe_settings.getPath(), "newpipe.settings");
outZip.close(); outZip.close();
@@ -207,6 +220,29 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
} }
} }
private void saveSharedPreferencesToFile(File dst) {
ObjectOutputStream output = null;
try {
output = new ObjectOutputStream(new FileOutputStream(dst));
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
output.writeObject(pref.getAll());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (output != null) {
output.flush();
output.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private void importDatabase(String filePath) { private void importDatabase(String filePath) {
// check if file is supported // check if file is supported
ZipFile zipFile = null; ZipFile zipFile = null;
@@ -223,30 +259,83 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
} }
try { try {
ZipInputStream zipIn = new ZipInputStream(
new BufferedInputStream(
new FileInputStream(filePath)));
if (!databasesDir.exists() && !databasesDir.mkdir()) { if (!databasesDir.exists() && !databasesDir.mkdir()) {
throw new Exception("Could not create databases dir"); throw new Exception("Could not create databases dir");
} }
if(!(ZipHelper.extractFileFromZip(zipIn, newpipe_db.getPath(), "newpipe.db") if(!(ZipHelper.extractFileFromZip(filePath, newpipe_db.getPath(), "newpipe.db")
&& ZipHelper.extractFileFromZip(zipIn, newpipe_db_journal.getPath(), "newpipe.db-journal"))) { && ZipHelper.extractFileFromZip(filePath, newpipe_db_journal.getPath(), "newpipe.db-journal"))) {
Toast.makeText(getContext(), R.string.could_not_import_all_files, Toast.LENGTH_LONG) Toast.makeText(getContext(), R.string.could_not_import_all_files, Toast.LENGTH_LONG)
.show(); .show();
} }
zipIn.close(); //If settings file exist, ask if it should be imported.
if(ZipHelper.extractFileFromZip(filePath, newpipe_settings.getPath(), "newpipe.settings")) {
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
alert.setTitle(R.string.import_settings);
alert.setNegativeButton(android.R.string.no, (dialog, which) -> {
dialog.dismiss();
// restart app to properly load db // restart app to properly load db
//App.restart(getContext());
System.exit(0); System.exit(0);
});
alert.setPositiveButton(android.R.string.yes, (dialog, which) -> {
dialog.dismiss();
loadSharedPreferences(newpipe_settings);
// restart app to properly load db
System.exit(0);
});
alert.show();
} else {
// restart app to properly load db
System.exit(0);
}
} catch (Exception e) { } catch (Exception e) {
onError(e); onError(e);
} }
} }
private void loadSharedPreferences(File src) {
ObjectInputStream input = null;
try {
input = new ObjectInputStream(new FileInputStream(src));
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
prefEdit.clear();
Map<String, ?> entries = (Map<String, ?>) input.readObject();
for (Map.Entry<String, ?> entry : entries.entrySet()) {
Object v = entry.getValue();
String key = entry.getKey();
if (v instanceof Boolean)
prefEdit.putBoolean(key, ((Boolean) v).booleanValue());
else if (v instanceof Float)
prefEdit.putFloat(key, ((Float) v).floatValue());
else if (v instanceof Integer)
prefEdit.putInt(key, ((Integer) v).intValue());
else if (v instanceof Long)
prefEdit.putLong(key, ((Long) v).longValue());
else if (v instanceof String)
prefEdit.putString(key, ((String) v));
}
prefEdit.commit();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (input != null) {
input.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();

View File

@@ -1,20 +1,45 @@
package org.schabi.newpipe.settings; package org.schabi.newpipe.settings;
import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.InfoCache; import org.schabi.newpipe.util.InfoCache;
import java.util.ArrayList;
import java.util.Collection;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.disposables.Disposables;
public class HistorySettingsFragment extends BasePreferenceFragment { public class HistorySettingsFragment extends BasePreferenceFragment {
private String cacheWipeKey; private String cacheWipeKey;
private String viewsHistroyClearKey;
private String searchHistoryClearKey;
private HistoryRecordManager recordManager;
private CompositeDisposable disposables;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
cacheWipeKey = getString(R.string.metadata_cache_wipe_key); cacheWipeKey = getString(R.string.metadata_cache_wipe_key);
viewsHistroyClearKey = getString(R.string.clear_views_history_key);
searchHistoryClearKey = getString(R.string.clear_search_history_key);
recordManager = new HistoryRecordManager(getActivity());
disposables = new CompositeDisposable();
} }
@Override @Override
@@ -30,6 +55,70 @@ public class HistorySettingsFragment extends BasePreferenceFragment {
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
if (preference.getKey().equals(viewsHistroyClearKey)) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.delete_view_history_alert)
.setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss()))
.setPositiveButton(R.string.delete, ((dialog, which) -> {
final Disposable onDelete = recordManager.deleteWholeStreamHistory()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
howManyDeleted -> Toast.makeText(getActivity(),
R.string.view_history_deleted,
Toast.LENGTH_SHORT).show(),
throwable -> ErrorActivity.reportError(getContext(),
throwable,
SettingsActivity.class, null,
ErrorActivity.ErrorInfo.make(
UserAction.DELETE_FROM_HISTORY,
"none",
"Delete view history",
R.string.general_error)));
final Disposable onClearOrphans = recordManager.removeOrphanedRecords()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
howManyDeleted -> {},
throwable -> ErrorActivity.reportError(getContext(),
throwable,
SettingsActivity.class, null,
ErrorActivity.ErrorInfo.make(
UserAction.DELETE_FROM_HISTORY,
"none",
"Delete search history",
R.string.general_error)));
disposables.add(onClearOrphans);
disposables.add(onDelete);
}))
.create()
.show();
}
if (preference.getKey().equals(searchHistoryClearKey)) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.delete_search_history_alert)
.setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss()))
.setPositiveButton(R.string.delete, ((dialog, which) -> {
final Disposable onDelete = recordManager.deleteWholeSearchHistory()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
howManyDeleted -> Toast.makeText(getActivity(),
R.string.search_history_deleted,
Toast.LENGTH_SHORT).show(),
throwable -> ErrorActivity.reportError(getContext(),
throwable,
SettingsActivity.class, null,
ErrorActivity.ErrorInfo.make(
UserAction.DELETE_FROM_HISTORY,
"none",
"Delete search history",
R.string.general_error)));
disposables.add(onDelete);
}))
.create()
.show();
}
return super.onPreferenceTreeClick(preference); return super.onPreferenceTreeClick(preference);
} }
} }

View File

@@ -20,7 +20,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.database.subscription.SubscriptionEntity;
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.subscription.SubscriptionService; import org.schabi.newpipe.local.subscription.SubscriptionService;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
@@ -159,7 +159,7 @@ public class SelectChannelFragment extends DialogFragment {
@Override @Override
public void onError(Throwable exception) { public void onError(Throwable exception) {
onError(exception); SelectChannelFragment.this.onError(exception);
} }
@Override @Override

View File

@@ -0,0 +1,10 @@
package org.schabi.newpipe.util;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class FallbackViewHolder extends RecyclerView.ViewHolder {
public FallbackViewHolder(View itemView) {
super(itemView);
}
}

View File

@@ -33,15 +33,13 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
import org.schabi.newpipe.fragments.list.feed.FeedFragment; import org.schabi.newpipe.local.feed.FeedFragment;
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment; import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment; import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment; import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.fragments.local.bookmark.LastPlayedFragment; import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
import org.schabi.newpipe.fragments.local.bookmark.LocalPlaylistFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.fragments.local.bookmark.MostPlayedFragment; import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.fragments.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.history.HistoryActivity;
import org.schabi.newpipe.player.BackgroundPlayer; import org.schabi.newpipe.player.BackgroundPlayer;
import org.schabi.newpipe.player.BackgroundPlayerActivity; import org.schabi.newpipe.player.BackgroundPlayerActivity;
import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.BasePlayer;
@@ -50,7 +48,7 @@ import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayerActivity; import org.schabi.newpipe.player.PopupVideoPlayerActivity;
import org.schabi.newpipe.player.VideoPlayer; import org.schabi.newpipe.player.VideoPlayer;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.settings.SettingsActivity; import org.schabi.newpipe.settings.SettingsActivity;
import java.util.ArrayList; import java.util.ArrayList;
@@ -352,16 +350,9 @@ public class NavigationHelper {
.commit(); .commit();
} }
public static void openLastPlayedFragment(FragmentManager fragmentManager) { public static void openStatisticFragment(FragmentManager fragmentManager) {
defaultTransaction(fragmentManager) defaultTransaction(fragmentManager)
.replace(R.id.fragment_holder, new LastPlayedFragment()) .replace(R.id.fragment_holder, new StatisticsPlaylistFragment())
.addToBackStack(null)
.commit();
}
public static void openMostPlayedFragment(FragmentManager fragmentManager) {
defaultTransaction(fragmentManager)
.replace(R.id.fragment_holder, new MostPlayedFragment())
.addToBackStack(null) .addToBackStack(null)
.commit(); .commit();
} }
@@ -417,11 +408,6 @@ public class NavigationHelper {
context.startActivity(intent); context.startActivity(intent);
} }
public static void openHistory(Context context) {
Intent intent = new Intent(context, HistoryActivity.class);
context.startActivity(intent);
}
public static void openSettings(Context context) { public static void openSettings(Context context) {
Intent intent = new Intent(context, SettingsActivity.class); Intent intent = new Intent(context, SettingsActivity.class);
context.startActivity(intent); context.startActivity(intent);

View File

@@ -190,4 +190,16 @@ public class ThemeHelper {
String defaultTheme = context.getResources().getString(R.string.default_theme_value); String defaultTheme = context.getResources().getString(R.string.default_theme_value);
return PreferenceManager.getDefaultSharedPreferences(context).getString(themeKey, defaultTheme); return PreferenceManager.getDefaultSharedPreferences(context).getString(themeKey, defaultTheme);
} }
/**
* This will get the R.drawable.* resource to which attr is currently pointing to.
*
* @param attr a R.attribute.* resource value
* @param context the context to use
* @return a R.drawable.* resource value
*/
public static int getIconByAttr(final int attr, final Context context) {
return context.obtainStyledAttributes(new int[] {attr})
.getResourceId(0, -1);
}
} }

View File

@@ -62,7 +62,12 @@ public class ZipHelper {
* @return will return true if the file was found within the zip file * @return will return true if the file was found within the zip file
* @throws Exception * @throws Exception
*/ */
public static boolean extractFileFromZip(ZipInputStream inZip, String file, String name) throws Exception { public static boolean extractFileFromZip(String filePath, String file, String name) throws Exception {
ZipInputStream inZip = new ZipInputStream(
new BufferedInputStream(
new FileInputStream(filePath)));
byte data[] = new byte[BUFFER_SIZE]; byte data[] = new byte[BUFFER_SIZE];
boolean found = false; boolean found = false;
@@ -89,6 +94,6 @@ public class ZipHelper {
inZip.closeEntry(); inZip.closeEntry();
} }
} }
return true; return found;
} }
} }

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