Merge branch 'develop' into fix-2359
This commit is contained in:
commit
f2af5192e6
@ -21,7 +21,10 @@ jobs:
|
||||
- v1-android-
|
||||
|
||||
- run:
|
||||
command: ./gradlew assembleDebug :core:testPlayDebugUnitTest -PdisablePreDex
|
||||
# To build release, we need to create a temporary keystore that can be used to sign the app
|
||||
command: |
|
||||
keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US"
|
||||
./gradlew assemblePlayRelease :core:testPlayReleaseUnitTest -PdisablePreDex
|
||||
no_output_timeout: 1800
|
||||
|
||||
- store_artifacts:
|
||||
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
33
.project
33
.project
@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>AntennaPod</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
17
.travis.yml
17
.travis.yml
@ -1,17 +0,0 @@
|
||||
language: android
|
||||
jdk: oraclejdk7
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- ANDROID_SDKS=android-19,sysimg-19 ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
|
||||
before_install:
|
||||
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
|
||||
- emulator -avd test -no-skin -no-audio -no-window &
|
||||
- cp src/de/danoeh/antennapod/util/flattr/FlattrConfig.java.example src/de/danoeh/antennapod/util/flattr/FlattrConfig.java
|
||||
|
||||
before_script:
|
||||
- chmod -R 777 ./ci/wait_for_emulator.sh
|
||||
- ./ci/wait_for_emulator.sh
|
||||
|
||||
script:
|
||||
- gradle connectedAndroidTest
|
79
.tx/config
79
.tx/config
@ -1,7 +1,7 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[antennapod.english]
|
||||
[antennapod.core-values]
|
||||
source_file = core/src/main/res/values/strings.xml
|
||||
source_lang = en
|
||||
trans.ast_ES = core/src/main/res/values-b+ast/strings.xml
|
||||
@ -25,14 +25,14 @@ trans.he_IL = core/src/main/res/values-iw-rIL/strings.xml
|
||||
trans.hi_IN = core/src/main/res/values-hi-rIN/strings.xml
|
||||
trans.hu = core/src/main/res/values-hu/strings.xml
|
||||
trans.id = core/src/main/res/values-id/strings.xml
|
||||
trans.it = core/src/main/res/values-it/strings.xml
|
||||
trans.it_IT = core/src/main/res/values-it-rIT/strings.xml
|
||||
trans.it_IT = core/src/main/res/values-it/strings.xml
|
||||
trans.is = core/src/main/res/values-is-rIS/strings.xml
|
||||
trans.ja = core/src/main/res/values-ja/strings.xml
|
||||
trans.kn_IN = core/src/main/res/values-kn-rIN/strings.xml
|
||||
trans.ko = core/src/main/res/values-ko/strings.xml
|
||||
trans.ko_KR = core/src/main/res/values-ko-rKR/strings.xml
|
||||
trans.lt = core/src/main/res/values-lt/strings.xml
|
||||
trans.mk = core/src/main/res/values-mk/strings.xml
|
||||
trans.nb = core/src/main/res/values-nb/strings.xml
|
||||
trans.no = core/src/main/res/values-no/strings.xml
|
||||
trans.nl = core/src/main/res/values-nl/strings.xml
|
||||
@ -58,16 +58,75 @@ trans.zh_TW = core/src/main/res/values-zh-rTW/strings.xml
|
||||
trans.zh_HK = core/src/main/res/values-zh-rHK/strings.xml
|
||||
|
||||
[antennapod.description]
|
||||
file_filter = app/src/main/play/<lang>/listing/fulldescription
|
||||
source_file = app/src/main/play/en-US/listing/fulldescription
|
||||
source_lang = en
|
||||
trans.ar = app/src/main/play/ar/listing/fulldescription
|
||||
trans.az = app/src/main/play/az-AZ/listing/fulldescription
|
||||
trans.bg = app/src/main/play/bg/listing/fulldescription
|
||||
trans.ca = app/src/main/play/ca/listing/fulldescription
|
||||
trans.cs = app/src/main/play/cs-CZ/listing/fulldescription
|
||||
trans.da = app/src/main/play/da-DK/listing/fulldescription
|
||||
trans.de = app/src/main/play/de-DE/listing/fulldescription
|
||||
trans.el = app/src/main/play/el-GR/listing/fulldescription
|
||||
trans.es = app/src/main/play/es-ES/listing/fulldescription
|
||||
trans.et = app/src/main/play/et/listing/fulldescription
|
||||
trans.fa = app/src/main/play/fa/listing/fulldescription
|
||||
trans.fr = app/src/main/play/fr-FR/listing/fulldescription
|
||||
trans.gl = app/src/main/play/gl-ES/listing/fulldescription
|
||||
trans.hi_IN = app/src/main/play/hi-IN/listing/fulldescription
|
||||
trans.hu = app/src/main/play/hu-HU/listing/fulldescription
|
||||
trans.it_IT = app/src/main/play/it-IT/listing/fulldescription
|
||||
trans.iw = app/src/main/play/iw-IL/listing/fulldescription
|
||||
trans.ja = app/src/main/play/ja-JP/listing/fulldescription
|
||||
trans.ko = app/src/main/play/ko-KR/listing/fulldescription
|
||||
trans.lt = app/src/main/play/lt/listing/fulldescription
|
||||
trans.nl = app/src/main/play/nl-NL/listing/fulldescription
|
||||
trans.pl_PL = app/src/main/play/pl-PL/listing/fulldescription
|
||||
trans.pt_BR = app/src/main/play/pt-BR/listing/fulldescription
|
||||
trans.pt_PT = app/src/main/play/pt-PT/listing/fulldescription
|
||||
trans.ro_RO = app/src/main/play/ro/listing/fulldescription
|
||||
trans.ru_RU = app/src/main/play/ru-RU/listing/fulldescription
|
||||
trans.sl_SI = app/src/main/play/sl/listing/fulldescription
|
||||
trans.sv_SE = app/src/main/play/sv-SE/listing/fulldescription
|
||||
trans.tr = app/src/main/play/tr-TR/listing/fulldescription
|
||||
trans.uk_UA = app/src/main/play/uk/listing/fulldescription
|
||||
trans.vi = app/src/main/play/vi/listing/fulldescription
|
||||
trans.zh_CN = app/src/main/play/zh-CN/listing/fulldescription
|
||||
trans.zh_TW = app/src/main/play/zh-TW/listing/fulldescription
|
||||
|
||||
[antennapod.shortdescription]
|
||||
file_filter = app/src/main/play/<lang>/listing/shortdescription
|
||||
source_file = app/src/main/play/en-US/listing/shortdescription
|
||||
source_lang = en
|
||||
|
||||
[antennapod.changelog]
|
||||
file_filter = app/src/main/play/<lang>/whatsnew
|
||||
source_file = app/src/main/play/en-US/whatsnew
|
||||
source_lang = en
|
||||
trans.ar = app/src/main/play/ar/listing/shortdescription
|
||||
trans.az = app/src/main/play/az-AZ/listing/shortdescription
|
||||
trans.bg = app/src/main/play/bg/listing/shortdescription
|
||||
trans.ca = app/src/main/play/ca/listing/shortdescription
|
||||
trans.cs = app/src/main/play/cs-CZ/listing/shortdescription
|
||||
trans.da = app/src/main/play/da-DK/listing/shortdescription
|
||||
trans.de = app/src/main/play/de-DE/listing/shortdescription
|
||||
trans.el = app/src/main/play/el-GR/listing/shortdescription
|
||||
trans.es = app/src/main/play/es-ES/listing/shortdescription
|
||||
trans.et = app/src/main/play/et/listing/shortdescription
|
||||
trans.fa = app/src/main/play/fa/listing/shortdescription
|
||||
trans.fr = app/src/main/play/fr-FR/listing/shortdescription
|
||||
trans.gl = app/src/main/play/gl-ES/listing/shortdescription
|
||||
trans.hi_IN = app/src/main/play/hi-IN/listing/shortdescription
|
||||
trans.hu = app/src/main/play/hu-HU/listing/shortdescription
|
||||
trans.it_IT = app/src/main/play/it-IT/listing/shortdescription
|
||||
trans.iw = app/src/main/play/iw-IL/listing/shortdescription
|
||||
trans.ja = app/src/main/play/ja-JP/listing/shortdescription
|
||||
trans.ko = app/src/main/play/ko-KR/listing/shortdescription
|
||||
trans.lt = app/src/main/play/lt/listing/shortdescription
|
||||
trans.nl = app/src/main/play/nl-NL/listing/shortdescription
|
||||
trans.pl_PL = app/src/main/play/pl-PL/listing/shortdescription
|
||||
trans.pt_BR = app/src/main/play/pt-BR/listing/shortdescription
|
||||
trans.pt_PT = app/src/main/play/pt-PT/listing/shortdescription
|
||||
trans.ro_RO = app/src/main/play/ro/listing/shortdescription
|
||||
trans.ru_RU = app/src/main/play/ru-RU/listing/shortdescription
|
||||
trans.sl_SI = app/src/main/play/sl/listing/shortdescription
|
||||
trans.sv_SE = app/src/main/play/sv-SE/listing/shortdescription
|
||||
trans.tr = app/src/main/play/tr-TR/listing/shortdescription
|
||||
trans.uk_UA = app/src/main/play/uk/listing/shortdescription
|
||||
trans.vi = app/src/main/play/vi/listing/shortdescription
|
||||
trans.zh_CN = app/src/main/play/zh-CN/listing/shortdescription
|
||||
trans.zh_TW = app/src/main/play/zh-TW/listing/shortdescription
|
||||
|
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,6 +1,25 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
|
||||
Version 1.7.1
|
||||
-------------
|
||||
|
||||
* Fix for database corruption
|
||||
|
||||
Version 1.7.0
|
||||
-------------
|
||||
|
||||
* NEW ExoPlayer (experimental)
|
||||
* Fix for Bluetooth Forward (Oreo)
|
||||
* Preference redesign + search
|
||||
* Notification improvements
|
||||
* Different screens for feed info and settings
|
||||
* Sort Queue with Random or Smart Shuffle
|
||||
* True Black Theme for AMOLED
|
||||
* Improvements to feed parsing
|
||||
* Fix for app being killed by Android Oreo
|
||||
|
||||
Version 1.6.5
|
||||
-------------
|
||||
|
||||
|
125
CONTRIBUTORS
125
CONTRIBUTORS
@ -1,107 +1,168 @@
|
||||
DEVELOPERS
|
||||
==========
|
||||
|
||||
Alan Orth
|
||||
Alexander Terczka
|
||||
alifeflow
|
||||
amhokies
|
||||
Anders Bo Rasmussen
|
||||
Andrew Gaul
|
||||
Andrey Krutov
|
||||
Anthony Lieuallen
|
||||
axq
|
||||
brad
|
||||
ByteHamster
|
||||
Cameron Banga
|
||||
Christian Ludwig
|
||||
Christopher Szucko
|
||||
Cj Malone
|
||||
Colin Willson
|
||||
Cédric Cabessa
|
||||
Danial Klimkin
|
||||
Daniel Oeh
|
||||
David Carver
|
||||
David Reiss
|
||||
Dean Brettle
|
||||
dethstar
|
||||
Dirk Mueller
|
||||
Domingos Lopes
|
||||
drabux
|
||||
egsavage
|
||||
EirikV
|
||||
Eoin Mcloughlin
|
||||
eraymond
|
||||
Ercan Erden
|
||||
Falko Lehmann
|
||||
Hannes Achleitner
|
||||
hannesa2
|
||||
Hanno Zulla
|
||||
heckler01
|
||||
Holger Jeromin
|
||||
Humberto Fraga
|
||||
InsidE
|
||||
James Falcon
|
||||
Jan Niehusmann
|
||||
Jens Klingenberg
|
||||
Jens Müller
|
||||
Johan Liesén
|
||||
Kaligule
|
||||
Katrin Leinweber
|
||||
keunes
|
||||
Kevin Dalley
|
||||
Koen Glotzbach
|
||||
kroegerama
|
||||
Kurian Vithayathil
|
||||
LatinSuD
|
||||
Lee Yeong Khang
|
||||
lightonflux
|
||||
ligi
|
||||
Luis Cruz
|
||||
Marc Lasson
|
||||
Martin Fietz
|
||||
Martin Olsson
|
||||
mat tso
|
||||
mateoeh
|
||||
Matthew Gaffen
|
||||
Matthias Schütz
|
||||
Maurice Gilden
|
||||
Meir Schwarz
|
||||
Michael Kaiser
|
||||
Michael Scarito
|
||||
Mike Chelen
|
||||
minusf
|
||||
MolarAmbiguity
|
||||
Mounir Lamouri
|
||||
mr-intj
|
||||
Nis Wechselberg
|
||||
Oliver Crow
|
||||
orelogo
|
||||
Paul Ortyl
|
||||
Raghul
|
||||
Raghul Jagannathan
|
||||
recalculated
|
||||
Ross Harrison
|
||||
Sam Lee
|
||||
Sam Whited
|
||||
saqura
|
||||
Selivanov Pavel
|
||||
Serge
|
||||
Seth Golub
|
||||
sevenmaster
|
||||
Shantana Hardy
|
||||
Simon Danner
|
||||
Simon Rutishauser
|
||||
Simon Schubert
|
||||
Soso Tughushi
|
||||
Spencer Visick
|
||||
Stefan Mitrik
|
||||
Terence Eden
|
||||
Tim Butram
|
||||
Tobias Preuss
|
||||
Tom Hennen
|
||||
Tom Tom
|
||||
tommy watson
|
||||
tuxayo
|
||||
twiceyuan
|
||||
Udi Finkelstein
|
||||
VarunBarad
|
||||
volhol
|
||||
Volker Hollich
|
||||
WangYun
|
||||
William Seemann
|
||||
ydinath
|
||||
|
||||
|
||||
TRANSLATORS
|
||||
===========
|
||||
|
||||
Arabic: abuzar3.khalid, iDemo
|
||||
Azerbaijani: phoenixar
|
||||
Catalan: dvd1985, javiercoll, xc70
|
||||
Catalan (Spain): javiercoll
|
||||
Chinese (China): bebeauties38, dudeG, Felix2yu, gaohongyuan, Guaidaodl, linxiangyu, molisiye, tupunco, wongsyrone, yangyang, YogaGuru
|
||||
Arabic: abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura
|
||||
Asturian (Spain): enolp
|
||||
Azerbaijani: danieloeh, kotfenix
|
||||
Bulgarian: solusitor
|
||||
Catalan: dvd1985, exort12, javiercoll, lambdani, marcmetallextrem, xc70
|
||||
Catalan (Spain): 00c0c0, javiercoll
|
||||
Chinese: dillonbecker, RainSlide, xukeek, yangyang
|
||||
Chinese (China): bebeauties38, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
|
||||
Chinese (Taiwan): gugod, nigelinux, pggdt, ymhuang0808
|
||||
Czech (Czech Republic): elich, Hanzmeister, mcepl, petnek, svetlemodry
|
||||
Danish: CasperHN
|
||||
Dutch: e2jk, glotzbach, rwv
|
||||
Danish: CasperHN, jhertel
|
||||
Dutch: e2jk, glotzbach, rwv, Vistaus
|
||||
English: mfietz, sterylmreep
|
||||
Estonian: Eraser
|
||||
Finnish: danieloeh
|
||||
French: cactux, ChaoticMind, clombion, e2jk, lacouture, Matth78, mfietz, repat, sterylmreep, vcariven
|
||||
German: 112358, altegedanken, bitsunited, ChaoticMind, Chaquotay, dab0015, DJaeger, HolgerJeromin, kalei, lohmann, mfietz, nilso, picsel2, repat, SAPlayer, schafia, ypid
|
||||
Greek: AlexanderKanetakis
|
||||
Hebrew (Israel): amir.dafnyman
|
||||
Hindi (India): purple.coder, siddhusengar
|
||||
Hungarian: glatz.balazs, naren93
|
||||
Indonesian: luke137, silvanael16
|
||||
Italian: aalex70, apanontin, Guybrush88, theloca95
|
||||
Italian (Italy): aalex70, apanontin, Guybrush88, m.chinni, theloca95
|
||||
French: cactux, ChaoticMind, clombion, e2jk, lacouture, Matth78, mfietz, Poussinou, PRIMOKORN, repat, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
|
||||
Galician: antiparvos, pikamoku, Raichely
|
||||
German: 112358, altegedanken, barilla, bitsunited, Buggi, ceving, ChaoticMind, Chaquotay, dab0015, dadosch, DerSilly, DJaeger, elkangaroo, enz, fidel, finsterwalder, Foso, GNi33, HolgerJeromin, kalei, lohmann, LostInWeb, mfietz, nilso, repat, SAPlayer, schafia, Schroedingberg, sevenmaster, sucaml, Teaspoon, theonlytruth, weltenwort, Wyrrrd, ypid
|
||||
Greek: antonist, danieloeh, hua2016s, MSavoritias, pavlosv
|
||||
Hebrew (Israel): amir.dafnyman, E1i9, mongoose4004, pinkasey, rellieberman, Yaron, הלוי11
|
||||
Hindi (India): nmabhinandan, purple.coder, siddhusengar
|
||||
Hungarian: glatz.balazs, lna91, naren93, tszauer, ttyborg42
|
||||
Icelandic: marthjod
|
||||
Indonesian: jff, luke137, rezafaiza, silvanael16
|
||||
Italian: aalex70, allin, apanontin, Bonnee, giuseppep, Guybrush88, marco_pag, neonsoftware, sevenmaster, theloca95
|
||||
Italian (Italy): aalex70, allin, apanontin, Bonnee, buongiorgio, giuseppep, Guybrush88, m.chinni, neonsoftware, nixxo, sevenmaster, theloca95
|
||||
Japanese: Naofumi, RACER1, sh3llc4t, TranslatorG
|
||||
Kannada (India): thejeshgn
|
||||
Korean: changwoo, halcyonest, seungrye, skcha
|
||||
Korean: changwoo, seungrye, skcha
|
||||
Korean (South Korea): changwoo, seungrye
|
||||
Lithuanian: naglis
|
||||
Macedonian: krisfremen
|
||||
Norwegian: hakonanes, timbast
|
||||
Norwegian Bokmål: hakonanes
|
||||
Norwegian Bokmål (Norway): hakonanes, kongk, swordfighter, timbast
|
||||
Polish: Iwangelion, maniexx, thedead4fun
|
||||
Polish (Poland): Iwangelion, lomapur, maniexx, Mephistofeles, shark103, tyle
|
||||
Portuguese: emansije, smarquespt
|
||||
Portuguese (Brazil): alexupits, edman, Firmino, lipefire, lucasmotacr, mbaltar, rogervezaro, SamWilliam, silvanael16
|
||||
Romanian (Romania): corneliu.e, fuzzmz
|
||||
Russian (Russia): astra1, Duke_Raven, mercutiy, null, overmind88, phoenixar, s.chebotar, skvheadless, whereisthetea, zhenya97
|
||||
Spanish: coperfix, dvd1985, Fitoschido, frandavid100, javiercoll, LatinSuD, tres.14159
|
||||
Spanish (Spain): dvd1985, e2jk, frandavid100
|
||||
Swedish (Sweden): albin.brantin, Bio, bpnilsson, ChaoticMind, Lumen, nilso, SharpMelon, TwoD
|
||||
Turkish: basarancaner, brsata, overbite
|
||||
Ukrainian (Ukraine): older, zhenya97
|
||||
Vietnamese: ppanhh, vietnamesel10n
|
||||
Norwegian Bokmål: corkie, hakonanes
|
||||
Norwegian Bokmål (Norway): corkie, hakonanes, kongk, timbast
|
||||
Persian: ahangarha, F7D
|
||||
Polish: Iwangelion, maniexx, mfloryan, thedead4fun
|
||||
Polish (Poland): d6210809, Iwangelion, lomapur, mandlus, maniexx, Mephistofeles, shark103, tyle
|
||||
Portuguese: domingos86, emansije, smarquespt
|
||||
Portuguese (Brazil): alexupits, alysonborges, arua, caioau, carlo_valente, castrors, deandreamatias, edman, Firmino, jackmiras, Junin, lipefire, lluccia, lucasmotacr, mbaltar, rogervezaro, RubeensVinicius, SamWilliam, silvanael16
|
||||
Romanian (Romania): corneliu.e, fuzzmz, ralienpp
|
||||
Russian (Russia): astra1, btimofeev, Duke_Raven, GaynullinDima, MegMasters98, mercutiy, null, overmind88, s.chebotar, shams4real, skvheadless, un_logic, whereisthetea, zhenya97
|
||||
Slovenian (Slovenia): panter23
|
||||
Spanish: AleksSyntek, coperfix, deandreamatias, domingos86, dvd1985, Fitoschido, frandavid100, hard_ware, javiercoll, Juanmuto, lambdani, LatinSuD, leogrignafini, palopezv, TacoTheDank, tres.14159, wakutiteo
|
||||
Spanish (Spain): dvd1985, e2jk, frandavid100, hard_ware, palopezv, Raichely, TacoTheDank
|
||||
Swahili (Kenya): BonfaceKilz
|
||||
Swedish (Sweden): albin.brantin, Bio, bpnilsson, ChaoticMind, jony08, nilso, SharpMelon, TwoD
|
||||
Telugu: veeven
|
||||
Turkish: basarancaner, brsata, Erdy, golcuk, overbite
|
||||
Ukrainian (Ukraine): older, sergiyr, zhenya97
|
||||
Vietnamese: abnvolk, nguyenvui, ppanhh, vietnamesel10n
|
||||
Vietnamese (Vietnam): bizover
|
||||
|
@ -5,7 +5,7 @@ This is the official repository of AntennaPod, the easy-to-use, flexible and ope
|
||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||
alt="Get it on Google Play"
|
||||
height="90">](https://play.google.com/store/apps/details?id=de.danoeh.antennapod)
|
||||
[<img src="https://f-droid.org/badge/get-it-on.png"
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="90">](https://f-droid.org/app/de.danoeh.antennapod)
|
||||
|
||||
|
@ -1,49 +1,27 @@
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
plugins {
|
||||
id('com.github.triplet.play') version '2.0.0'
|
||||
}
|
||||
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
apply plugin: 'com.getkeepsafe.dexcount'
|
||||
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
|
||||
}
|
||||
}
|
||||
|
||||
def getMyVersionName() {
|
||||
def parsedManifestXml = (new XmlSlurper())
|
||||
.parse("${projectDir}/src/main/AndroidManifest.xml")
|
||||
.declareNamespace(android: "http://schemas.android.com/apk/res/android")
|
||||
return parsedManifestXml."@android:versionName"
|
||||
}
|
||||
|
||||
def getMyVersionCode() {
|
||||
def parsedManifestXml = (new XmlSlurper())
|
||||
.parse("${projectDir}/src/main/AndroidManifest.xml")
|
||||
.declareNamespace(android: "http://schemas.android.com/apk/res/android")
|
||||
return parsedManifestXml."@android:versionCode".toInteger()
|
||||
}
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode getMyVersionCode()
|
||||
versionName "${getMyVersionName()}"
|
||||
vectorDrawables.useSupportLibrary true
|
||||
// Version code schema:
|
||||
// "1.2.3-SNAPSHOT" -> 1020300
|
||||
// "1.2.3-RC4" -> 1020304
|
||||
versionCode 1070196
|
||||
versionName "1.7.1"
|
||||
testApplicationId "de.test.antennapod"
|
||||
testInstrumentationRunner "de.test.antennapod.AntennaPodTestRunner"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
generatedDensities = []
|
||||
}
|
||||
|
||||
@ -95,7 +73,7 @@ android {
|
||||
release {
|
||||
resValue "string", "provider_authority", "de.danoeh.antennapod.provider"
|
||||
minifyEnabled true
|
||||
proguardFile "proguard.cfg"
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), "proguard.cfg"
|
||||
signingConfig signingConfigs.releaseConfig
|
||||
buildConfigField STRING, FLATTR_APP_KEY, mFlattrAppKey
|
||||
buildConfigField STRING, FLATTR_APP_SECRET, mFlattrAppSecret
|
||||
@ -120,6 +98,10 @@ android {
|
||||
additionalParameters "--no-version-vectors"
|
||||
}
|
||||
|
||||
testOptions {
|
||||
animationsDisabled = true
|
||||
}
|
||||
|
||||
flavorDimensions "market"
|
||||
productFlavors {
|
||||
free {
|
||||
@ -150,6 +132,7 @@ dependencies {
|
||||
implementation "com.android.support:gridlayout-v7:$supportVersion"
|
||||
implementation "com.android.support:percent:$supportVersion"
|
||||
implementation "com.android.support:recyclerview-v7:$supportVersion"
|
||||
compileOnly 'com.google.android.wearable:wearable:2.2.0'
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
implementation("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
||||
exclude group: "org.json", module: "json"
|
||||
@ -157,14 +140,14 @@ dependencies {
|
||||
implementation "commons-io:commons-io:$commonsioVersion"
|
||||
implementation "org.jsoup:jsoup:$jsoupVersion"
|
||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
||||
implementation "com.squareup.okio:okio:$okioVersion"
|
||||
implementation "de.greenrobot:eventbus:$eventbusVersion"
|
||||
implementation "io.reactivex:rxandroid:$rxAndroidVersion"
|
||||
implementation "io.reactivex:rxjava:$rxJavaVersion"
|
||||
// And ProGuard rules for RxJava!
|
||||
implementation "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
|
||||
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
|
||||
|
||||
implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
|
||||
implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
|
||||
implementation("com.afollestad.material-dialogs:commons:$materialDialogsVersion") {
|
||||
@ -176,18 +159,33 @@ dependencies {
|
||||
}
|
||||
|
||||
implementation "com.github.shts:TriangleLabelView:$triangleLabelViewVersion"
|
||||
implementation 'com.leinardi.android:speed-dial:1.0.2' // 1.0.2 uses support 27.1.1 ; newer versions use 28.0.0;
|
||||
|
||||
implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
|
||||
|
||||
implementation 'com.github.mfietz:fyydlin:v0.3'
|
||||
implementation 'com.github.ByteHamster:SearchPreference:v1.0.8'
|
||||
implementation 'com.github.mfietz:fyydlin:v0.4.2'
|
||||
implementation 'com.github.ByteHamster:SearchPreference:v1.2.5'
|
||||
implementation "org.awaitility:awaitility:$awaitilityVersion"
|
||||
|
||||
androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
||||
}
|
||||
|
||||
play {
|
||||
serviceAccountEmail = '522080222319-compute@developer.gserviceaccount.com'
|
||||
pk12File = file('../serviceaccount-c3d7d0f61387.p12')
|
||||
if (project.hasProperty("antennaPodServiceAccountEmail")) {
|
||||
serviceAccountEmail = antennaPodServiceAccountEmail
|
||||
} else {
|
||||
serviceAccountEmail = '522080222319-compute@developer.gserviceaccount.com'
|
||||
}
|
||||
if (project.hasProperty("antennaPodPk12File")) {
|
||||
serviceAccountCredentials = file(antennaPodPk12File)
|
||||
} else {
|
||||
serviceAccountCredentials = file('../serviceaccount-c3d7d0f61387.p12')
|
||||
}
|
||||
}
|
||||
|
||||
// about.html is templatized so that we can automatically insert
|
||||
@ -217,10 +215,3 @@ task copyTextFiles(type: Copy) {
|
||||
|
||||
preBuild.dependsOn filterAbout, copyTextFiles
|
||||
|
||||
allprojects {
|
||||
gradle.projectsEvaluated {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << "-Xlint" << "-Xlint:-deprecation" << "-Xlint:-serial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,12 @@
|
||||
public *;
|
||||
}
|
||||
|
||||
# for okhttp
|
||||
-dontwarn okhttp3.**
|
||||
-dontwarn okio.**
|
||||
-dontwarn javax.annotation.**
|
||||
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
|
||||
# for RxJava:
|
||||
-dontwarn sun.misc.Unsafe
|
||||
@ -71,8 +75,6 @@
|
||||
-dontwarn android.support.v7.**
|
||||
-dontwarn com.google.android.wearable.**
|
||||
|
||||
-keepattributes *Annotation*
|
||||
|
||||
-keep class org.shredzone.flattr4j.** { *; }
|
||||
-dontwarn org.shredzone.flattr4j.**
|
||||
|
||||
@ -94,16 +96,19 @@
|
||||
-keepclassmembers class ** {
|
||||
public void onEvent*(**);
|
||||
}
|
||||
-keep class de.danoeh.antennapod.core.event.*
|
||||
|
||||
# android-iconify
|
||||
-keep class com.joanzapata.** { *; }
|
||||
|
||||
# Glide
|
||||
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
-keep public class * extends com.bumptech.glide.module.AppGlideModule
|
||||
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
|
||||
|
||||
# for ViewPageIndicator problems (https://github.com/JakeWharton/ViewPagerIndicator/issues/366):
|
||||
-dontwarn com.viewpagerindicator.LinePageIndicator
|
||||
@ -125,3 +130,13 @@
|
||||
-keep class com.squareup.moshi.** { *; }
|
||||
-keep interface com.squareup.moshi.** { *; }
|
||||
-keep public class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory { *; }
|
||||
|
||||
# awaitility
|
||||
-dontwarn java.beans.BeanInfo
|
||||
-dontwarn java.beans.Introspector
|
||||
-dontwarn java.beans.IntrospectionException
|
||||
-dontwarn java.beans.PropertyDescriptor
|
||||
-dontwarn java.lang.management.ManagementFactory
|
||||
-dontwarn java.lang.management.ThreadInfo
|
||||
-dontwarn java.lang.management.ThreadMXBean
|
||||
|
||||
|
34
app/sampledata/episodes.json
Normal file
34
app/sampledata/episodes.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"title": "FLOSS Weekly 482: PyPI",
|
||||
"status_label": "NEW",
|
||||
"duration": "00:52:40",
|
||||
"published_at": "2. May"
|
||||
},
|
||||
{
|
||||
"title": "FLOSS Weekly 479: Pidgin",
|
||||
"status_label": " ",
|
||||
"duration": "01:08:08",
|
||||
"published_at": "11. Apr"
|
||||
},
|
||||
{
|
||||
"title": "Linux Outlaws 370 - Stay Free, Stay Open Source",
|
||||
"status_label": "NEW",
|
||||
"duration": "02:52:51",
|
||||
"published_at": "29. Dec 2014"
|
||||
},
|
||||
{
|
||||
"title": "Linux Outlaws 368 - The Dark Ages of Free Software",
|
||||
"status_label": " ",
|
||||
"duration": "02:26:54",
|
||||
"published_at": "14. Dec 2014"
|
||||
},
|
||||
{
|
||||
"title": "Linux Outlaws 365 - Last Stand",
|
||||
"status_label": " ",
|
||||
"duration": "00:39:59",
|
||||
"published_at": "3. Nov 2014"
|
||||
}
|
||||
]
|
||||
}
|
2
app/sampledata/inplaylist
Normal file
2
app/sampledata/inplaylist
Normal file
@ -0,0 +1,2 @@
|
||||
@null
|
||||
@drawable/ic_list_grey600_24dp
|
3
app/sampledata/secondaryaction
Normal file
3
app/sampledata/secondaryaction
Normal file
@ -0,0 +1,3 @@
|
||||
@drawable/ic_play_arrow_grey600_36dp
|
||||
@drawable/ic_file_download_grey600_24dp
|
||||
@drawable/ic_cancel_grey600_24dp
|
@ -1,18 +0,0 @@
|
||||
package de.test.antennapod;
|
||||
|
||||
import android.test.InstrumentationTestRunner;
|
||||
import android.test.suitebuilder.TestSuiteBuilder;
|
||||
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
public class AntennaPodTestRunner extends InstrumentationTestRunner {
|
||||
|
||||
@Override
|
||||
public TestSuite getAllTests() {
|
||||
return new TestSuiteBuilder(AntennaPodTestRunner.class)
|
||||
.includeAllPackagesUnderHere()
|
||||
.excludePackages("de.test.antennapod.gpodnet")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
38
app/src/androidTest/java/de/test/antennapod/NthMatcher.java
Normal file
38
app/src/androidTest/java/de/test/antennapod/NthMatcher.java
Normal file
@ -0,0 +1,38 @@
|
||||
package de.test.antennapod;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class NthMatcher {
|
||||
public static <T> Matcher<T> first(final Matcher<T> matcher) {
|
||||
return nth(matcher, 1);
|
||||
}
|
||||
|
||||
public static <T> Matcher<T> second(final Matcher<T> matcher) {
|
||||
return nth(matcher, 2);
|
||||
}
|
||||
|
||||
private static <T> Matcher<T> nth(final Matcher<T> matcher, final int index) {
|
||||
return new BaseMatcher<T>() {
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public boolean matches(final Object item) {
|
||||
if (matcher.matches(item)) {
|
||||
if (count.incrementAndGet() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(final Description description) {
|
||||
description.appendText("should return first matching item");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package de.test.antennapod.feed;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
||||
public class FeedItemTest extends AndroidTestCase {
|
||||
|
@ -1,43 +1,43 @@
|
||||
package de.test.antennapod.gpodnet;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* Test class for GpodnetService
|
||||
*/
|
||||
public class GPodnetServiceTest extends AndroidTestCase {
|
||||
@Ignore
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class GPodnetServiceTest {
|
||||
|
||||
private GpodnetService service;
|
||||
|
||||
private static final String USER = "";
|
||||
private static final String PW = "";
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@Before
|
||||
protected void setUp() {
|
||||
service = new GpodnetService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private void authenticate() throws GpodnetServiceException {
|
||||
service.authenticate(USER, PW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSubscription() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
@ -45,6 +45,7 @@ public class GPodnetServiceTest extends AndroidTestCase {
|
||||
service.uploadSubscriptions(USER, "radio", l);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSubscription2() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
@ -53,6 +54,7 @@ public class GPodnetServiceTest extends AndroidTestCase {
|
||||
service.uploadSubscriptions(USER, "radio", l);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadChanges() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
String[] URLS = {"http://bitsundso.de/feed", "http://gamesundso.de/feed", "http://cre.fm/feed/mp3/", "http://freakshow.fm/feed/m4a/"};
|
||||
@ -63,53 +65,63 @@ public class GPodnetServiceTest extends AndroidTestCase {
|
||||
service.uploadChanges(USER, "radio", added, removed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubscriptionChanges() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSubscriptionChanges(USER, "radio", 1362322610L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubscriptionsOfUser()
|
||||
throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSubscriptionsOfUser(USER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubscriptionsOfDevice()
|
||||
throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSubscriptionsOfDevice(USER, "radio");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureDevices() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.configureDevice(USER, "foo", "This is an updated caption",
|
||||
GpodnetDevice.DeviceType.LAPTOP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDevices() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getDevices(USER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSuggestions() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSuggestions(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTags() throws GpodnetServiceException {
|
||||
service.getTopTags(20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPodcastForTags() throws GpodnetServiceException {
|
||||
List<GpodnetTag> tags = service.getTopTags(20);
|
||||
service.getPodcastsForTag(tags.get(1),
|
||||
10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws GpodnetServiceException {
|
||||
service.searchPodcasts("linux", 64);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToplist() throws GpodnetServiceException {
|
||||
service.getPodcastToplist(10);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package de.test.antennapod.handler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
@ -17,7 +18,6 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
|
||||
@ -37,7 +37,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Context context = getInstrumentation().getContext();
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
File destDir = context.getExternalFilesDir(FEEDS_DIR);
|
||||
assertNotNull(destDir);
|
||||
|
||||
@ -82,15 +82,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
assertEquals(feed.getLink(), parsedFeed.getLink());
|
||||
assertEquals(feed.getDescription(), parsedFeed.getDescription());
|
||||
assertEquals(feed.getPaymentLink(), parsedFeed.getPaymentLink());
|
||||
|
||||
if (feed.getImage() != null) {
|
||||
FeedImage image = feed.getImage();
|
||||
FeedImage parsedImage = parsedFeed.getImage();
|
||||
assertNotNull(parsedImage);
|
||||
|
||||
assertEquals(image.getTitle(), parsedImage.getTitle());
|
||||
assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
|
||||
}
|
||||
assertEquals(feed.getImageUrl(), parsedFeed.getImageUrl());
|
||||
|
||||
if (feed.getItems() != null) {
|
||||
assertNotNull(parsedFeed.getItems());
|
||||
@ -119,14 +111,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
assertEquals(media.getMime_type(), parsedMedia.getMime_type());
|
||||
}
|
||||
|
||||
if (item.hasItemImage()) {
|
||||
assertTrue(parsedItem.hasItemImage());
|
||||
FeedImage image = item.getImage();
|
||||
FeedImage parsedImage = parsedItem.getImage();
|
||||
|
||||
assertEquals(image.getTitle(), parsedImage.getTitle());
|
||||
assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
|
||||
}
|
||||
assertEquals(item.getImageUrl(), parsedFeed.getImageUrl());
|
||||
|
||||
if (item.getChapters() != null) {
|
||||
assertNotNull(parsedItem.getChapters());
|
||||
@ -158,12 +143,8 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
private Feed createTestFeed(int numItems, boolean withImage, boolean withFeedMedia, boolean withChapters) {
|
||||
FeedImage image = null;
|
||||
if (withImage) {
|
||||
image = new FeedImage(0, "image", null, "http://example.com/picture", false);
|
||||
}
|
||||
Feed feed = new Feed(0, null, "title", "http://example.com", "This is the description",
|
||||
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", image, file.getAbsolutePath(),
|
||||
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", "http://example.com/picture", file.getAbsolutePath(),
|
||||
"http://example.com/feed", true);
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
|
@ -5,7 +5,6 @@ import android.test.FlakyTest;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -21,6 +21,7 @@ import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
|
||||
*/
|
||||
class DBTestUtils {
|
||||
|
||||
private DBTestUtils(){}
|
||||
/**
|
||||
* Use this method when tests don't involve chapters.
|
||||
*/
|
||||
|
@ -1,10 +1,14 @@
|
||||
package de.test.antennapod.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import android.util.Log;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -15,15 +19,14 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.SimpleChapter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.Consumer;
|
||||
|
||||
/**
|
||||
* Test class for DBWriter
|
||||
@ -58,6 +61,12 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.close();
|
||||
|
||||
Context context = getInstrumentation().getTargetContext();
|
||||
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()).edit();
|
||||
prefEdit.putBoolean(UserPreferences.PREF_DELETE_REMOVES_FROM_QUEUE, true).commit();
|
||||
|
||||
UserPreferences.init(context);
|
||||
}
|
||||
|
||||
public void testSetFeedMediaPlaybackInformation()
|
||||
@ -124,89 +133,54 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
assertNull(media.getFile_url());
|
||||
}
|
||||
|
||||
public void testDeleteFeed() throws IOException, ExecutionException, InterruptedException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
public void testDeleteFeedMediaOfItemRemoveFromQueue()
|
||||
throws IOException, ExecutionException, InterruptedException, TimeoutException {
|
||||
assertTrue(UserPreferences.shouldDeleteRemoveFromQueue());
|
||||
|
||||
File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
|
||||
|
||||
assertTrue(dest.createNewFile());
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
List<FeedItem> items = new ArrayList<>();
|
||||
List<FeedItem> queue = new ArrayList<>();
|
||||
feed.setItems(items);
|
||||
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.UNPLAYED, feed);
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0, 0);
|
||||
item.setMedia(media);
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed, true);
|
||||
feed.getItems().add(item);
|
||||
|
||||
File enc = new File(destFolder, "file " + i);
|
||||
assertTrue(enc.createNewFile());
|
||||
itemFiles.add(enc);
|
||||
|
||||
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
|
||||
item.setMedia(media);
|
||||
|
||||
item.setChapters(new ArrayList<>());
|
||||
item.getChapters().add(new SimpleChapter(0, "item " + i, item, "example.com"));
|
||||
}
|
||||
items.add(item);
|
||||
queue.add(item);
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.setQueue(queue);
|
||||
adapter.close();
|
||||
assertTrue(media.getId() != 0);
|
||||
assertTrue(item.getId() != 0);
|
||||
queue = DBReader.getQueue();
|
||||
assertTrue(queue.size() != 0);
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
assertTrue(item.getChapters().get(0).getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
for (File f : itemFiles) {
|
||||
assertFalse(f.exists());
|
||||
}
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getSimpleChaptersOfFeedItemCursor(item);
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
}
|
||||
adapter.close();
|
||||
DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId());
|
||||
Awaitility.await().until(() -> dest.exists() == false);
|
||||
media = DBReader.getFeedMedia(media.getId());
|
||||
assertNotNull(media);
|
||||
assertFalse(dest.exists());
|
||||
assertFalse(media.isDownloaded());
|
||||
assertNull(media.getFile_url());
|
||||
queue = DBReader.getQueue();
|
||||
assertTrue(queue.size() == 0);
|
||||
}
|
||||
|
||||
public void testDeleteFeedNoImage() throws ExecutionException, InterruptedException, IOException, TimeoutException {
|
||||
public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
feed.setImage(null);
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@ -261,13 +235,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(null);
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
@ -275,21 +243,14 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
@ -300,12 +261,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
// create items
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@ -320,24 +276,18 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
@ -346,65 +296,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void testDeleteFeedWithItemImages() throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
|
||||
// create items with images
|
||||
for (int i = 0; i < 10; i++) {
|
||||
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
|
||||
feed.getItems().add(item);
|
||||
File itemImageFile = new File(destFolder, "item-image-" + i);
|
||||
FeedImage itemImage = new FeedImage(0, "item-image" + i, itemImageFile.getAbsolutePath(), "url", true);
|
||||
item.setImage(itemImage);
|
||||
}
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getImage().getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(item.getImage().getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
}
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
@ -412,11 +303,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
@ -437,7 +324,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
@ -460,9 +346,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
@ -484,11 +367,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
@ -509,7 +388,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
@ -522,9 +400,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
@ -700,29 +575,16 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
final int NUM_ITEMS = 10;
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
for (int i = 0; i < NUM_ITEMS; i++) {
|
||||
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
|
||||
feed.getItems().add(item);
|
||||
}
|
||||
Feed feed = createTestFeed(NUM_ITEMS);
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
}
|
||||
for (int removeIndex = 0; removeIndex < NUM_ITEMS; removeIndex++) {
|
||||
final FeedItem item = feed.getItems().get(removeIndex);
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setQueue(feed.getItems());
|
||||
adapter.close();
|
||||
|
||||
DBWriter.removeQueueItem(context, item, false).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
DBWriter.removeQueueItem(context, false, item).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor queue = adapter.getQueueIDCursor();
|
||||
@ -742,6 +604,43 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveQueueItemMultipleItems() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
// Setup test data
|
||||
//
|
||||
final int NUM_ITEMS = 5;
|
||||
final int NUM_IN_QUEUE = NUM_ITEMS - 1; // the last one not in queue for boundary condition
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
Feed feed = createTestFeed(NUM_ITEMS);
|
||||
|
||||
List<FeedItem> itemsToAdd = feed.getItems().subList(0, NUM_IN_QUEUE);
|
||||
withPodDB(adapter -> adapter.setQueue(itemsToAdd) );
|
||||
|
||||
// Actual tests
|
||||
//
|
||||
|
||||
// Use array rather than List to make codes more succinct
|
||||
Long[] itemIds = toItemIds(feed.getItems()).toArray(new Long[0]);
|
||||
|
||||
DBWriter.removeQueueItem(context, false,
|
||||
itemIds[1], itemIds[3]).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
assertQueueByItemIds("Average case - 2 items removed successfully",
|
||||
itemIds[0], itemIds[2]);
|
||||
|
||||
DBWriter.removeQueueItem(context, false).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
assertQueueByItemIds("Boundary case - no items supplied. queue should see no change",
|
||||
itemIds[0], itemIds[2]);
|
||||
|
||||
DBWriter.removeQueueItem(context, false,
|
||||
itemIds[0], itemIds[4], -1L).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
assertQueueByItemIds("Boundary case - items not in queue ignored",
|
||||
itemIds[2]);
|
||||
|
||||
DBWriter.removeQueueItem(context, false,
|
||||
itemIds[2], -1L).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
assertQueueByItemIds("Boundary case - invalid itemIds ignored"); // the queue is empty
|
||||
|
||||
}
|
||||
|
||||
public void testMoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
final int NUM_ITEMS = 10;
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
@ -839,4 +738,53 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
assertTrue(item.isPlayed());
|
||||
}
|
||||
}
|
||||
|
||||
private static Feed createTestFeed(int numItems) {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
for (int i = 0; i < numItems; i++) {
|
||||
FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
|
||||
feed.getItems().add(item);
|
||||
}
|
||||
|
||||
withPodDB(adapter -> adapter.setCompleteFeed(feed));
|
||||
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
}
|
||||
return feed;
|
||||
}
|
||||
|
||||
private static void withPodDB(Consumer<PodDBAdapter> action) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
try {
|
||||
adapter.open();
|
||||
action.accept(adapter);
|
||||
} finally {
|
||||
adapter.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertQueueByItemIds(
|
||||
String message,
|
||||
long... itemIdsExpected
|
||||
) {
|
||||
List<FeedItem> queue = DBReader.getQueue();
|
||||
List<Long> itemIdsActualList = toItemIds(queue);
|
||||
List<Long> itemIdsExpectedList = new ArrayList<Long>(itemIdsExpected.length);
|
||||
for (long id : itemIdsExpected) {
|
||||
itemIdsExpectedList.add(id);
|
||||
}
|
||||
|
||||
assertEquals(message, itemIdsExpectedList, itemIdsActualList);
|
||||
}
|
||||
|
||||
private static List<Long> toItemIds(List<FeedItem> items) {
|
||||
List<Long> itemIds = new ArrayList<Long>(items.size());
|
||||
for(FeedItem item : items) {
|
||||
itemIds.add(item.getId());
|
||||
}
|
||||
return itemIds;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,16 +2,14 @@ package de.test.antennapod.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.FlakyTest;
|
||||
import android.support.test.espresso.contrib.DrawerActions;
|
||||
import android.support.test.espresso.intent.Intents;
|
||||
import android.support.test.filters.FlakyTest;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.robotium.solo.Solo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.robotium.solo.Timeout;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
@ -23,25 +21,46 @@ import de.danoeh.antennapod.fragment.DownloadsFragment;
|
||||
import de.danoeh.antennapod.fragment.EpisodesFragment;
|
||||
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
|
||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.action.ViewActions.longClick;
|
||||
import static android.support.test.espresso.intent.Intents.intended;
|
||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static de.test.antennapod.NthMatcher.first;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* User interface tests for MainActivity
|
||||
*/
|
||||
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MainActivityTest {
|
||||
|
||||
private Solo solo;
|
||||
private UITestUtils uiTestUtils;
|
||||
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public MainActivityTest() {
|
||||
super(MainActivity.class);
|
||||
}
|
||||
@Rule
|
||||
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Context context = getInstrumentation().getTargetContext();
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
Intents.init();
|
||||
Context context = mActivityRule.getActivity();
|
||||
uiTestUtils = new UITestUtils(context);
|
||||
uiTestUtils.setup();
|
||||
|
||||
@ -54,30 +73,26 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
|
||||
|
||||
// override first launch preference
|
||||
// do this BEFORE calling getActivity()!
|
||||
prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
|
||||
prefs = context.getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
|
||||
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
|
||||
|
||||
solo = new Solo(getInstrumentation(), getActivity());
|
||||
solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
uiTestUtils.tearDown();
|
||||
solo.finishOpenedActivities();
|
||||
|
||||
Intents.release();
|
||||
PodDBAdapter.deleteDatabase();
|
||||
|
||||
// reset preferences
|
||||
prefs.edit().clear().commit();
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private void openNavDrawer() {
|
||||
solo.clickOnImageButton(0);
|
||||
getInstrumentation().waitForIdleSync();
|
||||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddFeed() throws Exception {
|
||||
uiTestUtils.addHostedFeedData();
|
||||
final Feed feed = uiTestUtils.hostedFeeds.get(0);
|
||||
@ -89,10 +104,12 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
|
||||
solo.waitForView(R.id.butSubscribe);
|
||||
assertEquals(solo.getString(R.string.subscribe_label), solo.getButton(0).getText().toString());
|
||||
solo.clickOnButton(0);
|
||||
solo.waitForText(solo.getString(R.string.subscribed_label));
|
||||
assertTrue(solo.waitForText(solo.getString(R.string.open_podcast), 0, Timeout.getLargeTimeout(), false));
|
||||
}
|
||||
|
||||
@FlakyTest(tolerance = 3)
|
||||
|
||||
@Test
|
||||
@FlakyTest
|
||||
public void testClickNavDrawer() throws Exception {
|
||||
uiTestUtils.addLocalFeedData(false);
|
||||
|
||||
@ -150,57 +167,60 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
|
||||
return ((MainActivity) solo.getCurrentActivity()).getSupportActionBar().getTitle().toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@FlakyTest(tolerance = 3)
|
||||
|
||||
@Test
|
||||
@FlakyTest
|
||||
public void testGoToPreferences() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.waitForActivity(PreferenceActivity.class);
|
||||
onView(withText(R.string.settings_label)).perform(click());
|
||||
intended(hasComponent(PreferenceActivity.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawerPreferencesHideSomeElements() {
|
||||
UserPreferences.setHiddenDrawerItems(new ArrayList<>());
|
||||
openNavDrawer();
|
||||
solo.clickLongOnText(solo.getString(R.string.queue_label));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.episodes_label));
|
||||
solo.clickOnText(solo.getString(R.string.playback_history_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
solo.waitForDialogToClose();
|
||||
onView(first(withText(R.string.queue_label))).perform(longClick());
|
||||
onView(withText(R.string.episodes_label)).perform(click());
|
||||
onView(withText(R.string.playback_history_label)).perform(click());
|
||||
onView(withText(R.string.confirm_label)).perform(click());
|
||||
|
||||
List<String> hidden = UserPreferences.getHiddenDrawerItems();
|
||||
assertEquals(2, hidden.size());
|
||||
assertTrue(hidden.contains(EpisodesFragment.TAG));
|
||||
assertTrue(hidden.contains(PlaybackHistoryFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawerPreferencesUnhideSomeElements() {
|
||||
List<String> hidden = Arrays.asList(PlaybackHistoryFragment.TAG, DownloadsFragment.TAG);
|
||||
UserPreferences.setHiddenDrawerItems(hidden);
|
||||
openNavDrawer();
|
||||
solo.clickLongOnText(solo.getString(R.string.queue_label));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.downloads_label));
|
||||
solo.clickOnText(solo.getString(R.string.queue_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
solo.waitForDialogToClose();
|
||||
onView(first(withText(R.string.queue_label))).perform(longClick());
|
||||
|
||||
onView(withText(R.string.downloads_label)).perform(click());
|
||||
onView(withText(R.string.queue_label)).perform(click());
|
||||
onView(withText(R.string.confirm_label)).perform(click());
|
||||
|
||||
hidden = UserPreferences.getHiddenDrawerItems();
|
||||
assertEquals(2, hidden.size());
|
||||
assertTrue(hidden.contains(QueueFragment.TAG));
|
||||
assertTrue(hidden.contains(PlaybackHistoryFragment.TAG));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDrawerPreferencesHideAllElements() {
|
||||
UserPreferences.setHiddenDrawerItems(new ArrayList<>());
|
||||
String[] titles = getInstrumentation().getTargetContext().getResources().getStringArray(R.array.nav_drawer_titles);
|
||||
String[] titles = mActivityRule.getActivity().getResources().getStringArray(R.array.nav_drawer_titles);
|
||||
|
||||
openNavDrawer();
|
||||
solo.clickLongOnText(solo.getString(R.string.queue_label));
|
||||
solo.waitForDialogToOpen();
|
||||
onView(first(withText(R.string.queue_label))).perform(longClick());
|
||||
for (String title : titles) {
|
||||
solo.clickOnText(title);
|
||||
onView(first(withText(title))).perform(click());
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
solo.waitForDialogToClose();
|
||||
onView(withText(R.string.confirm_label)).perform(click());
|
||||
|
||||
List<String> hidden = UserPreferences.getHiddenDrawerItems();
|
||||
assertEquals(titles.length, hidden.size());
|
||||
for (String tag : MainActivity.NAV_DRAWER_TAGS) {
|
||||
@ -208,21 +228,85 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawerPreferencesHideCurrentElement() {
|
||||
UserPreferences.setHiddenDrawerItems(new ArrayList<>());
|
||||
openNavDrawer();
|
||||
onView(withText(R.string.downloads_label)).perform(click());
|
||||
openNavDrawer();
|
||||
|
||||
onView(first(withText(R.string.queue_label))).perform(longClick());
|
||||
onView(first(withText(R.string.downloads_label))).perform(click());
|
||||
onView(withText(R.string.confirm_label)).perform(click());
|
||||
|
||||
openNavDrawer();
|
||||
String downloads = solo.getString(R.string.downloads_label);
|
||||
solo.clickOnText(downloads);
|
||||
solo.waitForView(android.R.id.list);
|
||||
openNavDrawer();
|
||||
solo.clickLongOnText(downloads);
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(downloads);
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
solo.waitForDialogToClose();
|
||||
List<String> hidden = UserPreferences.getHiddenDrawerItems();
|
||||
assertEquals(1, hidden.size());
|
||||
assertTrue(hidden.contains(DownloadsFragment.TAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorGoToPage() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
|
||||
solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.subscriptions_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
solo.goBackToActivity(MainActivity.class.getSimpleName());
|
||||
solo.goBack();
|
||||
assertEquals(solo.getString(R.string.subscriptions_label), getActionbarTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorOpenDrawer() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
|
||||
solo.clickOnText(solo.getString(R.string.back_button_open_drawer));
|
||||
solo.goBackToActivity(MainActivity.class.getSimpleName());
|
||||
solo.goBack();
|
||||
assertTrue(((MainActivity)solo.getCurrentActivity()).isDrawerOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorDoubleTap() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
|
||||
solo.clickOnText(solo.getString(R.string.back_button_double_tap));
|
||||
solo.goBackToActivity(MainActivity.class.getSimpleName());
|
||||
solo.goBack();
|
||||
solo.goBack();
|
||||
assertTrue(solo.getCurrentActivity().isFinishing());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorPrompt() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
|
||||
solo.clickOnText(solo.getString(R.string.back_button_show_prompt));
|
||||
solo.goBackToActivity(MainActivity.class.getSimpleName());
|
||||
solo.goBack();
|
||||
solo.clickOnText(solo.getString(R.string.yes));
|
||||
solo.waitForDialogToClose();
|
||||
assertTrue(solo.getCurrentActivity().isFinishing());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorDefault() {
|
||||
openNavDrawer();
|
||||
solo.clickOnText(solo.getString(R.string.settings_label));
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_back_button_behavior_title));
|
||||
solo.clickOnText(solo.getString(R.string.back_button_default));
|
||||
solo.goBackToActivity(MainActivity.class.getSimpleName());
|
||||
solo.goBack();
|
||||
assertTrue(solo.getCurrentActivity().isFinishing());
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi
|
||||
.clear()
|
||||
.putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false)
|
||||
.putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false)
|
||||
.putBoolean(UserPreferences.PREF_SONIC, true)
|
||||
.putString(UserPreferences.PREF_MEDIA_PLAYER, "sonic")
|
||||
.commit();
|
||||
|
||||
solo = new Solo(getInstrumentation(), getActivity());
|
||||
|
@ -1,12 +1,23 @@
|
||||
package de.test.antennapod.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.test.espresso.contrib.RecyclerViewActions;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.view.View;
|
||||
|
||||
import com.robotium.solo.Solo;
|
||||
import com.robotium.solo.Timeout;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -17,36 +28,48 @@ import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.fragment.EpisodesFragment;
|
||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
|
||||
public class PreferencesTest extends ActivityInstrumentationTestCase2<PreferenceActivity> {
|
||||
|
||||
private static final String TAG = "PreferencesTest";
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PreferencesTest {
|
||||
private Solo solo;
|
||||
private Context context;
|
||||
private Resources res;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public PreferencesTest() {
|
||||
super(PreferenceActivity.class);
|
||||
}
|
||||
@Rule
|
||||
public ActivityTestRule<PreferenceActivity> mActivityRule = new ActivityTestRule<>(PreferenceActivity.class);
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
solo = new Solo(getInstrumentation(), getActivity());
|
||||
@Before
|
||||
public void setUp() {
|
||||
solo = new Solo(getInstrumentation(), mActivityRule.getActivity());
|
||||
Timeout.setSmallTimeout(500);
|
||||
Timeout.setLargeTimeout(1000);
|
||||
context = getInstrumentation().getTargetContext();
|
||||
res = getActivity().getResources();
|
||||
UserPreferences.init(context);
|
||||
res = mActivityRule.getActivity().getResources();
|
||||
UserPreferences.init(mActivityRule.getActivity());
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(mActivityRule.getActivity());
|
||||
prefs.edit().clear();
|
||||
prefs.edit().putBoolean(UserPreferences.PREF_ENABLE_AUTODL, true).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() {
|
||||
solo.finishOpenedActivities();
|
||||
super.tearDown();
|
||||
prefs.edit().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchTheme() {
|
||||
final int theme = UserPreferences.getTheme();
|
||||
int otherTheme;
|
||||
@ -55,13 +78,13 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
} else {
|
||||
otherTheme = R.string.pref_theme_title_light;
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(otherTheme));
|
||||
clickPreference(withText(R.string.user_interface_label));
|
||||
clickPreference(withText(R.string.pref_set_theme_title));
|
||||
onView(withText(otherTheme)).perform(click());
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getTheme() != theme, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchThemeBack() {
|
||||
final int theme = UserPreferences.getTheme();
|
||||
int otherTheme;
|
||||
@ -70,33 +93,23 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
} else {
|
||||
otherTheme = R.string.pref_theme_title_light;
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
solo.clickOnText(solo.getString(otherTheme));
|
||||
clickPreference(withText(R.string.user_interface_label));
|
||||
clickPreference(withText(R.string.pref_set_theme_title));
|
||||
onView(withText(otherTheme)).perform(click());
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getTheme() != theme, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
public void testExpandNotification() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
final int priority = UserPreferences.getNotifyPriority();
|
||||
solo.clickOnText(solo.getString(R.string.pref_expandNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> priority != UserPreferences.getNotifyPriority(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_expandNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> priority == UserPreferences.getNotifyPriority(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnablePersistentPlaybackControls() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
final boolean persistNotify = UserPreferences.isPersistNotify();
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
|
||||
clickPreference(withText(R.string.user_interface_label));
|
||||
clickPreference(withText(R.string.pref_persistNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> persistNotify != UserPreferences.isPersistNotify(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
|
||||
clickPreference(withText(R.string.pref_persistNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> persistNotify == UserPreferences.isPersistNotify(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLockscreenButtons() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.scrollDown();
|
||||
@ -123,6 +136,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> !UserPreferences.showSkipOnCompactNotification(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueAtFront() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean enqueueAtFront = UserPreferences.enqueueAtFront();
|
||||
@ -134,6 +148,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> enqueueAtFront == UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadPhonesDisconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean pauseOnHeadsetDisconnect = UserPreferences.isPauseOnHeadsetDisconnect();
|
||||
@ -143,6 +158,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> pauseOnHeadsetDisconnect == UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadPhonesReconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
|
||||
@ -156,6 +172,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> unpauseOnHeadsetReconnect == UserPreferences.isUnpauseOnHeadsetReconnect(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBluetoothReconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
|
||||
@ -169,6 +186,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> unpauseOnBluetoothReconnect == UserPreferences.isUnpauseOnBluetoothReconnect(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousPlayback() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean continuousPlayback = UserPreferences.isFollowQueue();
|
||||
@ -180,6 +198,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> continuousPlayback == UserPreferences.isFollowQueue(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoDelete() {
|
||||
solo.clickOnText(solo.getString(R.string.storage_pref));
|
||||
final boolean autoDelete = UserPreferences.isAutoDelete();
|
||||
@ -189,17 +208,15 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> autoDelete == UserPreferences.isAutoDelete(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaybackSpeeds() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_playback_speed_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
clickPreference(withText(R.string.playback_pref));
|
||||
clickPreference(withText(R.string.pref_playback_speed_title));
|
||||
assertTrue(solo.searchText(res.getStringArray(R.array.playback_speed_values)[0]));
|
||||
solo.clickOnText(solo.getString(R.string.cancel_label));
|
||||
solo.waitForDialogToClose(1000);
|
||||
onView(withText(R.string.cancel_label)).perform(click());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPauseForInterruptions() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean pauseForFocusLoss = UserPreferences.shouldPauseForFocusLoss();
|
||||
@ -209,6 +226,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> pauseForFocusLoss == UserPreferences.shouldPauseForFocusLoss(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableUpdateInterval() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_sum));
|
||||
@ -217,31 +235,31 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getUpdateInterval() == 0, 1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUpdateInterval() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
|
||||
solo.waitForDialogToOpen();
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_autoUpdateIntervallOrTime_title));
|
||||
onView(withText(R.string.pref_autoUpdateIntervallOrTime_Interval)).perform(click());
|
||||
String search = "12 " + solo.getString(R.string.pref_update_interval_hours_plural);
|
||||
solo.clickOnText(search);
|
||||
solo.waitForDialogToClose();
|
||||
onView(withText(search)).perform(click());
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getUpdateInterval() ==
|
||||
TimeUnit.HOURS.toMillis(12), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMobileUpdates() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
final boolean mobileUpdates = UserPreferences.isAllowMobileUpdate();
|
||||
solo.clickOnText(solo.getString(R.string.pref_mobileUpdate_title));
|
||||
clickPreference(withText(R.string.pref_mobileUpdate_title));
|
||||
assertTrue(solo.waitForCondition(() -> mobileUpdates != UserPreferences.isAllowMobileUpdate(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_mobileUpdate_title));
|
||||
clickPreference(withText(R.string.pref_mobileUpdate_title));
|
||||
assertTrue(solo.waitForCondition(() -> mobileUpdates == UserPreferences.isAllowMobileUpdate(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSequentialDownload() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
solo.enterText(0, "1");
|
||||
@ -249,9 +267,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getParallelDownloads() == 1, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParallelDownloads() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
solo.enterText(0, "10");
|
||||
@ -259,50 +278,50 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getParallelDownloads() == 10, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParallelDownloadsInvalidInput() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
solo.enterText(0, "0");
|
||||
assertEquals("1", solo.getEditText(0).getText().toString());
|
||||
assertEquals("", solo.getEditText(0).getText().toString());
|
||||
solo.clearEditText(0);
|
||||
solo.enterText(0, "100");
|
||||
assertEquals("50", solo.getEditText(0).getText().toString());
|
||||
assertEquals("", solo.getEditText(0).getText().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetEpisodeCache() {
|
||||
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
String entry = entries[entries.length/2];
|
||||
final int value = Integer.valueOf(values[values.length/2]);
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.pref_episode_cache_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(entry);
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == value, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetEpisodeCacheMin() {
|
||||
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
String minEntry = entries[0];
|
||||
final int minValue = Integer.valueOf(values[0]);
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
if(!UserPreferences.isEnableAutodownload()) {
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
|
||||
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.pref_episode_cache_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
solo.scrollUp();
|
||||
solo.clickOnText(minEntry);
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == minValue, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetEpisodeCacheMax() {
|
||||
String[] entries = res.getStringArray(R.array.episode_cache_size_entries);
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
@ -311,24 +330,22 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
if(!UserPreferences.isEnableAutodownload()) {
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(maxEntry);
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == maxValue, Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutomaticDownload() {
|
||||
final boolean automaticDownload = UserPreferences.isEnableAutodownload();
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
|
||||
assertTrue(solo.waitForCondition(() -> automaticDownload != UserPreferences.isEnableAutodownload(), Timeout.getLargeTimeout()));
|
||||
if(UserPreferences.isEnableAutodownload() == false) {
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
}
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.isEnableAutodownload() == true, Timeout.getLargeTimeout()));
|
||||
final boolean enableAutodownloadOnBattery = UserPreferences.isEnableAutodownloadOnBattery();
|
||||
@ -343,6 +360,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
assertTrue(solo.waitForCondition(() -> enableWifiFilter == UserPreferences.isEnableAutodownloadWifiFilter(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEpisodeCleanupQueueOnly() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
@ -356,6 +374,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEpisodeCleanupNeverAlg() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
@ -369,6 +388,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEpisodeCleanupClassic() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
@ -379,39 +399,39 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
|
||||
if (alg instanceof APCleanupAlgorithm) {
|
||||
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm)alg;
|
||||
return cleanupAlg.getNumberOfDaysAfterPlayback() == 0;
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 0;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEpisodeCleanupNumDays() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForText(solo.getString(R.string.episode_cleanup_after_listening));
|
||||
solo.clickOnText("5");
|
||||
clickPreference(withText(R.string.network_pref));
|
||||
clickPreference(withText(R.string.pref_automatic_download_title));
|
||||
clickPreference(withText(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForDialogToOpen();
|
||||
String search = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, 5, 5);
|
||||
onView(withText(search)).perform(click());
|
||||
assertTrue(solo.waitForCondition(() -> {
|
||||
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
|
||||
if (alg instanceof APCleanupAlgorithm) {
|
||||
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm)alg;
|
||||
return cleanupAlg.getNumberOfDaysAfterPlayback() == 5;
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 120; // 5 days
|
||||
}
|
||||
return false;
|
||||
},
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRewindChange() {
|
||||
int seconds = UserPreferences.getRewindSecs();
|
||||
int deltas[] = res.getIntArray(R.array.seek_delta_values);
|
||||
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_rewind));
|
||||
clickPreference(withText(R.string.playback_pref));
|
||||
clickPreference(withText(R.string.pref_rewind));
|
||||
solo.waitForDialogToOpen();
|
||||
|
||||
int currentIndex = Arrays.binarySearch(deltas, seconds);
|
||||
@ -419,24 +439,22 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
|
||||
// Find next value (wrapping around to next)
|
||||
int newIndex = (currentIndex + 1) % deltas.length;
|
||||
|
||||
solo.clickOnText(String.valueOf(deltas[newIndex]) + " seconds");
|
||||
solo.clickOnButton("Confirm");
|
||||
onView(withText(String.valueOf(deltas[newIndex]) + " seconds")).perform(click());
|
||||
onView(withText("Confirm")).perform(click());
|
||||
|
||||
solo.waitForDialogToClose();
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getRewindSecs() == deltas[newIndex],
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFastForwardChange() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
clickPreference(withText(R.string.playback_pref));
|
||||
for (int i = 2; i > 0; i--) { // repeat twice to catch any error where fastforward is tracking rewind
|
||||
int seconds = UserPreferences.getFastForwardSecs();
|
||||
int deltas[] = res.getIntArray(R.array.seek_delta_values);
|
||||
|
||||
solo.clickOnText(solo.getString(R.string.pref_fast_forward));
|
||||
clickPreference(withText(R.string.pref_fast_forward));
|
||||
solo.waitForDialogToOpen();
|
||||
|
||||
int currentIndex = Arrays.binarySearch(deltas, seconds);
|
||||
@ -445,12 +463,66 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
// Find next value (wrapping around to next)
|
||||
int newIndex = (currentIndex + 1) % deltas.length;
|
||||
|
||||
solo.clickOnText(String.valueOf(deltas[newIndex]) + " seconds");
|
||||
solo.clickOnButton("Confirm");
|
||||
onView(withText(String.valueOf(deltas[newIndex]) + " seconds")).perform(click());
|
||||
onView(withText("Confirm")).perform(click());
|
||||
|
||||
solo.waitForDialogToClose();
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getFastForwardSecs() == deltas[newIndex],
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackButtonBehaviorGoToPageSelector() {
|
||||
clickPreference(withText(R.string.user_interface_label));
|
||||
clickPreference(withText(R.string.pref_back_button_behavior_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.queue_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
|
||||
Timeout.getLargeTimeout()));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(QueueFragment.TAG),
|
||||
Timeout.getLargeTimeout()));
|
||||
clickPreference(withText(R.string.pref_back_button_behavior_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.episodes_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
|
||||
Timeout.getLargeTimeout()));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(EpisodesFragment.TAG),
|
||||
Timeout.getLargeTimeout()));
|
||||
clickPreference(withText(R.string.pref_back_button_behavior_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.back_button_go_to_page));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.subscriptions_label));
|
||||
solo.clickOnText(solo.getString(R.string.confirm_label));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonBehavior() == UserPreferences.BackButtonBehavior.GO_TO_PAGE,
|
||||
Timeout.getLargeTimeout()));
|
||||
assertTrue(solo.waitForCondition(() -> UserPreferences.getBackButtonGoToPage().equals(SubscriptionFragment.TAG),
|
||||
Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteRemovesFromQueue() {
|
||||
clickPreference(withText(R.string.storage_pref));
|
||||
if (!UserPreferences.shouldDeleteRemoveFromQueue()) {
|
||||
clickPreference(withText(R.string.pref_delete_removes_from_queue_title));
|
||||
assertTrue(solo.waitForCondition(UserPreferences::shouldDeleteRemoveFromQueue, Timeout.getLargeTimeout()));
|
||||
}
|
||||
final boolean deleteRemovesFromQueue = UserPreferences.shouldDeleteRemoveFromQueue();
|
||||
solo.clickOnText(solo.getString(R.string.pref_delete_removes_from_queue_title));
|
||||
assertTrue(solo.waitForCondition(() -> deleteRemovesFromQueue != UserPreferences.shouldDeleteRemoveFromQueue(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_delete_removes_from_queue_title));
|
||||
assertTrue(solo.waitForCondition(() -> deleteRemovesFromQueue == UserPreferences.shouldDeleteRemoveFromQueue(), Timeout.getLargeTimeout()));
|
||||
}
|
||||
|
||||
private void clickPreference(Matcher<View> matcher) {
|
||||
onView(withId(R.id.list))
|
||||
.perform(RecyclerViewActions.actionOnItem(hasDescendant(matcher), click()));
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
@ -136,12 +135,9 @@ class UITestUtils {
|
||||
public void addHostedFeedData() throws IOException {
|
||||
if (feedDataHosted) throw new IllegalStateException("addHostedFeedData was called twice on the same instance");
|
||||
for (int i = 0; i < NUM_FEEDS; i++) {
|
||||
File bitmapFile = newBitmapFile("image" + i);
|
||||
FeedImage image = new FeedImage(0, "image " + i, null, hostFile(bitmapFile), false);
|
||||
Feed feed = new Feed(0, null, "Title " + i, "http://example.com/" + i, "Description of feed " + i,
|
||||
"http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, image, null,
|
||||
"http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, null, null,
|
||||
"http://example.com/feed/src/" + i, false);
|
||||
image.setOwner(feed);
|
||||
|
||||
// create items
|
||||
List<FeedItem> items = new ArrayList<>();
|
||||
@ -187,12 +183,6 @@ class UITestUtils {
|
||||
List<FeedItem> queue = new ArrayList<>();
|
||||
for (Feed feed : hostedFeeds) {
|
||||
feed.setDownloaded(true);
|
||||
if (feed.getImage() != null) {
|
||||
FeedImage image = feed.getImage();
|
||||
int fileId = Integer.parseInt(StringUtils.substringAfter(image.getDownload_url(), "files/"));
|
||||
image.setFile_url(server.accessFile(fileId).getAbsolutePath());
|
||||
image.setDownloaded(true);
|
||||
}
|
||||
if (downloadEpisodes) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.hasMedia()) {
|
||||
|
@ -38,9 +38,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
|
||||
|
||||
for (Feed feed : feeds) {
|
||||
testUrlReachable(feed.getDownload_url());
|
||||
if (feed.getImage() != null) {
|
||||
testUrlReachable(feed.getImage().getDownload_url());
|
||||
}
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.hasMedia()) {
|
||||
testUrlReachable(item.getMedia().getDownload_url());
|
||||
@ -66,9 +63,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
|
||||
|
||||
for (Feed feed : uiTestUtils.hostedFeeds) {
|
||||
assertTrue(feed.getId() != 0);
|
||||
if (feed.getImage() != null) {
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
}
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
if (item.hasMedia()) {
|
||||
|
@ -1,35 +0,0 @@
|
||||
package de.test.antennapod.util;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
|
||||
/**
|
||||
* Test class for converter
|
||||
*/
|
||||
public class ConverterTest extends AndroidTestCase {
|
||||
|
||||
public void testGetDurationStringLong() throws Exception {
|
||||
String expected = "13:05:10";
|
||||
int input = 47110000;
|
||||
assertEquals(expected, Converter.getDurationStringLong(input));
|
||||
}
|
||||
|
||||
public void testGetDurationStringShort() throws Exception {
|
||||
String expected = "13:05";
|
||||
int input = 47110000;
|
||||
assertEquals(expected, Converter.getDurationStringShort(input));
|
||||
}
|
||||
|
||||
public void testDurationStringLongToMs() throws Exception {
|
||||
String input = "01:20:30";
|
||||
long expected = 4830000;
|
||||
assertEquals(expected, Converter.durationStringLongToMs(input));
|
||||
}
|
||||
|
||||
public void testDurationStringShortToMs() throws Exception {
|
||||
String input = "8:30";
|
||||
long expected = 30600000;
|
||||
assertEquals(expected, Converter.durationStringShortToMs(input));
|
||||
}
|
||||
}
|
@ -30,12 +30,12 @@ public class TimelineTest extends InstrumentationTestCase {
|
||||
context = getInstrumentation().getTargetContext();
|
||||
}
|
||||
|
||||
private Playable newTestPlayable(List<Chapter> chapters, String shownotes) {
|
||||
private Playable newTestPlayable(List<Chapter> chapters, String shownotes, int duration) {
|
||||
FeedItem item = new FeedItem(0, "Item", "item-id", "http://example.com/item", new Date(), FeedItem.PLAYED, null);
|
||||
item.setChapters(chapters);
|
||||
item.setContentEncoded(shownotes);
|
||||
FeedMedia media = new FeedMedia(item, "http://example.com/episode", 100, "audio/mp3");
|
||||
media.setDuration(Integer.MAX_VALUE);
|
||||
media.setDuration(duration);
|
||||
item.setMedia(media);
|
||||
return media;
|
||||
}
|
||||
@ -44,7 +44,17 @@ public class TimelineTest extends InstrumentationTestCase {
|
||||
final String timeStr = "10:11:12";
|
||||
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11 + 12 * 1000;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>");
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeHHMMSSMoreThen24HoursNoChapters() throws Exception {
|
||||
final String timeStr = "25:00:00";
|
||||
final long time = 25 * 60 * 60 * 1000;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
@ -54,17 +64,67 @@ public class TimelineTest extends InstrumentationTestCase {
|
||||
final String timeStr = "10:11";
|
||||
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>");
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeMMSSNoChapters() throws Exception {
|
||||
final String timeStr = "10:11";
|
||||
final long time = 10 * 60 * 1000 + 11 * 1000;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", 11 * 60 * 1000);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeHMMSSNoChapters() throws Exception {
|
||||
final String timeStr = "2:11:12";
|
||||
final long time = 2 * 60 * 60 * 1000 + 11 * 60 * 1000 + 12 * 1000;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeMSSNoChapters() throws Exception {
|
||||
final String timeStr = "1:12";
|
||||
final long time = 60 * 1000 + 12 * 1000;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStr + " here.</p>", 2 * 60 * 1000);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeMultipleFormatsNoChapters() throws Exception {
|
||||
final String[] timeStrings = new String[]{ "10:12", "1:10:12" };
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!</p>", 2 * 60 * 60 * 1000);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 60 * 60 * 1000 + 10 * 60 * 1000 + 12 * 1000 }, timeStrings);
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeMultipleShortFormatNoChapters() throws Exception {
|
||||
|
||||
// One of these timecodes fits as HH:MM and one does not so both should be parsed as MM:SS.
|
||||
final String[] timeStrings = new String[]{ "10:12", "2:12" };
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!</p>", 3 * 60 * 60 * 1000);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 2 * 60 * 1000 + 12 * 1000 }, timeStrings);
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeParentheses() throws Exception {
|
||||
final String timeStr = "10:11";
|
||||
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode (" + timeStr + ") here.</p>");
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode (" + timeStr + ") here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
@ -74,7 +134,7 @@ public class TimelineTest extends InstrumentationTestCase {
|
||||
final String timeStr = "10:11";
|
||||
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode [" + timeStr + "] here.</p>");
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode [" + timeStr + "] here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
@ -84,12 +144,27 @@ public class TimelineTest extends InstrumentationTestCase {
|
||||
final String timeStr = "10:11";
|
||||
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode <" + timeStr + "> here.</p>");
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode <" + timeStr + "> here.</p>", Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{time}, new String[]{timeStr});
|
||||
}
|
||||
|
||||
public void testProcessShownotesAndInvalidTimecode() throws Exception {
|
||||
final String[] timeStrs = new String[] {"2:1", "0:0", "000", "00", "00:000"};
|
||||
|
||||
StringBuilder shownotes = new StringBuilder("<p> Some test text with timecodes ");
|
||||
for (String timeStr : timeStrs) {
|
||||
shownotes.append(timeStr).append(" ");
|
||||
}
|
||||
shownotes.append("here.</p>");
|
||||
|
||||
Playable p = newTestPlayable(null, shownotes.toString(), Integer.MAX_VALUE);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[0], new String[0]);
|
||||
}
|
||||
|
||||
private void checkLinkCorrect(String res, long[] timecodes, String[] timecodeStr) {
|
||||
assertNotNull(res);
|
||||
Document d = Jsoup.parse(res);
|
||||
|
@ -56,6 +56,11 @@ public class AtomGenerator implements FeedGenerator{
|
||||
xml.text(feed.getDescription());
|
||||
xml.endTag(null, "subtitle");
|
||||
}
|
||||
if (feed.getImageUrl() != null) {
|
||||
xml.startTag(null, "logo");
|
||||
xml.text(feed.getImageUrl());
|
||||
xml.endTag(null, "logo");
|
||||
}
|
||||
|
||||
if (feed.getPaymentLink() != null) {
|
||||
GeneratorUtil.addPaymentLink(xml, feed.getPaymentLink(), false);
|
||||
|
@ -8,6 +8,7 @@ import java.io.IOException;
|
||||
* Utility methods for FeedGenerator
|
||||
*/
|
||||
class GeneratorUtil {
|
||||
private GeneratorUtil(){}
|
||||
|
||||
public static void addPaymentLink(XmlSerializer xml, String paymentLink, boolean withNamespace) throws IOException {
|
||||
String ns = (withNamespace) ? "http://www.w3.org/2005/Atom" : null;
|
||||
|
@ -54,6 +54,13 @@ public class RSS2Generator implements FeedGenerator{
|
||||
xml.text(feed.getLanguage());
|
||||
xml.endTag(null, "language");
|
||||
}
|
||||
if (feed.getImageUrl() != null) {
|
||||
xml.startTag(null, "image");
|
||||
xml.startTag(null, "url");
|
||||
xml.text(feed.getImageUrl());
|
||||
xml.endTag(null, "url");
|
||||
xml.endTag(null, "image");
|
||||
}
|
||||
|
||||
if (feed.getPaymentLink() != null) {
|
||||
GeneratorUtil.addPaymentLink(xml, feed.getPaymentLink(), true);
|
||||
|
1
app/src/free/play
Symbolic link
1
app/src/free/play
Symbolic link
@ -0,0 +1 @@
|
||||
../main/play
|
@ -1,14 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.danoeh.antennapod"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="1060595"
|
||||
android:versionName="1.6.5">
|
||||
<!--
|
||||
Version code schema:
|
||||
"1.2.3-SNAPSHOT" -> 1020300
|
||||
"1.2.3-RC4" -> 1020304
|
||||
-->
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
@ -47,10 +41,13 @@
|
||||
|
||||
<activity
|
||||
android:name=".activity.SplashActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/Theme.AntennaPod.Dark.Splash">
|
||||
<!-- android:launchMode="singleTask" removed for #2948, so that
|
||||
when app is launched again, the app will go to the last activity users use
|
||||
(if the app has been used recently, e.g., last 30 minutes),
|
||||
rather than always go to MainActivity (launched by SplashActivity here) -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
@ -391,10 +388,6 @@
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="de.danoeh.antennapod.core.glide.ApGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
android:resource="@xml/automotive_app_desc"/>
|
||||
|
91
app/src/main/assets/LICENSE_SIL.txt
Normal file
91
app/src/main/assets/LICENSE_SIL.txt
Normal file
@ -0,0 +1,91 @@
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 59 KiB |
@ -20,7 +20,7 @@ public class PodcastApp extends Application {
|
||||
try {
|
||||
Class.forName("de.danoeh.antennapod.config.ClientConfigurator");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("ClientConfigurator not found");
|
||||
throw new RuntimeException("ClientConfigurator not found", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,10 @@ import java.nio.charset.Charset;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import rx.Single;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays the 'about' screen
|
||||
@ -35,7 +35,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
|
||||
private WebView webView;
|
||||
private LinearLayout webViewContainer;
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -43,8 +43,8 @@ public class AboutActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
setContentView(R.layout.about);
|
||||
webViewContainer = (LinearLayout) findViewById(R.id.webViewContainer);
|
||||
webView = (WebView) findViewById(R.id.webViewAbout);
|
||||
webViewContainer = findViewById(R.id.webViewContainer);
|
||||
webView = findViewById(R.id.webViewAbout);
|
||||
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
@ -69,13 +69,16 @@ public class AboutActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void loadAsset(String filename) {
|
||||
subscription = Single.create(subscriber -> {
|
||||
disposable = Single.create(subscriber -> {
|
||||
InputStream input = null;
|
||||
try {
|
||||
TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes(
|
||||
new int[] { android.R.attr.textColorPrimary });
|
||||
int colorResource = res.getColor(0, 0);
|
||||
String colorString = String.format("#%06X", 0xFFFFFF & colorResource);
|
||||
new int[] { R.attr.about_screen_font_color, R.attr.about_screen_background,
|
||||
R.attr.about_screen_card_background, R.attr.about_screen_card_border});
|
||||
String fontColor = String.format("#%06X", 0xFFFFFF & res.getColor(0, 0));
|
||||
String backgroundColor = String.format("#%06X", 0xFFFFFF & res.getColor(1, 0));
|
||||
String cardBackground = String.format("#%06X", 0xFFFFFF & res.getColor(2, 0));
|
||||
String cardBorder = String.format("#%06X", 0xFFFFFF & res.getColor(3, 0));
|
||||
res.recycle();
|
||||
input = getAssets().open(filename);
|
||||
String webViewData = IOUtils.toString(input, Charset.defaultCharset());
|
||||
@ -92,7 +95,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
" src: url('file:///android_asset/Roboto-Light.ttf');" +
|
||||
" }" +
|
||||
" * {" +
|
||||
" color: %s;" +
|
||||
" color: @fontcolor@;" +
|
||||
" font-family: roboto-Light;" +
|
||||
" font-size: 8pt;" +
|
||||
" }" +
|
||||
@ -100,7 +103,10 @@ public class AboutActivity extends AppCompatActivity {
|
||||
"</head><body><p>" + webViewData + "</p></body></html>";
|
||||
webViewData = webViewData.replace("\n", "<br/>");
|
||||
}
|
||||
webViewData = String.format(webViewData, colorString);
|
||||
webViewData = webViewData.replace("@fontcolor@", fontColor);
|
||||
webViewData = webViewData.replace("@background@", backgroundColor);
|
||||
webViewData = webViewData.replace("@card_background@", cardBackground);
|
||||
webViewData = webViewData.replace("@card_border@", cardBorder);
|
||||
subscriber.onSuccess(webViewData);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
@ -109,7 +115,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
IOUtils.closeQuietly(input);
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
webViewData ->
|
||||
@ -140,8 +146,8 @@ public class AboutActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if (webViewContainer != null && webView != null) {
|
||||
webViewContainer.removeAllViews();
|
||||
|
@ -12,8 +12,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||
|
||||
/**
|
||||
@ -28,20 +26,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
|
||||
Intent intent = getIntent();
|
||||
if (intent.getData() == null) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
|
||||
ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
|
||||
MediaType.AUDIO);
|
||||
|
||||
new PlaybackServiceStarter(this, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.prepareImmediately(true)
|
||||
.start();
|
||||
|
||||
playExternalMedia(getIntent(), MediaType.AUDIO);
|
||||
} else if (PlaybackService.isCasting()) {
|
||||
Intent intent = PlaybackService.getPlayerActivityIntent(this);
|
||||
if (intent.getComponent() != null &&
|
||||
|
@ -64,11 +64,11 @@ public class DirectoryChooserActivity extends AppCompatActivity {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(R.layout.directory_chooser);
|
||||
butConfirm = (Button) findViewById(R.id.butConfirm);
|
||||
butCancel = (Button) findViewById(R.id.butCancel);
|
||||
butNavUp = (ImageButton) findViewById(R.id.butNavUp);
|
||||
txtvSelectedFolder = (TextView) findViewById(R.id.txtvSelectedFolder);
|
||||
listDirectories = (ListView) findViewById(R.id.directory_list);
|
||||
butConfirm = findViewById(R.id.butConfirm);
|
||||
butCancel = findViewById(R.id.butCancel);
|
||||
butNavUp = findViewById(R.id.butNavUp);
|
||||
txtvSelectedFolder = findViewById(R.id.txtvSelectedFolder);
|
||||
listDirectories = findViewById(R.id.directory_list);
|
||||
|
||||
butConfirm.setOnClickListener(new OnClickListener() {
|
||||
|
||||
|
@ -49,11 +49,11 @@ public class DownloadAuthenticationActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
setContentView(R.layout.download_authentication_activity);
|
||||
TextView txtvDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
etxtUsername = (EditText) findViewById(R.id.etxtUsername);
|
||||
etxtPassword = (EditText) findViewById(R.id.etxtPassword);
|
||||
Button butConfirm = (Button) findViewById(R.id.butConfirm);
|
||||
Button butCancel = (Button) findViewById(R.id.butCancel);
|
||||
TextView txtvDescription = findViewById(R.id.txtvDescription);
|
||||
etxtUsername = findViewById(R.id.etxtUsername);
|
||||
etxtPassword = findViewById(R.id.etxtPassword);
|
||||
Button butConfirm = findViewById(R.id.butConfirm);
|
||||
Button butCancel = findViewById(R.id.butCancel);
|
||||
|
||||
Validate.isTrue(getIntent().hasExtra(ARG_DOWNLOAD_REQUEST), "Download request missing");
|
||||
DownloadRequest request = getIntent().getParcelableExtra(ARG_DOWNLOAD_REQUEST);
|
||||
|
@ -16,8 +16,15 @@ import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
@ -30,13 +37,11 @@ import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LangUtils;
|
||||
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
|
||||
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.MaybeOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays information about a feed.
|
||||
@ -56,7 +61,7 @@ public class FeedInfoActivity extends AppCompatActivity {
|
||||
private TextView txtvAuthor;
|
||||
private TextView txtvUrl;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
|
||||
private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
|
||||
@ -82,52 +87,57 @@ public class FeedInfoActivity extends AppCompatActivity {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
|
||||
|
||||
imgvCover = (ImageView) findViewById(R.id.imgvCover);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthorHeader = (TextView) findViewById(R.id.txtvAuthor);
|
||||
ImageView imgvBackground = (ImageView) findViewById(R.id.imgvBackground);
|
||||
imgvCover = findViewById(R.id.imgvCover);
|
||||
txtvTitle = findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor);
|
||||
ImageView imgvBackground = findViewById(R.id.imgvBackground);
|
||||
findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
|
||||
// https://github.com/bumptech/glide/issues/529
|
||||
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
|
||||
|
||||
|
||||
txtvDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
lblLanguage = (TextView) findViewById(R.id.lblLanguage);
|
||||
txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
|
||||
lblAuthor = (TextView) findViewById(R.id.lblAuthor);
|
||||
txtvAuthor = (TextView) findViewById(R.id.txtvDetailsAuthor);
|
||||
txtvUrl = (TextView) findViewById(R.id.txtvUrl);
|
||||
txtvDescription = findViewById(R.id.txtvDescription);
|
||||
lblLanguage = findViewById(R.id.lblLanguage);
|
||||
txtvLanguage = findViewById(R.id.txtvLanguage);
|
||||
lblAuthor = findViewById(R.id.lblAuthor);
|
||||
txtvAuthor = findViewById(R.id.txtvDetailsAuthor);
|
||||
txtvUrl = findViewById(R.id.txtvUrl);
|
||||
|
||||
txtvUrl.setOnClickListener(copyUrlToClipboard);
|
||||
|
||||
subscription = Observable.fromCallable(()-> DBReader.getFeed(feedId))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
||||
Feed feed = DBReader.getFeed(feedId);
|
||||
if (feed != null) {
|
||||
emitter.onSuccess(feed);
|
||||
} else {
|
||||
emitter.onComplete();
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result == null) {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
finish();
|
||||
}
|
||||
feed = result;
|
||||
Log.d(TAG, "Language is " + feed.getLanguage());
|
||||
Log.d(TAG, "Author is " + feed.getAuthor());
|
||||
Log.d(TAG, "URL is " + feed.getDownload_url());
|
||||
Glide.with(FeedInfoActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
Glide.with(FeedInfoActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(FeedInfoActivity.this))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
@ -164,14 +174,17 @@ public class FeedInfoActivity extends AppCompatActivity {
|
||||
}, error -> {
|
||||
Log.d(TAG, Log.getStackTraceString(error));
|
||||
finish();
|
||||
}, () -> {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -24,8 +23,10 @@ import android.widget.ImageView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
@ -40,10 +41,11 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.MaybeOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays information about a feed.
|
||||
@ -67,23 +69,7 @@ public class FeedSettingsActivity extends AppCompatActivity {
|
||||
private Spinner spnAutoDelete;
|
||||
private boolean filterInclude = true;
|
||||
|
||||
private Subscription subscription;
|
||||
|
||||
|
||||
private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(feed != null && feed.getDownload_url() != null) {
|
||||
String url = feed.getDownload_url();
|
||||
ClipData clipData = ClipData.newPlainText(url, url);
|
||||
android.content.ClipboardManager cm = (android.content.ClipboardManager) FeedSettingsActivity.this
|
||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(clipData);
|
||||
Toast t = Toast.makeText(FeedSettingsActivity.this, R.string.copied_url_msg, Toast.LENGTH_SHORT);
|
||||
t.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
private Disposable disposable;
|
||||
|
||||
private boolean authInfoChanged = false;
|
||||
|
||||
@ -127,57 +113,62 @@ public class FeedSettingsActivity extends AppCompatActivity {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
|
||||
|
||||
imgvCover = (ImageView) findViewById(R.id.imgvCover);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthorHeader = (TextView) findViewById(R.id.txtvAuthor);
|
||||
ImageView imgvBackground = (ImageView) findViewById(R.id.imgvBackground);
|
||||
imgvCover = findViewById(R.id.imgvCover);
|
||||
txtvTitle = findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor);
|
||||
ImageView imgvBackground = findViewById(R.id.imgvBackground);
|
||||
findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
|
||||
// https://github.com/bumptech/glide/issues/529
|
||||
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
|
||||
|
||||
cbxAutoDownload = (CheckBox) findViewById(R.id.cbxAutoDownload);
|
||||
cbxKeepUpdated = (CheckBox) findViewById(R.id.cbxKeepUpdated);
|
||||
spnAutoDelete = (Spinner) findViewById(R.id.spnAutoDelete);
|
||||
etxtUsername = (EditText) findViewById(R.id.etxtUsername);
|
||||
etxtPassword = (EditText) findViewById(R.id.etxtPassword);
|
||||
etxtFilterText = (EditText) findViewById(R.id.etxtEpisodeFilterText);
|
||||
rdoFilterInclude = (RadioButton) findViewById(R.id.radio_filter_include);
|
||||
cbxAutoDownload = findViewById(R.id.cbxAutoDownload);
|
||||
cbxKeepUpdated = findViewById(R.id.cbxKeepUpdated);
|
||||
spnAutoDelete = findViewById(R.id.spnAutoDelete);
|
||||
etxtUsername = findViewById(R.id.etxtUsername);
|
||||
etxtPassword = findViewById(R.id.etxtPassword);
|
||||
etxtFilterText = findViewById(R.id.etxtEpisodeFilterText);
|
||||
rdoFilterInclude = findViewById(R.id.radio_filter_include);
|
||||
rdoFilterInclude.setOnClickListener(v -> {
|
||||
filterInclude = true;
|
||||
filterTextChanged = true;
|
||||
});
|
||||
rdoFilterExclude = (RadioButton) findViewById(R.id.radio_filter_exclude);
|
||||
rdoFilterExclude = findViewById(R.id.radio_filter_exclude);
|
||||
rdoFilterExclude.setOnClickListener(v -> {
|
||||
filterInclude = false;
|
||||
filterTextChanged = true;
|
||||
});
|
||||
|
||||
subscription = Observable.fromCallable(()-> DBReader.getFeed(feedId))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
||||
Feed feed = DBReader.getFeed(feedId);
|
||||
if (feed != null) {
|
||||
emitter.onSuccess(feed);
|
||||
} else {
|
||||
emitter.onComplete();
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result == null) {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
finish();
|
||||
}
|
||||
feed = result;
|
||||
FeedPreferences prefs = feed.getPreferences();
|
||||
Glide.with(FeedSettingsActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
Glide.with(FeedSettingsActivity.this)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(FeedSettingsActivity.this))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
@ -259,6 +250,9 @@ public class FeedSettingsActivity extends AppCompatActivity {
|
||||
}, error -> {
|
||||
Log.d(TAG, Log.getStackTraceString(error));
|
||||
finish();
|
||||
}, () -> {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
@ -296,8 +290,8 @@ public class FeedSettingsActivity extends AppCompatActivity {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,9 @@ public class FlattrAuthActivity extends AppCompatActivity {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Activity created");
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.flattr_auth);
|
||||
txtvExplanation = (TextView) findViewById(R.id.txtvExplanation);
|
||||
butAuthenticate = (Button) findViewById(R.id.but_authenticate);
|
||||
butReturn = (Button) findViewById(R.id.but_return_home);
|
||||
txtvExplanation = findViewById(R.id.txtvExplanation);
|
||||
butAuthenticate = findViewById(R.id.but_authenticate);
|
||||
butReturn = findViewById(R.id.but_return_home);
|
||||
|
||||
butReturn.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(FlattrAuthActivity.this, MainActivity.class);
|
||||
|
@ -13,9 +13,7 @@ import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
@ -26,6 +24,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
|
||||
/**
|
||||
* Displays the 'import/export' screen
|
||||
*/
|
||||
|
@ -27,11 +27,10 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
@ -44,17 +43,20 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.event.MessageEvent;
|
||||
import de.danoeh.antennapod.core.event.ProgressEvent;
|
||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.Flavors;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import de.danoeh.antennapod.dialog.RatingDialog;
|
||||
import de.danoeh.antennapod.dialog.RenameFeedDialog;
|
||||
import de.danoeh.antennapod.fragment.AddFeedFragment;
|
||||
@ -67,10 +69,10 @@ import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* The activity that is shown when the user launches the app.
|
||||
@ -120,7 +122,9 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
|
||||
private ProgressDialog pd;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
private long lastBackButtonPressTime = 0;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -129,7 +133,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
@ -141,8 +145,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
|
||||
currentTitle = getTitle();
|
||||
|
||||
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
navList = (ListView) findViewById(R.id.nav_list);
|
||||
drawerLayout = findViewById(R.id.drawer_layout);
|
||||
navList = findViewById(R.id.nav_list);
|
||||
navDrawer = findViewById(R.id.nav_layout);
|
||||
|
||||
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
|
||||
@ -470,7 +474,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
DBTasks.checkShouldRefreshFeeds(getApplicationContext());
|
||||
AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent.hasExtra(EXTRA_FEED_ID) ||
|
||||
@ -487,8 +491,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
super.onStop();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
EventBus.getDefault().unregister(this);
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if(pd != null) {
|
||||
pd.dismiss();
|
||||
@ -627,8 +631,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
remover.skipOnCompletion = true;
|
||||
int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
|
||||
if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
|
||||
sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
|
||||
IntentUtils.sendLocalBroadcast(MainActivity.this, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
|
||||
}
|
||||
}
|
||||
remover.executeAsync();
|
||||
@ -643,10 +646,40 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if(isDrawerOpen()) {
|
||||
if (isDrawerOpen()) {
|
||||
drawerLayout.closeDrawer(navDrawer);
|
||||
} else {
|
||||
} else if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
switch (UserPreferences.getBackButtonBehavior()) {
|
||||
case OPEN_DRAWER:
|
||||
drawerLayout.openDrawer(navDrawer);
|
||||
break;
|
||||
case SHOW_PROMPT:
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.close_prompt)
|
||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> MainActivity.super.onBackPressed())
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
break;
|
||||
case DOUBLE_TAP:
|
||||
if (lastBackButtonPressTime < System.currentTimeMillis() - 2000) {
|
||||
Toast.makeText(this, R.string.double_tap_toast, Toast.LENGTH_SHORT).show();
|
||||
lastBackButtonPressTime = System.currentTimeMillis();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
break;
|
||||
case GO_TO_PAGE:
|
||||
if (getLastNavFragment().equals(UserPreferences.getBackButtonGoToPage())) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
loadFragment(UserPreferences.getBackButtonGoToPage(), null);
|
||||
}
|
||||
break;
|
||||
default: super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,8 +750,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
};
|
||||
|
||||
private void loadData() {
|
||||
subscription = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
boolean handleIntent = (navDrawerData == null);
|
||||
|
@ -1,9 +1,11 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
@ -11,7 +13,9 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@ -37,28 +41,33 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.Consumer;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.Flavors;
|
||||
import de.danoeh.antennapod.core.util.Function;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.core.util.Supplier;
|
||||
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.danoeh.antennapod.dialog.SleepTimerDialog;
|
||||
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Action1;
|
||||
import rx.functions.Func1;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
|
||||
/**
|
||||
@ -69,6 +78,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
private static final String TAG = "MediaplayerActivity";
|
||||
private static final String PREFS = "MediaPlayerActivityPreferences";
|
||||
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
|
||||
private static final int REQUEST_CODE_STORAGE = 42;
|
||||
private static final float PLAYBACK_SPEED_STEP = 0.05f;
|
||||
private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
|
||||
private static final float DEFAULT_MAX_PLAYBACK_SPEED = 2.5f;
|
||||
|
||||
PlaybackController controller;
|
||||
|
||||
@ -86,6 +99,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
|
||||
private boolean isFavorite = false;
|
||||
|
||||
private Disposable disposable;
|
||||
|
||||
private PlaybackController newPlaybackController() {
|
||||
return new PlaybackController(this, false) {
|
||||
|
||||
@ -222,8 +237,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
Log.d(TAG, "onCreate()");
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
|
||||
orientation = getResources().getConfiguration().orientation;
|
||||
getWindow().setFormat(PixelFormat.TRANSPARENT);
|
||||
setupGUI();
|
||||
loadMediaInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -256,15 +272,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
|
||||
private void onBufferUpdate(float progress) {
|
||||
if (sbPosition != null) {
|
||||
sbPosition.setSecondaryProgress((int) progress * sbPosition.getMax());
|
||||
sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Current screen orientation.
|
||||
*/
|
||||
private int orientation;
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
@ -272,8 +283,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
controller.release();
|
||||
}
|
||||
controller = newPlaybackController();
|
||||
setupGUI();
|
||||
loadMediaInfo();
|
||||
onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@ -284,6 +293,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
controller.release();
|
||||
controller = null; // prevent leak
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@ -460,7 +472,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
|
||||
butDecSpeed.setOnClickListener(v -> {
|
||||
if(controller != null && controller.canSetPlaybackSpeed()) {
|
||||
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
|
||||
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 1);
|
||||
} else {
|
||||
VariableSpeedDialog.showGetPluginDialog(this);
|
||||
}
|
||||
@ -468,7 +480,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
|
||||
butIncSpeed.setOnClickListener(v -> {
|
||||
if(controller != null && controller.canSetPlaybackSpeed()) {
|
||||
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
|
||||
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 1);
|
||||
} else {
|
||||
VariableSpeedDialog.showGetPluginDialog(this);
|
||||
}
|
||||
@ -483,12 +495,20 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
|
||||
}
|
||||
|
||||
String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
|
||||
final float minPlaybackSpeed = availableSpeeds.length > 1 ?
|
||||
Float.valueOf(availableSpeeds[0]) : DEFAULT_MIN_PLAYBACK_SPEED;
|
||||
float maxPlaybackSpeed = availableSpeeds.length > 1 ?
|
||||
Float.valueOf(availableSpeeds[availableSpeeds.length - 1]) : DEFAULT_MAX_PLAYBACK_SPEED;
|
||||
int progressMax = (int) ((maxPlaybackSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP);
|
||||
barPlaybackSpeed.setMax(progressMax);
|
||||
|
||||
txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
|
||||
barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if(controller != null && controller.canSetPlaybackSpeed()) {
|
||||
float playbackSpeed = (progress + 10) / 20.0f;
|
||||
float playbackSpeed = progress * PLAYBACK_SPEED_STEP + minPlaybackSpeed;
|
||||
controller.setPlaybackSpeed(playbackSpeed);
|
||||
String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
|
||||
UserPreferences.setPlaybackSpeed(speedPref);
|
||||
@ -496,7 +516,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
txtvPlaybackSpeed.setText(speedStr);
|
||||
} else if(fromUser) {
|
||||
float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
|
||||
barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress((int) (20 * speed) - 10));
|
||||
barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress(
|
||||
(int) ((speed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +532,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
});
|
||||
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
|
||||
barPlaybackSpeed.setProgress((int) ((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
|
||||
|
||||
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
|
||||
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
|
||||
@ -525,6 +546,22 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
|
||||
}
|
||||
|
||||
if (UserPreferences.useExoplayer()) {
|
||||
barRightVolume.setEnabled(false);
|
||||
}
|
||||
|
||||
final CheckBox skipSilence = (CheckBox) dialog.findViewById(R.id.skipSilence);
|
||||
skipSilence.setChecked(UserPreferences.isSkipSilence());
|
||||
if (!UserPreferences.useExoplayer()) {
|
||||
skipSilence.setEnabled(false);
|
||||
String exoplayerOnly = getString(R.string.exoplayer_only);
|
||||
skipSilence.setText(skipSilence.getText() + " [" + exoplayerOnly + "]");
|
||||
}
|
||||
skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
UserPreferences.setSkipSilence(isChecked);
|
||||
controller.setSkipSilence(isChecked);
|
||||
});
|
||||
|
||||
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
@ -635,7 +672,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
if (controller != null) {
|
||||
controller.init();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,7 +726,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
if(controller == null || controller.getMedia() == null) {
|
||||
return false;
|
||||
}
|
||||
Playable media = controller.getMedia();
|
||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
|
||||
onPositionObserverUpdate();
|
||||
@ -722,8 +757,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
R.string.pref_rewind);
|
||||
|
||||
private final Supplier<Integer> getPrefSecsFn;
|
||||
private final Func1<MediaplayerActivity, TextView> getTextViewFn;
|
||||
private final Action1<Integer> setPrefSecsFn;
|
||||
private final Function<MediaplayerActivity, TextView> getTextViewFn;
|
||||
private final Consumer<Integer> setPrefSecsFn;
|
||||
private final int titleResourceID;
|
||||
|
||||
/**
|
||||
@ -735,7 +770,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
* @param setPrefSecsFn Handle to function that sets the preference (setting) for the skip delta value (and optionally updates the button label with the current values)
|
||||
* @param titleResourceID ID of the resource string with the title for a view
|
||||
*/
|
||||
SkipDirection(Supplier<Integer> getPrefSecsFn, Func1<MediaplayerActivity, TextView> getTextViewFn, Action1<Integer> setPrefSecsFn, int titleResourceID) {
|
||||
SkipDirection(Supplier<Integer> getPrefSecsFn, Function<MediaplayerActivity, TextView> getTextViewFn, Consumer<Integer> setPrefSecsFn, int titleResourceID) {
|
||||
this.getPrefSecsFn = getPrefSecsFn;
|
||||
this.getTextViewFn = getTextViewFn;
|
||||
this.setPrefSecsFn = setPrefSecsFn;
|
||||
@ -754,10 +789,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
* @param activity MediaplyerActivity that contains textview to update the display of the skip delta setting (or null if nothing to update)
|
||||
*/
|
||||
public void setPrefSkipSeconds(int seconds, @Nullable Activity activity) {
|
||||
setPrefSecsFn.call(seconds);
|
||||
setPrefSecsFn.accept(seconds);
|
||||
|
||||
if (activity != null && activity instanceof MediaplayerActivity) {
|
||||
TextView tv = getTextViewFn.call((MediaplayerActivity)activity);
|
||||
TextView tv = getTextViewFn.apply((MediaplayerActivity)activity);
|
||||
if (tv != null) tv.setText(String.valueOf(seconds));
|
||||
}
|
||||
}
|
||||
@ -795,13 +830,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
|
||||
void setupGUI() {
|
||||
setContentView(getContentViewResourceId());
|
||||
sbPosition = (SeekBar) findViewById(R.id.sbPosition);
|
||||
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
|
||||
sbPosition = findViewById(R.id.sbPosition);
|
||||
txtvPosition = findViewById(R.id.txtvPosition);
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
|
||||
Log.d("timeleft", showTimeLeft ? "true" : "false");
|
||||
txtvLength = (TextView) findViewById(R.id.txtvLength);
|
||||
txtvLength = findViewById(R.id.txtvLength);
|
||||
if (txtvLength != null) {
|
||||
txtvLength.setOnClickListener(v -> {
|
||||
showTimeLeft = !showTimeLeft;
|
||||
@ -825,18 +860,18 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
});
|
||||
}
|
||||
|
||||
butRev = (ImageButton) findViewById(R.id.butRev);
|
||||
txtvRev = (TextView) findViewById(R.id.txtvRev);
|
||||
butRev = findViewById(R.id.butRev);
|
||||
txtvRev = findViewById(R.id.txtvRev);
|
||||
if (txtvRev != null) {
|
||||
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
|
||||
}
|
||||
butPlay = (ImageButton) findViewById(R.id.butPlay);
|
||||
butFF = (ImageButton) findViewById(R.id.butFF);
|
||||
txtvFF = (TextView) findViewById(R.id.txtvFF);
|
||||
butPlay = findViewById(R.id.butPlay);
|
||||
butFF = findViewById(R.id.butFF);
|
||||
txtvFF = findViewById(R.id.txtvFF);
|
||||
if (txtvFF != null) {
|
||||
txtvFF.setText(String.valueOf(UserPreferences.getFastForwardSecs()));
|
||||
}
|
||||
butSkip = (ImageButton) findViewById(R.id.butSkip);
|
||||
butSkip = findViewById(R.id.butSkip);
|
||||
|
||||
// SEEKBAR SETUP
|
||||
|
||||
@ -863,7 +898,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
}
|
||||
|
||||
if (butSkip != null) {
|
||||
butSkip.setOnClickListener(v -> sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE)));
|
||||
butSkip.setOnClickListener(v ->
|
||||
IntentUtils.sendLocalBroadcast(MediaplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -937,22 +973,62 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
|
||||
private void checkFavorite() {
|
||||
Playable playable = controller.getMedia();
|
||||
if (playable != null && playable instanceof FeedMedia) {
|
||||
FeedItem feedItem = ((FeedMedia) playable).getItem();
|
||||
if (feedItem != null) {
|
||||
Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
item -> {
|
||||
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
|
||||
if (isFavorite != isFav) {
|
||||
isFavorite = isFav;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
if (!(playable instanceof FeedMedia)) {
|
||||
return;
|
||||
}
|
||||
FeedItem feedItem = ((FeedMedia) playable).getItem();
|
||||
if (feedItem == null) {
|
||||
return;
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
item -> {
|
||||
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
|
||||
if (isFavorite != isFav) {
|
||||
isFavorite = isFav;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
void playExternalMedia(Intent intent, MediaType type) {
|
||||
if (intent == null || intent.getData() == null) {
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 23
|
||||
&& ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_STORAGE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
|
||||
ExternalMedia media = new ExternalMedia(intent.getData().getPath(), type);
|
||||
|
||||
new PlaybackServiceStarter(this, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.prepareImmediately(true)
|
||||
.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_STORAGE) {
|
||||
if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,8 +46,9 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import de.danoeh.antennapod.dialog.RenameFeedDialog;
|
||||
@ -62,10 +63,10 @@ import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.danoeh.antennapod.fragment.SubscriptionFragment;
|
||||
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Activity for playing files that do not require a video surface.
|
||||
@ -105,7 +106,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
private ViewPager pager;
|
||||
private MediaplayerInfoPagerAdapter pagerAdapter;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
@ -126,8 +127,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
if(pagerAdapter != null) {
|
||||
pagerAdapter.setController(null);
|
||||
}
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
saveCurrentFragment();
|
||||
@ -186,7 +187,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
pagerAdapter.onMediaChanged(media);
|
||||
pagerAdapter.setController(controller);
|
||||
}
|
||||
DBTasks.checkShouldRefreshFeeds(getApplicationContext());
|
||||
AutoUpdateManager.checkShouldRefreshFeeds(getApplicationContext());
|
||||
|
||||
EventDistributor.getInstance().register(contentUpdate);
|
||||
EventBus.getDefault().register(this);
|
||||
@ -226,18 +227,18 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
@Override
|
||||
protected void setupGUI() {
|
||||
super.setupGUI();
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle("");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
findViewById(R.id.shadow).setVisibility(View.GONE);
|
||||
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
|
||||
AppBarLayout appBarLayout = findViewById(R.id.appBar);
|
||||
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
|
||||
appBarLayout.setElevation(px);
|
||||
}
|
||||
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
navList = (ListView) findViewById(R.id.nav_list);
|
||||
drawerLayout = findViewById(R.id.drawer_layout);
|
||||
navList = findViewById(R.id.nav_list);
|
||||
navDrawer = findViewById(R.id.nav_layout);
|
||||
|
||||
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
|
||||
@ -273,14 +274,15 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
startActivity(new Intent(MediaplayerInfoActivity.this, PreferenceActivity.class));
|
||||
});
|
||||
|
||||
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
|
||||
butCastDisconnect = (ImageButton) findViewById(R.id.butCastDisconnect);
|
||||
butPlaybackSpeed = findViewById(R.id.butPlaybackSpeed);
|
||||
butCastDisconnect = findViewById(R.id.butCastDisconnect);
|
||||
|
||||
pager = (ViewPager) findViewById(R.id.pager);
|
||||
pager = findViewById(R.id.pager);
|
||||
pager.setOffscreenPageLimit(3);
|
||||
pagerAdapter = new MediaplayerInfoPagerAdapter(getSupportFragmentManager(), media);
|
||||
pagerAdapter.setController(controller);
|
||||
pager.setAdapter(pagerAdapter);
|
||||
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
|
||||
CirclePageIndicator pageIndicator = findViewById(R.id.page_indicator);
|
||||
pageIndicator.setViewPager(pager);
|
||||
loadLastFragment();
|
||||
pager.onSaveInstanceState();
|
||||
@ -356,7 +358,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return drawerToggle != null && drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
|
||||
return (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -413,8 +415,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
|
||||
remover.skipOnCompletion = true;
|
||||
if(controller.getStatus() == PlayerStatus.PLAYING) {
|
||||
sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
|
||||
IntentUtils.sendLocalBroadcast(MediaplayerInfoActivity.this, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -472,8 +473,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
|
||||
private DBReader.NavDrawerData navDrawerData;
|
||||
|
||||
private void loadData() {
|
||||
subscription = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
navDrawerData = result;
|
||||
|
@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v7.app.ActionBar;
|
||||
@ -27,6 +28,7 @@ import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
@ -56,19 +58,21 @@ import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
|
||||
import de.danoeh.antennapod.core.syndication.handler.FeedHandlerResult;
|
||||
import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
|
||||
import de.danoeh.antennapod.core.util.DownloadError;
|
||||
import de.danoeh.antennapod.core.util.FileNameGenerator;
|
||||
import de.danoeh.antennapod.core.util.Optional;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.core.util.URLChecker;
|
||||
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
|
||||
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
|
||||
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Downloads a feed from a feed URL and parses it. Subclasses can display the
|
||||
@ -97,15 +101,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
|
||||
private Button subscribeButton;
|
||||
|
||||
private Subscription download;
|
||||
private Subscription parser;
|
||||
private Subscription updater;
|
||||
private Disposable download;
|
||||
private Disposable parser;
|
||||
private Disposable updater;
|
||||
private final EventDistributor.EventListener listener = new EventDistributor.EventListener() {
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) {
|
||||
updater = Observable.fromCallable(DBReader::getFeedList)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
feeds -> {
|
||||
@ -139,26 +143,33 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
|
||||
final String feedUrl;
|
||||
String feedUrl = null;
|
||||
if (getIntent().hasExtra(ARG_FEEDURL)) {
|
||||
feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
|
||||
} else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
|
||||
|| TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
|
||||
feedUrl = (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND))
|
||||
feedUrl = TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
|
||||
? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(R.string.add_feed_label);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Activity must be started with feedurl argument!");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Activity was started with url " + feedUrl);
|
||||
setLoadingLayout();
|
||||
if (savedInstanceState == null) {
|
||||
startFeedDownload(feedUrl, null, null);
|
||||
if (feedUrl == null) {
|
||||
Log.e(TAG, "feedUrl is null.");
|
||||
new AlertDialog.Builder(OnlineFeedViewActivity.this).
|
||||
setNeutralButton(android.R.string.ok,
|
||||
(dialog, which) -> finish()).
|
||||
setTitle(R.string.error_label).
|
||||
setMessage(R.string.null_value_podcast_error).create().show();
|
||||
} else {
|
||||
startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password"));
|
||||
Log.d(TAG, "Activity was started with url " + feedUrl);
|
||||
setLoadingLayout();
|
||||
if (savedInstanceState == null) {
|
||||
startFeedDownload(feedUrl, null, null);
|
||||
} else {
|
||||
startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,13 +223,13 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(updater != null) {
|
||||
updater.unsubscribe();
|
||||
updater.dispose();
|
||||
}
|
||||
if(download != null) {
|
||||
download.unsubscribe();
|
||||
download.dispose();
|
||||
}
|
||||
if(parser != null) {
|
||||
parser.unsubscribe();
|
||||
parser.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,18 +284,13 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
downloader.call();
|
||||
return downloader.getResult();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::checkDownloadResult,
|
||||
error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
private void checkDownloadResult(DownloadStatus status) {
|
||||
if (status == null) {
|
||||
Log.wtf(TAG, "DownloadStatus returned by Downloader was null");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
private void checkDownloadResult(@NonNull DownloadStatus status) {
|
||||
if (status.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
@ -306,35 +312,17 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void parseFeed() {
|
||||
if (feed == null || feed.getFile_url() == null && feed.isDownloaded()) {
|
||||
if (feed == null || (feed.getFile_url() == null && feed.isDownloaded())) {
|
||||
throw new IllegalStateException("feed must be non-null and downloaded when parseFeed is called");
|
||||
}
|
||||
Log.d(TAG, "Parsing feed");
|
||||
|
||||
parser = Observable.fromCallable(() -> {
|
||||
FeedHandler handler = new FeedHandler();
|
||||
try {
|
||||
return handler.parseFeed(feed);
|
||||
} catch (UnsupportedFeedtypeException e) {
|
||||
Log.d(TAG, "Unsupported feed type detected");
|
||||
if (TextUtils.equals("html", e.getRootElement().toLowerCase())) {
|
||||
showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
|
||||
return null;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
throw e;
|
||||
} finally {
|
||||
boolean rc = new File(feed.getFile_url()).delete();
|
||||
Log.d(TAG, "Deleted feed source file. Result: " + rc);
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
parser = Observable.fromCallable(this::doParseFeed)
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if(result != null) {
|
||||
.subscribe(optionalResult -> {
|
||||
if(optionalResult.isPresent()) {
|
||||
FeedHandlerResult result = optionalResult.get();
|
||||
beforeShowFeedInformation(result.feed);
|
||||
showFeedInformation(result.feed, result.alternateFeedUrls);
|
||||
}
|
||||
@ -342,9 +330,37 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
String errorMsg = DownloadError.ERROR_PARSER_EXCEPTION.getErrorString(
|
||||
OnlineFeedViewActivity.this) + " (" + error.getMessage() + ")";
|
||||
showErrorDialog(errorMsg);
|
||||
Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Optional<FeedHandlerResult> doParseFeed() throws Exception {
|
||||
FeedHandler handler = new FeedHandler();
|
||||
try {
|
||||
return Optional.of(handler.parseFeed(feed));
|
||||
} catch (UnsupportedFeedtypeException e) {
|
||||
Log.d(TAG, "Unsupported feed type detected");
|
||||
if ("html".equalsIgnoreCase(e.getRootElement())) {
|
||||
boolean dialogShown = showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
|
||||
if (dialogShown) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
Log.d(TAG, "Supplied feed is an HTML web page that has no references to any feed");
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
throw e;
|
||||
} finally {
|
||||
boolean rc = new File(feed.getFile_url()).delete();
|
||||
Log.d(TAG, "Deleted feed source file. Result: " + rc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the feed has been downloaded and parsed and before showFeedInformation is called.
|
||||
* This method is executed on a background thread
|
||||
@ -378,29 +394,30 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
this.feed = feed;
|
||||
this.selectedDownloadUrl = feed.getDownload_url();
|
||||
EventDistributor.getInstance().register(listener);
|
||||
ListView listView = (ListView) findViewById(R.id.listview);
|
||||
ListView listView = findViewById(R.id.listview);
|
||||
LayoutInflater inflater = LayoutInflater.from(this);
|
||||
View header = inflater.inflate(R.layout.onlinefeedview_header, listView, false);
|
||||
listView.addHeaderView(header);
|
||||
|
||||
listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
|
||||
|
||||
ImageView cover = (ImageView) header.findViewById(R.id.imgvCover);
|
||||
TextView title = (TextView) header.findViewById(R.id.txtvTitle);
|
||||
TextView author = (TextView) header.findViewById(R.id.txtvAuthor);
|
||||
TextView description = (TextView) header.findViewById(R.id.txtvDescription);
|
||||
Spinner spAlternateUrls = (Spinner) header.findViewById(R.id.spinnerAlternateUrls);
|
||||
ImageView cover = header.findViewById(R.id.imgvCover);
|
||||
TextView title = header.findViewById(R.id.txtvTitle);
|
||||
TextView author = header.findViewById(R.id.txtvAuthor);
|
||||
TextView description = header.findViewById(R.id.txtvDescription);
|
||||
Spinner spAlternateUrls = header.findViewById(R.id.spinnerAlternateUrls);
|
||||
|
||||
subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
|
||||
subscribeButton = header.findViewById(R.id.butSubscribe);
|
||||
|
||||
if (feed.getImage() != null && StringUtils.isNotBlank(feed.getImage().getDownload_url())) {
|
||||
if (StringUtils.isNotBlank(feed.getImageUrl())) {
|
||||
Glide.with(this)
|
||||
.load(feed.getImage().getDownload_url())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.load(feed.getImageUrl())
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(cover);
|
||||
}
|
||||
|
||||
@ -527,21 +544,25 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void showFeedDiscoveryDialog(File feedFile, String baseUrl) {
|
||||
/**
|
||||
*
|
||||
* @return true if a FeedDiscoveryDialog is shown, false otherwise (e.g., due to no feed found).
|
||||
*/
|
||||
private boolean showFeedDiscoveryDialog(File feedFile, String baseUrl) {
|
||||
FeedDiscoverer fd = new FeedDiscoverer();
|
||||
final Map<String, String> urlsMap;
|
||||
try {
|
||||
urlsMap = fd.findLinks(feedFile, baseUrl);
|
||||
if (urlsMap == null || urlsMap.isEmpty()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isPaused || isFinishing()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<String> titles = new ArrayList<>();
|
||||
@ -577,6 +598,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
}
|
||||
dialog = ab.show();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private class FeedViewAuthenticationDialog extends AuthenticationDialog {
|
||||
|
@ -39,9 +39,9 @@ public class OpmlFeedChooserActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.opml_selection);
|
||||
butConfirm = (Button) findViewById(R.id.butConfirm);
|
||||
butCancel = (Button) findViewById(R.id.butCancel);
|
||||
feedlist = (ListView) findViewById(R.id.feedlist);
|
||||
butConfirm = findViewById(R.id.butConfirm);
|
||||
butCancel = findViewById(R.id.butCancel);
|
||||
feedlist = findViewById(R.id.feedlist);
|
||||
|
||||
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
listAdapter = new ArrayAdapter<>(this,
|
||||
|
@ -36,16 +36,16 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.opml_import);
|
||||
|
||||
final TextView txtvHeaderExplanation1 = (TextView) findViewById(R.id.txtvHeadingExplanation1);
|
||||
final TextView txtvExplanation1 = (TextView) findViewById(R.id.txtvExplanation1);
|
||||
final TextView txtvHeaderExplanation2 = (TextView) findViewById(R.id.txtvHeadingExplanation2);
|
||||
final TextView txtvExplanation2 = (TextView) findViewById(R.id.txtvExplanation2);
|
||||
final TextView txtvHeaderExplanation3 = (TextView) findViewById(R.id.txtvHeadingExplanation3);
|
||||
final TextView txtvHeaderExplanation1 = findViewById(R.id.txtvHeadingExplanation1);
|
||||
final TextView txtvExplanation1 = findViewById(R.id.txtvExplanation1);
|
||||
final TextView txtvHeaderExplanation2 = findViewById(R.id.txtvHeadingExplanation2);
|
||||
final TextView txtvExplanation2 = findViewById(R.id.txtvExplanation2);
|
||||
final TextView txtvHeaderExplanation3 = findViewById(R.id.txtvHeadingExplanation3);
|
||||
|
||||
Button butChooseFilesystem = (Button) findViewById(R.id.butChooseFileFromFilesystem);
|
||||
Button butChooseFilesystem = findViewById(R.id.butChooseFileFromFilesystem);
|
||||
butChooseFilesystem.setOnClickListener(v -> chooseFileFromFilesystem());
|
||||
|
||||
Button butChooseExternal = (Button) findViewById(R.id.butChooseFileFromExternal);
|
||||
Button butChooseExternal = findViewById(R.id.butChooseFileFromExternal);
|
||||
butChooseExternal.setOnClickListener(v -> chooseFileFromExternal());
|
||||
|
||||
int nextOption = 1;
|
||||
|
@ -14,6 +14,8 @@ import de.danoeh.antennapod.core.export.opml.OpmlElement;
|
||||
*/
|
||||
public class OpmlImportHolder {
|
||||
|
||||
private OpmlImportHolder(){}
|
||||
|
||||
private static ArrayList<OpmlElement> readElements;
|
||||
|
||||
public static ArrayList<OpmlElement> getReadElements() {
|
||||
|
@ -12,11 +12,11 @@ import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreference;
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreferenceResult;
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.preferences.PreferenceController;
|
||||
|
@ -1,23 +1,51 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.graphics.drawable.DrawableCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Creator: vbarad
|
||||
* Date: 2016-12-03
|
||||
* Project: AntennaPod
|
||||
* Shows the AntennaPod logo while waiting for the main activity to start
|
||||
*/
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.splash);
|
||||
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
ProgressBar progressBar = findViewById(R.id.progressBar);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
Drawable wrapDrawable = DrawableCompat.wrap(progressBar.getIndeterminateDrawable());
|
||||
DrawableCompat.setTint(wrapDrawable, 0xffffffff);
|
||||
progressBar.setIndeterminateDrawable(DrawableCompat.unwrap(wrapDrawable));
|
||||
} else {
|
||||
progressBar.getIndeterminateDrawable().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
Completable.create(subscriber -> {
|
||||
// Trigger schema updates
|
||||
PodDBAdapter.getInstance().open();
|
||||
PodDBAdapter.getInstance().close();
|
||||
subscriber.onComplete();
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(() -> {
|
||||
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ import de.danoeh.antennapod.adapter.StatisticsListAdapter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays the 'statistics' screen
|
||||
@ -35,7 +35,7 @@ public class StatisticsActivity extends AppCompatActivity
|
||||
private static final String PREF_NAME = "StatisticsActivityPrefs";
|
||||
private static final String PREF_COUNT_ALL = "countAll";
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
private TextView totalTimeTextView;
|
||||
private ListView feedStatisticsList;
|
||||
private ProgressBar progressBar;
|
||||
@ -53,9 +53,9 @@ public class StatisticsActivity extends AppCompatActivity
|
||||
prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
|
||||
|
||||
totalTimeTextView = (TextView) findViewById(R.id.total_time);
|
||||
feedStatisticsList = (ListView) findViewById(R.id.statistics_list);
|
||||
progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
||||
totalTimeTextView = findViewById(R.id.total_time);
|
||||
feedStatisticsList = findViewById(R.id.statistics_list);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
listAdapter = new StatisticsListAdapter(this);
|
||||
listAdapter.setCountAll(countAll);
|
||||
feedStatisticsList.setAdapter(listAdapter);
|
||||
@ -119,21 +119,19 @@ public class StatisticsActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
private void loadStatistics() {
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
subscription = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result != null) {
|
||||
totalTimeTextView.setText(Converter
|
||||
.shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime));
|
||||
listAdapter.update(result.feedTime);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
totalTimeTextView.setVisibility(View.VISIBLE);
|
||||
feedStatisticsList.setVisibility(View.VISIBLE);
|
||||
}
|
||||
totalTimeTextView.setText(Converter
|
||||
.shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime));
|
||||
listAdapter.update(result.feedTime);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
totalTimeTextView.setVisibility(View.VISIBLE);
|
||||
feedStatisticsList.setVisibility(View.VISIBLE);
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class StorageErrorActivity extends AppCompatActivity {
|
||||
|
||||
setContentView(R.layout.storage_error);
|
||||
|
||||
Button btnChooseDataFolder = (Button) findViewById(R.id.btnChooseDataFolder);
|
||||
Button btnChooseDataFolder = findViewById(R.id.btnChooseDataFolder);
|
||||
btnChooseDataFolder.setOnClickListener(v -> {
|
||||
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
|
||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
|
@ -8,6 +8,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.view.WindowCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.Menu;
|
||||
@ -22,20 +23,19 @@ import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.danoeh.antennapod.view.AspectRatioVideoView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Activity for playing video files.
|
||||
*/
|
||||
@ -47,6 +47,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
*/
|
||||
private boolean videoControlsShowing = true;
|
||||
private boolean videoSurfaceCreated = false;
|
||||
private boolean playbackStoppedUponExitVideo = false;
|
||||
private boolean destroyingDueToReload = false;
|
||||
|
||||
private VideoControlsHider videoControlsHider = new VideoControlsHider(this);
|
||||
@ -77,18 +78,9 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (getIntent().getAction() != null
|
||||
&& getIntent().getAction().equals(Intent.ACTION_VIEW)) {
|
||||
Intent intent = getIntent();
|
||||
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
|
||||
ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
|
||||
MediaType.VIDEO);
|
||||
|
||||
new PlaybackServiceStarter(this, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.prepareImmediately(true)
|
||||
.start();
|
||||
playbackStoppedUponExitVideo = false;
|
||||
if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
|
||||
playExternalMedia(getIntent(), MediaType.VIDEO);
|
||||
} else if (PlaybackService.isCasting()) {
|
||||
Intent intent = PlaybackService.getPlayerActivityIntent(this);
|
||||
if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
|
||||
@ -101,12 +93,32 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
stopPlaybackIfUserPreferencesSpecified(); // MUST be called before super.onStop(), while it still has member variable controller
|
||||
super.onStop();
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
videoControlsHider.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void stopPlaybackIfUserPreferencesSpecified() {
|
||||
// to avoid the method being called twice during leaving Videoplayer
|
||||
// , which will double-pause the media
|
||||
// (it is usually first called by surfaceHolderCallback.surfaceDestroyed(),
|
||||
// then VideoplayerActivity.onStop() , but sometimes VideoplayerActivity.onStop()
|
||||
// will first be invoked.)
|
||||
if (playbackStoppedUponExitVideo) {
|
||||
return;
|
||||
}
|
||||
playbackStoppedUponExitVideo = true;
|
||||
|
||||
if (controller != null && !destroyingDueToReload
|
||||
&& UserPreferences.getVideoBackgroundBehavior()
|
||||
!= UserPreferences.VideoBackgroundBehavior.CONTINUE_PLAYING) {
|
||||
Log.v(TAG, "stop video playback per UserPreference");
|
||||
controller.notifyVideoSurfaceAbandoned();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLeaveHint () {
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this) && UserPreferences.getVideoBackgroundBehavior()
|
||||
@ -153,11 +165,11 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
}
|
||||
super.setupGUI();
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
controls = (LinearLayout) findViewById(R.id.controls);
|
||||
videoOverlay = (LinearLayout) findViewById(R.id.overlay);
|
||||
videoview = (AspectRatioVideoView) findViewById(R.id.videoview);
|
||||
videoframe = (FrameLayout) findViewById(R.id.videoframe);
|
||||
progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
|
||||
controls = findViewById(R.id.controls);
|
||||
videoOverlay = findViewById(R.id.overlay);
|
||||
videoview = findViewById(R.id.videoview);
|
||||
videoframe = findViewById(R.id.videoframe);
|
||||
progressIndicator = findViewById(R.id.progressIndicator);
|
||||
videoview.getHolder().addCallback(surfaceHolderCallback);
|
||||
videoframe.setOnTouchListener(onVideoviewTouched);
|
||||
videoOverlay.setOnTouchListener((view, motionEvent) -> true); // To suppress touches directly below the slider
|
||||
@ -285,13 +297,12 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.d(TAG, "Videosurface was destroyed");
|
||||
Log.d(TAG, "Videosurface was destroyed." );
|
||||
Log.v(TAG, " hasController=" + (controller != null)
|
||||
+ " , destroyingDueToReload=" + destroyingDueToReload
|
||||
+ " , videoBackgroundBehavior=" + UserPreferences.getVideoBackgroundBehavior());
|
||||
videoSurfaceCreated = false;
|
||||
if (controller != null && !destroyingDueToReload
|
||||
&& UserPreferences.getVideoBackgroundBehavior()
|
||||
!= UserPreferences.VideoBackgroundBehavior.CONTINUE_PLAYING) {
|
||||
controller.notifyVideoSurfaceAbandoned();
|
||||
}
|
||||
stopPlaybackIfUserPreferencesSpecified();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -45,8 +45,6 @@ import de.danoeh.antennapod.core.service.GpodnetSyncService;
|
||||
public class GpodnetAuthenticationActivity extends AppCompatActivity {
|
||||
private static final String TAG = "GpodnetAuthActivity";
|
||||
|
||||
private static final String CURRENT_STEP = "current_step";
|
||||
|
||||
private ViewFlipper viewFlipper;
|
||||
|
||||
private static final int STEP_DEFAULT = -1;
|
||||
@ -72,7 +70,7 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
|
||||
setContentView(R.layout.gpodnetauth_activity);
|
||||
service = new GpodnetService();
|
||||
|
||||
viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
|
||||
viewFlipper = findViewById(R.id.viewflipper);
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
views = new View[]{
|
||||
@ -109,11 +107,11 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void setupLoginView(View view) {
|
||||
final EditText username = (EditText) view.findViewById(R.id.etxtUsername);
|
||||
final EditText password = (EditText) view.findViewById(R.id.etxtPassword);
|
||||
final Button login = (Button) view.findViewById(R.id.butLogin);
|
||||
final TextView txtvError = (TextView) view.findViewById(R.id.txtvError);
|
||||
final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progBarLogin);
|
||||
final EditText username = view.findViewById(R.id.etxtUsername);
|
||||
final EditText password = view.findViewById(R.id.etxtPassword);
|
||||
final Button login = view.findViewById(R.id.butLogin);
|
||||
final TextView txtvError = view.findViewById(R.id.txtvError);
|
||||
final ProgressBar progressBar = view.findViewById(R.id.progBarLogin);
|
||||
|
||||
password.setOnEditorActionListener((v, actionID, event) ->
|
||||
actionID == EditorInfo.IME_ACTION_GO && login.performClick());
|
||||
@ -177,13 +175,13 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void setupDeviceView(View view) {
|
||||
final EditText deviceID = (EditText) view.findViewById(R.id.etxtDeviceID);
|
||||
final EditText caption = (EditText) view.findViewById(R.id.etxtCaption);
|
||||
final Button createNewDevice = (Button) view.findViewById(R.id.butCreateNewDevice);
|
||||
final Button chooseDevice = (Button) view.findViewById(R.id.butChooseExistingDevice);
|
||||
final TextView txtvError = (TextView) view.findViewById(R.id.txtvError);
|
||||
final ProgressBar progBarCreateDevice = (ProgressBar) view.findViewById(R.id.progbarCreateDevice);
|
||||
final Spinner spinnerDevices = (Spinner) view.findViewById(R.id.spinnerChooseDevice);
|
||||
final EditText deviceID = view.findViewById(R.id.etxtDeviceID);
|
||||
final EditText caption = view.findViewById(R.id.etxtCaption);
|
||||
final Button createNewDevice = view.findViewById(R.id.butCreateNewDevice);
|
||||
final Button chooseDevice = view.findViewById(R.id.butChooseExistingDevice);
|
||||
final TextView txtvError = view.findViewById(R.id.txtvError);
|
||||
final ProgressBar progBarCreateDevice = view.findViewById(R.id.progbarCreateDevice);
|
||||
final Spinner spinnerDevices = view.findViewById(R.id.spinnerChooseDevice);
|
||||
|
||||
|
||||
// load device list
|
||||
@ -348,8 +346,8 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void setupFinishView(View view) {
|
||||
final Button sync = (Button) view.findViewById(R.id.butSyncNow);
|
||||
final Button back = (Button) view.findViewById(R.id.butGoMainscreen);
|
||||
final Button sync = view.findViewById(R.id.butSyncNow);
|
||||
final Button back = view.findViewById(R.id.butGoMainscreen);
|
||||
|
||||
sync.setOnClickListener(v -> {
|
||||
GpodnetSyncService.sendSyncIntent(GpodnetAuthenticationActivity.this);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
@ -19,7 +20,6 @@ import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -28,13 +28,12 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.fragment.ItemFragment;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
@ -51,7 +50,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
private final ActionButtonUtils actionButtonUtils;
|
||||
private final boolean showOnlyNewEpisodes;
|
||||
|
||||
private int position = -1;
|
||||
private FeedItem selectedItem;
|
||||
|
||||
private final int playingBackGroundColor;
|
||||
private final int normalBackGroundColor;
|
||||
@ -67,11 +66,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
this.actionButtonCallback = actionButtonCallback;
|
||||
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
|
||||
}
|
||||
|
||||
@ -80,24 +75,24 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.new_episodes_listitem, parent, false);
|
||||
Holder holder = new Holder(view);
|
||||
holder.container = (FrameLayout) view.findViewById(R.id.container);
|
||||
holder.content = (LinearLayout) view.findViewById(R.id.content);
|
||||
holder.placeholder = (TextView) view.findViewById(R.id.txtvPlaceholder);
|
||||
holder.title = (TextView) view.findViewById(R.id.txtvTitle);
|
||||
holder.container = view.findViewById(R.id.container);
|
||||
holder.content = view.findViewById(R.id.content);
|
||||
holder.placeholder = view.findViewById(R.id.txtvPlaceholder);
|
||||
holder.title = view.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
holder.pubDate = (TextView) view
|
||||
holder.pubDate = view
|
||||
.findViewById(R.id.txtvPublished);
|
||||
holder.statusUnread = view.findViewById(R.id.statusUnread);
|
||||
holder.butSecondary = (ImageButton) view
|
||||
holder.butSecondary = view
|
||||
.findViewById(R.id.butSecondaryAction);
|
||||
holder.queueStatus = (ImageView) view
|
||||
holder.queueStatus = view
|
||||
.findViewById(R.id.imgvInPlaylist);
|
||||
holder.progress = (ProgressBar) view
|
||||
holder.progress = view
|
||||
.findViewById(R.id.pbar_progress);
|
||||
holder.cover = (ImageView) view.findViewById(R.id.imgvCover);
|
||||
holder.txtvDuration = (TextView) view.findViewById(R.id.txtvDuration);
|
||||
holder.cover = view.findViewById(R.id.imgvCover);
|
||||
holder.txtvDuration = view.findViewById(R.id.txtvDuration);
|
||||
holder.item = null;
|
||||
holder.mainActivityRef = mainActivityRef;
|
||||
// so we can grab this later
|
||||
@ -111,7 +106,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
final FeedItem item = itemAccess.getItem(position);
|
||||
if (item == null) return;
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
this.position = holder.getAdapterPosition();
|
||||
this.selectedItem = item;
|
||||
return false;
|
||||
});
|
||||
holder.item = item;
|
||||
@ -196,12 +191,17 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
holder.butSecondary.setTag(item);
|
||||
holder.butSecondary.setOnClickListener(secondaryActionListener);
|
||||
|
||||
Glide.with(mainActivityRef.get())
|
||||
.load(item.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(item.getFeed().getImageLocation(), holder.placeholder, holder.cover, mainActivityRef.get()));
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(item.getImageLocation())
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(holder.placeholder)
|
||||
.withCoverView(holder.cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FeedItem getSelectedItem() {
|
||||
return selectedItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -215,16 +215,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
public FeedItem getItem(int position) {
|
||||
return itemAccess.getItem(position);
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
int pos = position;
|
||||
position = -1; // reset
|
||||
return pos;
|
||||
}
|
||||
|
||||
private final View.OnClickListener secondaryActionListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@ -299,6 +289,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
}
|
||||
};
|
||||
FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
|
||||
|
||||
contextMenuInterface.setItemVisibility(R.id.mark_as_seen_item, item.isNew());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ import android.widget.TextView;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
|
||||
public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||
@ -57,12 +57,12 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||
|
||||
convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
|
||||
holder.view = convertView;
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
defaultTextColor = holder.title.getTextColors().getDefaultColor();
|
||||
holder.start = (TextView) convertView.findViewById(R.id.txtvStart);
|
||||
holder.link = (TextView) convertView.findViewById(R.id.txtvLink);
|
||||
holder.duration = (TextView) convertView.findViewById(R.id.txtvDuration);
|
||||
holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
|
||||
holder.start = convertView.findViewById(R.id.txtvStart);
|
||||
holder.link = convertView.findViewById(R.id.txtvLink);
|
||||
holder.duration = convertView.findViewById(R.id.txtvDuration);
|
||||
holder.butPlayChapter = convertView.findViewById(R.id.butPlayChapter);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (Holder) convertView.getTag();
|
||||
@ -143,9 +143,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||
|
||||
Chapter current = ChapterUtils.getCurrentChapter(media);
|
||||
if (current == sc) {
|
||||
boolean darkTheme = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark;
|
||||
int highlight = darkTheme ? R.color.highlight_dark : R.color.highlight_light;
|
||||
int playingBackGroundColor = ContextCompat.getColor(getContext(), highlight);
|
||||
int playingBackGroundColor = ThemeUtils.getColorFromAttr(getContext(), R.attr.currently_playing_background);
|
||||
holder.view.setBackgroundColor(playingBackGroundColor);
|
||||
} else {
|
||||
holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
|
113
app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
Normal file
113
app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
Normal file
@ -0,0 +1,113 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.CustomViewTarget;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
|
||||
public class CoverLoader {
|
||||
private String uri;
|
||||
private String fallbackUri;
|
||||
private TextView txtvPlaceholder;
|
||||
private ImageView imgvCover;
|
||||
private MainActivity activity;
|
||||
private int errorResource = -1;
|
||||
|
||||
public CoverLoader(MainActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public CoverLoader withUri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withFallbackUri(String uri) {
|
||||
fallbackUri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withCoverView(ImageView coverView) {
|
||||
imgvCover = coverView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withError(int errorResource) {
|
||||
this.errorResource = errorResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CoverLoader withPlaceholderView(TextView placeholderView) {
|
||||
txtvPlaceholder = placeholderView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
RequestOptions options = new RequestOptions()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate();
|
||||
|
||||
if (errorResource != -1) {
|
||||
options = options.error(errorResource);
|
||||
}
|
||||
|
||||
RequestBuilder builder = Glide.with(activity)
|
||||
.load(uri)
|
||||
.apply(options);
|
||||
|
||||
if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
|
||||
builder = builder.error(Glide.with(activity)
|
||||
.load(fallbackUri)
|
||||
.apply(options));
|
||||
}
|
||||
|
||||
builder.into(new CoverTarget(txtvPlaceholder, imgvCover));
|
||||
}
|
||||
|
||||
class CoverTarget extends CustomViewTarget<ImageView, Drawable> {
|
||||
private final WeakReference<TextView> placeholder;
|
||||
private final WeakReference<ImageView> cover;
|
||||
|
||||
public CoverTarget(TextView txtvPlaceholder, ImageView imgvCover) {
|
||||
super(imgvCover);
|
||||
placeholder = new WeakReference<>(txtvPlaceholder);
|
||||
cover = new WeakReference<>(imgvCover);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Drawable errorDrawable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
if (txtvPlaceholder != null) {
|
||||
txtvPlaceholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResourceCleared(@Nullable Drawable placeholder) {
|
||||
ImageView ivCover = cover.get();
|
||||
ivCover.setImageDrawable(placeholder);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
|
||||
class CoverTarget extends GlideDrawableImageViewTarget {
|
||||
|
||||
private final WeakReference<String> fallback;
|
||||
private final WeakReference<TextView> placeholder;
|
||||
private final WeakReference<ImageView> cover;
|
||||
private final WeakReference<MainActivity> mainActivity;
|
||||
|
||||
public CoverTarget(String fallbackUri, TextView txtvPlaceholder, ImageView imgvCover, MainActivity activity) {
|
||||
super(imgvCover);
|
||||
fallback = new WeakReference<>(fallbackUri);
|
||||
placeholder = new WeakReference<>(txtvPlaceholder);
|
||||
cover = new WeakReference<>(imgvCover);
|
||||
mainActivity = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
String fallbackUri = fallback.get();
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
ImageView imgvCover = cover.get();
|
||||
if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
|
||||
MainActivity activity = mainActivity.get();
|
||||
Glide.with(activity)
|
||||
.load(fallbackUri)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(null, txtvPlaceholder, imgvCover, activity));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceReady(GlideDrawable drawable, GlideAnimation<? super GlideDrawable> anim) {
|
||||
super.onResourceReady(drawable, anim);
|
||||
TextView txtvPlaceholder = placeholder.get();
|
||||
if (txtvPlaceholder != null) {
|
||||
txtvPlaceholder.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
@ -20,15 +18,17 @@ import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
|
||||
/**
|
||||
* Default implementation of an ActionButtonCallback
|
||||
*/
|
||||
public class DefaultActionButtonCallback implements ActionButtonCallback {
|
||||
|
||||
private static final String TAG = "DefaultActionButtonCallback";
|
||||
private static final String TAG = "DefaultActionBtnCb";
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -82,17 +82,13 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
|
||||
}
|
||||
} else { // media is downloaded
|
||||
if (media.isCurrentlyPlaying()) {
|
||||
new PlaybackServiceStarter(context, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.start();
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
|
||||
} else if (media.isCurrentlyPaused()) {
|
||||
new PlaybackServiceStarter(context, media)
|
||||
new PlaybackServiceStarter(context, media) // need to start the service in case it's been stopped by system.
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.start();
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE));
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE);
|
||||
} else {
|
||||
DBTasks.playMedia(context, media, false, true, false);
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import com.joanzapata.iconify.widget.IconTextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -50,15 +49,15 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
|
||||
holder.icon = (IconTextView) convertView.findViewById(R.id.txtvIcon);
|
||||
holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
|
||||
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.icon = convertView.findViewById(R.id.txtvIcon);
|
||||
holder.retry = convertView.findViewById(R.id.btnRetry);
|
||||
holder.date = convertView.findViewById(R.id.txtvDate);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
holder.type = (TextView) convertView.findViewById(R.id.txtvType);
|
||||
holder.reason = (TextView) convertView.findViewById(R.id.txtvReason);
|
||||
holder.type = convertView.findViewById(R.id.txtvType);
|
||||
holder.reason = convertView.findViewById(R.id.txtvReason);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (Holder) convertView.getTag();
|
||||
@ -67,8 +66,6 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
holder.type.setText(R.string.download_type_feed);
|
||||
} else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
||||
holder.type.setText(R.string.download_type_media);
|
||||
} else if (status.getFeedfileType() == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
|
||||
holder.type.setText(R.string.download_type_image);
|
||||
}
|
||||
if (status.getTitle() != null) {
|
||||
holder.title.setText(status.getTitle());
|
||||
@ -94,8 +91,7 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
}
|
||||
holder.reason.setText(reasonText);
|
||||
holder.reason.setVisibility(View.VISIBLE);
|
||||
if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
|
||||
!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
|
||||
if(!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
|
||||
holder.retry.setVisibility(View.VISIBLE);
|
||||
holder.retry.setOnClickListener(clickListener);
|
||||
ButtonHolder btnHolder;
|
||||
|
@ -13,9 +13,11 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
|
||||
@ -60,16 +62,16 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.downloaded_episodeslist_item,
|
||||
parent, false);
|
||||
holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.imageView = convertView.findViewById(R.id.imgvImage);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
|
||||
holder.queueStatus = (ImageView) convertView.findViewById(R.id.imgvInPlaylist);
|
||||
holder.pubDate = (TextView) convertView
|
||||
holder.txtvSize = convertView.findViewById(R.id.txtvSize);
|
||||
holder.queueStatus = convertView.findViewById(R.id.imgvInPlaylist);
|
||||
holder.pubDate = convertView
|
||||
.findViewById(R.id.txtvPublished);
|
||||
holder.butSecondary = (ImageButton) convertView
|
||||
holder.butSecondary = convertView
|
||||
.findViewById(R.id.butSecondaryAction);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
@ -78,11 +80,12 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(item.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.imageView);
|
||||
|
||||
if(item.isPlayed()) {
|
||||
@ -98,7 +101,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
|
||||
holder.pubDate.setText(pubDateStr);
|
||||
|
||||
FeedItem.State state = item.getState();
|
||||
if (state == FeedItem.State.PLAYING) {
|
||||
if (state == FeedItem.State.PLAYING && PlaybackService.isRunning) {
|
||||
holder.butSecondary.setEnabled(false);
|
||||
holder.butSecondary.setAlpha(0.5f);
|
||||
} else {
|
||||
|
@ -59,14 +59,14 @@ public class DownloadlistAdapter extends BaseAdapter {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.downloadlist_item, parent, false);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.downloaded = (TextView) convertView
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.downloaded = convertView
|
||||
.findViewById(R.id.txtvDownloaded);
|
||||
holder.percent = (TextView) convertView
|
||||
holder.percent = convertView
|
||||
.findViewById(R.id.txtvPercent);
|
||||
holder.progbar = (ProgressBar) convertView
|
||||
holder.progbar = convertView
|
||||
.findViewById(R.id.progProgress);
|
||||
holder.butSecondary = (ImageButton) convertView
|
||||
holder.butSecondary = convertView
|
||||
.findViewById(R.id.butSecondaryAction);
|
||||
|
||||
convertView.setTag(holder);
|
||||
@ -121,15 +121,6 @@ public class DownloadlistAdapter extends BaseAdapter {
|
||||
ImageButton butSecondary;
|
||||
}
|
||||
|
||||
public int getSelectedItemIndex() {
|
||||
return selectedItemIndex;
|
||||
}
|
||||
|
||||
public void setSelectedItemIndex(int selectedItemIndex) {
|
||||
this.selectedItemIndex = selectedItemIndex;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
int getCount();
|
||||
|
||||
|
@ -21,7 +21,6 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
@ -60,11 +59,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
|
||||
this.actionButtonUtils = new ActionButtonUtils(context);
|
||||
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent);
|
||||
}
|
||||
|
||||
@ -95,24 +90,24 @@ public class FeedItemlistAdapter extends BaseAdapter {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.feeditemlist_item, parent, false);
|
||||
holder.container = (LinearLayout) convertView
|
||||
holder.container = convertView
|
||||
.findViewById(R.id.container);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvItemname);
|
||||
holder.title = convertView.findViewById(R.id.txtvItemname);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
holder.lenSize = (TextView) convertView
|
||||
holder.lenSize = convertView
|
||||
.findViewById(R.id.txtvLenSize);
|
||||
holder.butAction = (ImageButton) convertView
|
||||
holder.butAction = convertView
|
||||
.findViewById(R.id.butSecondaryAction);
|
||||
holder.published = (TextView) convertView
|
||||
holder.published = convertView
|
||||
.findViewById(R.id.txtvPublished);
|
||||
holder.inPlaylist = (ImageView) convertView
|
||||
holder.inPlaylist = convertView
|
||||
.findViewById(R.id.imgvInPlaylist);
|
||||
holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
|
||||
holder.type = convertView.findViewById(R.id.imgvType);
|
||||
holder.statusUnread = convertView
|
||||
.findViewById(R.id.statusUnread);
|
||||
holder.episodeProgress = (ProgressBar) convertView
|
||||
holder.episodeProgress = convertView
|
||||
.findViewById(R.id.pbar_episode_progress);
|
||||
|
||||
convertView.setTag(holder);
|
||||
|
@ -34,9 +34,9 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate);
|
||||
holder.description = (TextView) convertView.findViewById(R.id.txtvDescription);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.pubDate = convertView.findViewById(R.id.txtvPubDate);
|
||||
holder.description = convertView.findViewById(R.id.txtvDescription);
|
||||
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
|
@ -8,6 +8,7 @@ import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -17,6 +18,7 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
|
||||
@ -212,11 +214,18 @@ public class NavListAdapter extends BaseAdapter
|
||||
v = getFeedView(position, convertView, parent);
|
||||
}
|
||||
if (v != null && viewType != VIEW_TYPE_SECTION_DIVIDER) {
|
||||
TextView txtvTitle = (TextView) v.findViewById(R.id.txtvTitle);
|
||||
TextView txtvTitle = v.findViewById(R.id.txtvTitle);
|
||||
TypedValue typedValue = new TypedValue();
|
||||
|
||||
if (position == itemAccess.getSelectedItemIndex()) {
|
||||
txtvTitle.setTypeface(null, Typeface.BOLD);
|
||||
v.getContext().getTheme().resolveAttribute(de.danoeh.antennapod.core.R.attr.drawer_activated_color, typedValue, true);
|
||||
v.setBackgroundResource(typedValue.resourceId);
|
||||
|
||||
} else {
|
||||
txtvTitle.setTypeface(null, Typeface.NORMAL);
|
||||
v.getContext().getTheme().resolveAttribute(de.danoeh.antennapod.core.R.attr.nav_drawer_background, typedValue, true);
|
||||
v.setBackgroundResource(typedValue.resourceId);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
@ -235,9 +244,9 @@ public class NavListAdapter extends BaseAdapter
|
||||
|
||||
convertView = inflater.inflate(R.layout.nav_listitem, parent, false);
|
||||
|
||||
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.count = (TextView) convertView.findViewById(R.id.txtvCount);
|
||||
holder.image = convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.count = convertView.findViewById(R.id.txtvCount);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (NavHolder) convertView.getTag();
|
||||
@ -325,10 +334,10 @@ public class NavListAdapter extends BaseAdapter
|
||||
|
||||
convertView = inflater.inflate(R.layout.nav_feedlistitem, parent, false);
|
||||
|
||||
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.failure = (IconTextView) convertView.findViewById(R.id.itxtvFailure);
|
||||
holder.count = (TextView) convertView.findViewById(R.id.txtvCount);
|
||||
holder.image = convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.failure = convertView.findViewById(R.id.itxtvFailure);
|
||||
holder.count = convertView.findViewById(R.id.txtvCount);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (FeedHolder) convertView.getTag();
|
||||
@ -336,11 +345,12 @@ public class NavListAdapter extends BaseAdapter
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
@ -23,6 +23,7 @@ import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@ -40,6 +41,7 @@ import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.fragment.ItemFragment;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
@ -75,11 +77,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
||||
this.itemTouchHelper = itemTouchHelper;
|
||||
locked = UserPreferences.isQueueLocked();
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
|
||||
}
|
||||
|
||||
@ -137,19 +135,19 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
container = (FrameLayout) v.findViewById(R.id.container);
|
||||
dragHandle = (ImageView) v.findViewById(R.id.drag_handle);
|
||||
placeholder = (TextView) v.findViewById(R.id.txtvPlaceholder);
|
||||
cover = (ImageView) v.findViewById(R.id.imgvCover);
|
||||
title = (TextView) v.findViewById(R.id.txtvTitle);
|
||||
container = v.findViewById(R.id.container);
|
||||
dragHandle = v.findViewById(R.id.drag_handle);
|
||||
placeholder = v.findViewById(R.id.txtvPlaceholder);
|
||||
cover = v.findViewById(R.id.imgvCover);
|
||||
title = v.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
pubDate = (TextView) v.findViewById(R.id.txtvPubDate);
|
||||
progressLeft = (TextView) v.findViewById(R.id.txtvProgressLeft);
|
||||
progressRight = (TextView) v.findViewById(R.id.txtvProgressRight);
|
||||
butSecondary = (ImageButton) v.findViewById(R.id.butSecondaryAction);
|
||||
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
|
||||
pubDate = v.findViewById(R.id.txtvPubDate);
|
||||
progressLeft = v.findViewById(R.id.txtvProgressLeft);
|
||||
progressRight = v.findViewById(R.id.txtvProgressRight);
|
||||
butSecondary = v.findViewById(R.id.butSecondaryAction);
|
||||
progressBar = v.findViewById(R.id.progressBar);
|
||||
v.setTag(this);
|
||||
v.setOnClickListener(this);
|
||||
v.setOnCreateContextMenuListener(this);
|
||||
@ -294,12 +292,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
||||
butSecondary.setTag(item);
|
||||
butSecondary.setOnClickListener(secondaryActionListener);
|
||||
|
||||
Glide.with(mainActivity.get())
|
||||
.load(item.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(item.getFeed().getImageLocation(), placeholder, cover, mainActivity.get()));
|
||||
new CoverLoader(mainActivity.get())
|
||||
.withUri(item.getImageLocation())
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
@ -61,13 +62,13 @@ public class SearchlistAdapter extends BaseAdapter {
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
convertView = inflater.inflate(R.layout.searchlist_item, parent, false);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
holder.cover = (ImageView) convertView
|
||||
holder.cover = convertView
|
||||
.findViewById(R.id.imgvFeedimage);
|
||||
holder.subtitle = (TextView) convertView
|
||||
holder.subtitle = convertView
|
||||
.findViewById(R.id.txtvSubtitle);
|
||||
|
||||
convertView.setTag(holder);
|
||||
@ -81,11 +82,12 @@ public class SearchlistAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.cover);
|
||||
|
||||
} else if (component.getClass() == FeedItem.class) {
|
||||
@ -100,11 +102,12 @@ public class SearchlistAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(item.getFeed().getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.cover);
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import com.bumptech.glide.Glide;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -62,9 +63,9 @@ public class StatisticsListAdapter extends BaseAdapter {
|
||||
|
||||
convertView = inflater.inflate(R.layout.statistics_listitem, parent, false);
|
||||
|
||||
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.time = (TextView) convertView.findViewById(R.id.txtvTime);
|
||||
holder.image = convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.time = convertView.findViewById(R.id.txtvTime);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (StatisticsHolder) convertView.getTag();
|
||||
@ -72,11 +73,12 @@ public class StatisticsListAdapter extends BaseAdapter {
|
||||
|
||||
Glide.with(context)
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
|
@ -14,6 +14,7 @@ import com.bumptech.glide.Glide;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
@ -89,9 +90,9 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
||||
LayoutInflater layoutInflater =
|
||||
(LayoutInflater) mainActivityRef.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = layoutInflater.inflate(R.layout.subscription_item, parent, false);
|
||||
holder.feedTitle = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.imageView = (ImageView) convertView.findViewById(R.id.imgvCover);
|
||||
holder.count = (TriangleLabelView) convertView.findViewById(R.id.triangleCountView);
|
||||
holder.feedTitle = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.imageView = convertView.findViewById(R.id.imgvCover);
|
||||
holder.count = convertView.findViewById(R.id.triangleCountView);
|
||||
|
||||
|
||||
convertView.setTag(holder);
|
||||
@ -108,7 +109,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
||||
holder.count.setVisibility(View.INVISIBLE);
|
||||
|
||||
// when this holder is reused, we could else end up with a cover image
|
||||
Glide.clear(holder.imageView);
|
||||
Glide.with(mainActivityRef.get()).clear(holder.imageView);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
@ -125,13 +126,13 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
|
||||
} else {
|
||||
holder.count.setVisibility(View.GONE);
|
||||
}
|
||||
Glide.with(mainActivityRef.get())
|
||||
.load(feed.getImageLocation())
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(new CoverTarget(null, holder.feedTitle, holder.imageView, mainActivityRef.get()));
|
||||
|
||||
new CoverLoader(mainActivityRef.get())
|
||||
.withUri(feed.getImageLocation())
|
||||
.withPlaceholderView(holder.feedTitle)
|
||||
.withCoverView(holder.imageView)
|
||||
.withError(R.color.light_gray)
|
||||
.load();
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -40,10 +41,10 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
convertView = inflater.inflate(R.layout.gpodnet_podcast_listitem, parent, false);
|
||||
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.subscribers = (TextView) convertView.findViewById(R.id.txtvSubscribers);
|
||||
holder.url = (TextView) convertView.findViewById(R.id.txtvUrl);
|
||||
holder.image = convertView.findViewById(R.id.imgvCover);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.subscribers = convertView.findViewById(R.id.txtvSubscribers);
|
||||
holder.url = convertView.findViewById(R.id.txtvUrl);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (Holder) convertView.getTag();
|
||||
@ -52,11 +53,12 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
|
||||
if (StringUtils.isNotBlank(podcast.getLogoUrl())) {
|
||||
Glide.with(convertView.getContext())
|
||||
.load(podcast.getLogoUrl())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(holder.image);
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,8 @@ public class TagListAdapter extends ArrayAdapter<GpodnetTag> {
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
convertView = inflater.inflate(R.layout.gpodnet_tag_listitem, parent, false);
|
||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||
holder.usage = (TextView) convertView.findViewById(R.id.txtvUsage);
|
||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
||||
holder.usage = convertView.findViewById(R.id.txtvUsage);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (Holder) convertView.getTag();
|
||||
|
@ -12,6 +12,8 @@ import android.widget.TextView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@ -80,10 +82,11 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
||||
//Update the empty imageView with the image from the feed
|
||||
Glide.with(context)
|
||||
.load(podcast.imageUrl)
|
||||
.placeholder(R.color.light_gray)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(viewHolder.coverView);
|
||||
|
||||
//Feed the grid view
|
||||
@ -132,7 +135,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
||||
}
|
||||
|
||||
public static Podcast fromSearch(SearchHit searchHit) {
|
||||
return new Podcast(searchHit.getTitle(), searchHit.getImageUrl(), searchHit.getXmlUrl());
|
||||
return new Podcast(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,9 +185,9 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
||||
* @param view GridView cell
|
||||
*/
|
||||
PodcastViewHolder(View view){
|
||||
coverView = (ImageView) view.findViewById(R.id.imgvCover);
|
||||
titleView = (TextView) view.findViewById(R.id.txtvTitle);
|
||||
urlView = (TextView) view.findViewById(R.id.txtvUrl);
|
||||
coverView = view.findViewById(R.id.imgvCover);
|
||||
titleView = view.findViewById(R.id.txtvTitle);
|
||||
urlView = view.findViewById(R.id.txtvUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import de.danoeh.antennapod.core.export.ExportWriter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.LangUtils;
|
||||
import rx.Observable;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
/**
|
||||
* Writes an OPML file into the export directory in the background.
|
||||
@ -23,15 +23,15 @@ public class ExportWorker {
|
||||
private static final String TAG = "ExportWorker";
|
||||
private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds";
|
||||
|
||||
private final ExportWriter exportWriter;
|
||||
private final File output;
|
||||
private final @NonNull ExportWriter exportWriter;
|
||||
private final @NonNull File output;
|
||||
|
||||
public ExportWorker(ExportWriter exportWriter) {
|
||||
public ExportWorker(@NonNull ExportWriter exportWriter) {
|
||||
this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
|
||||
DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()));
|
||||
}
|
||||
|
||||
private ExportWorker(ExportWriter exportWriter, @NonNull File output) {
|
||||
private ExportWorker(@NonNull ExportWriter exportWriter, @NonNull File output) {
|
||||
this.exportWriter = exportWriter;
|
||||
this.output = output;
|
||||
}
|
||||
@ -57,7 +57,7 @@ public class ExportWorker {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
subscriber.onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import de.danoeh.antennapod.core.ClientConfig;
|
||||
*/
|
||||
class ClientConfigurator {
|
||||
|
||||
private ClientConfigurator(){}
|
||||
|
||||
static {
|
||||
ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
|
||||
ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
|
||||
|
@ -2,7 +2,6 @@ package de.danoeh.antennapod.config;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Build;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
||||
|
@ -35,11 +35,11 @@ public abstract class AuthenticationDialog extends Dialog {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.authentication_dialog);
|
||||
final EditText etxtUsername = (EditText) findViewById(R.id.etxtUsername);
|
||||
final EditText etxtPassword = (EditText) findViewById(R.id.etxtPassword);
|
||||
final CheckBox saveUsernamePassword = (CheckBox) findViewById(R.id.chkSaveUsernamePassword);
|
||||
final Button butConfirm = (Button) findViewById(R.id.butConfirm);
|
||||
final Button butCancel = (Button) findViewById(R.id.butCancel);
|
||||
final EditText etxtUsername = findViewById(R.id.etxtUsername);
|
||||
final EditText etxtPassword = findViewById(R.id.etxtPassword);
|
||||
final CheckBox saveUsernamePassword = findViewById(R.id.chkSaveUsernamePassword);
|
||||
final Button butConfirm = findViewById(R.id.butConfirm);
|
||||
final Button butCancel = findViewById(R.id.butCancel);
|
||||
|
||||
if (titleRes != 0) {
|
||||
setTitle(titleRes);
|
||||
|
@ -29,9 +29,9 @@ public class AutoFlattrPreferenceDialog {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
|
||||
@SuppressLint("InflateParams") View view = activity.getLayoutInflater().inflate(R.layout.autoflattr_preference_dialog, null);
|
||||
final CheckBox chkAutoFlattr = (CheckBox) view.findViewById(R.id.chkAutoFlattr);
|
||||
final SeekBar skbPercent = (SeekBar) view.findViewById(R.id.skbPercent);
|
||||
final TextView txtvStatus = (TextView) view.findViewById(R.id.txtvStatus);
|
||||
final CheckBox chkAutoFlattr = view.findViewById(R.id.chkAutoFlattr);
|
||||
final SeekBar skbPercent = view.findViewById(R.id.skbPercent);
|
||||
final TextView txtvStatus = view.findViewById(R.id.txtvStatus);
|
||||
|
||||
chkAutoFlattr.setChecked(UserPreferences.isAutoFlattr());
|
||||
skbPercent.setEnabled(chkAutoFlattr.isChecked());
|
||||
|
@ -1,11 +1,20 @@
|
||||
package de.danoeh.antennapod.dialog;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.PluralsRes;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -13,11 +22,12 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.leinardi.android.speeddial.SpeedDialView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -34,22 +44,42 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
|
||||
public static final String TAG = "EpisodeActionFragment";
|
||||
|
||||
private static final int ACTION_QUEUE = 1;
|
||||
private static final int ACTION_MARK_PLAYED = 2;
|
||||
private static final int ACTION_MARK_UNPLAYED = 4;
|
||||
private static final int ACTION_DOWNLOAD = 8;
|
||||
public static final int ACTION_REMOVE = 16;
|
||||
private static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED
|
||||
| ACTION_DOWNLOAD | ACTION_REMOVE;
|
||||
public static final int ACTION_ADD_TO_QUEUE = 1;
|
||||
private static final int ACTION_REMOVE_FROM_QUEUE = 2;
|
||||
private static final int ACTION_MARK_PLAYED = 4;
|
||||
private static final int ACTION_MARK_UNPLAYED = 8;
|
||||
private static final int ACTION_DOWNLOAD = 16;
|
||||
public static final int ACTION_DELETE = 32;
|
||||
private static final int ACTION_ALL = ACTION_ADD_TO_QUEUE | ACTION_REMOVE_FROM_QUEUE
|
||||
| ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED | ACTION_DOWNLOAD | ACTION_DELETE;
|
||||
|
||||
/**
|
||||
* Specify an action (defined by #flag) 's UI bindings.
|
||||
*
|
||||
* Includes: the menu / action item and the actual logic
|
||||
*/
|
||||
private class ActionBinding {
|
||||
int flag;
|
||||
@IdRes
|
||||
final int actionItemId;
|
||||
@NonNull
|
||||
final Runnable action;
|
||||
|
||||
ActionBinding(int flag, @IdRes int actionItemId, @NonNull Runnable action) {
|
||||
this.flag = flag;
|
||||
this.actionItemId = actionItemId;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<? extends ActionBinding> actionBindings;
|
||||
|
||||
private ListView mListView;
|
||||
private ArrayAdapter<String> mAdapter;
|
||||
|
||||
private Button btnAddToQueue;
|
||||
private Button btnMarkAsPlayed;
|
||||
private Button btnMarkAsUnplayed;
|
||||
private Button btnDownload;
|
||||
private Button btnDelete;
|
||||
private SpeedDialView mSpeedDialView;
|
||||
@NonNull
|
||||
private CharSequence actionBarTitleOriginal = "";
|
||||
|
||||
private final Map<Long,FeedItem> idMap = new ArrayMap<>();
|
||||
private final List<FeedItem> episodes = new ArrayList<>();
|
||||
@ -59,6 +89,23 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
|
||||
private MenuItem mSelectToggle;
|
||||
|
||||
public EpisodesApplyActionFragment() {
|
||||
actionBindings = Arrays.asList(
|
||||
new ActionBinding(ACTION_ADD_TO_QUEUE,
|
||||
R.id.add_to_queue_batch, this::queueChecked),
|
||||
new ActionBinding(ACTION_REMOVE_FROM_QUEUE,
|
||||
R.id.remove_from_queue_batch, this::removeFromQueueChecked),
|
||||
new ActionBinding(ACTION_MARK_PLAYED,
|
||||
R.id.mark_read_batch, this::markedCheckedPlayed),
|
||||
new ActionBinding(ACTION_MARK_UNPLAYED,
|
||||
R.id.mark_unread_batch, this::markedCheckedUnplayed),
|
||||
new ActionBinding(ACTION_DOWNLOAD,
|
||||
R.id.download_batch, this::downloadChecked),
|
||||
new ActionBinding(ACTION_DELETE,
|
||||
R.id.delete_batch, this::deleteChecked)
|
||||
);
|
||||
}
|
||||
|
||||
public static EpisodesApplyActionFragment newInstance(List<FeedItem> items) {
|
||||
return newInstance(items, ACTION_ALL);
|
||||
}
|
||||
@ -76,6 +123,7 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@ -84,7 +132,7 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.episodes_apply_action_fragment, container, false);
|
||||
|
||||
mListView = (ListView) view.findViewById(android.R.id.list);
|
||||
mListView = view.findViewById(android.R.id.list);
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
mListView.setOnItemClickListener((ListView, view1, position, rowId) -> {
|
||||
long id = episodes.get(position).getId();
|
||||
@ -95,62 +143,85 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
}
|
||||
refreshCheckboxes();
|
||||
});
|
||||
mListView.setOnItemLongClickListener((adapterView, view12, position, id) -> {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setItems(R.array.batch_long_press_options, (dialogInterface, item) -> {
|
||||
int direction;
|
||||
if (item == 0) {
|
||||
direction = -1;
|
||||
} else {
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
int currentPosition = position + direction;
|
||||
while (currentPosition >= 0 && currentPosition < episodes.size()) {
|
||||
long id1 = episodes.get(currentPosition).getId();
|
||||
if (!checkedIds.contains(id1)) {
|
||||
checkedIds.add(id1);
|
||||
}
|
||||
currentPosition += direction;
|
||||
}
|
||||
refreshCheckboxes();
|
||||
}).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
for(FeedItem episode : episodes) {
|
||||
titles.add(episode.getTitle());
|
||||
}
|
||||
|
||||
mAdapter = new ArrayAdapter<>(getActivity(),
|
||||
android.R.layout.simple_list_item_multiple_choice, titles);
|
||||
R.layout.simple_list_item_multiple_choice_on_start, titles);
|
||||
mListView.setAdapter(mAdapter);
|
||||
checkAll();
|
||||
|
||||
int lastVisibleDiv = 0;
|
||||
btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue);
|
||||
if((actions & ACTION_QUEUE) != 0) {
|
||||
btnAddToQueue.setOnClickListener(v -> queueChecked());
|
||||
lastVisibleDiv = R.id.divider1;
|
||||
} else {
|
||||
btnAddToQueue.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.divider1).setVisibility(View.GONE);
|
||||
}
|
||||
btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed);
|
||||
if((actions & ACTION_MARK_PLAYED) != 0) {
|
||||
btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed());
|
||||
lastVisibleDiv = R.id.divider2;
|
||||
} else {
|
||||
btnMarkAsPlayed.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.divider2).setVisibility(View.GONE);
|
||||
}
|
||||
btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed);
|
||||
if((actions & ACTION_MARK_UNPLAYED) != 0) {
|
||||
btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed());
|
||||
lastVisibleDiv = R.id.divider3;
|
||||
} else {
|
||||
btnMarkAsUnplayed.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.divider3).setVisibility(View.GONE);
|
||||
}
|
||||
btnDownload = (Button) view.findViewById(R.id.btnDownload);
|
||||
if((actions & ACTION_DOWNLOAD) != 0) {
|
||||
btnDownload.setOnClickListener(v -> downloadChecked());
|
||||
lastVisibleDiv = R.id.divider4;
|
||||
} else {
|
||||
btnDownload.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.divider4).setVisibility(View.GONE);
|
||||
}
|
||||
btnDelete = (Button) view.findViewById(R.id.btnDelete);
|
||||
if((actions & ACTION_REMOVE) != 0) {
|
||||
btnDelete.setOnClickListener(v -> deleteChecked());
|
||||
} else {
|
||||
btnDelete.setVisibility(View.GONE);
|
||||
if(lastVisibleDiv > 0) {
|
||||
view.findViewById(lastVisibleDiv).setVisibility(View.GONE);
|
||||
saveActionBarTitle(); // needed when we dynamically change the title based on selection
|
||||
|
||||
// Init action UI (via a FAB Speed Dial)
|
||||
mSpeedDialView = view.findViewById(R.id.fabSD);
|
||||
mSpeedDialView.inflate(R.menu.episodes_apply_action_speeddial);
|
||||
|
||||
// show only specified actions, and bind speed dial UIs to the actual logic
|
||||
for (ActionBinding binding : actionBindings) {
|
||||
if ((actions & binding.flag) == 0) {
|
||||
mSpeedDialView.removeActionItemById(binding.actionItemId);
|
||||
}
|
||||
}
|
||||
|
||||
mSpeedDialView.setOnActionSelectedListener(actionItem -> {
|
||||
ActionBinding selectedBinding = null;
|
||||
for (ActionBinding binding : actionBindings) {
|
||||
if (actionItem.getId() == binding.actionItemId) {
|
||||
selectedBinding = binding;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selectedBinding != null) {
|
||||
selectedBinding.action.run();
|
||||
} else {
|
||||
Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + actionItem.getId());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
showSpeedDialIfAnyChecked();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
restoreActionBarTitle(); // it might have been changed to "N selected". Restore original.
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void showSpeedDialIfAnyChecked() {
|
||||
mSpeedDialView.setVisibility(checkedIds.size() > 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void hideSpeedDial() {
|
||||
mSpeedDialView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
@ -173,11 +244,9 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
|
||||
int[] icon = new int[1];
|
||||
if (checkedIds.size() == episodes.size()) {
|
||||
icon[0] = R.attr.ic_check_box;
|
||||
} else if (checkedIds.size() == 0) {
|
||||
icon[0] = R.attr.ic_check_box_outline;
|
||||
icon[0] = R.attr.ic_select_none;
|
||||
} else {
|
||||
icon[0] = R.attr.ic_indeterminate_check_box;
|
||||
icon[0] = R.attr.ic_select_all;
|
||||
}
|
||||
|
||||
TypedArray a = getActivity().obtainStyledAttributes(icon);
|
||||
@ -189,7 +258,7 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int resId = 0;
|
||||
@StringRes int resId = 0;
|
||||
switch(item.getItemId()) {
|
||||
case R.id.select_options:
|
||||
return true;
|
||||
@ -249,7 +318,8 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
return true;
|
||||
}
|
||||
if(resId != 0) {
|
||||
Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show();
|
||||
Snackbar.make(getActivity().findViewById(R.id.content), resId, Snackbar.LENGTH_SHORT)
|
||||
.show();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -387,21 +457,56 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
mListView.setItemChecked(i, checked);
|
||||
}
|
||||
ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
|
||||
showSpeedDialIfAnyChecked();
|
||||
updateActionBarTitle();
|
||||
}
|
||||
|
||||
private void saveActionBarTitle() {
|
||||
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
CharSequence title = actionBar.getTitle();
|
||||
if (title == null) {
|
||||
title = "";
|
||||
}
|
||||
actionBarTitleOriginal = title;
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreActionBarTitle() {
|
||||
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(actionBarTitleOriginal);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateActionBarTitle() {
|
||||
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
CharSequence title = checkedIds.size() > 0 ?
|
||||
getString(R.string.num_selected_label, checkedIds.size()) :
|
||||
actionBarTitleOriginal;
|
||||
actionBar.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
private void queueChecked() {
|
||||
DBWriter.addQueueItem(getActivity(), true, checkedIds.toArray());
|
||||
close();
|
||||
close(R.plurals.added_to_queue_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void removeFromQueueChecked() {
|
||||
DBWriter.removeQueueItem(getActivity(), true, checkedIds.toArray());
|
||||
close(R.plurals.removed_from_queue_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void markedCheckedPlayed() {
|
||||
DBWriter.markItemPlayed(FeedItem.PLAYED, checkedIds.toArray());
|
||||
close();
|
||||
close(R.plurals.marked_read_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void markedCheckedUnplayed() {
|
||||
DBWriter.markItemPlayed(FeedItem.UNPLAYED, checkedIds.toArray());
|
||||
close();
|
||||
close(R.plurals.marked_unread_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void downloadChecked() {
|
||||
@ -418,7 +523,7 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
|
||||
}
|
||||
close();
|
||||
close(R.plurals.downloading_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void deleteChecked() {
|
||||
@ -428,10 +533,18 @@ public class EpisodesApplyActionFragment extends Fragment {
|
||||
DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId());
|
||||
}
|
||||
}
|
||||
close();
|
||||
close(R.plurals.deleted_episode_batch_label, checkedIds.size());
|
||||
}
|
||||
|
||||
private void close() {
|
||||
private void close(@PluralsRes int msgId, int numItems) {
|
||||
if (numItems > 0) {
|
||||
Snackbar.make(getActivity().findViewById(R.id.content),
|
||||
getResources().getQuantityString(msgId, numItems, numItems),
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(android.R.string.ok, v -> {})
|
||||
.show();
|
||||
}
|
||||
getActivity().getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,9 @@ import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
* Creates a dialog that lets the user change the hostname for the gpodder.net service.
|
||||
*/
|
||||
public class GpodnetSetHostnameDialog {
|
||||
|
||||
private GpodnetSetHostnameDialog(){}
|
||||
|
||||
private static final String TAG = "GpodnetSetHostnameDialog";
|
||||
|
||||
public static AlertDialog createDialog(final Context context) {
|
||||
|
@ -29,15 +29,15 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.service.download.ProxyConfig;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.Credentials;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class ProxyDialog {
|
||||
|
||||
@ -55,7 +55,7 @@ public class ProxyDialog {
|
||||
|
||||
private boolean testSuccessful = false;
|
||||
private TextView txtvMessage;
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
public ProxyDialog(Context context) {
|
||||
this.context = context;
|
||||
@ -102,7 +102,7 @@ public class ProxyDialog {
|
||||
.autoDismiss(false)
|
||||
.build();
|
||||
View view = dialog.getCustomView();
|
||||
spType = (Spinner) view.findViewById(R.id.spType);
|
||||
spType = view.findViewById(R.id.spType);
|
||||
String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() };
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
|
||||
android.R.layout.simple_spinner_item, types);
|
||||
@ -110,22 +110,22 @@ public class ProxyDialog {
|
||||
spType.setAdapter(adapter);
|
||||
ProxyConfig proxyConfig = UserPreferences.getProxyConfig();
|
||||
spType.setSelection(adapter.getPosition(proxyConfig.type.name()));
|
||||
etHost = (EditText) view.findViewById(R.id.etHost);
|
||||
etHost = view.findViewById(R.id.etHost);
|
||||
if(!TextUtils.isEmpty(proxyConfig.host)) {
|
||||
etHost.setText(proxyConfig.host);
|
||||
}
|
||||
etHost.addTextChangedListener(requireTestOnChange);
|
||||
etPort = (EditText) view.findViewById(R.id.etPort);
|
||||
etPort = view.findViewById(R.id.etPort);
|
||||
if(proxyConfig.port > 0) {
|
||||
etPort.setText(String.valueOf(proxyConfig.port));
|
||||
}
|
||||
etPort.addTextChangedListener(requireTestOnChange);
|
||||
etUsername = (EditText) view.findViewById(R.id.etUsername);
|
||||
etUsername = view.findViewById(R.id.etUsername);
|
||||
if(!TextUtils.isEmpty(proxyConfig.username)) {
|
||||
etUsername.setText(proxyConfig.username);
|
||||
}
|
||||
etUsername.addTextChangedListener(requireTestOnChange);
|
||||
etPassword = (EditText) view.findViewById(R.id.etPassword);
|
||||
etPassword = view.findViewById(R.id.etPassword);
|
||||
if(!TextUtils.isEmpty(proxyConfig.password)) {
|
||||
etPassword.setText(proxyConfig.username);
|
||||
}
|
||||
@ -146,7 +146,7 @@ public class ProxyDialog {
|
||||
enableSettings(false);
|
||||
}
|
||||
});
|
||||
txtvMessage = (TextView) view.findViewById(R.id.txtvMessage);
|
||||
txtvMessage = view.findViewById(R.id.txtvMessage);
|
||||
checkValidity();
|
||||
return dialog;
|
||||
}
|
||||
@ -229,8 +229,8 @@ public class ProxyDialog {
|
||||
}
|
||||
|
||||
private void test() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if(!checkValidity()) {
|
||||
setTestRequired(true);
|
||||
@ -243,7 +243,7 @@ public class ProxyDialog {
|
||||
txtvMessage.setTextColor(textColorPrimary);
|
||||
txtvMessage.setText("{fa-circle-o-notch spin} " + checking);
|
||||
txtvMessage.setVisibility(View.VISIBLE);
|
||||
subscription = Observable.create((Observable.OnSubscribe<Response>) subscriber -> {
|
||||
disposable = Single.create((SingleOnSubscribe<Response>) emitter -> {
|
||||
String type = (String) spType.getSelectedItem();
|
||||
String host = etHost.getText().toString();
|
||||
String port = etPort.getText().toString();
|
||||
@ -275,13 +275,12 @@ public class ProxyDialog {
|
||||
.build();
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
subscriber.onNext(response);
|
||||
emitter.onSuccess(response);
|
||||
} catch(IOException e) {
|
||||
subscriber.onError(e);
|
||||
emitter.onError(e);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
response -> {
|
||||
|
@ -17,6 +17,8 @@ import de.danoeh.antennapod.R;
|
||||
|
||||
public class RatingDialog {
|
||||
|
||||
private RatingDialog(){}
|
||||
|
||||
private static final String TAG = RatingDialog.class.getSimpleName();
|
||||
private static final int AFTER_DAYS = 7;
|
||||
|
||||
|
@ -61,11 +61,11 @@ public abstract class SleepTimerDialog {
|
||||
dialog = builder.build();
|
||||
|
||||
View view = dialog.getView();
|
||||
etxtTime = (EditText) view.findViewById(R.id.etxtTime);
|
||||
spTimeUnit = (Spinner) view.findViewById(R.id.spTimeUnit);
|
||||
cbShakeToReset = (CheckBox) view.findViewById(R.id.cbShakeToReset);
|
||||
cbVibrate = (CheckBox) view.findViewById(R.id.cbVibrate);
|
||||
chAutoEnable = (CheckBox) view.findViewById(R.id.chAutoEnable);
|
||||
etxtTime = view.findViewById(R.id.etxtTime);
|
||||
spTimeUnit = view.findViewById(R.id.spTimeUnit);
|
||||
cbShakeToReset = view.findViewById(R.id.cbShakeToReset);
|
||||
cbVibrate = view.findViewById(R.id.cbVibrate);
|
||||
chAutoEnable = view.findViewById(R.id.chAutoEnable);
|
||||
|
||||
etxtTime.setText(SleepTimerPreferences.lastTimerValue());
|
||||
etxtTime.addTextChangedListener(new TextWatcher() {
|
||||
|
@ -52,7 +52,7 @@ public class VariableSpeedDialog {
|
||||
builder.neutralText(R.string.close_label);
|
||||
builder.onPositive((dialog, which) -> {
|
||||
if (Build.VERSION.SDK_INT >= 16) { // just to be safe
|
||||
UserPreferences.enableSonic(true);
|
||||
UserPreferences.enableSonic();
|
||||
if(showSpeedSelector) {
|
||||
showSpeedSelectorDialog(context);
|
||||
}
|
||||
|
@ -32,18 +32,18 @@ public class AddFeedFragment extends Fragment {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View root = inflater.inflate(R.layout.addfeed, container, false);
|
||||
|
||||
final EditText etxtFeedurl = (EditText) root.findViewById(R.id.etxtFeedurl);
|
||||
final EditText etxtFeedurl = root.findViewById(R.id.etxtFeedurl);
|
||||
|
||||
Bundle args = getArguments();
|
||||
if (args != null && args.getString(ARG_FEED_URL) != null) {
|
||||
etxtFeedurl.setText(args.getString(ARG_FEED_URL));
|
||||
}
|
||||
|
||||
Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes);
|
||||
Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
|
||||
Button butSearchFyyd = (Button) root.findViewById(R.id.butSearchFyyd);
|
||||
Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport);
|
||||
Button butConfirm = (Button) root.findViewById(R.id.butConfirm);
|
||||
Button butSearchITunes = root.findViewById(R.id.butSearchItunes);
|
||||
Button butBrowserGpoddernet = root.findViewById(R.id.butBrowseGpoddernet);
|
||||
Button butSearchFyyd = root.findViewById(R.id.butSearchFyyd);
|
||||
Button butOpmlImport = root.findViewById(R.id.butOpmlImport);
|
||||
Button butConfirm = root.findViewById(R.id.butConfirm);
|
||||
|
||||
final MainActivity activity = (MainActivity) getActivity();
|
||||
activity.getSupportActionBar().setTitle(R.string.add_feed_label);
|
||||
@ -66,4 +66,15 @@ public class AddFeedFragment extends Fragment {
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
|
||||
// So, we certainly *don't* have an options menu,
|
||||
// but unless we say we do, old options menus sometimes
|
||||
// persist. mfietz thinks this causes the ActionBar to be invalidated
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
@ -18,6 +21,7 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
@ -36,22 +40,22 @@ import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Shows unread or recently published episodes
|
||||
@ -72,6 +76,7 @@ public class AllEpisodesFragment extends Fragment {
|
||||
RecyclerView recyclerView;
|
||||
AllEpisodesRecycleAdapter listAdapter;
|
||||
private ProgressBar progLoading;
|
||||
private View emptyView;
|
||||
|
||||
List<FeedItem> episodes;
|
||||
private List<Downloader> downloaderList;
|
||||
@ -82,7 +87,7 @@ public class AllEpisodesFragment extends Fragment {
|
||||
private boolean isUpdatingFeeds;
|
||||
boolean isMenuInvalidationAllowed = false;
|
||||
|
||||
Subscription subscription;
|
||||
Disposable disposable;
|
||||
private LinearLayoutManager layoutManager;
|
||||
|
||||
boolean showOnlyNewEpisodes() { return false; }
|
||||
@ -123,8 +128,8 @@ public class AllEpisodesFragment extends Fragment {
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,17 +278,23 @@ public class AllEpisodesFragment extends Fragment {
|
||||
if(item.getItemId() == R.id.share_item) {
|
||||
return true; // avoids that the position is reset when we need it in the submenu
|
||||
}
|
||||
int pos = listAdapter.getPosition();
|
||||
if(pos < 0) {
|
||||
return false;
|
||||
}
|
||||
FeedItem selectedItem = itemAccess.getItem(pos);
|
||||
|
||||
FeedItem selectedItem = listAdapter.getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
Log.i(TAG, "Selected item at position " + pos + " was null, ignoring selection");
|
||||
Log.i(TAG, "Selected item was null, ignoring selection");
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
// Mark as seen contains UI logic specific to All/New/FavoriteSegments,
|
||||
// e.g., Undo with Snackbar,
|
||||
// and is handled by this class rather than the generic FeedItemMenuHandler
|
||||
// Undo is useful for Mark as seen, given there is no UI to undo it otherwise,
|
||||
// i.e., there is context menu item for Mark as new
|
||||
if (R.id.mark_as_seen_item == item.getItemId()) {
|
||||
markItemAsSeenWithUndo(selectedItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
|
||||
}
|
||||
|
||||
@ -301,7 +312,7 @@ public class AllEpisodesFragment extends Fragment {
|
||||
|
||||
View root = inflater.inflate(fragmentResource, container, false);
|
||||
|
||||
recyclerView = (RecyclerView) root.findViewById(android.R.id.list);
|
||||
recyclerView = root.findViewById(android.R.id.list);
|
||||
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
|
||||
if (animator instanceof SimpleItemAnimator) {
|
||||
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
|
||||
@ -311,7 +322,7 @@ public class AllEpisodesFragment extends Fragment {
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
|
||||
|
||||
progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
|
||||
progLoading = root.findViewById(R.id.progLoading);
|
||||
|
||||
if (!itemsLoaded) {
|
||||
progLoading.setVisibility(View.VISIBLE);
|
||||
@ -323,17 +334,31 @@ public class AllEpisodesFragment extends Fragment {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
|
||||
emptyView = (View) root.findViewById(R.id.emptyView);
|
||||
emptyView.setVisibility(View.GONE);
|
||||
((TextView)emptyView.findViewById(R.id.emptyViewTitle)).setText(R.string.no_all_episodes_head_label);
|
||||
((TextView)emptyView.findViewById(R.id.emptyViewMessage)).setText(R.string.no_all_episodes_label);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void onFragmentLoaded() {
|
||||
if (listAdapter == null) {
|
||||
MainActivity mainActivity = (MainActivity) getActivity();
|
||||
listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess,
|
||||
new DefaultActionButtonCallback(mainActivity), showOnlyNewEpisodes());
|
||||
listAdapter.setHasStableIds(true);
|
||||
recyclerView.setAdapter(listAdapter);
|
||||
if (episodes != null && episodes.size() > 0) {
|
||||
if (listAdapter == null) {
|
||||
MainActivity mainActivity = (MainActivity) getActivity();
|
||||
listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess,
|
||||
new DefaultActionButtonCallback(mainActivity), showOnlyNewEpisodes());
|
||||
listAdapter.setHasStableIds(true);
|
||||
recyclerView.setAdapter(listAdapter);
|
||||
}
|
||||
emptyView.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
listAdapter = null;
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
listAdapter.notifyDataSetChanged();
|
||||
restoreScrollPosition();
|
||||
getActivity().supportInvalidateOptionsMenu();
|
||||
@ -406,20 +431,26 @@ public class AllEpisodesFragment extends Fragment {
|
||||
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if(episodes == null || listAdapter == null) {
|
||||
if (episodes == null || listAdapter == null) {
|
||||
return;
|
||||
}
|
||||
for(int i=0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
for (FeedItem item : event.items) {
|
||||
int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
|
||||
if(pos >= 0) {
|
||||
if (pos >= 0) {
|
||||
episodes.remove(pos);
|
||||
episodes.add(pos, item);
|
||||
listAdapter.notifyItemChanged(pos);
|
||||
if (shouldUpdatedItemRemainInList(item)) {
|
||||
episodes.add(pos, item);
|
||||
listAdapter.notifyItemChanged(pos);
|
||||
} else {
|
||||
listAdapter.notifyItemRemoved(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onEventMainThread(DownloadEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
@ -454,31 +485,63 @@ public class AllEpisodesFragment extends Fragment {
|
||||
}
|
||||
|
||||
void loadItems() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if (viewsCreated && !itemsLoaded) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
emptyView.setVisibility(View.GONE);
|
||||
progLoading.setVisibility(View.VISIBLE);
|
||||
}
|
||||
subscription = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(data -> {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
progLoading.setVisibility(View.GONE);
|
||||
if (data != null) {
|
||||
episodes = data;
|
||||
itemsLoaded = true;
|
||||
if (viewsCreated) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
episodes = data;
|
||||
itemsLoaded = true;
|
||||
if (viewsCreated) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
List<FeedItem> loadData() {
|
||||
return DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT);
|
||||
}
|
||||
|
||||
void markItemAsSeenWithUndo(FeedItem item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "markItemAsSeenWithUndo(" + item.getId() + ")");
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
// we're marking it as unplayed since the user didn't actually play it
|
||||
// but they don't want it considered 'NEW' anymore
|
||||
DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
|
||||
|
||||
final Handler h = new Handler(getActivity().getMainLooper());
|
||||
final Runnable r = () -> {
|
||||
FeedMedia media = item.getMedia();
|
||||
if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
|
||||
DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
|
||||
}
|
||||
};
|
||||
|
||||
Snackbar snackbar = Snackbar.make(getView(), getString(R.string.marked_as_seen_label),
|
||||
Snackbar.LENGTH_LONG);
|
||||
snackbar.setAction(getString(R.string.undo), v -> {
|
||||
DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
|
||||
// don't forget to cancel the thing that's going to remove the media
|
||||
h.removeCallbacks(r);
|
||||
});
|
||||
snackbar.show();
|
||||
h.postDelayed(r, (int)Math.ceil(snackbar.getDuration() * 1.05f));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.util.Log;
|
||||
@ -12,9 +10,6 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.joanzapata.iconify.IconDrawable;
|
||||
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
@ -22,15 +17,15 @@ import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays all running downloads and provides a button to delete them
|
||||
@ -48,7 +43,7 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
|
||||
private boolean viewCreated = false;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -67,16 +62,16 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,8 +80,8 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
super.onDestroyView();
|
||||
listAdapter = null;
|
||||
viewCreated = false;
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,6 +107,11 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
if (items != null && getActivity() != null) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
|
||||
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
|
||||
emptyView.setTitle(R.string.no_comp_downloads_head_label);
|
||||
emptyView.setMessage(R.string.no_comp_downloads_label);
|
||||
emptyView.attachToListView(getListView());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,7 +149,7 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.episode_actions:
|
||||
EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
|
||||
.newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE);
|
||||
.newInstance(items, EpisodesApplyActionFragment.ACTION_DELETE | EpisodesApplyActionFragment.ACTION_ADD_TO_QUEUE);
|
||||
((MainActivity) getActivity()).loadChildFragment(fragment);
|
||||
return true;
|
||||
default:
|
||||
@ -188,21 +188,19 @@ public class CompletedDownloadsFragment extends ListFragment {
|
||||
};
|
||||
|
||||
private void loadItems() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if (items == null && viewCreated) {
|
||||
setListShown(false);
|
||||
}
|
||||
subscription = Observable.fromCallable(DBReader::getDownloadedItems)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(DBReader::getDownloadedItems)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result != null) {
|
||||
items = result;
|
||||
if (viewCreated && getActivity() != null) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
items = result;
|
||||
if (viewCreated && getActivity() != null) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MediaplayerInfoActivity.MediaplayerInfoContentFragment;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
@ -22,7 +23,6 @@ import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
public class CoverFragment extends Fragment implements MediaplayerInfoContentFragment {
|
||||
|
||||
private static final String TAG = "CoverFragment";
|
||||
private static final String ARG_PLAYABLE = "arg.playable";
|
||||
|
||||
private Playable media;
|
||||
|
||||
@ -48,10 +48,11 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
setRetainInstance(true);
|
||||
root = inflater.inflate(R.layout.cover_fragment, container, false);
|
||||
txtvPodcastTitle = (TextView) root.findViewById(R.id.txtvPodcastTitle);
|
||||
txtvEpisodeTitle = (TextView) root.findViewById(R.id.txtvEpisodeTitle);
|
||||
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
|
||||
txtvPodcastTitle = root.findViewById(R.id.txtvPodcastTitle);
|
||||
txtvEpisodeTitle = root.findViewById(R.id.txtvEpisodeTitle);
|
||||
imgvCover = root.findViewById(R.id.imgvCover);
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -61,9 +62,10 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra
|
||||
txtvEpisodeTitle.setText(media.getEpisodeTitle());
|
||||
Glide.with(this)
|
||||
.load(media.getImageLocation())
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.dontAnimate()
|
||||
.fitCenter()
|
||||
.apply(new RequestOptions()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.dontAnimate()
|
||||
.fitCenter())
|
||||
.into(imgvCover);
|
||||
} else {
|
||||
Log.w(TAG, "loadMediaInfo was called while media was null");
|
||||
|
@ -12,21 +12,23 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.widget.TextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Shows the download log
|
||||
@ -41,7 +43,7 @@ public class DownloadLogFragment extends ListFragment {
|
||||
private boolean viewsCreated = false;
|
||||
private boolean itemsLoaded = false;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
@ -55,8 +57,8 @@ public class DownloadLogFragment extends ListFragment {
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +76,12 @@ public class DownloadLogFragment extends ListFragment {
|
||||
if (itemsLoaded) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
|
||||
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
|
||||
emptyView.setTitle(R.string.no_log_downloads_head_label);
|
||||
emptyView.setMessage(R.string.no_log_downloads_label);
|
||||
emptyView.attachToListView(getListView());
|
||||
|
||||
}
|
||||
|
||||
private void onFragmentLoaded() {
|
||||
@ -93,10 +101,18 @@ public class DownloadLogFragment extends ListFragment {
|
||||
DownloadStatus status = adapter.getItem(position);
|
||||
String url = "unknown";
|
||||
String message = getString(R.string.download_successful);
|
||||
FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
|
||||
if (media != null) {
|
||||
url = media.getDownload_url();
|
||||
if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
||||
FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
|
||||
if (media != null) {
|
||||
url = media.getDownload_url();
|
||||
}
|
||||
} else if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
||||
Feed feed = DBReader.getFeed(status.getFeedfileId());
|
||||
if (feed != null) {
|
||||
url = feed.getDownload_url();
|
||||
}
|
||||
}
|
||||
|
||||
if (!status.isSuccessful()) {
|
||||
message = status.getReasonDetailed();
|
||||
}
|
||||
@ -178,11 +194,11 @@ public class DownloadLogFragment extends ListFragment {
|
||||
}
|
||||
|
||||
private void loadItems() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
subscription = Observable.fromCallable(DBReader::getDownloadLog)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(DBReader::getDownloadLog)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result != null) {
|
||||
|
@ -38,12 +38,12 @@ public class DownloadsFragment extends Fragment {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View root = inflater.inflate(R.layout.pager_fragment, container, false);
|
||||
|
||||
viewPager = (ViewPager)root.findViewById(R.id.viewpager);
|
||||
viewPager = root.findViewById(R.id.viewpager);
|
||||
DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());
|
||||
viewPager.setAdapter(pagerAdapter);
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = (TabLayout) root.findViewById(R.id.sliding_tabs);
|
||||
tabLayout = root.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
return root;
|
||||
|
@ -46,11 +46,11 @@ public class EpisodesFragment extends Fragment {
|
||||
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.episodes_label);
|
||||
|
||||
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
|
||||
viewPager = (ViewPager)rootView.findViewById(R.id.viewpager);
|
||||
viewPager = rootView.findViewById(R.id.viewpager);
|
||||
viewPager.setAdapter(new EpisodesPagerAdapter(getChildFragmentManager(), getResources()));
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = (TabLayout) rootView.findViewById(R.id.sliding_tabs);
|
||||
tabLayout = rootView.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
return rootView;
|
||||
|
@ -16,13 +16,17 @@ import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
|
||||
@ -38,6 +42,7 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
private TextView mFeedName;
|
||||
private ProgressBar mProgressBar;
|
||||
private PlaybackController controller;
|
||||
private Disposable disposable;
|
||||
|
||||
public ExternalPlayerFragment() {
|
||||
super();
|
||||
@ -48,12 +53,12 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.external_player_fragment,
|
||||
container, false);
|
||||
fragmentLayout = (ViewGroup) root.findViewById(R.id.fragmentLayout);
|
||||
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
|
||||
txtvTitle = (TextView) root.findViewById(R.id.txtvTitle);
|
||||
butPlay = (ImageButton) root.findViewById(R.id.butPlay);
|
||||
mFeedName = (TextView) root.findViewById(R.id.txtvAuthor);
|
||||
mProgressBar = (ProgressBar) root.findViewById(R.id.episodeProgress);
|
||||
fragmentLayout = root.findViewById(R.id.fragmentLayout);
|
||||
imgvCover = root.findViewById(R.id.imgvCover);
|
||||
txtvTitle = root.findViewById(R.id.txtvTitle);
|
||||
butPlay = root.findViewById(R.id.butPlay);
|
||||
mFeedName = root.findViewById(R.id.txtvAuthor);
|
||||
mProgressBar = root.findViewById(R.id.episodeProgress);
|
||||
|
||||
fragmentLayout.setOnClickListener(v -> {
|
||||
Log.d(TAG, "layoutInfo was clicked");
|
||||
@ -78,7 +83,7 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
controller = setupPlaybackController();
|
||||
butPlay.setOnClickListener(v -> {
|
||||
if(controller != null) {
|
||||
if (controller != null) {
|
||||
controller.playPause();
|
||||
}
|
||||
});
|
||||
@ -127,8 +132,9 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
controller.init();
|
||||
onPositionObserverUpdate();
|
||||
|
||||
controller.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -138,6 +144,9 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
if (controller != null) {
|
||||
controller.release();
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,7 +167,7 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
controller = setupPlaybackController();
|
||||
if (butPlay != null) {
|
||||
butPlay.setOnClickListener(v -> {
|
||||
if(controller != null) {
|
||||
if (controller != null) {
|
||||
controller.playPause();
|
||||
}
|
||||
});
|
||||
@ -173,7 +182,25 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
return false;
|
||||
}
|
||||
|
||||
Playable media = controller.getMedia();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
disposable = Maybe.create(emitter -> {
|
||||
Playable media = controller.getMedia();
|
||||
if (media != null) {
|
||||
emitter.onSuccess(media);
|
||||
} else {
|
||||
emitter.onComplete();
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(media -> updateUi((Playable) media),
|
||||
error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateUi(Playable media) {
|
||||
if (media != null) {
|
||||
txtvTitle.setText(media.getEpisodeTitle());
|
||||
mFeedName.setText(media.getFeedTitle());
|
||||
@ -181,11 +208,12 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(media.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
|
||||
fragmentLayout.setVisibility(View.VISIBLE);
|
||||
@ -194,18 +222,11 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
} else {
|
||||
butPlay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
|
||||
return false;
|
||||
Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
|
||||
}
|
||||
}
|
||||
|
||||
private String getPositionString(int position, int duration) {
|
||||
return Converter.getDurationStringLong(position) + " / "
|
||||
+ Converter.getDurationStringLong(duration);
|
||||
}
|
||||
|
||||
public PlaybackController getPlaybackControllerTestingOnly() {
|
||||
return controller;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -50,6 +51,8 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = super.onCreateViewHelper(inflater, container, savedInstanceState,
|
||||
R.layout.all_episodes_fragment);
|
||||
((TextView)root.findViewById(R.id.emptyViewTitle)).setText(R.string.no_fav_episodes_head_label);
|
||||
((TextView)root.findViewById(R.id.emptyViewMessage)).setText(R.string.no_fav_episodes_label);
|
||||
|
||||
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
|
||||
@Override
|
||||
@ -62,8 +65,8 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
|
||||
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
|
||||
Log.d(TAG, "remove(" + holder.getItemId() + ")");
|
||||
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
FeedItem item = holder.getFeedItem();
|
||||
if (item != null) {
|
||||
|
@ -28,9 +28,9 @@ import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.mfietz.fyydlin.FyydClient;
|
||||
import de.mfietz.fyydlin.FyydResponse;
|
||||
import de.mfietz.fyydlin.SearchHit;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
|
||||
import static java.util.Collections.emptyList;
|
||||
@ -55,7 +55,7 @@ public class FyydSearchFragment extends Fragment {
|
||||
* List of podcasts retreived from the search
|
||||
*/
|
||||
private List<Podcast> searchResults;
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -75,7 +75,7 @@ public class FyydSearchFragment extends Fragment {
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
|
||||
gridView = (GridView) root.findViewById(R.id.gridView);
|
||||
gridView = root.findViewById(R.id.gridView);
|
||||
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
|
||||
gridView.setAdapter(adapter);
|
||||
|
||||
@ -87,10 +87,10 @@ public class FyydSearchFragment extends Fragment {
|
||||
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
|
||||
startActivity(intent);
|
||||
});
|
||||
progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
|
||||
txtvError = (TextView) root.findViewById(R.id.txtvError);
|
||||
butRetry = (Button) root.findViewById(R.id.butRetry);
|
||||
txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
|
||||
progressBar = root.findViewById(R.id.progressBar);
|
||||
txtvError = root.findViewById(R.id.txtvError);
|
||||
butRetry = root.findViewById(R.id.butRetry);
|
||||
txtvEmpty = root.findViewById(android.R.id.empty);
|
||||
|
||||
return root;
|
||||
}
|
||||
@ -98,8 +98,8 @@ public class FyydSearchFragment extends Fragment {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
adapter = null;
|
||||
}
|
||||
@ -141,12 +141,12 @@ public class FyydSearchFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void search(String query) {
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
showOnlyProgressBar();
|
||||
subscription = client.searchPodcasts(query)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = client.searchPodcasts(query, 10)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
@ -174,7 +174,7 @@ public class FyydSearchFragment extends Fragment {
|
||||
if (!response.getData().isEmpty()) {
|
||||
adapter.clear();
|
||||
searchResults = new ArrayList<>();
|
||||
for (SearchHit searchHit : response.getData().values()) {
|
||||
for (SearchHit searchHit : response.getData()) {
|
||||
Podcast podcast = Podcast.fromSearch(searchHit);
|
||||
searchResults.add(podcast);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
@ -39,10 +40,10 @@ import de.danoeh.antennapod.core.util.ShownotesProvider;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import de.danoeh.antennapod.core.util.playback.Timeline;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays the description of a Playable object in a Webview.
|
||||
@ -66,7 +67,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
private ShownotesProvider shownotesProvider;
|
||||
private Playable media;
|
||||
|
||||
private Subscription webViewLoader;
|
||||
private Disposable webViewLoader;
|
||||
|
||||
/**
|
||||
* URL that was selected via long-press.
|
||||
@ -113,10 +114,13 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
Log.d(TAG, "Creating view");
|
||||
webvDescription = new WebView(getActivity().getApplicationContext());
|
||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
|
||||
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(new int[]
|
||||
{android.R.attr.colorBackground});
|
||||
int backgroundColor = ta.getColor(0, UserPreferences.getTheme() ==
|
||||
R.style.Theme_AntennaPod_Dark ? Color.BLACK : Color.WHITE);
|
||||
boolean black = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark
|
||||
|| UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack;
|
||||
int backgroundColor = ta.getColor(0, black ? Color.BLACK : Color.WHITE);
|
||||
|
||||
ta.recycle();
|
||||
webvDescription.setBackgroundColor(backgroundColor);
|
||||
if (!NetworkUtils.networkAvailable()) {
|
||||
@ -164,7 +168,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "Fragment destroyed");
|
||||
if (webViewLoader != null) {
|
||||
webViewLoader.unsubscribe();
|
||||
webViewLoader.dispose();
|
||||
}
|
||||
if (webvDescription != null) {
|
||||
webvDescription.removeAllViews();
|
||||
@ -195,7 +199,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
|
||||
long id = getArguments().getLong(ARG_FEEDITEM_ID);
|
||||
Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(feedItem -> {
|
||||
shownotesProvider = feedItem;
|
||||
@ -295,21 +299,22 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
private void load() {
|
||||
Log.d(TAG, "load()");
|
||||
if(webViewLoader != null) {
|
||||
webViewLoader.unsubscribe();
|
||||
webViewLoader.dispose();
|
||||
}
|
||||
if(shownotesProvider == null) {
|
||||
return;
|
||||
}
|
||||
webViewLoader = Observable.defer(() -> Observable.just(loadData()))
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
webViewLoader = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(data -> {
|
||||
webvDescription.loadDataWithBaseURL(null, data, "text/html",
|
||||
webvDescription.loadDataWithBaseURL("https://127.0.0.1", data, "text/html",
|
||||
"utf-8", "about:blank");
|
||||
Log.d(TAG, "Webview loaded");
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String loadData() {
|
||||
Timeline timeline = new Timeline(getActivity(), shownotesProvider);
|
||||
return timeline.processShownotes(highlightTimecodes);
|
||||
|
@ -31,11 +31,10 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconButton;
|
||||
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -53,26 +52,27 @@ import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.Flavors;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.Timeline;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.view.OnSwipeGesture;
|
||||
import de.danoeh.antennapod.view.SwipeGestureDetector;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays information about a FeedItem and actions.
|
||||
@ -135,7 +135,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
private IconButton butAction2;
|
||||
private Menu popupMenu;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
/**
|
||||
* URL that was selected via long-press.
|
||||
@ -166,26 +166,27 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
|
||||
|
||||
root = (ViewGroup) layout.findViewById(R.id.content_root);
|
||||
root = layout.findViewById(R.id.content_root);
|
||||
|
||||
LinearLayout header = (LinearLayout) root.findViewById(R.id.header);
|
||||
LinearLayout header = root.findViewById(R.id.header);
|
||||
if(feedItems.length > 0) {
|
||||
header.setOnTouchListener((v, event) -> headerGestureDetector.onTouchEvent(event));
|
||||
}
|
||||
|
||||
txtvPodcast = (TextView) layout.findViewById(R.id.txtvPodcast);
|
||||
txtvPodcast = layout.findViewById(R.id.txtvPodcast);
|
||||
txtvPodcast.setOnClickListener(v -> openPodcast());
|
||||
txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
|
||||
txtvTitle = layout.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
txtvTitle.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
|
||||
txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
|
||||
txtvDuration = layout.findViewById(R.id.txtvDuration);
|
||||
txtvPublished = layout.findViewById(R.id.txtvPublished);
|
||||
if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
|
||||
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
|
||||
}
|
||||
webvDescription = (WebView) layout.findViewById(R.id.webvDescription);
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
webvDescription = layout.findViewById(R.id.webvDescription);
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark ||
|
||||
UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
@ -215,12 +216,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
});
|
||||
registerForContextMenu(webvDescription);
|
||||
|
||||
imgvCover = (ImageView) layout.findViewById(R.id.imgvCover);
|
||||
imgvCover = layout.findViewById(R.id.imgvCover);
|
||||
imgvCover.setOnClickListener(v -> openPodcast());
|
||||
progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload);
|
||||
progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
|
||||
butAction1 = (IconButton) layout.findViewById(R.id.butAction1);
|
||||
butAction2 = (IconButton) layout.findViewById(R.id.butAction2);
|
||||
progbarDownload = layout.findViewById(R.id.progbarDownload);
|
||||
progbarLoading = layout.findViewById(R.id.progbarLoading);
|
||||
butAction1 = layout.findViewById(R.id.butAction1);
|
||||
butAction2 = layout.findViewById(R.id.butAction2);
|
||||
|
||||
butAction1.setOnClickListener(v -> {
|
||||
if (item == null) {
|
||||
@ -285,8 +286,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if (webvDescription != null && root != null) {
|
||||
root.removeView(webvDescription);
|
||||
@ -357,7 +358,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
|
||||
private void onFragmentLoaded() {
|
||||
if (webviewData != null) {
|
||||
webvDescription.loadDataWithBaseURL(null, webviewData, "text/html", "utf-8", "about:blank");
|
||||
webvDescription.loadDataWithBaseURL("https://127.0.0.1", webviewData, "text/html", "utf-8", "about:blank");
|
||||
}
|
||||
updateAppearance();
|
||||
}
|
||||
@ -378,11 +379,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(item.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
|
||||
progbarDownload.setVisibility(View.GONE);
|
||||
@ -435,7 +437,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
}
|
||||
|
||||
FeedItem.State state = item.getState();
|
||||
if (butAction2Text == R.string.delete_label && state == FeedItem.State.PLAYING) {
|
||||
if (butAction2Text == R.string.delete_label && state == FeedItem.State.PLAYING && PlaybackService.isRunning) {
|
||||
butAction2.setEnabled(false);
|
||||
butAction2.setAlpha(0.5f);
|
||||
} else {
|
||||
@ -571,12 +573,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
};
|
||||
|
||||
private void load() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
progbarLoading.setVisibility(View.VISIBLE);
|
||||
subscription = Observable.fromCallable(this::loadInBackground)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(this::loadInBackground)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
progbarLoading.setVisibility(View.GONE);
|
||||
@ -586,6 +588,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private FeedItem loadInBackground() {
|
||||
FeedItem feedItem = DBReader.getFeedItem(feedItems[feedItemPos]);
|
||||
if (feedItem != null) {
|
||||
|
@ -4,10 +4,9 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LightingColorFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.widget.SearchView;
|
||||
@ -26,18 +25,17 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.joanzapata.iconify.IconDrawable;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
|
||||
import de.danoeh.antennapod.activity.FeedSettingsActivity;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.FeedInfoActivity;
|
||||
import de.danoeh.antennapod.activity.FeedSettingsActivity;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
|
||||
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
|
||||
@ -55,7 +53,6 @@ import de.danoeh.antennapod.core.feed.FeedItemFilter;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -71,10 +68,10 @@ import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays a list of FeedItems.
|
||||
@ -114,7 +111,7 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
private TextView txtvInformation;
|
||||
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
/**
|
||||
* Creates new ItemlistFragment which shows the Feeditems of a specific
|
||||
@ -165,8 +162,8 @@ public class ItemlistFragment extends ListFragment {
|
||||
super.onPause();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
EventBus.getDefault().unregister(this);
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,13 +414,10 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
}
|
||||
|
||||
private boolean insideOnFragmentLoaded = false;
|
||||
|
||||
private void onFragmentLoaded() {
|
||||
if(!isVisible()) {
|
||||
return;
|
||||
}
|
||||
insideOnFragmentLoaded = true;
|
||||
if (adapter == null) {
|
||||
setListAdapter(null);
|
||||
setupHeaderView();
|
||||
@ -440,9 +434,6 @@ public class ItemlistFragment extends ListFragment {
|
||||
if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
|
||||
getListView().removeFooterView(listFooter.getRoot());
|
||||
}
|
||||
|
||||
insideOnFragmentLoaded = false;
|
||||
|
||||
}
|
||||
|
||||
private void refreshHeaderView() {
|
||||
@ -486,14 +477,14 @@ public class ItemlistFragment extends ListFragment {
|
||||
View header = inflater.inflate(R.layout.feeditemlist_header, lv, false);
|
||||
lv.addHeaderView(header);
|
||||
|
||||
txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor);
|
||||
imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground);
|
||||
imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
|
||||
ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo);
|
||||
ImageButton butShowSettings = (ImageButton) header.findViewById(R.id.butShowSettings);
|
||||
txtvInformation = (TextView) header.findViewById(R.id.txtvInformation);
|
||||
txtvFailure = (IconTextView) header.findViewById(R.id.txtvFailure);
|
||||
txtvTitle = header.findViewById(R.id.txtvTitle);
|
||||
TextView txtvAuthor = header.findViewById(R.id.txtvAuthor);
|
||||
imgvBackground = header.findViewById(R.id.imgvBackground);
|
||||
imgvCover = header.findViewById(R.id.imgvCover);
|
||||
ImageButton butShowInfo = header.findViewById(R.id.butShowInfo);
|
||||
ImageButton butShowSettings = header.findViewById(R.id.butShowSettings);
|
||||
txtvInformation = header.findViewById(R.id.txtvInformation);
|
||||
txtvFailure = header.findViewById(R.id.txtvFailure);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
txtvAuthor.setText(feed.getAuthor());
|
||||
@ -529,20 +520,22 @@ public class ItemlistFragment extends ListFragment {
|
||||
private void loadFeedImage() {
|
||||
Glide.with(getActivity())
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation(getActivity()))
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.image_readability_tint)
|
||||
.error(R.color.image_readability_tint)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.transform(new FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(imgvBackground);
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(feed.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.apply(new RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(imgvCover);
|
||||
}
|
||||
|
||||
@ -618,23 +611,22 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
|
||||
private void loadItems() {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if(disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
subscription = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
disposable = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
if (result != null) {
|
||||
feed = result;
|
||||
itemsLoaded = true;
|
||||
if (viewsCreated) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
feed = result;
|
||||
itemsLoaded = true;
|
||||
if (viewsCreated) {
|
||||
onFragmentLoaded();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Feed loadData() {
|
||||
Feed feed = DBReader.getFeed(feedID);
|
||||
DBReader.loadAdditionalFeedItemListData(feed.getItems());
|
||||
|
@ -36,13 +36,14 @@ import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
|
||||
|
||||
@ -69,7 +70,7 @@ public class ItunesSearchFragment extends Fragment {
|
||||
*/
|
||||
private List<Podcast> searchResults;
|
||||
private List<Podcast> topList;
|
||||
private Subscription subscription;
|
||||
private Disposable disposable;
|
||||
|
||||
/**
|
||||
* Replace adapter data with provided search results from SearchTask.
|
||||
@ -109,7 +110,7 @@ public class ItunesSearchFragment extends Fragment {
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
|
||||
gridView = (GridView) root.findViewById(R.id.gridView);
|
||||
gridView = root.findViewById(R.id.gridView);
|
||||
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
|
||||
gridView.setAdapter(adapter);
|
||||
|
||||
@ -127,7 +128,7 @@ public class ItunesSearchFragment extends Fragment {
|
||||
} else {
|
||||
gridView.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
subscription = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
|
||||
disposable = Single.create((SingleOnSubscribe<String>) emitter -> {
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
.url(podcast.feedUrl)
|
||||
@ -139,17 +140,16 @@ public class ItunesSearchFragment extends Fragment {
|
||||
JSONObject result = new JSONObject(resultString);
|
||||
JSONObject results = result.getJSONArray("results").getJSONObject(0);
|
||||
String feedUrl = results.getString("feedUrl");
|
||||
subscriber.onNext(feedUrl);
|
||||
emitter.onSuccess(feedUrl);
|
||||
} else {
|
||||
String prefix = getString(R.string.error_msg_prefix);
|
||||
subscriber.onError(new IOException(prefix + response));
|
||||
emitter.onError(new IOException(prefix + response));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
emitter.onError(e);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(feedUrl -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
@ -170,10 +170,10 @@ public class ItunesSearchFragment extends Fragment {
|
||||
});
|
||||
}
|
||||
});
|
||||
progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
|
||||
txtvError = (TextView) root.findViewById(R.id.txtvError);
|
||||
butRetry = (Button) root.findViewById(R.id.butRetry);
|
||||
txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
|
||||
progressBar = root.findViewById(R.id.progressBar);
|
||||
txtvError = root.findViewById(R.id.txtvError);
|
||||
butRetry = root.findViewById(R.id.butRetry);
|
||||
txtvEmpty = root.findViewById(android.R.id.empty);
|
||||
|
||||
loadToplist();
|
||||
|
||||
@ -183,8 +183,8 @@ public class ItunesSearchFragment extends Fragment {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
adapter = null;
|
||||
}
|
||||
@ -228,15 +228,15 @@ public class ItunesSearchFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void loadToplist() {
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.GONE);
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
subscription = Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
|
||||
disposable = Single.create((SingleOnSubscribe<List<Podcast>>) emitter -> {
|
||||
String lang = Locale.getDefault().getLanguage();
|
||||
String url = "https://itunes.apple.com/" + lang + "/rss/toppodcasts/limit=25/explicit=true/json";
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
@ -268,15 +268,14 @@ public class ItunesSearchFragment extends Fragment {
|
||||
}
|
||||
else {
|
||||
String prefix = getString(R.string.error_msg_prefix);
|
||||
subscriber.onError(new IOException(prefix + response));
|
||||
emitter.onError(new IOException(prefix + response));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
emitter.onError(e);
|
||||
}
|
||||
subscriber.onNext(results);
|
||||
subscriber.onCompleted();
|
||||
emitter.onSuccess(results);
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(podcasts -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
@ -293,15 +292,15 @@ public class ItunesSearchFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void search(String query) {
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.GONE);
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
|
||||
disposable = Single.create((SingleOnSubscribe<List<Podcast>>) subscriber -> {
|
||||
String encodedQuery = null;
|
||||
try {
|
||||
encodedQuery = URLEncoder.encode(query, "UTF-8");
|
||||
@ -312,8 +311,7 @@ public class ItunesSearchFragment extends Fragment {
|
||||
encodedQuery = query; // failsafe
|
||||
}
|
||||
|
||||
//Spaces in the query need to be replaced with '+' character.
|
||||
String formattedUrl = String.format(API_URL, query).replace(' ', '+');
|
||||
String formattedUrl = String.format(API_URL, encodedQuery);
|
||||
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
@ -341,10 +339,9 @@ public class ItunesSearchFragment extends Fragment {
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
subscriber.onNext(podcasts);
|
||||
subscriber.onCompleted();
|
||||
subscriber.onSuccess(podcasts);
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(podcasts -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user