diff options
Diffstat (limited to 'app')
29 files changed, 278 insertions, 459 deletions
diff --git a/app/build.gradle b/app/build.gradle index ebbc355e2..37044d629 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { // Version code schema: // "1.2.3-beta4" -> 1020304 // "1.2.3" -> 1020395 - versionCode 2050296 - versionName "2.5.2" + versionCode 2060195 + versionName "2.6.1" def commit = "" try { diff --git a/app/proguard.cfg b/app/proguard.cfg index 12fc358b1..57c5ca9dc 100644 --- a/app/proguard.cfg +++ b/app/proguard.cfg @@ -4,7 +4,6 @@ -optimizations !code/allocation/variable -optimizationpasses 5 --dontpreverify -allowaccessmodification -dontskipnonpubliclibraryclassmembers @@ -25,15 +24,6 @@ public static void write(...); } --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keepclassmembers class * implements android.os.Parcelable { - static android.os.Parcelable$Creator CREATOR; -} - -keep public class org.jsoup.** { public *; } @@ -42,25 +32,9 @@ -dontwarn okhttp3.** -dontwarn okio.** -# greenrobot EventBus --keepattributes *Annotation* --keepclassmembers class * { - @org.greenrobot.eventbus.Subscribe <methods>; -} --keep enum org.greenrobot.eventbus.ThreadMode { *; } - # android-iconify -keep class com.joanzapata.** { *; } -# Glide --keep public class * implements com.bumptech.glide.module.GlideModule --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 - #### Proguard rules for fyyd client # Retrofit 2.0 -dontwarn retrofit2.** diff --git a/app/src/main/assets/developers.csv b/app/src/main/assets/developers.csv index 2c6cec48b..675f3cf93 100644 --- a/app/src/main/assets/developers.csv +++ b/app/src/main/assets/developers.csv @@ -4,8 +4,8 @@ mfietz;6860662;Maintainer (retired) TomHennen;5216560;Maintainer (retired) orionlee;250644;Contributor domingos86;9538859;Contributor -tonytamsf;149837;Contributor TacoTheDank;32376686;Contributor +tonytamsf;149837;Contributor damoasda;46045854;Contributor andersonvom;69922;Contributor shortspider;5712543;Contributor @@ -53,6 +53,7 @@ bibz;5141956;Contributor hzulla;1705654;Contributor deandreamatias;21011641;Contributor MeirAtIMDDE;4421079;Contributor +cketti;218061;Contributor egsavage;126165;Contributor ligi;111600;Contributor Xeitor;8825715;Contributor @@ -130,6 +131,7 @@ edwinhere;19705425;Contributor eirikv;4076243;Contributor eerden;277513;Contributor Geist5000;37940313;Contributor +IordanisKokk;72551397;Contributor jklippel;8657220;Contributor jannic;232606;Contributor Foso;5015532;Contributor @@ -152,7 +154,10 @@ max-wittig;6639323;Contributor Mengshi24;58278376;Contributor MolarAmbiguity;10541979;Contributor mounirlamouri;573590;Contributor +nicoolasj;63880378;Contributor nikhil097;35090769;Contributor +nproth;48482306;Contributor +oliver;2344;Contributor panoreak;25068506;Contributor patrickjkennedy;8617261;Contributor ortylp;470439;Contributor @@ -166,6 +171,7 @@ sonnayasomnambula;7716779;Contributor sethoscope;534043;Contributor shantanahardy;26757164;Contributor shombando;42972338;Contributor +Silverwarriorin;46795935;Contributor danners;116551;Contributor corecode;177979;Contributor vimsick;20211590;Contributor @@ -185,7 +191,9 @@ fossterer;4236021;Contributor sak96;26397224;Contributor gregoryjtom;32783177;Contributor lightonflux;1377943;Contributor +loucasal;25279797;Contributor minusf;3632883;Contributor +NWuensche;15856197;Contributor rubenh-be;22374542;Contributor s3lph;5564491;Contributor silansuslu;72400543;Contributor diff --git a/app/src/main/assets/translators.csv b/app/src/main/assets/translators.csv index 36ed00142..e60f85313 100644 --- a/app/src/main/assets/translators.csv +++ b/app/src/main/assets/translators.csv @@ -1,45 +1,47 @@ Arabic;abuzar3.khalid, AhmedHll, badarotti, HeshamTB, keunes, Mehyar, mhamade, moftasa, mohmans, MustafaAlgurabi, nabilMaghura, rex07, shubbar Asturian (ast_ES);enolp, keunes Azerbaijani;5NOER227O -Basque;gaztainalde, IngrownMink4, keunes, Osoitz, pospolos +Basque;bipoza, gaztainalde, IngrownMink4, keunes, Osoitz, pospolos +Bengali;laggybird Breton;Belvar, Eorn, Iriep, keunes, technozuzici Bulgarian;keunes, ma4ko, ppk89, solusitor, x7ype -Catalan;arseru, carles.llacer, dvd1985, exort12, IvanAmarante, javiercoll, keunes, Kintu, lambdani, marcmetallextrem, xc70 +Catalan;arseru, badlop, bluegeekgh, carles.llacer, dvd1985, exort12, IvanAmarante, javiercoll, keunes, Kintu, lambdani, marcmetallextrem, xc70 Chinese (zh_CN);Biacke, brnme, claybiockiller, cyril3, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, jhxie, jxj2zzz79pfp9bpo, JY3, keunes, kyleehee, molisiye, owen8877, RainSlide, RangerNJU, Sak94664, spice2wolf, tupunco, wongsyrone, yangyang, yiqiok Chinese (zh_TW);bobchao, ijliao, keunes, mapobi, pggdt, ymhuang0808 -Czech (cs_CZ);anotheranonymoususer, elich, Hanzmeister, jjh, md.share, svetlemodry, Thomaash +Czech (cs_CZ);anotheranonymoususer, befeleme, elich, Hanzmeister, jjh, McLenin666, md.share, svetlemodry, Thomaash, viotalJiplk Danish;deusdenton, ERYpTION, JFreak, jhertel, keunes, mikini, petterbejo, SebastianKiwiDk -Dutch;e2jk, keunes, mijnheer, rwv, Vistaus +Dutch;e2jk, keunes, mijnheer, oldblue, rwv, Vistaus Estonian;beez276, Eraser, keunes, mahfiaz Finnish;Ban3, keunes, ktstmu, Kuutar, noppa, Sahtor, scop, teemue -French;5NOER227O, ayiniho, ChaoticMind, clombion, Cornegidouille, e2jk, keunes, klintom, Kuscoo, lacouture, LouFex, Matth78, petterbejo, Poussinou, RomainTT, sterylmreep +French;5NOER227O, ayiniho, ChaoticMind, clombion, Cornegidouille, Daremo, e2jk, keunes, klintom, Kuscoo, lacouture, LouFex, Matth78, petterbejo, Poussinou, RomainTT, sterylmreep, teamon Galician;antiparvos, pikamoku, Raichely -German;5NOER227O, _Er, axre, ByteHamster, ceving, dadosch, DerSilly, elkangaroo, enz, f_grubm, finsterwalder, forght, hbilke, HolgerJeromin, JoeMcFly, jokap, JoniArida, JonOfUs, kalei, keunes, Macusercom, max.wittig, mfietz, Michael_Strecke, petterbejo, pudeeh, Quiss42, repat, sadfgdf, timo.rohwedder, toaskoas, Tobiasff3200, tomte, tweimer, Willhelm, ypid +German;5NOER227O, _Er, axre, ByteHamster, Ceekay, ceving, dadosch, datesastick, DerSilly, elkangaroo, enz, Erc187, f_grubm, finsterwalder, forght, hbilke, HolgerJeromin, JMAN, JoeMcFly, jokap, JoniArida, JonOfUs, kalei, keunes, Macusercom, max.wittig, mfietz, Michael_Strecke, mkida, petterbejo, pudeeh, Quiss42, repat, sadfgdf, Sargon_Isa, teamon, thetrash23, timo.rohwedder, toaskoas, Tobiasff3200, tomte, Tonne11, tweimer, VfBFan, Willhelm, ypid Hebrew (he_IL);amir.dafnyman, E1i9, mongoose4004, pinkasey, rellieberman, Yaron Hindi (hi_IN);keunes, purple.coder, siddhusengar, thelazyoxymoron Hu;hurrikan, keunes, lna91, lomapur, marthynw, meskobalazs, naren93 Icelandic;keunes, marthjod Indonesian;dbrw, justch, keunes, levirs565, liimee -Italian (it_IT);aalex70, allin, alvami, Bonnee, dontknowcris, giuseppep, Guybrush88, ilmanzo, keunes, m.chinni, marco_pag, mircocau, neonsoftware, niccord, salorock, theloca95 -Japanese;ayiniho, keunes, KotaKato, Naofumi, sh3llc4t, TranslatorG +Italian (it_IT);aalex70, allin, alvami, Bonnee, datesastick, dontknowcris, giuseppep, Guybrush88, ilmanzo, juanjom, keunes, lu.por, m.chinni, marco_pag, mat650, mircocau, neonsoftware, niccord, salorock, theloca95 +Japanese;ayiniho, keunes, KotaKato, Naofumi, sh3llc4t, tko_cactus, TranslatorG Kannada (kn_IN);chiraag.nataraj, keunes, thejeshgn Ko;changwoo, eshc123, keunes, libliboom +Latin;nivaca Lithuanian;keunes, naglis, Sharper Macedonian;krisfremen -Malayalam;joice, keunes, rashivkp +Malayalam;joice, keunes, KiranS, rashivkp Modern Greek (1453-);AnimaRain, antonist, keunes, pavlosv Norwegian Bokmål (nb_NO);abstrakct, ahysing, bablecopherye, corkie, forteller, heraldo, jakobkg, keunes, kongk, sevenmaster, tc5, timbast, ttick Persian;ahangarha, danialbehzadi, ebadi, ebraminio, F7D, hamidrezabayat76, keunes, sinamoghaddas -Polish (pl_PL);befeleme, ewm, hiro2020, Iwangelion, kamila.miodek1991, keunes, lomapur, mandlus, maniexx, Mephistofeles, Rakowy_Manaska, shark103, tyle -Portuguese;emansije, keunes, lecalam, smarquespt, WalkerPt -Portuguese (pt_BR);alexupits, alysonborges, amalvarenga, andersonvom, aracnus, arua, bandreghetti, caioau, carlo_valente, castrors, edman, keunes, lipefire, mbaltar, olivoto, rogervezaro, RubeensVinicius, SamWilliam, tepadilha +Polish (pl_PL);befeleme, ewm, hiro2020, Iwangelion, kamila.miodek1991, keunes, lomapur, mandlus, maniexx, Mephistofeles, millup, Rakowy_Manaska, shark103, tyle +Portuguese;emansije, jmelo461, keunes, lecalam, smarquespt, WalkerPt +Portuguese (pt_BR);alexupits, alysonborges, amalvarenga, andersonvom, aracnus, arua, bandreghetti, caioau, carlo_valente, castrors, jmelo461, keunes, lipefire, mbaltar, olivoto, rogervezaro, RubeensVinicius, SamWilliam, tepadilha, tschertel, ziul123 Romanian (ro_RO);AdrianMirica, corneliu.e, fuzzmz, keunes, mozartro, ralienpp -Russian (ru_RU);ashed, btimofeev, Duke_Raven, flexagoon, gammja, homocomputeris, IgorPolyakov, keunes, mercutiy, nachoman, null, overmind88, Platun0v, PtilopsisLeucotis, s.chebotar, tepxd, un_logic, Vladryyu, whereisthetea -Slovak;ati3, jose1711, keunes, marulinko, real_name, tiborepcek +Russian (ru_RU);ashed, btimofeev, Duke_Raven, flexagoon, gammja, homocomputeris, IgorPolyakov, keunes, mercutiy, nachoman, null, overmind88, Platun0v, PtilopsisLeucotis, s.chebotar, tepxd, un_logic, Vladryyu, whereisthetea, yako +Slovak;ati3, jose1711, keunes, marulinko, McLenin666, real_name, tiborepcek Slovenian (sl_SI);anzepintar, asovic, keunes, panter23, TheFireFighter, trus2 -Spanish;AleksSyntek, andersonvom, andrespelaezp, arseru, Atreyu94, CaeM0R, carlos.levy, cartojo, deandreamatias, devarops, dvd1985, elojodepajaro, Fitoschido, frandavid100, hard_ware, javiercoll, keunes, kiekie, LatinSuD, leogrignafini, meanderingDot, nivaca, rafael.osuna, technozuzici, tres.14159, vfmatzkin, wakutiteo +Spanish;AleksSyntek, andersonvom, andrespelaezp, arseru, Atreyu94, badlop, CaeM0R, carlos.levy, cartojo, deandreamatias, devarops, dvd1985, elojodepajaro, Fitoschido, frandavid100, hard_ware, javiercoll, keunes, kiekie, LatinSuD, leogrignafini, meanderingDot, nivaca, rafael.osuna, technozuzici, tres.14159, vfmatzkin, wakutiteo, ziul123 Swahili (macrolanguage);1silvester, keunes, kmtra -Swedish (sv_SE);aiix, bpnilsson, keunes, nilso, TwoD, victorhggqvst +Swedish (sv_SE);aiix, bittin, bpnilsson, keunes, LinAGKar, nilso, TwoD, victorhggqvst Tatar;seber Telugu;keunes, veeven Turkish;AhmedDuran, alianilkocak, AliGaygisiz, androtuna, brsata, Erdy, keunes, overbite, Slsdem diff --git a/app/src/main/assets/website-languages.txt b/app/src/main/assets/website-languages.txt new file mode 100644 index 000000000..b52b558f9 --- /dev/null +++ b/app/src/main/assets/website-languages.txt @@ -0,0 +1,4 @@ +en +fr +nl +it diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 9e71ac1db..3b28a5e27 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -101,7 +101,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity { private static final String PREF_LAST_AUTO_DOWNLOAD = "lastAutoDownload"; private volatile List<Feed> feeds; - private Feed feed; private String selectedDownloadUrl; private Downloader downloader; private String username = null; @@ -289,13 +288,11 @@ public class OnlineFeedViewActivity extends AppCompatActivity { private void startFeedDownload(String url) { Log.d(TAG, "Starting feed download"); - url = URLChecker.prepareURL(url); - feed = new Feed(url, null); - DownloadRequest request = DownloadRequestCreator.create(feed) + selectedDownloadUrl = URLChecker.prepareURL(url); + DownloadRequest request = DownloadRequestCreator.create(new Feed(selectedDownloadUrl, null)) .withAuthentication(username, password) .withInitiatedByUser(true) .build(); - feed.setFile_url(request.getDestination()); download = Observable.fromCallable(() -> { feeds = DBReader.getFeedList(); @@ -305,16 +302,16 @@ public class OnlineFeedViewActivity extends AppCompatActivity { }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::checkDownloadResult, + .subscribe(status -> checkDownloadResult(status, request.getDestination()), error -> Log.e(TAG, Log.getStackTraceString(error))); } - private void checkDownloadResult(@NonNull DownloadStatus status) { + private void checkDownloadResult(@NonNull DownloadStatus status, String destination) { if (status.isCancelled()) { return; } if (status.isSuccessful()) { - parseFeed(); + parseFeed(destination); } else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { if (!isFinishing() && !isPaused) { if (username != null && password != null) { @@ -338,7 +335,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { .subscribe( feeds -> { OnlineFeedViewActivity.this.feeds = feeds; - handleUpdatedFeedStatus(feed); + handleUpdatedFeedStatus(); }, error -> Log.e(TAG, Log.getStackTraceString(error)) ); } @@ -346,16 +343,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - handleUpdatedFeedStatus(feed); + handleUpdatedFeedStatus(); } - private void parseFeed() { - if (feed == null || (feed.getFile_url() == null && feed.isDownloaded())) { - throw new IllegalStateException("feed must be non-null and downloaded when parseFeed is called"); - } + private void parseFeed(String destination) { Log.d(TAG, "Parsing feed"); - - parser = Maybe.fromCallable(this::doParseFeed) + parser = Maybe.fromCallable(() -> doParseFeed(destination)) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableMaybeObserver<FeedHandlerResult>() { @@ -384,14 +377,17 @@ public class OnlineFeedViewActivity extends AppCompatActivity { * @throws Exception If unsuccessful but we do not know a resolution. */ @Nullable - private FeedHandlerResult doParseFeed() throws Exception { + private FeedHandlerResult doParseFeed(String destination) throws Exception { FeedHandler handler = new FeedHandler(); + Feed feed = new Feed(selectedDownloadUrl, null); + feed.setFile_url(destination); + File destinationFile = new File(destination); try { return 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()); + boolean dialogShown = showFeedDiscoveryDialog(destinationFile, selectedDownloadUrl); if (dialogShown) { return null; // Should not display an error message } else { @@ -404,7 +400,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { Log.e(TAG, Log.getStackTraceString(e)); throw e; } finally { - boolean rc = new File(feed.getFile_url()).delete(); + boolean rc = destinationFile.delete(); Log.d(TAG, "Deleted feed source file. Result: " + rc); } } @@ -420,8 +416,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity { int resId = R.string.no_feed_url_podcast_found_by_search; Snackbar.make(findViewById(android.R.id.content), resId, Snackbar.LENGTH_LONG).show(); } - this.feed = feed; - this.selectedDownloadUrl = feed.getDownload_url(); viewBinding.backgroundImage.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); @@ -459,15 +453,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity { description.setText(HtmlToPlainText.getPlainText(feed.getDescription())); viewBinding.subscribeButton.setOnClickListener(v -> { - if (feedInFeedlist(feed)) { + if (feedInFeedlist()) { openFeed(); } else { Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle()); - f.setPreferences(feed.getPreferences()); - this.feed = f; - DownloadService.download(this, false, DownloadRequestCreator.create(f).build()); + DownloadService.download(this, false, DownloadRequestCreator.create(f) + .withAuthentication(username, password) + .build()); didPressSubscribe = true; - handleUpdatedFeedStatus(feed); + handleUpdatedFeedStatus(); } }); @@ -531,72 +525,62 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } }); } - handleUpdatedFeedStatus(feed); + handleUpdatedFeedStatus(); } private void openFeed() { // feed.getId() is always 0, we have to retrieve the id from the feed list from // the database - Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId(feed)); + Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId()); intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, getIntent().getBooleanExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, false)); finish(); startActivity(intent); } - private void handleUpdatedFeedStatus(Feed feed) { - if (feed != null) { - if (DownloadService.isDownloadingFile(feed.getDownload_url())) { - viewBinding.subscribeButton.setEnabled(false); - viewBinding.subscribeButton.setText(R.string.subscribing_label); - } else if (feedInFeedlist(feed)) { - viewBinding.subscribeButton.setEnabled(true); - viewBinding.subscribeButton.setText(R.string.open_podcast); - if (didPressSubscribe) { - didPressSubscribe = false; - if (UserPreferences.isEnableAutodownload()) { - boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked(); - - Feed feed1 = DBReader.getFeed(getFeedId(feed)); - FeedPreferences feedPreferences = feed1.getPreferences(); - feedPreferences.setAutoDownload(autoDownload); - DBWriter.setFeedPreferences(feedPreferences); - - SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE); - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload); - editor.apply(); - } - openFeed(); - } - } else { - viewBinding.subscribeButton.setEnabled(true); - viewBinding.subscribeButton.setText(R.string.subscribe_label); + private void handleUpdatedFeedStatus() { + if (DownloadService.isDownloadingFile(selectedDownloadUrl)) { + viewBinding.subscribeButton.setEnabled(false); + viewBinding.subscribeButton.setText(R.string.subscribing_label); + } else if (feedInFeedlist()) { + viewBinding.subscribeButton.setEnabled(true); + viewBinding.subscribeButton.setText(R.string.open_podcast); + if (didPressSubscribe) { + didPressSubscribe = false; if (UserPreferences.isEnableAutodownload()) { - viewBinding.autoDownloadCheckBox.setVisibility(View.VISIBLE); + boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked(); + + Feed feed1 = DBReader.getFeed(getFeedId()); + FeedPreferences feedPreferences = feed1.getPreferences(); + feedPreferences.setAutoDownload(autoDownload); + DBWriter.setFeedPreferences(feedPreferences); + + SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload); + editor.apply(); } + openFeed(); + } + } else { + viewBinding.subscribeButton.setEnabled(true); + viewBinding.subscribeButton.setText(R.string.subscribe_label); + if (UserPreferences.isEnableAutodownload()) { + viewBinding.autoDownloadCheckBox.setVisibility(View.VISIBLE); } } } - private boolean feedInFeedlist(Feed feed) { - if (feeds == null || feed == null) { - return false; - } - for (Feed f : feeds) { - if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) { - return true; - } - } - return false; + private boolean feedInFeedlist() { + return getFeedId() != 0; } - private long getFeedId(Feed feed) { - if (feeds == null || feed == null) { + private long getFeedId() { + if (feeds == null) { return 0; } for (Feed f : feeds) { - if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) { + if (f.getDownload_url().equals(selectedDownloadUrl)) { return f.getId(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java index 4ffed949e..52293091e 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java @@ -118,7 +118,7 @@ public class SelectSubscriptionActivity extends AppCompatActivity { Glide.with(this) .asBitmap() .load(feed.getImageUrl()) - .apply(new RequestOptions().override(iconSize, iconSize)) + .apply(RequestOptions.overrideOf(iconSize, iconSize)) .listener(new RequestListener<Bitmap>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index 954a6c2f6..9ffade1ca 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -36,6 +36,7 @@ import androidx.core.view.WindowCompat; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import com.bumptech.glide.Glide; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.dialog.VariableSpeedDialog; import de.danoeh.antennapod.event.playback.BufferUpdateEvent; import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.event.PlayerErrorEvent; @@ -591,6 +592,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. menu.findItem(R.id.player_switch_to_audio_only).setVisible(true); menu.findItem(R.id.audio_controls).setIcon(R.drawable.ic_sliders); + menu.findItem(R.id.playback_speed).setVisible(true); return true; } @@ -640,6 +642,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } else if (item.getItemId() == R.id.share_item && feedItem != null) { ShareDialog shareDialog = ShareDialog.newInstance(feedItem); shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog"); + } else if (item.getItemId() == R.id.playback_speed) { + new VariableSpeedDialog().show(getSupportFragmentManager(), null); } else { return false; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java index 82b1c0d00..20a50308f 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java @@ -108,7 +108,7 @@ public class ChaptersListAdapter extends RecyclerView.Adapter<ChaptersListAdapte .apply(new RequestOptions() .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .dontAnimate() - .transforms(new FitCenter(), new RoundedCorners((int) + .transform(new FitCenter(), new RoundedCorners((int) (4 * context.getResources().getDisplayMetrics().density)))) .into(holder.image); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index 442076d35..4a057196a 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -237,6 +237,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder> // reset for re-use holder.count.setVisibility(View.GONE); holder.count.setOnClickListener(null); + holder.count.setClickable(false); String tag = fragmentTags.get(position); if (tag.equals(QueueFragment.TAG)) { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java index 40c2029d6..9b514dd98 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java @@ -85,7 +85,7 @@ public class ItunesAdapter extends ArrayAdapter<PodcastSearchResult> { .apply(new RequestOptions() .placeholder(R.color.light_gray) .diskCacheStrategy(DiskCacheStrategy.NONE) - .transforms(new FitCenter(), + .transform(new FitCenter(), new RoundedCorners((int) (4 * context.getResources().getDisplayMetrics().density))) .dontAnimate()) .into(viewHolder.coverView); diff --git a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java index 52df91282..120134344 100644 --- a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java +++ b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java @@ -32,7 +32,7 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks { activityIntent.setAction("request" + request.getFeedfileId()); activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, request); return PendingIntent.getActivity(context.getApplicationContext(), - R.id.pending_intent_download_service_auth, activityIntent, + request.getSource().hashCode(), activityIntent, PendingIntent.FLAG_ONE_SHOT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0)); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index 2d448faa8..5b030f0c2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -310,7 +310,7 @@ public class CoverFragment extends Fragment { RequestOptions options = new RequestOptions() .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .dontAnimate() - .transforms(new FitCenter(), + .transform(new FitCenter(), new RoundedCorners((int) (16 * getResources().getDisplayMetrics().density))); RequestBuilder<Drawable> cover = Glide.with(this) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java index 7902a4988..bca0f8640 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -185,6 +185,9 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); + if (header == null || infoContainer == null) { + return; + } int horizontalSpacing = (int) getResources().getDimension(R.dimen.additional_horizontal_spacing); header.setPadding(horizontalSpacing, header.getPaddingTop(), horizontalSpacing, header.getPaddingBottom()); infoContainer.setPadding(horizontalSpacing, infoContainer.getPaddingTop(), diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 80a65e518..f4fafb0ac 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -162,8 +162,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem public void onScrolled(@NonNull RecyclerView view, int deltaX, int deltaY) { super.onScrolled(view, deltaX, deltaY); boolean hasMorePages = feed != null && feed.isPaged() && feed.getNextPageLink() != null; - nextPageLoader.getRoot().setVisibility( - (viewBinding.recyclerView.isScrolledToBottom() && hasMorePages) ? View.VISIBLE : View.GONE); + boolean pageLoaderVisible = viewBinding.recyclerView.isScrolledToBottom() && hasMorePages; + nextPageLoader.getRoot().setVisibility(pageLoaderVisible ? View.VISIBLE : View.GONE); + viewBinding.recyclerView.setPadding( + viewBinding.recyclerView.getPaddingLeft(), 0, viewBinding.recyclerView.getPaddingRight(), + pageLoaderVisible ? nextPageLoader.getRoot().getMeasuredHeight() : 0); } }); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index 067e7466c..9d5376c2a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java @@ -49,9 +49,9 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View inboxContainer = View.inflate(getContext(), R.layout.inbox_fragment, null); + View inboxContainer = View.inflate(getContext(), R.layout.list_container_fragment, null); View root = super.onCreateView(inflater, container, savedInstanceState); - ((FrameLayout) inboxContainer.findViewById(R.id.inboxContent)).addView(root); + ((FrameLayout) inboxContainer.findViewById(R.id.listContent)).addView(root); emptyView.setTitle(R.string.no_inbox_head_label); emptyView.setMessage(R.string.no_inbox_label); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 83dc0c554..3bdc0e49f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -293,7 +293,7 @@ public class ItemFragment extends Fragment { RequestOptions options = new RequestOptions() .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .transforms(new FitCenter(), + .transform(new FitCenter(), new RoundedCorners((int) (4 * getResources().getDisplayMetrics().density))) .dontAnimate(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index 857b59967..8bcef4181 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -1,57 +1,36 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.util.Log; import android.view.ContextMenu; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; +import android.widget.FrameLayout; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.Fragment; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; -import de.danoeh.antennapod.core.event.DownloadEvent; -import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; -import de.danoeh.antennapod.event.FeedItemEvent; import de.danoeh.antennapod.event.playback.PlaybackHistoryEvent; -import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.event.PlayerStatusEvent; import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.model.feed.FeedItem; 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.menuhandler.FeedItemMenuHandler; -import de.danoeh.antennapod.view.EmptyViewHandler; -import de.danoeh.antennapod.view.EpisodeItemListRecyclerView; -import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; -import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.List; -public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuItemClickListener { +public class PlaybackHistoryFragment extends EpisodesListFragment implements Toolbar.OnMenuItemClickListener { public static final String TAG = "PlaybackHistoryFragment"; private static final String KEY_UP_ARROW = "up_arrow"; - private List<FeedItem> playbackHistory; - private PlaybackHistoryListAdapter adapter; - private Disposable disposable; - private EpisodeItemListRecyclerView recyclerView; - private EmptyViewHandler emptyView; - private ProgressBar progressBar; private Toolbar toolbar; private boolean displayUpArrow; @@ -64,8 +43,12 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.simple_list_fragment, container, false); - toolbar = root.findViewById(R.id.toolbar); + View historyContainer = View.inflate(getContext(), R.layout.list_container_fragment, null); + View root = super.onCreateView(inflater, container, savedInstanceState); + + ((FrameLayout) historyContainer.findViewById(R.id.listContent)).addView(root); + + toolbar = historyContainer.findViewById(R.id.toolbar); toolbar.setTitle(R.string.playback_history_label); toolbar.setOnMenuItemClickListener(this); displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0; @@ -76,34 +59,14 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI toolbar.inflateMenu(R.menu.playback_history); refreshToolbarState(); - recyclerView = root.findViewById(R.id.recyclerView); - recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool()); - adapter = new PlaybackHistoryListAdapter((MainActivity) getActivity()); - recyclerView.setAdapter(adapter); - progressBar = root.findViewById(R.id.progLoading); + listAdapter = new PlaybackHistoryListAdapter((MainActivity) getActivity()); + recyclerView.setAdapter(listAdapter); - emptyView = new EmptyViewHandler(getActivity()); emptyView.setIcon(R.drawable.ic_history); emptyView.setTitle(R.string.no_history_head_label); emptyView.setMessage(R.string.no_history_label); - emptyView.attachToRecyclerView(recyclerView); - return root; - } - - @Override - public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - loadItems(); - } - @Override - public void onStop() { - super.onStop(); - EventBus.getDefault().unregister(this); - if (disposable != null) { - disposable.dispose(); - } + return historyContainer; } @Override @@ -112,55 +75,8 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI super.onSaveInstanceState(outState); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FeedItemEvent event) { - Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - if (playbackHistory == null) { - return; - } else if (adapter == null) { - loadItems(); - return; - } - for (int i = 0, size = event.items.size(); i < size; i++) { - FeedItem item = event.items.get(i); - int pos = FeedItemUtil.indexOfItemWithId(playbackHistory, item.getId()); - if (pos >= 0) { - playbackHistory.remove(pos); - playbackHistory.add(pos, item); - adapter.notifyItemChangedCompat(pos); - } - } - } - - @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) - public void onEventMainThread(DownloadEvent event) { - Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - DownloaderUpdate update = event.update; - if (adapter != null && update.mediaIds.length > 0) { - for (long mediaId : update.mediaIds) { - int pos = FeedItemUtil.indexOfItemWithMediaId(playbackHistory, mediaId); - if (pos >= 0) { - adapter.notifyItemChangedCompat(pos); - } - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(PlaybackPositionEvent event) { - if (adapter != null) { - for (int i = 0; i < adapter.getItemCount(); i++) { - EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i); - if (holder != null && holder.isCurrentlyPlayingItem()) { - holder.notifyPlaybackPositionUpdated(event); - break; - } - } - } - } - public void refreshToolbarState() { - boolean hasHistory = playbackHistory != null && !playbackHistory.isEmpty(); + boolean hasHistory = episodes != null && !episodes.isEmpty(); toolbar.getMenu().findItem(R.id.clear_history_item).setVisible(hasHistory); } @@ -173,33 +89,6 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI return false; } - @Override - public boolean onContextItemSelected(@NonNull MenuItem item) { - FeedItem selectedItem = adapter.getLongPressedItem(); - if (selectedItem == null) { - Log.i(TAG, "Selected item at current position was null, ignoring selection"); - return super.onContextItemSelected(item); - } - return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onKeyUp(KeyEvent event) { - if (!isAdded() || !isVisible() || !isMenuVisible()) { - return; - } - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_T: - recyclerView.smoothScrollToPosition(0); - break; - case KeyEvent.KEYCODE_B: - recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1); - break; - default: - break; - } - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onHistoryUpdated(PlaybackHistoryEvent event) { loadItems(); @@ -212,41 +101,20 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI refreshToolbarState(); } + @Override @Subscribe(threadMode = ThreadMode.MAIN) public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) { loadItems(); refreshToolbarState(); } - private void onFragmentLoaded() { - adapter.notifyDataSetChanged(); + @Override + protected void onFragmentLoaded(List<FeedItem> episodes) { + super.onFragmentLoaded(episodes); + listAdapter.notifyDataSetChanged(); refreshToolbarState(); } - private void loadItems() { - if (disposable != null) { - disposable.dispose(); - } - progressBar.setVisibility(View.VISIBLE); - emptyView.hide(); - disposable = Observable.fromCallable(this::loadData) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - progressBar.setVisibility(View.GONE); - playbackHistory = result; - adapter.updateItems(playbackHistory); - onFragmentLoaded(); - }, error -> Log.e(TAG, Log.getStackTraceString(error))); - } - - @NonNull - private List<FeedItem> loadData() { - List<FeedItem> history = DBReader.getPlaybackHistory(); - DBReader.loadAdditionalFeedItemListData(history); - return history; - } - private class PlaybackHistoryListAdapter extends EpisodeItemListAdapter { public PlaybackHistoryListAdapter(MainActivity mainActivity) { @@ -254,17 +122,26 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI } @Override - protected void afterBindViewHolder(EpisodeItemViewHolder holder, int pos) { - // played items shouldn't be transparent for this fragment since, *all* items - // in this fragment will, by definition, be played. So it serves no purpose and can make - // it harder to read. - holder.itemView.setAlpha(1.0f); - } - - @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuItemUtils.setOnClickListeners(menu, PlaybackHistoryFragment.this::onContextItemSelected); } } + + @NonNull + @Override + protected List<FeedItem> loadData() { + return DBReader.getPlaybackHistory(0, page * EPISODES_PER_PAGE); + } + + @NonNull + @Override + protected List<FeedItem> loadMoreData(int page) { + return DBReader.getPlaybackHistory((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); + } + + @Override + protected int loadTotalItemCount() { + return (int) DBReader.getPlaybackHistoryLength(); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index 94c0b0a41..10f80441a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -146,13 +146,8 @@ public class SubscriptionFragment extends Fragment } subscriptionRecycler = root.findViewById(R.id.subscriptions_grid); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), - prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()), - RecyclerView.VERTICAL, - false); - subscriptionRecycler.setLayoutManager(gridLayoutManager); + setColumnNumber(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns())); subscriptionRecycler.addItemDecoration(new SubscriptionsRecyclerAdapter.GridDividerItemDecorator()); - gridLayoutManager.setSpanCount(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns())); registerForContextMenu(subscriptionRecycler); subscriptionAddButton = root.findViewById(R.id.subscriptions_add); progressBar = root.findViewById(R.id.progLoading); @@ -239,9 +234,9 @@ public class SubscriptionFragment extends Fragment } private void setColumnNumber(int columns) { - GridLayoutManager gridLayoutManager = (GridLayoutManager) subscriptionRecycler.getLayoutManager(); - gridLayoutManager.setSpanCount(columns); - subscriptionAdapter.notifyDataSetChanged(); + GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), + columns, RecyclerView.VERTICAL, false); + subscriptionRecycler.setLayoutManager(gridLayoutManager); prefs.edit().putInt(PREF_NUM_COLUMNS, columns).apply(); refreshToolbarState(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java index e2c5036df..7f5205db4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java @@ -17,6 +17,13 @@ import de.danoeh.antennapod.activity.BugReportActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.util.IntentUtils; import de.danoeh.antennapod.fragment.preferences.about.AboutFragment; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Locale; public class MainPreferencesFragment extends PreferenceFragmentCompat { @@ -106,7 +113,7 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { } ); findPreference(PREF_DOCUMENTATION).setOnPreferenceClickListener(preference -> { - IntentUtils.openInBrowser(getContext(), "https://antennapod.org/documentation/"); + IntentUtils.openInBrowser(getContext(), getLocalizedWebsiteLink() + "/documentation/"); return true; }); findPreference(PREF_VIEW_FORUM).setOnPreferenceClickListener(preference -> { @@ -114,7 +121,7 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { return true; }); findPreference(PREF_CONTRIBUTE).setOnPreferenceClickListener(preference -> { - IntentUtils.openInBrowser(getContext(), "https://antennapod.org/contribute/"); + IntentUtils.openInBrowser(getContext(), getLocalizedWebsiteLink() + "/contribute/"); return true; }); findPreference(PREF_SEND_BUG_REPORT).setOnPreferenceClickListener(preference -> { @@ -123,6 +130,20 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { }); } + private String getLocalizedWebsiteLink() { + try (InputStream is = getContext().getAssets().open("website-languages.txt")) { + String[] languages = IOUtils.toString(is, StandardCharsets.UTF_8.name()).split("\n"); + String deviceLanguage = Locale.getDefault().getLanguage(); + if (ArrayUtils.contains(languages, deviceLanguage) && !"en".equals(deviceLanguage)) { + return "https://antennapod.org/" + deviceLanguage; + } else { + return "https://antennapod.org"; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + private void setupSearch() { SearchPreference searchPreference = findPreference("searchPreference"); SearchConfiguration config = searchPreference.getSearchConfiguration(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java index 358985cea..e3e069868 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.fragment.preferences.synchronization; import android.app.Dialog; import android.content.Context; -import android.graphics.Paint; import android.os.Build; import android.os.Bundle; import android.view.View; @@ -12,31 +11,20 @@ import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ProgressBar; -import android.widget.RadioGroup; import android.widget.TextView; import android.widget.ViewFlipper; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; - import com.google.android.material.button.MaterialButton; -import com.google.android.material.textfield.TextInputLayout; - -import java.util.List; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.sync.SynchronizationCredentials; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.core.sync.SyncService; +import de.danoeh.antennapod.core.sync.SynchronizationCredentials; import de.danoeh.antennapod.core.sync.SynchronizationProviderViewData; import de.danoeh.antennapod.core.sync.SynchronizationSettings; import de.danoeh.antennapod.core.util.FileNameGenerator; -import de.danoeh.antennapod.core.util.IntentUtils; import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService; import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice; import io.reactivex.Completable; @@ -44,6 +32,11 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Guides the user through the authentication process. */ @@ -70,7 +63,7 @@ public class GpodderAuthenticationFragment extends DialogFragment { @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { AlertDialog.Builder dialog = new AlertDialog.Builder(getContext()); - dialog.setTitle(GpodnetService.DEFAULT_BASE_HOST); + dialog.setTitle(R.string.gpodnetauth_login_butLabel); dialog.setNegativeButton(R.string.cancel_label, null); dialog.setCancelable(false); this.setCancelable(false); @@ -85,23 +78,13 @@ public class GpodderAuthenticationFragment extends DialogFragment { private void setupHostView(View view) { final Button selectHost = view.findViewById(R.id.chooseHostButton); - final RadioGroup serverRadioGroup = view.findViewById(R.id.serverRadioGroup); final EditText serverUrlText = view.findViewById(R.id.serverUrlText); - - if (!GpodnetService.DEFAULT_BASE_HOST.equals(SynchronizationCredentials.getHosturl())) { - serverUrlText.setText(SynchronizationCredentials.getHosturl()); - } - final TextInputLayout serverUrlTextInput = view.findViewById(R.id.serverUrlTextInput); - serverRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { - serverUrlTextInput.setVisibility(checkedId == R.id.customServerRadio ? View.VISIBLE : View.GONE); - }); selectHost.setOnClickListener(v -> { - SynchronizationCredentials.clear(getContext()); - if (serverRadioGroup.getCheckedRadioButtonId() == R.id.customServerRadio) { - SynchronizationCredentials.setHosturl(serverUrlText.getText().toString()); - } else { - SynchronizationCredentials.setHosturl(GpodnetService.DEFAULT_BASE_HOST); + if (serverUrlText.getText().length() == 0) { + return; } + SynchronizationCredentials.clear(getContext()); + SynchronizationCredentials.setHosturl(serverUrlText.getText().toString()); service = new GpodnetService(AntennapodHttpClient.getHttpClient(), SynchronizationCredentials.getHosturl(), SynchronizationCredentials.getDeviceID(), SynchronizationCredentials.getUsername(), SynchronizationCredentials.getPassword()); @@ -116,12 +99,8 @@ public class GpodderAuthenticationFragment extends DialogFragment { final Button login = view.findViewById(R.id.butLogin); final TextView txtvError = view.findViewById(R.id.credentialsError); final ProgressBar progressBar = view.findViewById(R.id.progBarLogin); - final TextView createAccount = view.findViewById(R.id.createAccountButton); final TextView createAccountWarning = view.findViewById(R.id.createAccountWarning); - createAccount.setPaintFlags(createAccount.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - createAccount.setOnClickListener(v -> IntentUtils.openInBrowser(getContext(), "https://gpodder.net/register/")); - if (SynchronizationCredentials.getHosturl().startsWith("http://")) { createAccountWarning.setVisibility(View.VISIBLE); } diff --git a/app/src/main/play/release-notes/en-US/default.txt b/app/src/main/play/release-notes/en-US/default.txt index de4eb38b7..f74f32c72 100644 --- a/app/src/main/play/release-notes/en-US/default.txt +++ b/app/src/main/play/release-notes/en-US/default.txt @@ -1,7 +1,6 @@ -- Synchronization with Nextcloud ("GPodder Sync" app) (@thrillfall) -- 'Duration' filter in podcast-specific auto-download settings (@thomasdomingos) -- 'Downloaded episodes' screen in Android Auto (@ByteHamster) -- Tags (previously folders): add to multiple podcasts via multi-select, rename tags (@vbh) -- Accessibility: more TalkBack (@johnjohndoe @TacoTheDank) -- Improvements for local feeds, mobile connections, physical keyboard/mouse support -- Many minor & bigger bug fixes and other improvements
\ No newline at end of file +∙ Support for podcasting 2.0 chapters (@tonytamsf) +∙ Statistics: filter based on month/year (@ByteHamster), access via button on Subscriptions toolbar instead of Settings (@IordanisKokk) +∙ Local feed bug fixes & improvements (@ByteHamster) +∙ Design improvements (design: George, code: @ByteHamster) +∙ Update feeds to https if possible, better handle captive portal redirects (@ByteHamster) +∙ As always, even though we never list it: new & updated translations (thanks to all our lovely translators) diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml index 6d96141a2..6bd31ed9d 100644 --- a/app/src/main/res/layout/feeditemlist_header.xml +++ b/app/src/main/res/layout/feeditemlist_header.xml @@ -71,7 +71,7 @@ android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:scaleType="fitXY" - android:src="@drawable/ic_rounded_corner_left" /> + app:srcCompat="@drawable/ic_rounded_corner_left" /> <ImageView android:layout_width="12dp" @@ -79,7 +79,7 @@ android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:scaleType="fitXY" - android:src="@drawable/ic_rounded_corner_right" /> + app:srcCompat="@drawable/ic_rounded_corner_right" /> <androidx.cardview.widget.CardView android:id="@+id/coverHolder" diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index 675d3ee58..b6a332acc 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -117,8 +117,8 @@ android:layout_height="14sp" android:layout_marginRight="4dp" android:layout_marginEnd="4dp" - android:src="@drawable/ic_inbox" android:contentDescription="@string/is_inbox_label" + app:srcCompat="@drawable/ic_inbox" app:tint="?attr/colorAccent" /> <ImageView diff --git a/app/src/main/res/layout/gpodnetauth_credentials.xml b/app/src/main/res/layout/gpodnetauth_credentials.xml index 8cf6941c9..91224744b 100644 --- a/app/src/main/res/layout/gpodnetauth_credentials.xml +++ b/app/src/main/res/layout/gpodnetauth_credentials.xml @@ -1,107 +1,84 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:layout_marginBottom="8dp"> - - <ImageView - android:layout_width="64dp" - android:layout_height="64dp" - app:srcCompat="@drawable/gpodder_icon"/> - - <TextView - android:id="@+id/createAccountButton" - android:layout_width="0dp" - android:textAlignment="textEnd" - android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" - android:textColor="?colorAccent" - android:layout_weight="1" - android:layout_gravity="center_vertical|end" - android:text="@string/create_account"/> - </LinearLayout> + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> <TextView - android:id="@+id/createAccountWarning" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/gpodnetauth_encryption_warning" - android:textColor="#F44336" - android:textStyle="bold" - android:visibility="invisible" /> + android:id="@+id/createAccountWarning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/gpodnetauth_encryption_warning" + android:textColor="#F44336" + android:textStyle="bold" + android:visibility="invisible" /> <com.google.android.material.textfield.TextInputLayout - style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <com.google.android.material.textfield.TextInputEditText - android:id="@+id/etxtUsername" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/username_label" - android:lines="1" - android:imeOptions="actionNext|flagNoFullscreen"/> + android:id="@+id/etxtUsername" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/username_label" + android:lines="1" + android:imeOptions="actionNext|flagNoFullscreen" /> </com.google.android.material.textfield.TextInputLayout> <com.google.android.material.textfield.TextInputLayout - style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <com.google.android.material.textfield.TextInputEditText - android:id="@+id/etxtPassword" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/password_label" - android:inputType="textPassword" - android:lines="1" - android:imeOptions="actionNext|flagNoFullscreen" - android:imeActionLabel="@string/gpodnetauth_login_butLabel"/> + android:id="@+id/etxtPassword" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/password_label" + android:inputType="textPassword" + android:lines="1" + android:imeOptions="actionNext|flagNoFullscreen" + android:imeActionLabel="@string/gpodnetauth_login_butLabel" /> </com.google.android.material.textfield.TextInputLayout> <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:gravity="end|center_vertical"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="end|center_vertical"> <TextView - android:id="@+id/credentialsError" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="wrap_content" - android:textColor="@color/download_failed_red" - android:textSize="@dimen/text_size_small" - android:maxLines="2" - android:ellipsize="end" - android:gravity="center" - tools:text="Error message" - tools:background="@android:color/holo_green_dark"/> + android:id="@+id/credentialsError" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="@color/download_failed_red" + android:textSize="@dimen/text_size_small" + android:maxLines="2" + android:ellipsize="end" + android:gravity="center" + tools:text="Error message" + tools:background="@android:color/holo_green_dark" /> <ProgressBar - android:id="@+id/progBarLogin" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:visibility="gone" - android:layout_gravity="right"/> + android:id="@+id/progBarLogin" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" + android:layout_gravity="right" /> <Button - android:id="@+id/butLogin" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/gpodnetauth_login_butLabel"/> + android:id="@+id/butLogin" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/gpodnetauth_login_butLabel" /> + </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/gpodnetauth_host.xml b/app/src/main/res/layout/gpodnetauth_host.xml index 52c5fdb5d..bcee9b880 100644 --- a/app/src/main/res/layout/gpodnetauth_host.xml +++ b/app/src/main/res/layout/gpodnetauth_host.xml @@ -1,50 +1,31 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <RadioGroup - android:id="@+id/serverRadioGroup" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <RadioButton - android:id="@+id/officialServerRadio" - android:text="@string/gpodnetauth_server_official" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:checked="true"/> - <RadioButton - android:id="@+id/customServerRadio" - android:text="@string/gpodnetauth_server_custom" - android:layout_width="match_parent" - android:layout_height="wrap_content"/> - </RadioGroup> + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> <com.google.android.material.textfield.TextInputLayout - android:id="@+id/serverUrlTextInput" - style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" - android:visibility="gone" - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <com.google.android.material.textfield.TextInputEditText - android:id="@+id/serverUrlText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/gpodnetauth_host" - android:inputType="textNoSuggestions" - android:lines="1" - android:imeOptions="actionNext|flagNoFullscreen" /> + android:id="@+id/serverUrlText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/gpodnetauth_host" + android:inputType="textNoSuggestions" + android:lines="1" + android:imeOptions="actionNext|flagNoFullscreen" /> </com.google.android.material.textfield.TextInputLayout> <Button - android:id="@+id/chooseHostButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right|end" - android:text="@string/gpodnetauth_select_server"/> + android:id="@+id/chooseHostButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|end" + android:text="@string/gpodnetauth_select_server" /> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/app/src/main/res/layout/inbox_fragment.xml b/app/src/main/res/layout/list_container_fragment.xml index fbacf7827..1b6debb13 100644 --- a/app/src/main/res/layout/inbox_fragment.xml +++ b/app/src/main/res/layout/list_container_fragment.xml @@ -9,13 +9,13 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_alignParentTop="true" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" - android:layout_alignParentTop="true" app:title="@string/inbox_label" /> <FrameLayout - android:id="@+id/inboxContent" + android:id="@+id/listContent" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/toolbar" /> diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml index 7c66a4d10..ebb0befb0 100644 --- a/app/src/main/res/menu/mediaplayer.xml +++ b/app/src/main/res/menu/mediaplayer.xml @@ -36,6 +36,13 @@ </item> <item + android:id="@+id/playback_speed" + android:title="@string/playback_speed" + android:visible="false" + custom:showAsAction="never"> + </item> + + <item android:id="@+id/open_feed_item" android:icon="@drawable/ic_feed" custom:showAsAction="collapseActionView" diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml index fa63bf583..845ee92a2 100644 --- a/app/src/main/res/menu/subscriptions.xml +++ b/app/src/main/res/menu/subscriptions.xml @@ -8,7 +8,7 @@ android:title="@string/search_label"/> <item android:id="@+id/action_statistics" - android:icon="@drawable/chart_box_outline" + android:icon="@drawable/ic_chart_box" android:title="@string/statistics_label" custom:showAsAction="always" /> <item |