summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java59
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java160
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java55
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java225
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java130
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java117
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java156
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java45
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java181
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java145
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java153
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java137
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java107
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java31
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java59
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java133
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java72
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java112
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java51
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java47
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java122
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java73
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java63
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java152
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java226
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java142
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java112
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java247
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java193
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java34
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java197
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java81
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java56
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java126
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java88
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java33
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java180
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java195
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/PieChartView.java121
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java30
122 files changed, 3511 insertions, 2517 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
index ea2166674..061ea9ae2 100644
--- a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
+++ b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
@@ -9,6 +9,9 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -32,13 +35,7 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter(path));
- out.println("[ Environment ]");
- out.println("Android version: " + Build.VERSION.RELEASE);
- out.println("OS version: " + System.getProperty("os.version"));
- out.println("AntennaPod version: " + BuildConfig.VERSION_NAME);
- out.println("Model: " + Build.MODEL);
- out.println("Device: " + Build.DEVICE);
- out.println("Product: " + Build.PRODUCT);
+ out.println(getSystemInfo());
out.println();
out.println("[ StackTrace ]");
ex.printStackTrace(out);
@@ -49,4 +46,15 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
}
defaultHandler.uncaughtException(thread, ex);
}
+
+ public static String getSystemInfo() {
+ return "[ Environment ]" +
+ "\nAndroid version: " + Build.VERSION.RELEASE +
+ "\nOS version: " + System.getProperty("os.version") +
+ "\nAntennaPod version: " + BuildConfig.VERSION_NAME +
+ "\nModel: " + Build.MODEL +
+ "\nDevice: " + Build.DEVICE +
+ "\nProduct: " + Build.PRODUCT +
+ "\nTime: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date()) + "\n";
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index cb2f597d6..4e6b8fa29 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod;
import android.app.Application;
-import android.os.Build;
import android.os.StrictMode;
import com.joanzapata.iconify.Iconify;
@@ -10,7 +9,6 @@ import com.joanzapata.iconify.fonts.MaterialModule;
import de.danoeh.antennapod.core.ApCoreEventBusIndex;
import de.danoeh.antennapod.core.ClientConfig;
-import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.spa.SPAUtil;
import org.greenrobot.eventbus.EventBus;
@@ -26,44 +24,43 @@ public class PodcastApp extends Application {
}
}
- private static PodcastApp singleton;
+ private static PodcastApp singleton;
- public static PodcastApp getInstance() {
- return singleton;
- }
+ public static PodcastApp getInstance() {
+ return singleton;
+ }
- @Override
- public void onCreate() {
- super.onCreate();
+ @Override
+ public void onCreate() {
+ super.onCreate();
- Thread.setDefaultUncaughtExceptionHandler(new CrashReportWriter());
+ Thread.setDefaultUncaughtExceptionHandler(new CrashReportWriter());
- if(BuildConfig.DEBUG) {
- StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .penaltyLog()
- .penaltyDropBox();
- builder.detectActivityLeaks();
- builder.detectLeakedClosableObjects();
- if(Build.VERSION.SDK_INT >= 16) {
- builder.detectLeakedRegistrationObjects();
- }
- StrictMode.setVmPolicy(builder.build());
- }
+ if (BuildConfig.DEBUG) {
+ StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder()
+ .detectLeakedSqlLiteObjects()
+ .penaltyLog()
+ .penaltyDropBox()
+ .detectActivityLeaks()
+ .detectLeakedClosableObjects()
+ .detectLeakedRegistrationObjects();
+ StrictMode.setVmPolicy(builder.build());
+ }
- singleton = this;
+ singleton = this;
- ClientConfig.initialize(this);
+ ClientConfig.initialize(this);
- EventDistributor.getInstance();
- Iconify.with(new FontAwesomeModule());
- Iconify.with(new MaterialModule());
+ Iconify.with(new FontAwesomeModule());
+ Iconify.with(new MaterialModule());
SPAUtil.sendSPAppsQueryFeedsIntent(this);
- EventBus.builder()
- .addIndex(new ApEventBusIndex())
- .addIndex(new ApCoreEventBusIndex())
- .installDefaultEventBus();
+ EventBus.builder()
+ .addIndex(new ApEventBusIndex())
+ .addIndex(new ApCoreEventBusIndex())
+ .logNoSubscriberMessages(false)
+ .sendNoSubscriberEvent(false)
+ .installDefaultEventBus();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
deleted file mode 100644
index 1bcdada44..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.LinearLayout;
-
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.Charset;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import io.reactivex.Single;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-/**
- * Displays the 'about' screen
- */
-public class AboutActivity extends AppCompatActivity {
-
- private static final String TAG = AboutActivity.class.getSimpleName();
-
- private WebView webView;
- private LinearLayout webViewContainer;
- private Disposable disposable;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- setContentView(R.layout.about);
- webViewContainer = findViewById(R.id.webViewContainer);
- webView = findViewById(R.id.webViewAbout);
- webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
- webView.setBackgroundColor(Color.TRANSPARENT);
- webView.setWebViewClient(new WebViewClient() {
-
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (url.startsWith("http")) {
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(browserIntent);
- return true;
- } else {
- url = url.replace("file:///android_asset/", "");
- loadAsset(url);
- return true;
- }
- }
-
- });
- loadAsset("about.html");
- }
-
- private void loadAsset(String filename) {
- disposable = Single.create(subscriber -> {
- InputStream input = null;
- try {
- TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes(
- 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());
- if (!webViewData.startsWith("<!DOCTYPE html>")) {
- webViewData = webViewData.replace("%", "&#37;");
- webViewData =
- "<!DOCTYPE html>" +
- "<html>" +
- "<head>" +
- " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">" +
- " <style type=\"text/css\">" +
- " @font-face {" +
- " font-family: 'Roboto-Light';" +
- " src: url('file:///android_asset/Roboto-Light.ttf');" +
- " }" +
- " * {" +
- " color: @fontcolor@;" +
- " font-family: roboto-Light;" +
- " font-size: 8pt;" +
- " }" +
- " </style>" +
- "</head><body><p>" + webViewData + "</p></body></html>";
- webViewData = webViewData.replace("\n", "<br/>");
- }
- 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));
- subscriber.onError(e);
- } finally {
- IOUtils.closeQuietly(input);
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- webViewData ->
- webView.loadDataWithBaseURL("file:///android_asset/", webViewData.toString(), "text/html", "utf-8", "file:///android_asset/" + filename.toString()),
- error -> Log.e(TAG, Log.getStackTraceString(error))
- );
- }
-
- @Override
- public void onBackPressed() {
- if (webView.canGoBack()) {
- webView.goBack();
- } else {
- super.onBackPressed();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (disposable != null) {
- disposable.dispose();
- }
- if (webViewContainer != null && webView != null) {
- webViewContainer.removeAllViews();
- webView.destroy();
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 2321a3602..7f8c14b03 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.activity;
import android.content.Intent;
-import android.support.v4.view.ViewCompat;
+import androidx.core.view.ViewCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -12,6 +12,8 @@ import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
@@ -60,11 +62,13 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
if (controller == null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
return;
}
updatePlaybackSpeedButtonText();
ViewCompat.setAlpha(butPlaybackSpeed, controller.canSetPlaybackSpeed() ? 1.0f : 0.5f);
butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
}
@Override
@@ -74,14 +78,15 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
if (controller == null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
return;
}
float speed = 1.0f;
if(controller.canSetPlaybackSpeed()) {
- speed = UserPreferences.getPlaybackSpeed();
+ speed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(controller.getMedia());
}
- String speedStr = new DecimalFormat("0.00x").format(speed);
- butPlaybackSpeed.setText(speedStr);
+ String speedStr = new DecimalFormat("0.00").format(speed);
+ txtvPlaybackSpeed.setText(speedStr);
}
@Override
@@ -102,7 +107,9 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
format.setDecimalSeparator('.');
- String currentSpeed = new DecimalFormat("0.00", format).format(UserPreferences.getPlaybackSpeed());
+
+ float currentSpeedValue = controller.getCurrentPlaybackSpeedMultiplier();
+ String currentSpeed = new DecimalFormat("0.00", format).format(currentSpeedValue);
// Provide initial value in case the speed list has changed
// out from under us
@@ -124,6 +131,12 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
break;
}
}
+
+ try {
+ PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(Float.parseFloat(newSpeed));
+ } catch (NumberFormatException e) {
+ // Well this was awkward...
+ }
UserPreferences.setPlaybackSpeed(newSpeed);
controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
onPositionObserverUpdate();
@@ -136,6 +149,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
return true;
});
butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
new file mode 100644
index 000000000..666eacfa8
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.activity;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Bundle;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.AppCompatActivity;
+import android.widget.TextView;
+import de.danoeh.antennapod.CrashReportWriter;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+/**
+ * Displays the 'crash report' screen
+ */
+public class BugReportActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ setContentView(R.layout.bug_report);
+
+ TextView crashDetailsText = findViewById(R.id.crash_report_logs);
+
+ try {
+ File crashFile = CrashReportWriter.getFile();
+ String crashReportContent = IOUtils.toString(new FileInputStream(crashFile), Charset.forName("UTF-8"));
+ crashDetailsText.setText(crashReportContent);
+ } catch (IOException e) {
+ e.printStackTrace();
+ crashDetailsText.setText("No crash report recorded\n" + CrashReportWriter.getSystemInfo());
+ }
+
+ findViewById(R.id.btn_open_bug_tracker).setOnClickListener(v -> {
+ IntentUtils.openInBrowser(BugReportActivity.this, "https://github.com/AntennaPod/AntennaPod/issues");
+ });
+
+ findViewById(R.id.btn_copy_log).setOnClickListener(v -> {
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getString(R.string.bug_report_title), crashDetailsText.getText());
+ clipboard.setPrimaryClip(clip);
+ Snackbar.make(findViewById(android.R.id.content), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show();
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
index 871e9c279..c60c7b769 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java
@@ -49,6 +49,7 @@ public class CastplayerActivity extends MediaplayerInfoActivity {
super.setupGUI();
if (butPlaybackSpeed != null) {
butPlaybackSpeed.setVisibility(View.GONE);
+ txtvPlaybackSpeed.setVisibility(View.GONE);
}
// if (butCastDisconnect != null) {
// butCastDisconnect.setOnClickListener(v -> castManager.disconnect());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
index 33def125e..49ce954bc 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
@@ -5,9 +5,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.core.app.NavUtils;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
index 5e04d743d..08ebc6421 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
deleted file mode 100644
index 26e360bd3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.ClipData;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.LightingColorFilter;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-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;
-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.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-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 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.
- */
-public class FeedInfoActivity extends AppCompatActivity {
-
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
- private static final String TAG = "FeedInfoActivity";
- private Feed feed;
-
- private ImageView imgvCover;
- private TextView txtvTitle;
- private TextView txtvDescription;
- private TextView lblLanguage;
- private TextView txtvLanguage;
- private TextView lblAuthor;
- private TextView txtvAuthor;
- private TextView txtvUrl;
-
- private Disposable disposable;
-
-
- 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) FeedInfoActivity.this
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- Toast t = Toast.makeText(FeedInfoActivity.this, R.string.copied_url_msg, Toast.LENGTH_SHORT);
- t.show();
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.feedinfo);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
-
- 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 = 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);
-
- 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 -> {
- 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())
- .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())
- .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());
-
- String description = feed.getDescription();
- if(description != null) {
- if(Feed.TYPE_ATOM1.equals(feed.getType())) {
- HtmlToPlainText formatter = new HtmlToPlainText();
- Document feedDescription = Jsoup.parse(feed.getDescription());
- description = StringUtils.trim(formatter.getPlainText(feedDescription));
- }
- } else {
- description = "";
- }
- txtvDescription.setText(description);
-
- if (!TextUtils.isEmpty(feed.getAuthor())) {
- txtvAuthor.setText(feed.getAuthor());
- txtvAuthorHeader.setText(feed.getAuthor());
- } else {
- lblAuthor.setVisibility(View.GONE);
- txtvAuthor.setVisibility(View.GONE);
- }
- if (!TextUtils.isEmpty(feed.getLanguage())) {
- txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage()));
- } else {
- lblLanguage.setVisibility(View.GONE);
- txtvLanguage.setVisibility(View.GONE);
- }
- txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}");
- Iconify.addIcons(txtvUrl);
-
- supportInvalidateOptionsMenu();
- }, 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 (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.feedinfo, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
- menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
- IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- try {
- return FeedMenuHandler.onOptionsItemClicked(this, item, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
deleted file mode 100644
index fbd19f88a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.arch.lifecycle.ViewModelProviders;
-import android.graphics.LightingColorFilter;
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
-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.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.glide.FastBlurTransformation;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.fragment.FeedSettingsFragment;
-import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-/**
- * Displays information about a feed.
- */
-public class FeedSettingsActivity extends AppCompatActivity {
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
- private static final String TAG = "FeedSettingsActivity";
- private Feed feed;
- private Disposable disposable;
- private ImageView imgvCover;
- private TextView txtvTitle;
- private ImageView imgvBackground;
- private TextView txtvAuthorHeader;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.feedsettings);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- imgvCover = findViewById(R.id.imgvCover);
- txtvTitle = findViewById(R.id.txtvTitle);
- txtvAuthorHeader = findViewById(R.id.txtvAuthor);
- 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));
-
- long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
- disposable = ViewModelProviders.of(this).get(FeedSettingsViewModel.class).getFeed(feedId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- feed = result;
- showFragment();
- showHeader();
- }, error -> {
- Log.d(TAG, Log.getStackTraceString(error));
- finish();
- }, () -> {
- Log.e(TAG, "Activity was started with invalid arguments");
- finish();
- });
- }
-
- private void showFragment() {
- FeedSettingsFragment fragment = new FeedSettingsFragment();
- fragment.setArguments(getIntent().getExtras());
-
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fragmentTransaction =
- fragmentManager.beginTransaction();
- fragmentTransaction.replace(R.id.settings_fragment_container, fragment);
- fragmentTransaction.commit();
- }
-
- private void showHeader() {
- txtvTitle.setText(feed.getTitle());
-
- if (!TextUtils.isEmpty(feed.getAuthor())) {
- txtvAuthorHeader.setText(feed.getAuthor());
- }
-
- Glide.with(FeedSettingsActivity.this)
- .load(feed.getImageLocation())
- .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())
- .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);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
index 9795c1240..f85a1cd77 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
@@ -7,10 +7,10 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 339ce01c2..0023e6d7f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -10,15 +11,16 @@ import android.database.DataSetObserver;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
@@ -32,9 +34,13 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
-import de.danoeh.antennapod.preferences.PreferenceUpgrader;
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
@@ -43,9 +49,7 @@ import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
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.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -66,14 +70,13 @@ import de.danoeh.antennapod.fragment.FeedItemlistFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
+import de.danoeh.antennapod.fragment.TransitionEffect;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.preferences.PreferenceUpgrader;
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;
/**
* The activity that is shown when the user launches the app.
@@ -82,9 +85,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
private static final String TAG = "MainActivity";
- private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
-
public static final String PREF_NAME = "MainActivityPrefs";
public static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
public static final String PREF_LAST_FRAGMENT_TAG = "prefMainActivityLastFragmentTag";
@@ -93,7 +93,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
public static final String EXTRA_NAV_INDEX = "nav_index";
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
- public static final String EXTRA_FEED_ID = "fragment_feed_id";
+ private static final String EXTRA_FEED_ID = "fragment_feed_id";
private static final String SAVE_BACKSTACK_COUNT = "backstackCount";
private static final String SAVE_TITLE = "title";
@@ -127,6 +127,14 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
private long lastBackButtonPressTime = 0;
+ @NonNull
+ public static Intent getIntentToOpenFeed(@NonNull Context context, long feedId) {
+ Intent intent = new Intent(context.getApplicationContext(), MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return intent;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getNoTitleTheme());
@@ -240,7 +248,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
- edit.commit();
+ edit.apply();
}
}
@@ -309,8 +317,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
fragment = new AddFeedFragment();
break;
case SubscriptionFragment.TAG:
- SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
- fragment = subscriptionFragment;
+ fragment = new SubscriptionFragment();
break;
default:
// default to the queue
@@ -368,15 +375,34 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
- public void loadChildFragment(Fragment fragment) {
+ public void loadChildFragment(Fragment fragment, TransitionEffect transition) {
Validate.notNull(fragment);
- FragmentManager fm = getSupportFragmentManager();
- fm.beginTransaction()
- .replace(R.id.main_view, fragment, "main")
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+
+ switch (transition) {
+ case FADE:
+ transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
+ break;
+ case FLIP:
+ transaction.setCustomAnimations(
+ R.anim.card_flip_left_in,
+ R.anim.card_flip_left_out,
+ R.anim.card_flip_right_in,
+ R.anim.card_flip_right_out);
+ break;
+ }
+
+ transaction
+ .hide(getSupportFragmentManager().findFragmentByTag("main"))
+ .add(R.id.main_view, fragment, "main")
.addToBackStack(null)
.commit();
}
+ public void loadChildFragment(Fragment fragment) {
+ loadChildFragment(fragment, TransitionEffect.NONE);
+ }
+
public void dismissChildFragment() {
getSupportFragmentManager().popBackStack();
}
@@ -461,7 +487,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
RatingDialog.init(this);
}
@@ -489,7 +514,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
@Override
protected void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if (disposable != null) {
disposable.dispose();
@@ -778,25 +802,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(ProgressEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
- switch(event.action) {
- case START:
- pd = new ProgressDialog(this);
- pd.setMessage(event.message);
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.show();
- break;
- case END:
- if(pd != null) {
- pd.dismiss();
- }
- break;
- }
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
View parentLayout = findViewById(R.id.drawer_layout);
@@ -807,16 +812,16 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
snackbar.show();
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Subscribe
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ loadData();
+ }
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EVENTS & arg) != 0) {
- Log.d(TAG, "Received contentUpdate Intent.");
- loadData();
- }
- }
- };
+
+ @Subscribe
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ loadData();
+ }
private void handleNavIntent() {
Log.d(TAG, "handleNavIntent()");
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 52497a27f..538ed1231 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -9,14 +9,14 @@ import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
-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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.content.ContextCompat;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -28,12 +28,12 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
-import com.afollestad.materialdialogs.MaterialDialog;
import com.bumptech.glide.Glide;
import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
@@ -63,6 +63,10 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.StringUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
@@ -73,7 +77,8 @@ 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 int REQUEST_CODE_STORAGE_PLAY_VIDEO = 42;
+ private static final int REQUEST_CODE_STORAGE_PLAY_AUDIO = 43;
PlaybackController controller;
@@ -194,6 +199,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
};
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ onPositionObserverUpdate();
+ }
+
private static TextView getTxtvFFFromActivity(MediaplayerActivity activity) {
return activity.txtvFF;
}
@@ -274,6 +284,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
controller.init();
loadMediaInfo();
onPositionObserverUpdate();
+ EventBus.getDefault().register(this);
}
@Override
@@ -286,6 +297,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
if (disposable != null) {
disposable.dispose();
}
+ EventBus.getDefault().unregister(this);
super.onStop();
}
@@ -322,6 +334,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Playable media = controller.getMedia();
boolean isFeedMedia = media != null && (media instanceof FeedMedia);
+ menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed
+
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
@@ -377,10 +391,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
| Intent.FLAG_ACTIVITY_NEW_TASK);
View cover = findViewById(R.id.imgvCover);
- if (cover != null && Build.VERSION.SDK_INT >= 16) {
- ActivityOptionsCompat options = ActivityOptionsCompat.
- makeSceneTransitionAnimation(MediaplayerActivity.this,
- cover, "coverTransition");
+ if (cover != null) {
+ ActivityOptionsCompat options = ActivityOptionsCompat
+ .makeSceneTransitionAnimation(MediaplayerActivity.this, cover, "coverTransition");
startActivity(intent, options.toBundle());
} else {
startActivity(intent);
@@ -389,47 +402,38 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return true;
} else {
if (media != null) {
+ final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem
switch (item.getItemId()) {
case R.id.add_to_favorites_item:
- if(media instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia)media).getItem();
- if(feedItem != null) {
- DBWriter.addFavoriteItem(feedItem);
- isFavorite = true;
- invalidateOptionsMenu();
- Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
- .show();
- }
+ if (feedItem != null) {
+ DBWriter.addFavoriteItem(feedItem);
+ isFavorite = true;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
+ .show();
}
break;
case R.id.remove_from_favorites_item:
- if(media instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia)media).getItem();
- if(feedItem != null) {
- DBWriter.removeFavoriteItem(feedItem);
- isFavorite = false;
- invalidateOptionsMenu();
- Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
- .show();
- }
+ if (feedItem != null) {
+ DBWriter.removeFavoriteItem(feedItem);
+ isFavorite = false;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
+ .show();
}
break;
case R.id.disable_sleeptimer_item:
if (controller.serviceAvailable()) {
- MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
- stDialog.title(R.string.sleep_timer_label);
- stDialog.content(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) controller
- .getSleepTimerTimeLeft()));
- stDialog.positiveText(R.string.disable_sleeptimer_label);
- stDialog.negativeText(R.string.cancel_label);
- stDialog.onPositive((dialog, which) -> {
- dialog.dismiss();
- controller.disableSleepTimer();
- });
- stDialog.onNegative((dialog, which) -> dialog.dismiss());
- stDialog.build().show();
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.sleep_timer_label)
+ .setMessage(getString(R.string.time_left_label)
+ + Converter.getDurationStringLong((int) controller
+ .getSleepTimerTimeLeft()))
+ .setPositiveButton(R.string.disable_sleeptimer_label, (dialog, which)
+ -> controller.disableSleepTimer())
+ .setNegativeButton(R.string.cancel_label, null)
+ .show();
}
break;
case R.id.set_sleeptimer_item:
@@ -448,28 +452,33 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(isPlayingVideo);
dialog.show(getSupportFragmentManager(), "playback_controls");
break;
+ case R.id.open_feed_item:
+ if (feedItem != null) {
+ Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId());
+ startActivity(intent);
+ }
+ break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media));
break;
case R.id.share_link_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemLink(this, feedItem);
}
break;
case R.id.share_download_url_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem);
}
break;
case R.id.share_link_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemLink(this, feedItem, true);
}
break;
case R.id.share_download_url_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
+ if (feedItem != null) {
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem, true);
}
break;
case R.id.share_file:
@@ -490,7 +499,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private static String getWebsiteLinkWithFallback(Playable media) {
if (media == null) {
return null;
- } else if (media.getWebsiteLink() != null) {
+ } else if (StringUtils.isNotBlank(media.getWebsiteLink())) {
return media.getWebsiteLink();
} else if (media instanceof FeedMedia) {
return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
@@ -635,7 +644,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
}
- static public void showSkipPreference(Activity activity, SkipDirection direction) {
+ public static void showSkipPreference(Activity activity, SkipDirection direction) {
int checked = 0;
int skipSecs = direction.getPrefSkipSeconds();
final int[] values = activity.getResources().getIntArray(R.array.seek_delta_values);
@@ -813,11 +822,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
private void checkFavorite() {
- Playable playable = controller.getMedia();
- if (!(playable instanceof FeedMedia)) {
- return;
- }
- FeedItem feedItem = ((FeedMedia) playable).getItem();
+ FeedItem feedItem = getFeedItem(controller.getMedia());
if (feedItem == null) {
return;
}
@@ -847,10 +852,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
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);
}
+
+ int code = REQUEST_CODE_STORAGE_PLAY_AUDIO;
+ if (type == MediaType.VIDEO) {
+ code = REQUEST_CODE_STORAGE_PLAY_VIDEO;
+ }
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, code);
return;
}
@@ -858,6 +866,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
ExternalMedia media = new ExternalMedia(intent.getData().getPath(), type);
new PlaybackServiceStarter(this, media)
+ .callEvenIfRunning(true)
.startWhenPrepared(true)
.shouldStream(false)
.prepareImmediately(true)
@@ -865,11 +874,24 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
@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();
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, int[] grantResults) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (requestCode == REQUEST_CODE_STORAGE_PLAY_AUDIO) {
+ playExternalMedia(getIntent(), MediaType.AUDIO);
+ } else if (requestCode == REQUEST_CODE_STORAGE_PLAY_VIDEO) {
+ playExternalMedia(getIntent(), MediaType.VIDEO);
}
+ } else {
+ Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Nullable
+ private static FeedItem getFeedItem(@Nullable Playable playable) {
+ if (playable instanceof FeedMedia) {
+ return ((FeedMedia) playable).getItem();
+ } else {
+ return null;
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
index 4fec1cfc5..21f4ad5be 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -7,15 +7,15 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
-import android.support.design.widget.AppBarLayout;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.widget.Toolbar;
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
@@ -23,9 +23,9 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
-import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
+import android.widget.TextView;
import android.widget.Toast;
import com.viewpagerindicator.CirclePageIndicator;
@@ -36,8 +36,8 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.MessageEvent;
-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.preferences.UserPreferences;
@@ -63,7 +63,6 @@ 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;
@@ -92,7 +91,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
- Button butPlaybackSpeed;
+ ImageButton butPlaybackSpeed;
+ TextView txtvPlaybackSpeed;
ImageButton butCastDisconnect;
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
@@ -119,8 +119,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
if (disposable != null) {
disposable.dispose();
}
- EventDistributor.getInstance().unregister(contentUpdate);
- EventBus.getDefault().unregister(this);
saveCurrentFragment();
}
@@ -172,8 +170,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
@Override
protected void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
loadData();
}
@@ -258,6 +254,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
});
butPlaybackSpeed = findViewById(R.id.butPlaybackSpeed);
+ txtvPlaybackSpeed = findViewById(R.id.txtvPlaybackSpeed);
butCastDisconnect = findViewById(R.id.butCastDisconnect);
pager = findViewById(R.id.pager);
@@ -446,16 +443,10 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
snackbar.show();
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EventDistributor.FEED_LIST_UPDATE & arg) != 0) {
- Log.d(TAG, "Received contentUpdate Intent.");
- loadData();
- }
- }
- };
+ @Subscribe
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ loadData();
+ }
private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
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 ea7687bc9..0c6c63e73 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -7,12 +7,11 @@ import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Build;
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;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.annotation.UiThread;
+import androidx.core.app.NavUtils;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -22,23 +21,19 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.core.glide.FastBlurTransformation;
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
import java.io.File;
import java.io.IOException;
@@ -50,11 +45,11 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
-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.FeedPreferences;
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.DownloadRequest;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
@@ -94,60 +89,31 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
public static final String ARG_TITLE = "title";
private static final int RESULT_ERROR = 2;
private static final String TAG = "OnlineFeedViewActivity";
- private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE;
private volatile List<Feed> feeds;
private Feed feed;
private String selectedDownloadUrl;
private Downloader downloader;
private boolean isPaused;
+ private boolean didPressSubscribe = false;
private Dialog dialog;
-
+ private ListView listView;
private Button subscribeButton;
+ private ProgressBar progressBar;
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.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- feeds -> {
- OnlineFeedViewActivity.this.feeds = feeds;
- setSubscribeButtonState(feed);
- }, error -> Log.e(TAG, Log.getStackTraceString(error))
- );
- } else if ((arg & EVENTS) != 0) {
- setSubscribeButtonState(feed);
- }
- }
- };
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(DownloadEvent event) {
- Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- setSubscribeButtonState(feed);
- }
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
+ setTheme(UserPreferences.getTranslucentTheme());
super.onCreate(savedInstanceState);
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
-
- if (actionBar != null && getIntent() != null && getIntent().hasExtra(ARG_TITLE)) {
- actionBar.setTitle(getIntent().getStringExtra(ARG_TITLE));
- }
-
StorageUtils.checkStorageAvailability(this);
+ setContentView(R.layout.onlinefeedview_activity);
+ listView = findViewById(R.id.listview);
+ progressBar = findViewById(R.id.progressBar);
String feedUrl = null;
if (getIntent().hasExtra(ARG_FEEDURL)) {
@@ -156,9 +122,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|| TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
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);
- }
}
if (feedUrl == null) {
@@ -183,26 +146,14 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
* Displays a progress indicator.
*/
private void setLoadingLayout() {
- RelativeLayout rl = new RelativeLayout(this);
- RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.MATCH_PARENT);
-
- ProgressBar pb = new ProgressBar(this);
- pb.setIndeterminate(true);
- RelativeLayout.LayoutParams pbLayoutParams = new RelativeLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT);
- pbLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
- rl.addView(pb, pbLayoutParams);
- addContentView(rl, rlLayoutParams);
+ progressBar.setVisibility(View.VISIBLE);
+ findViewById(R.id.feedDisplay).setVisibility(View.GONE);
}
@Override
protected void onStart() {
super.onStart();
isPaused = false;
- EventDistributor.getInstance().register(listener);
EventBus.getDefault().register(this);
}
@@ -210,7 +161,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
protected void onStop() {
super.onStop();
isPaused = true;
- EventDistributor.getInstance().unregister(listener);
EventBus.getDefault().unregister(this);
if (downloader != null && !downloader.isFinished()) {
downloader.cancel();
@@ -251,6 +201,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
@Override
+ public void finish() {
+ super.finish();
+ overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
@@ -312,6 +268,25 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
}
+ @Subscribe
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ updater = Observable.fromCallable(DBReader::getFeedList)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ feeds -> {
+ OnlineFeedViewActivity.this.feeds = feeds;
+ handleUpdatedFeedStatus(feed);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error))
+ );
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ handleUpdatedFeedStatus(feed);
+ }
+
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");
@@ -367,20 +342,14 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
* This method is executed on a background thread
*/
private void beforeShowFeedInformation(Feed feed) {
- final HtmlToPlainText formatter = new HtmlToPlainText();
- if(Feed.TYPE_ATOM1.equals(feed.getType()) && feed.getDescription() != null) {
- // remove HTML tags from descriptions
- Log.d(TAG, "Removing HTML from feed description");
- Document feedDescription = Jsoup.parse(feed.getDescription());
- feed.setDescription(StringUtils.trim(formatter.getPlainText(feedDescription)));
- }
+ Log.d(TAG, "Removing HTML from feed description");
+
+ feed.setDescription(HtmlToPlainText.getPlainText(feed.getDescription()));
+
Log.d(TAG, "Removing HTML from shownotes");
if (feed.getItems() != null) {
for (FeedItem item : feed.getItems()) {
- if (item.getDescription() != null) {
- Document itemDescription = Jsoup.parse(item.getDescription());
- item.setDescription(StringUtils.trim(formatter.getPlainText(itemDescription)));
- }
+ item.setDescription(HtmlToPlainText.getPlainText(item.getDescription()));
}
}
}
@@ -390,30 +359,27 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
* This method is executed on the GUI thread.
*/
private void showFeedInformation(final Feed feed, Map<String, String> alternateFeedUrls) {
- setContentView(R.layout.listview_activity);
-
+ progressBar.setVisibility(View.GONE);
+ findViewById(R.id.feedDisplay).setVisibility(View.VISIBLE);
this.feed = feed;
this.selectedDownloadUrl = feed.getDownload_url();
- EventDistributor.getInstance().register(listener);
- ListView listView = findViewById(R.id.listview);
listView.setSelector(android.R.color.transparent);
- 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 = header.findViewById(R.id.imgvCover);
- ImageView headerBackground = header.findViewById(R.id.imgvBackground);
- header.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
- header.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
+ ImageView cover = findViewById(R.id.imgvCover);
+ ImageView headerBackground = findViewById(R.id.imgvBackground);
+ findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
+ findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
headerBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
- TextView title = header.findViewById(R.id.txtvTitle);
- TextView author = header.findViewById(R.id.txtvAuthor);
+ TextView title = findViewById(R.id.txtvTitle);
+ TextView author = findViewById(R.id.txtvAuthor);
+ Spinner spAlternateUrls = findViewById(R.id.spinnerAlternateUrls);
+
+ View header = View.inflate(this, R.layout.onlinefeedview_header, null);
+ listView.addHeaderView(header);
TextView description = header.findViewById(R.id.txtvDescription);
- Spinner spAlternateUrls = header.findViewById(R.id.spinnerAlternateUrls);
- subscribeButton = header.findViewById(R.id.butSubscribe);
+ subscribeButton = findViewById(R.id.butSubscribe);
if (StringUtils.isNotBlank(feed.getImageUrl())) {
Glide.with(this)
@@ -441,13 +407,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
description.setText(feed.getDescription());
subscribeButton.setOnClickListener(v -> {
- if(feedInFeedlist(feed)) {
- Intent intent = new Intent(OnlineFeedViewActivity.this, MainActivity.class);
- // feed.getId() is always 0, we have to retrieve the id from the feed list from
- // the database
- intent.putExtra(MainActivity.EXTRA_FEED_ID, getFeedId(feed));
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
+ if (feedInFeedlist(feed)) {
+ openFeed();
} else {
Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
f.setPreferences(feed.getPreferences());
@@ -458,7 +419,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
Log.e(TAG, Log.getStackTraceString(e));
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, e.getMessage());
}
- setSubscribeButtonState(feed);
+ didPressSubscribe = true;
+ handleUpdatedFeedStatus(feed);
}
});
@@ -504,17 +466,28 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
});
}
- setSubscribeButtonState(feed);
+ handleUpdatedFeedStatus(feed);
}
- private void setSubscribeButtonState(Feed feed) {
+ 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));
+ finish();
+ startActivity(intent);
+ }
+
+ private void handleUpdatedFeedStatus(Feed feed) {
if (subscribeButton != null && feed != null) {
if (DownloadRequester.getInstance().isDownloadingFile(feed.getDownload_url())) {
subscribeButton.setEnabled(false);
- subscribeButton.setText(R.string.downloading_label);
+ subscribeButton.setText(R.string.subscribing_label);
} else if (feedInFeedlist(feed)) {
subscribeButton.setEnabled(true);
subscribeButton.setText(R.string.open_podcast);
+ if (didPressSubscribe) {
+ openFeed();
+ }
} else {
subscribeButton.setEnabled(true);
subscribeButton.setText(R.string.subscribe_label);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 72759c59c..376074525 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index c04ae051e..d7a4b9517 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -5,13 +5,12 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
-import android.support.annotation.Nullable;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.app.ActivityCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
-import com.afollestad.materialdialogs.MaterialDialog;
-
import org.apache.commons.lang3.ArrayUtils;
import java.io.InputStreamReader;
@@ -30,55 +29,55 @@ import de.danoeh.antennapod.core.util.LangUtils;
public class OpmlImportBaseActivity extends AppCompatActivity {
private static final String TAG = "OpmlImportBaseActivity";
- private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
+ private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
private OpmlImportWorker importWorker;
- @Nullable private Uri uri;
-
- /**
- * Handles the choices made by the user in the OpmlFeedChooserActivity and
- * starts the OpmlFeedQueuer if necessary.
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- Log.d(TAG, "Received result");
- if (resultCode == RESULT_CANCELED) {
- Log.d(TAG, "Activity was cancelled");
+ @Nullable private Uri uri;
+
+ /**
+ * Handles the choices made by the user in the OpmlFeedChooserActivity and
+ * starts the OpmlFeedQueuer if necessary.
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ Log.d(TAG, "Received result");
+ if (resultCode == RESULT_CANCELED) {
+ Log.d(TAG, "Activity was cancelled");
if (finishWhenCanceled()) {
- finish();
- }
- } else {
- int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS);
- if (selected != null && selected.length > 0) {
- OpmlFeedQueuer queuer = new OpmlFeedQueuer(this, selected) {
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- Intent intent = new Intent(OpmlImportBaseActivity.this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
-
- };
- queuer.executeAsync();
- } else {
- Log.d(TAG, "No items were selected");
- }
- }
- }
-
- void importUri(@Nullable Uri uri) {
+ finish();
+ }
+ } else {
+ int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS);
+ if (selected != null && selected.length > 0) {
+ OpmlFeedQueuer queuer = new OpmlFeedQueuer(this, selected) {
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ Intent intent = new Intent(OpmlImportBaseActivity.this, MainActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+
+ };
+ queuer.executeAsync();
+ } else {
+ Log.d(TAG, "No items were selected");
+ }
+ }
+ }
+
+ void importUri(@Nullable Uri uri) {
if(uri == null) {
- new MaterialDialog.Builder(this)
- .content(R.string.opml_import_error_no_file)
- .positiveText(android.R.string.ok)
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.opml_import_error_no_file)
+ .setPositiveButton(android.R.string.ok, null)
.show();
return;
}
- this.uri = uri;
+ this.uri = uri;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
- uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
+ uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
requestPermission();
@@ -88,30 +87,28 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
startImport();
}
- private void requestPermission() {
- String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE };
- ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- String[] permissions,
- int[] grantResults) {
- if (requestCode != PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
- return;
- }
- if (grantResults.length > 0 && ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED)) {
- startImport();
- } else {
- new MaterialDialog.Builder(this)
- .content(R.string.opml_import_ask_read_permission)
- .positiveText(android.R.string.ok)
- .negativeText(R.string.cancel_label)
- .onPositive((dialog, which) -> requestPermission())
- .onNegative((dialog, which) -> finish())
+ private void requestPermission() {
+ String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE };
+ ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String[] permissions,
+ int[] grantResults) {
+ if (requestCode != PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
+ return;
+ }
+ if (grantResults.length > 0 && ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED)) {
+ startImport();
+ } else {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.opml_import_ask_read_permission)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> requestPermission())
+ .setNegativeButton(R.string.cancel_label, (dialog, which) -> finish())
.show();
- }
- }
+ }
+ }
/** Starts the import process. */
private void startImport() {
@@ -136,10 +133,10 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
importWorker.executeAsync();
} catch (Exception e) {
Log.d(TAG, Log.getStackTraceString(e));
- String message = getString(R.string.opml_reader_error);
- new MaterialDialog.Builder(this)
- .content(message + " " + e.getMessage())
- .positiveText(android.R.string.ok)
+ String message = getString(R.string.opml_reader_error);
+ new AlertDialog.Builder(this)
+ .setMessage(message + " " + e.getMessage())
+ .setPositiveButton(android.R.string.ok, null)
.show();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index 7e0ae173f..a0f9bf6d8 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.activity;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.PreferenceFragmentCompat;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
index 52102eee1..bd1ccaea4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
@@ -5,9 +5,9 @@ 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 androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.widget.ProgressBar;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
deleted file mode 100644
index 37199ccf7..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.ProgressBar;
-import android.widget.RadioButton;
-import android.widget.TextView;
-
-import de.danoeh.antennapod.R;
-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 io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-/**
- * Displays the 'statistics' screen
- */
-public class StatisticsActivity extends AppCompatActivity
- implements AdapterView.OnItemClickListener {
-
- private static final String TAG = StatisticsActivity.class.getSimpleName();
- private static final String PREF_NAME = "StatisticsActivityPrefs";
- private static final String PREF_COUNT_ALL = "countAll";
-
- private Disposable disposable;
- private TextView totalTimeTextView;
- private ListView feedStatisticsList;
- private ProgressBar progressBar;
- private StatisticsListAdapter listAdapter;
- private boolean countAll = false;
- private SharedPreferences prefs;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- setContentView(R.layout.statistics_activity);
-
- prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
- countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
-
- 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);
- feedStatisticsList.setOnItemClickListener(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- refreshStatistics();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.statistics, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- } else if (item.getItemId() == R.id.statistics_mode) {
- selectStatisticsMode();
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void selectStatisticsMode() {
- View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null);
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setView(contentView);
- builder.setTitle(R.string.statistics_mode);
-
- if (countAll) {
- ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true);
- } else {
- ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true);
- }
-
- builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
- countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked();
- listAdapter.setCountAll(countAll);
- prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply();
- refreshStatistics();
- });
-
- builder.show();
- }
-
- private void refreshStatistics() {
- progressBar.setVisibility(View.VISIBLE);
- totalTimeTextView.setVisibility(View.GONE);
- feedStatisticsList.setVisibility(View.GONE);
- loadStatistics();
- }
-
- private void loadStatistics() {
- if (disposable != null) {
- disposable.dispose();
- }
- disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- 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)));
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- DBReader.StatisticsItem stats = listAdapter.getItem(position);
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setTitle(stats.feed.getTitle());
- dialog.setMessage(getString(R.string.statistics_details_dialog,
- countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted,
- stats.episodes,
- Converter.shortLocalizedDuration(this, countAll ?
- stats.timePlayedCountAll : stats.timePlayed),
- Converter.shortLocalizedDuration(this, stats.time)));
- dialog.setPositiveButton(android.R.string.ok, null);
- dialog.show();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
index 20e34cc52..8527949b0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -9,15 +9,13 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
-import com.afollestad.materialdialogs.MaterialDialog;
-
import java.io.File;
import de.danoeh.antennapod.R;
@@ -28,22 +26,22 @@ import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
/** Is show if there is now external storage available. */
public class StorageErrorActivity extends AppCompatActivity {
- private static final String TAG = "StorageErrorActivity";
+ private static final String TAG = "StorageErrorActivity";
private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 42;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
- setContentView(R.layout.storage_error);
+ setContentView(R.layout.storage_error);
- Button btnChooseDataFolder = findViewById(R.id.btnChooseDataFolder);
- btnChooseDataFolder.setOnClickListener(v -> {
+ 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) {
showChooseDataFolderDialog();
@@ -82,11 +80,10 @@ public class StorageErrorActivity extends AppCompatActivity {
}
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED) {
- new MaterialDialog.Builder(this)
- .content(R.string.choose_data_directory_permission_rationale)
- .positiveText(android.R.string.ok)
- .onPositive((dialog, which) -> requestPermission())
- .onNegative((dialog, which) -> finish())
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.choose_data_directory_permission_rationale)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> requestPermission())
+ .setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
.show();
}
}
@@ -101,15 +98,15 @@ public class StorageErrorActivity extends AppCompatActivity {
}
}
- @Override
- protected void onPause() {
- super.onPause();
- try {
- unregisterReceiver(mediaUpdate);
- } catch (IllegalArgumentException e) {
+ @Override
+ protected void onPause() {
+ super.onPause();
+ try {
+ unregisterReceiver(mediaUpdate);
+ } catch (IllegalArgumentException e) {
Log.e(TAG, Log.getStackTraceString(e));
- }
- }
+ }
+ }
// see PreferenceController.showChooseDataFolderDialog()
private void showChooseDataFolderDialog() {
@@ -123,9 +120,9 @@ public class StorageErrorActivity extends AppCompatActivity {
});
}
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK &&
- requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK &&
+ requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
@@ -138,46 +135,46 @@ public class StorageErrorActivity extends AppCompatActivity {
return;
}
String message = null;
- if(!path.exists()) {
- message = String.format(getString(R.string.folder_does_not_exist_error), dir);
- } else if(!path.canRead()) {
- message = String.format(getString(R.string.folder_not_readable_error), dir);
- } else if(!path.canWrite()) {
- message = String.format(getString(R.string.folder_not_writable_error), dir);
- }
-
- if(message == null) {
- Log.d(TAG, "Setting data folder: " + dir);
- UserPreferences.setDataFolder(dir);
- leaveErrorState();
- } else {
- AlertDialog.Builder ab = new AlertDialog.Builder(this);
- ab.setMessage(message);
- ab.setPositiveButton(android.R.string.ok, null);
- ab.show();
- }
- }
- }
-
- private void leaveErrorState() {
- finish();
- startActivity(new Intent(this, MainActivity.class));
- }
-
- private final BroadcastReceiver mediaUpdate = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
- if (intent.getBooleanExtra("read-only", true)) {
- Log.d(TAG, "Media was mounted; Finishing activity");
- leaveErrorState();
- } else {
- Log.d(TAG, "Media seemed to have been mounted read only");
- }
- }
- }
-
- };
+ if(!path.exists()) {
+ message = String.format(getString(R.string.folder_does_not_exist_error), dir);
+ } else if(!path.canRead()) {
+ message = String.format(getString(R.string.folder_not_readable_error), dir);
+ } else if(!path.canWrite()) {
+ message = String.format(getString(R.string.folder_not_writable_error), dir);
+ }
+
+ if(message == null) {
+ Log.d(TAG, "Setting data folder: " + dir);
+ UserPreferences.setDataFolder(dir);
+ leaveErrorState();
+ } else {
+ AlertDialog.Builder ab = new AlertDialog.Builder(this);
+ ab.setMessage(message);
+ ab.setPositiveButton(android.R.string.ok, null);
+ ab.show();
+ }
+ }
+ }
+
+ private void leaveErrorState() {
+ finish();
+ startActivity(new Intent(this, MainActivity.class));
+ }
+
+ private final BroadcastReceiver mediaUpdate = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
+ if (intent.getBooleanExtra("read-only", true)) {
+ Log.d(TAG, "Media was mounted; Finishing activity");
+ leaveErrorState();
+ } else {
+ Log.d(TAG, "Media seemed to have been mounted read only");
+ }
+ }
+ }
+
+ };
}
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 78cc15b2c..0c6ae2645 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -6,8 +6,8 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v4.view.WindowCompat;
-import android.support.v7.app.ActionBar;
+import androidx.core.view.WindowCompat;
+import androidx.appcompat.app.ActionBar;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -151,10 +151,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoview.getHolder().addCallback(surfaceHolderCallback);
videoframe.setOnTouchListener(onVideoviewTouched);
videoOverlay.setOnTouchListener((view, motionEvent) -> true); // To suppress touches directly below the slider
-
- if (Build.VERSION.SDK_INT >= 16) {
- videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- }
+ videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
videoOverlay.setFitsSystemWindows(true);
setupVideoControlsToggler();
@@ -351,9 +348,9 @@ public class VideoplayerActivity extends MediaplayerActivity {
controls.startAnimation(animation);
}
}
- int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0;
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag);
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
+ | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
videoOverlay.setFitsSystemWindows(true);
videoOverlay.setVisibility(View.GONE);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
new file mode 100644
index 000000000..474b96c38
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
@@ -0,0 +1,107 @@
+package de.danoeh.antennapod.activity;
+
+import android.Manifest;
+import android.app.WallpaperManager;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import androidx.core.content.ContextCompat;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.receiver.PlayerWidget;
+import de.danoeh.antennapod.core.service.PlayerWidgetJobService;
+
+public class WidgetConfigActivity extends AppCompatActivity {
+ private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+
+ private SeekBar opacitySeekBar;
+ private TextView opacityTextView;
+ private RelativeLayout widgetPreview;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_widget_config);
+
+ Intent configIntent = getIntent();
+ Bundle extras = configIntent.getExtras();
+ if (extras != null) {
+ appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ setResult(RESULT_CANCELED, resultValue);
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish();
+ }
+
+ displayDeviceBackground();
+ opacityTextView = findViewById(R.id.widget_opacity_textView);
+ opacitySeekBar = findViewById(R.id.widget_opacity_seekBar);
+ widgetPreview = findViewById(R.id.widgetLayout);
+ findViewById(R.id.butConfirm).setOnClickListener(this::confirmCreateWidget);
+ opacitySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ opacityTextView.setText(seekBar.getProgress() + "%");
+ int color = getColorWithAlpha(PlayerWidget.DEFAULT_COLOR, opacitySeekBar.getProgress());
+ widgetPreview.setBackgroundColor(color);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+
+ });
+ }
+
+ private void displayDeviceBackground() {
+ int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
+ if (Build.VERSION.SDK_INT < 27 || permission == PackageManager.PERMISSION_GRANTED) {
+ final WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
+ final Drawable wallpaperDrawable = wallpaperManager.getDrawable();
+ ImageView background = findViewById(R.id.widget_config_background);
+ background.setImageDrawable(wallpaperDrawable);
+ }
+ }
+
+ private void confirmCreateWidget(View v) {
+ int backgroundColor = getColorWithAlpha(PlayerWidget.DEFAULT_COLOR, opacitySeekBar.getProgress());
+
+ SharedPreferences prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(PlayerWidget.KEY_WIDGET_COLOR + appWidgetId, backgroundColor);
+ editor.apply();
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ setResult(RESULT_OK, resultValue);
+ finish();
+ PlayerWidgetJobService.updateWidget(this);
+ }
+
+ private int getColorWithAlpha(int color, int opacity) {
+ return (int) Math.round(0xFF * (0.01 * opacity)) * 0x1000000 + color;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
index 2d7898d5b..c79c611ce 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
@@ -2,11 +2,10 @@ package de.danoeh.antennapod.activity.gpoddernet;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index 2eff33339..9cd5cc3ab 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -1,10 +1,11 @@
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;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Layout;
import android.util.Log;
import android.view.ContextMenu;
@@ -23,19 +24,23 @@ import android.widget.TextView;
import com.joanzapata.iconify.Iconify;
import java.lang.ref.WeakReference;
+import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
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.feed.util.ImageResourceUtils;
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.fragment.ItemPagerFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
/**
@@ -165,7 +170,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.progress.setVisibility(View.INVISIBLE);
}
- if(media.isCurrentlyPlaying()) {
+ if (media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
@@ -189,7 +194,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.butSecondary.setTag(item);
new CoverLoader(mainActivityRef.get())
- .withUri(item.getImageLocation())
+ .withUri(ImageResourceUtils.getImageLocation(item))
.withFallbackUri(item.getFeed().getImageLocation())
.withPlaceholderView(holder.placeholder)
.withCoverView(holder.cover)
@@ -241,7 +246,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
MainActivity mainActivity = mainActivityRef.get();
if (mainActivity != null) {
long[] ids = itemAccess.getItemsIds().toArray();
- mainActivity.loadChildFragment(ItemFragment.newInstance(ids, getAdapterPosition()));
+ mainActivity.loadChildFragment(ItemPagerFragment.newInstance(ids, getAdapterPosition()));
}
}
@@ -262,7 +267,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
- inflater.inflate(R.menu.allepisodes_context, menu);
+ inflater.inflate(R.menu.feeditemlist_context, menu);
if (item != null) {
menu.setHeaderTitle(item.getTitle());
@@ -277,9 +282,15 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item);
+ }
+
+ public boolean isCurrentlyPlayingItem() {
+ return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
+ }
- contextMenuInterface.setItemVisibility(R.id.remove_new_flag_item, item.isNew());
+ public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) {
+ progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
}
}
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 c3fac7e18..f6e6da8b4 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
index 33f925e3f..098e9a616 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java
@@ -1,9 +1,8 @@
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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
index 74bc84878..e3ca5b5a5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
@@ -2,9 +2,10 @@ package de.danoeh.antennapod.adapter;
import android.app.Dialog;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
+import android.widget.ProgressBar;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -20,7 +21,6 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
-import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.ViewHolder> {
@@ -105,7 +105,7 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
private TextView path;
private TextView size;
private RadioButton radioButton;
- private MaterialProgressBar progressBar;
+ private ProgressBar progressBar;
ViewHolder(View itemView) {
super(itemView);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 789c01a26..4d66fd486 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
import android.text.Layout;
import android.text.format.DateUtils;
import android.util.Log;
@@ -13,6 +12,8 @@ import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.core.content.ContextCompat;
+
import com.joanzapata.iconify.widget.IconButton;
import com.joanzapata.iconify.widget.IconTextView;
@@ -24,6 +25,7 @@ import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
/** Displays a list of DownloadStatus entries. */
public class DownloadLogAdapter extends BaseAdapter {
@@ -132,7 +134,7 @@ public class DownloadLogAdapter extends BaseAdapter {
FeedMedia media = DBReader.getFeedMedia(holder.id);
if (media != null) {
try {
- DBTasks.downloadFeedItems(context, media.getItem());
+ DownloadRequester.getInstance().downloadMedia(context, media.getItem());
Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
} catch (DownloadRequestException e) {
e.printStackTrace();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
index 98d55dd97..b083908a8 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -17,9 +17,9 @@ 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;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
/**
* Shows a list of downloaded episodes
@@ -79,7 +79,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
}
Glide.with(context)
- .load(item.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(item))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
index df7ec46e0..66fa79a4e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
@@ -59,6 +59,8 @@ public class FeedDiscoverAdapter extends BaseAdapter {
final PodcastSearchResult podcast = getItem(position);
+ holder.imageView.setContentDescription(podcast.title);
+
Glide.with(mainActivityRef.get())
.load(podcast.imageUrl)
.apply(new RequestOptions()
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index d090bc4b1..aec0f0c91 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
+import androidx.core.content.ContextCompat;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,15 +13,18 @@ import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
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.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.ThemeUtils;
@@ -39,6 +42,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
private final int playingBackGroundColor;
private final int normalBackGroundColor;
+ private int currentlyPlayingItem = -1;
+
public FeedItemlistAdapter(Context context,
ItemAccess itemAccess,
boolean showFeedtitle,
@@ -176,8 +181,9 @@ public class FeedItemlistAdapter extends BaseAdapter {
}
typeDrawables.recycle();
- if(media.isCurrentlyPlaying()) {
+ if (media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
+ currentlyPlayingItem = position;
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
}
@@ -195,6 +201,20 @@ public class FeedItemlistAdapter extends BaseAdapter {
return convertView;
}
+ public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) {
+ if (currentlyPlayingItem != -1 && currentlyPlayingItem < getCount()) {
+ View view = listView.getChildAt(currentlyPlayingItem
+ - listView.getFirstVisiblePosition() + listView.getHeaderViewsCount());
+ if (view == null) {
+ return;
+ }
+ Holder holder = (Holder) view.getTag();
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ holder.episodeProgress.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
+ holder.lenSize.setText(Converter.getDurationStringLong(event.getDuration() - event.getPosition()));
+ }
+ }
+
static class Holder {
LinearLayout container;
TextView title;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
index c10bb7638..8d469c7a6 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -51,6 +52,17 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
.replaceAll("\\s+", " ")
.trim();
holder.description.setText(description);
+
+ final int MAX_LINES_COLLAPSED = 3;
+ holder.description.setMaxLines(MAX_LINES_COLLAPSED);
+ holder.description.setOnClickListener(v -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+ && holder.description.getMaxLines() > MAX_LINES_COLLAPSED) {
+ holder.description.setMaxLines(MAX_LINES_COLLAPSED);
+ } else {
+ holder.description.setMaxLines(2000);
+ }
+ });
}
return convertView;
}
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 be8e52cfc..50b11a15b 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -7,7 +7,7 @@ import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
index 382abfb32..5ccec0ade 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -1,12 +1,11 @@
package de.danoeh.antennapod.adapter;
-import android.content.Context;
import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.MotionEventCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
@@ -25,6 +24,8 @@ import android.widget.TextView;
import com.joanzapata.iconify.Iconify;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.fragment.ItemPagerFragment;
import org.apache.commons.lang3.ArrayUtils;
import java.lang.ref.WeakReference;
@@ -38,10 +39,10 @@ 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.feed.util.ImageResourceUtils;
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;
/**
@@ -80,11 +81,13 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
notifyDataSetChanged();
}
+ @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.queue_listitem, parent, false);
return new ViewHolder(view);
}
+ @Override
public void onBindViewHolder(ViewHolder holder, int pos) {
FeedItem item = itemAccess.getItem(pos);
holder.bind(item);
@@ -160,7 +163,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
if (activity != null) {
long[] ids = itemAccess.getQueueIds().toArray();
int position = ArrayUtils.indexOf(ids, item.getId());
- activity.loadChildFragment(ItemFragment.newInstance(ids, position));
+ activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
}
}
@@ -169,7 +172,8 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivity.get().getMenuInflater();
- inflater.inflate(R.menu.queue_context, menu);
+ inflater.inflate(R.menu.queue_context, menu); // queue-specific menu items
+ inflater.inflate(R.menu.feeditemlist_context, menu); // generic menu items for item feeds
if (item != null) {
menu.setHeaderTitle(item.getTitle());
@@ -184,7 +188,18 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
item1.setVisible(visible);
}
};
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, itemAccess.getQueueIds());
+
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item,
+ R.id.skip_episode_item); // Skip Episode is not useful in Queue, so hide it.
+ // Queue-specific menu preparation
+ final boolean keepSorted = UserPreferences.isQueueKeepSorted();
+ final LongList queueAccess = itemAccess.getQueueIds();
+ if (queueAccess.size() == 0 || queueAccess.get(0) == item.getId() || keepSorted) {
+ contextMenuInterface.setItemVisibility(R.id.move_to_top_item, false);
+ }
+ if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == item.getId() || keepSorted) {
+ contextMenuInterface.setItemVisibility(R.id.move_to_bottom_item, false);
+ }
}
@Override
@@ -288,13 +303,22 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
butSecondary.setTag(item);
new CoverLoader(mainActivity.get())
- .withUri(item.getImageLocation())
+ .withUri(ImageResourceUtils.getImageLocation(item))
.withFallbackUri(item.getFeed().getImageLocation())
.withPlaceholderView(placeholder)
.withCoverView(cover)
.load();
}
+ public boolean isCurrentlyPlayingItem() {
+ return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
+ }
+
+ public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) {
+ progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
+ progressLeft.setText(Converter.getDurationStringLong(event.getPosition()));
+ progressRight.setText(Converter.getDurationStringLong(event.getDuration()));
+ }
}
public interface ItemAccess {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java
new file mode 100644
index 000000000..10bda4efa
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java
@@ -0,0 +1,59 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+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.R;
+
+import java.util.List;
+
+/**
+ * Displays a list of items that have a subtitle and an icon.
+ */
+public class SimpleIconListAdapter<T extends SimpleIconListAdapter.ListItem> extends ArrayAdapter<T> {
+ private final Context context;
+ private final List<T> listItems;
+
+ public SimpleIconListAdapter(Context context, List<T> listItems) {
+ super(context, R.layout.simple_icon_list_item, listItems);
+ this.context = context;
+ this.listItems = listItems;
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ if (view == null) {
+ view = View.inflate(context, R.layout.simple_icon_list_item, null);
+ }
+
+ ListItem item = listItems.get(position);
+ ((TextView) view.findViewById(R.id.title)).setText(item.title);
+ ((TextView) view.findViewById(R.id.subtitle)).setText(item.subtitle);
+ Glide.with(context)
+ .load(item.imageUrl)
+ .apply(new RequestOptions()
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .fitCenter()
+ .dontAnimate())
+ .into(((ImageView) view.findViewById(R.id.icon)));
+ return view;
+ }
+
+ public static class ListItem {
+ public final String title;
+ public final String subtitle;
+ public final String imageUrl;
+
+ public ListItem(String title, String subtitle, String imageUrl) {
+ this.title = title;
+ this.subtitle = subtitle;
+ this.imageUrl = imageUrl;
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
index 31e82dbe0..f013f2a49 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
@@ -1,31 +1,30 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-
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;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.view.PieChartView;
/**
* Adapter for the statistics list
*/
-public class StatisticsListAdapter extends BaseAdapter {
+public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ private static final int TYPE_HEADER = 0;
+ private static final int TYPE_FEED = 1;
private final Context context;
- private List<DBReader.StatisticsItem> feedTime = new ArrayList<>();
+ private DBReader.StatisticsData statisticsData;
private boolean countAll = true;
public StatisticsListAdapter(Context context) {
@@ -37,66 +36,102 @@ public class StatisticsListAdapter extends BaseAdapter {
}
@Override
- public int getCount() {
- return feedTime.size();
+ public int getItemCount() {
+ return statisticsData.feedTime.size() + 1;
}
- @Override
public DBReader.StatisticsItem getItem(int position) {
- return feedTime.get(position);
+ if (position == 0) {
+ return null;
+ }
+ return statisticsData.feedTime.get(position - 1);
}
@Override
- public long getItemId(int position) {
- return feedTime.get(position).feed.getId();
+ public int getItemViewType(int position) {
+ return position == 0 ? TYPE_HEADER : TYPE_FEED;
}
+ @NonNull
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- StatisticsHolder holder;
- Feed feed = feedTime.get(position).feed;
-
- if (convertView == null) {
- holder = new StatisticsHolder();
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.statistics_listitem, parent, false);
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ if (viewType == TYPE_HEADER) {
+ return new HeaderHolder(inflater.inflate(R.layout.statistics_listitem_total_time, parent, false));
+ }
+ return new StatisticsHolder(inflater.inflate(R.layout.statistics_listitem, parent, false));
+ }
- holder.image = convertView.findViewById(R.id.imgvCover);
- holder.title = convertView.findViewById(R.id.txtvTitle);
- holder.time = convertView.findViewById(R.id.txtvTime);
- convertView.setTag(holder);
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
+ if (getItemViewType(position) == TYPE_HEADER) {
+ HeaderHolder holder = (HeaderHolder) h;
+ long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime;
+ holder.totalTime.setText(Converter.shortLocalizedDuration(context, time));
+ float[] dataValues = new float[statisticsData.feedTime.size()];
+ for (int i = 0; i < statisticsData.feedTime.size(); i++) {
+ DBReader.StatisticsItem item = statisticsData.feedTime.get(i);
+ dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
+ }
+ holder.pieChart.setData(dataValues);
} else {
- holder = (StatisticsHolder) convertView.getTag();
+ StatisticsHolder holder = (StatisticsHolder) h;
+ DBReader.StatisticsItem statsItem = statisticsData.feedTime.get(position - 1);
+ Glide.with(context)
+ .load(statsItem.feed.getImageLocation())
+ .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(statsItem.feed.getTitle());
+ long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
+ holder.time.setText(Converter.shortLocalizedDuration(context, time));
+
+ holder.itemView.setOnClickListener(v -> {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(statsItem.feed.getTitle());
+ dialog.setMessage(context.getString(R.string.statistics_details_dialog,
+ countAll ? statsItem.episodesStartedIncludingMarked : statsItem.episodesStarted,
+ statsItem.episodes, Converter.shortLocalizedDuration(context,
+ countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed),
+ Converter.shortLocalizedDuration(context, statsItem.time)));
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.show();
+ });
}
-
- Glide.with(context)
- .load(feed.getImageLocation())
- .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());
- holder.time.setText(Converter.shortLocalizedDuration(context,
- countAll ? feedTime.get(position).timePlayedCountAll
- : feedTime.get(position).timePlayed));
- return convertView;
}
- public void update(List<DBReader.StatisticsItem> feedTime) {
- this.feedTime = feedTime;
+ public void update(DBReader.StatisticsData statistics) {
+ this.statisticsData = statistics;
notifyDataSetChanged();
}
- static class StatisticsHolder {
+ static class HeaderHolder extends RecyclerView.ViewHolder {
+ TextView totalTime;
+ PieChartView pieChart;
+
+ HeaderHolder(View itemView) {
+ super(itemView);
+ totalTime = itemView.findViewById(R.id.total_time);
+ pieChart = itemView.findViewById(R.id.pie_chart);
+ }
+ }
+
+ static class StatisticsHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView title;
TextView time;
+
+ StatisticsHolder(View itemView) {
+ super(itemView);
+ image = itemView.findViewById(R.id.imgvCover);
+ title = itemView.findViewById(R.id.txtvTitle);
+ time = itemView.findViewById(R.id.txtvTime);
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
index e0fb65c61..3141c6046 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
-import android.support.v4.app.Fragment;
+import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -30,7 +30,6 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
public static final Object ADD_ITEM_OBJ = new Object();
/** the position in the view that holds the add item; 0 is the first, -1 is the last position */
- private static final int ADD_POSITION = -1;
private static final String TAG = "SubscriptionsAdapter";
private final WeakReference<MainActivity> mainActivityRef;
@@ -41,28 +40,14 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
this.itemAccess = itemAccess;
}
- private int getAddTilePosition() {
- if(ADD_POSITION < 0) {
- return ADD_POSITION + getCount();
- }
- return ADD_POSITION;
- }
-
- private int getAdjustedPosition(int origPosition) {
- return origPosition < getAddTilePosition() ? origPosition : origPosition - 1;
- }
-
@Override
public int getCount() {
- return 1 + itemAccess.getCount();
+ return itemAccess.getCount();
}
@Override
public Object getItem(int position) {
- if (position == getAddTilePosition()) {
- return ADD_ITEM_OBJ;
- }
- return itemAccess.getItem(getAdjustedPosition(position));
+ return itemAccess.getItem(position);
}
@Override
@@ -72,10 +57,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
@Override
public long getItemId(int position) {
- if (position == getAddTilePosition()) {
- return 0;
- }
- return itemAccess.getItem(getAdjustedPosition(position)).getId();
+ return itemAccess.getItem(position).getId();
}
@Override
@@ -98,24 +80,11 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
holder = (Holder) convertView.getTag();
}
- if (position == getAddTilePosition()) {
- holder.feedTitle.setText("{md-add 500%}\n\n" + mainActivityRef.get().getString(R.string.add_feed_label));
- holder.feedTitle.setVisibility(View.VISIBLE);
- // prevent any accidental re-use of old values (not sure how that would happen...)
- holder.count.setPrimaryText("");
- // make it go away, we don't need it for add feed
- holder.count.setVisibility(View.INVISIBLE);
-
- // when this holder is reused, we could else end up with a cover image
- Glide.with(mainActivityRef.get()).clear(holder.imageView);
-
- return convertView;
- }
-
final Feed feed = (Feed) getItem(position);
if (feed == null) return null;
holder.feedTitle.setText(feed.getTitle());
+ holder.imageView.setContentDescription(feed.getTitle());
holder.feedTitle.setVisibility(View.VISIBLE);
int count = itemAccess.getFeedCounter(feed.getId());
if(count > 0) {
@@ -137,12 +106,8 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (position == getAddTilePosition()) {
- mainActivityRef.get().loadChildFragment(new AddFeedFragment());
- } else {
- Fragment fragment = FeedItemlistFragment.newInstance(getItemId(position));
- mainActivityRef.get().loadChildFragment(fragment);
- }
+ Fragment fragment = FeedItemlistFragment.newInstance(getItemId(position));
+ mainActivityRef.get().loadChildFragment(fragment);
}
static class Holder {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
index 3299db3ab..a8001eeb1 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
index 1275a799b..10458ed46 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import android.widget.Toast;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
index c1559528e..026386cf9 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java
@@ -1,16 +1,16 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
import android.widget.Toast;
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-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;
@@ -64,7 +64,7 @@ class DownloadActionButton extends ItemActionButton {
private void downloadEpisode(Context context) {
try {
- DBTasks.downloadFeedItems(context, item);
+ DownloadRequester.getInstance().downloadMedia(context, item);
Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
} catch (DownloadRequestException e) {
e.printStackTrace();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
index da5ebf6e1..861c6a4be 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
@@ -2,14 +2,15 @@ package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
import android.content.res.TypedArray;
-import android.support.annotation.AttrRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.view.View;
import android.widget.ImageButton;
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.storage.DownloadRequester;
public abstract class ItemActionButton {
@@ -20,12 +21,12 @@ public abstract class ItemActionButton {
}
@StringRes
- abstract public int getLabel();
+ public abstract int getLabel();
@AttrRes
- abstract public int getDrawable();
+ public abstract int getDrawable();
- abstract public void onClick(Context context);
+ public abstract void onClick(Context context);
public int getVisibility() {
return View.VISIBLE;
@@ -43,6 +44,8 @@ public abstract class ItemActionButton {
return new PlayActionButton(item);
} else if (isDownloadingMedia) {
return new CancelDownloadActionButton(item);
+ } else if (UserPreferences.streamOverDownload()) {
+ return new StreamActionButton(item);
} else if (MobileDownloadHelper.userAllowedMobileDownloads() || !MobileDownloadHelper.userChoseAddToQueue() || isInQueue) {
return new DownloadActionButton(item, isInQueue);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
index 4d906cee5..354ded73d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import android.view.View;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java
index f8d2a139e..77efd9023 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java
@@ -3,15 +3,14 @@ package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
import android.widget.Toast;
-import com.afollestad.materialdialogs.MaterialDialog;
-
+import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
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;
class MobileDownloadHelper {
private static long addToQueueTimestamp;
@@ -27,16 +26,15 @@ class MobileDownloadHelper {
}
static void confirmMobileDownload(final Context context, final FeedItem item) {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context)
- .title(R.string.confirm_mobile_download_dialog_title)
- .content(R.string.confirm_mobile_download_dialog_message)
- .positiveText(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily))
- .onPositive((dialog, which) -> downloadFeedItems(context, item));
+ AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setTitle(R.string.confirm_mobile_download_dialog_title)
+ .setMessage(R.string.confirm_mobile_download_dialog_message)
+ .setPositiveButton(context.getText(R.string.confirm_mobile_download_dialog_enable_temporarily),
+ (dialog, which) -> downloadFeedItems(context, item));
if (!DBReader.getQueueIDList().contains(item.getId())) {
- builder
- .content(R.string.confirm_mobile_download_dialog_message_not_in_queue)
- .neutralText(R.string.confirm_mobile_download_dialog_only_add_to_queue)
- .onNeutral((dialog, which) -> addToQueue(context, item));
+ builder.setMessage(R.string.confirm_mobile_download_dialog_message_not_in_queue)
+ .setNeutralButton(R.string.confirm_mobile_download_dialog_only_add_to_queue,
+ (dialog, which) -> addToQueue(context, item));
}
builder.show();
}
@@ -50,7 +48,7 @@ class MobileDownloadHelper {
private static void downloadFeedItems(Context context, FeedItem item) {
allowMobileDownloadTimestamp = System.currentTimeMillis();
try {
- DBTasks.downloadFeedItems(context, item);
+ DownloadRequester.getInstance().downloadMedia(context, item);
Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
} catch (DownloadRequestException e) {
e.printStackTrace();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
index 3992c7240..0d314b5eb 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.adapter.actionbutton;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.StringRes;
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -12,7 +12,6 @@ import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE;
-import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE;
class PlayActionButton extends ItemActionButton {
@@ -52,12 +51,14 @@ class PlayActionButton extends ItemActionButton {
}
private void togglePlayPause(Context context, FeedMedia media) {
- new PlaybackServiceStarter(context, media)
- .startWhenPrepared(true)
- .shouldStream(false)
- .start();
-
- String pauseOrResume = media.isCurrentlyPlaying() ? ACTION_PAUSE_PLAY_CURRENT_EPISODE : ACTION_RESUME_PLAY_CURRENT_EPISODE;
- IntentUtils.sendLocalBroadcast(context, pauseOrResume);
+ if (media.isCurrentlyPlaying()) {
+ IntentUtils.sendLocalBroadcast(context, ACTION_PAUSE_PLAY_CURRENT_EPISODE);
+ } else {
+ new PlaybackServiceStarter(context, media)
+ .callEvenIfRunning(true)
+ .startWhenPrepared(true)
+ .shouldStream(false)
+ .start();
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
new file mode 100644
index 000000000..c1e619fdf
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
@@ -0,0 +1,64 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
+
+import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE;
+
+public class StreamActionButton extends ItemActionButton {
+
+ StreamActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.stream_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ FeedMedia media = item.getMedia();
+ if (media != null && media.isCurrentlyPlaying()) {
+ return R.attr.av_pause;
+ }
+ return R.attr.action_stream;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ final FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ if (media.isPlaying()) {
+ togglePlayPause(context, media);
+ } else {
+ DBTasks.playMedia(context, media, false, true, true);
+ }
+ }
+
+ private void togglePlayPause(Context context, FeedMedia media) {
+ if (media.isCurrentlyPlaying()) {
+ IntentUtils.sendLocalBroadcast(context, ACTION_PAUSE_PLAY_CURRENT_EPISODE);
+ } else {
+ new PlaybackServiceStarter(context, media)
+ .callEvenIfRunning(true)
+ .startWhenPrepared(true)
+ .shouldStream(true)
+ .start();
+ }
+ }
+}
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 f5213e4ab..cc3b6fba0 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
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.adapter.itunes;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
new file mode 100644
index 000000000..339a98dfa
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
@@ -0,0 +1,72 @@
+package de.danoeh.antennapod.asynctask;
+
+import android.content.Context;
+import android.net.Uri;
+import androidx.annotation.NonNull;
+import androidx.documentfile.provider.DocumentFile;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.util.LangUtils;
+import io.reactivex.Observable;
+
+/**
+ * Writes an OPML file into the user selected export directory in the background.
+ */
+public class DocumentFileExportWorker {
+
+ private final @NonNull ExportWriter exportWriter;
+ private @NonNull Context context;
+ private @NonNull Uri outputFileUri;
+
+ public DocumentFileExportWorker(@NonNull ExportWriter exportWriter, @NonNull Context context, @NonNull Uri outputFileUri) {
+ this.exportWriter = exportWriter;
+ this.context = context;
+ this.outputFileUri = outputFileUri;
+ }
+
+ public Observable<DocumentFile> exportObservable() {
+ DocumentFile output = DocumentFile.fromSingleUri(context, outputFileUri);
+ return Observable.create(subscriber -> {
+ OutputStream outputStream = null;
+ OutputStreamWriter writer = null;
+ try {
+ Uri uri = output.getUri();
+ if (uri == null) {
+ throw new FileNotFoundException("Export file not found.");
+ }
+ outputStream = context.getContentResolver().openOutputStream(uri);
+ if (outputStream == null) {
+ throw new IOException();
+ }
+ writer = new OutputStreamWriter(outputStream, LangUtils.UTF_8);
+ exportWriter.writeDocument(DBReader.getFeedList(), writer);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ }
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ }
+ subscriber.onComplete();
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
index 219725b01..40b101ddf 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.asynctask;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.io.File;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index 13b95907f..b88b58537 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -3,7 +3,7 @@ package de.danoeh.antennapod.asynctask;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
index eb70d8e0b..c3f5d898c 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/PlaybackServiceCallbacksImpl.java
@@ -35,6 +35,6 @@ public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
@Override
public int getNotificationIconResource(Context context) {
- return R.drawable.ic_stat_antenna_default;
+ return R.drawable.ic_antenna;
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
index c185a5557..ec285a8f6 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ChooseDataFolderDialog.java
@@ -2,14 +2,16 @@ package de.danoeh.antennapod.dialog;
import android.content.Context;
-import com.afollestad.materialdialogs.MaterialDialog;
-
+import android.view.View;
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DataFolderAdapter;
public class ChooseDataFolderDialog {
- public static abstract class RunnableWithString implements Runnable {
+ public abstract static class RunnableWithString implements Runnable {
public RunnableWithString() {
super();
}
@@ -25,21 +27,23 @@ public class ChooseDataFolderDialog {
DataFolderAdapter adapter = new DataFolderAdapter(context, handlerFunc);
if (adapter.getItemCount() == 0) {
- new MaterialDialog.Builder(context)
- .title(R.string.error_label)
- .content(R.string.external_storage_error_msg)
- .neutralText(android.R.string.ok)
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.error_label)
+ .setMessage(R.string.external_storage_error_msg)
+ .setPositiveButton(android.R.string.ok, null)
.show();
return;
}
- MaterialDialog dialog = new MaterialDialog.Builder(context)
- .title(R.string.choose_data_directory)
- .content(R.string.choose_data_directory_message)
- .adapter(adapter, null)
- .negativeText(R.string.cancel_label)
- .cancelable(true)
- .build();
+ View content = View.inflate(context, R.layout.choose_data_folder_dialog, null);
+ AlertDialog dialog = new AlertDialog.Builder(context)
+ .setView(content)
+ .setTitle(R.string.choose_data_directory)
+ .setMessage(R.string.choose_data_directory_message)
+ .setNegativeButton(R.string.cancel_label, null)
+ .create();
+ ((RecyclerView) content.findViewById(R.id.recyclerView)).setLayoutManager(new LinearLayoutManager(context));
+ ((RecyclerView) content.findViewById(R.id.recyclerView)).setAdapter(adapter);
adapter.setDialog(dialog);
dialog.show();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index ed35495fa..ff131aeba 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -4,16 +4,6 @@ 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;
@@ -24,6 +14,17 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.PluralsRes;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.collection.ArrayMap;
+import androidx.core.app.ActivityCompat;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.material.snackbar.Snackbar;
import com.leinardi.android.speeddial.SpeedDialView;
import java.util.ArrayList;
@@ -35,10 +36,12 @@ import java.util.Map;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
-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.FeedItemPermutors;
import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.core.util.SortOrder;
public class EpisodesApplyActionFragment extends Fragment {
@@ -263,6 +266,18 @@ public class EpisodesApplyActionFragment extends Fragment {
mSelectToggle.setTitle(titleResId);
}
+ private static final Map<Integer, SortOrder> menuItemIdToSortOrder;
+ static {
+ Map<Integer, SortOrder> map = new ArrayMap<>();
+ map.put(R.id.sort_title_a_z, SortOrder.EPISODE_TITLE_A_Z);
+ map.put(R.id.sort_title_z_a, SortOrder.EPISODE_TITLE_Z_A);
+ map.put(R.id.sort_date_new_old, SortOrder.DATE_NEW_OLD);
+ map.put(R.id.sort_date_old_new, SortOrder.DATE_OLD_NEW);
+ map.put(R.id.sort_duration_long_short, SortOrder.DURATION_LONG_SHORT);
+ map.put(R.id.sort_duration_short_long, SortOrder.DURATION_SHORT_LONG);
+ menuItemIdToSortOrder = Collections.unmodifiableMap(map);
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@StringRes int resId = 0;
@@ -305,24 +320,12 @@ public class EpisodesApplyActionFragment extends Fragment {
checkWithMedia();
resId = R.string.selected_has_media_label;
break;
- case R.id.sort_title_a_z:
- sortByTitle(false);
- return true;
- case R.id.sort_title_z_a:
- sortByTitle(true);
- return true;
- case R.id.sort_date_new_old:
- sortByDate(true);
- return true;
- case R.id.sort_date_old_new:
- sortByDate(false);
- return true;
- case R.id.sort_duration_long_short:
- sortByDuration(true);
- return true;
- case R.id.sort_duration_short_long:
- sortByDuration(false);
- return true;
+ default: // handle various sort options
+ SortOrder sortOrder = menuItemIdToSortOrder.get(item.getItemId());
+ if (sortOrder != null) {
+ sort(sortOrder);
+ return true;
+ }
}
if(resId != 0) {
Snackbar.make(getActivity().findViewById(R.id.content), resId, Snackbar.LENGTH_SHORT)
@@ -333,52 +336,9 @@ public class EpisodesApplyActionFragment extends Fragment {
}
}
- private void sortByTitle(final boolean reverse) {
- Collections.sort(episodes, (lhs, rhs) -> {
- if (reverse) {
- return -1 * lhs.getTitle().compareTo(rhs.getTitle());
- } else {
- return lhs.getTitle().compareTo(rhs.getTitle());
- }
- });
- refreshTitles();
- refreshCheckboxes();
- }
-
- private void sortByDate(final boolean reverse) {
- Collections.sort(episodes, (lhs, rhs) -> {
- if (lhs.getPubDate() == null) {
- return -1;
- } else if (rhs.getPubDate() == null) {
- return 1;
- }
- int code = lhs.getPubDate().compareTo(rhs.getPubDate());
- if (reverse) {
- return -1 * code;
- } else {
- return code;
- }
- });
- refreshTitles();
- refreshCheckboxes();
- }
-
- private void sortByDuration(final boolean reverse) {
- Collections.sort(episodes, (lhs, rhs) -> {
- int ordering;
- if (!lhs.hasMedia()) {
- ordering = 1;
- } else if (!rhs.hasMedia()) {
- ordering = -1;
- } else {
- ordering = lhs.getMedia().getDuration() - rhs.getMedia().getDuration();
- }
- if(reverse) {
- return -1 * ordering;
- } else {
- return ordering;
- }
- });
+ private void sort(@NonNull SortOrder sortOrder) {
+ FeedItemPermutors.getPermutor(sortOrder)
+ .reorder(episodes);
refreshTitles();
refreshCheckboxes();
}
@@ -525,7 +485,7 @@ public class EpisodesApplyActionFragment extends Fragment {
}
}
try {
- DBTasks.downloadFeedItems(getActivity(), toDownload.toArray(new FeedItem[toDownload.size()]));
+ DownloadRequester.getInstance().downloadMedia(getActivity(), toDownload.toArray(new FeedItem[toDownload.size()]));
} catch (DownloadRequestException e) {
e.printStackTrace();
DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
index 607084c42..d2912f90f 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.text.TextUtils;
import java.util.Arrays;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
index 933ced0f9..17668586b 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java
new file mode 100644
index 000000000..2ee716c7c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java
@@ -0,0 +1,51 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.util.SortOrder;
+
+public abstract class IntraFeedSortDialog {
+
+ @Nullable
+ protected SortOrder currentSortOrder;
+ @NonNull
+ protected Context context;
+
+ public IntraFeedSortDialog(@NonNull Context context, @Nullable SortOrder sortOrder) {
+ this.context = context;
+ this.currentSortOrder = sortOrder;
+ }
+
+ public void openDialog() {
+ final String[] items = context.getResources().getStringArray(R.array.feed_episodes_sort_options);
+ final String[] valueStrs = context.getResources().getStringArray(R.array.feed_episodes_sort_values);
+ final SortOrder[] values = new SortOrder[valueStrs.length];
+ for (int i = 0; i < valueStrs.length; i++) {
+ values[i] = SortOrder.valueOf(valueStrs[i]);
+ }
+
+ int idxCurrentSort = -1;
+ for (int i = 0; i < values.length; i++) {
+ if (currentSortOrder == values[i]) {
+ idxCurrentSort = i;
+ break;
+ }
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.sort);
+ builder.setSingleChoiceItems(items, idxCurrentSort, (dialog, idxNewSort) -> {
+ updateSort(values[idxNewSort]);
+ dialog.dismiss();
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
+
+ protected abstract void updateSort(@NonNull SortOrder sortOrder);
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index e8c7520b7..3e4e40a5b 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -2,20 +2,22 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
-import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import java.util.Locale;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
-import java.util.Locale;
-
public class PlaybackControlsDialog extends DialogFragment {
private static final float PLAYBACK_SPEED_STEP = 0.05f;
private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
@@ -23,7 +25,7 @@ public class PlaybackControlsDialog extends DialogFragment {
private static final String ARGUMENT_IS_PLAYING_VIDEO = "isPlayingVideo";
private PlaybackController controller;
- private MaterialDialog dialog;
+ private AlertDialog dialog;
private boolean isPlayingVideo;
public static PlaybackControlsDialog newInstance(boolean isPlayingVideo) {
@@ -41,7 +43,12 @@ public class PlaybackControlsDialog extends DialogFragment {
@Override
public void onStart() {
super.onStart();
- controller = new PlaybackController(getActivity(), false);
+ controller = new PlaybackController(getActivity(), false) {
+ @Override
+ public void setupGUI() {
+ setupUi();
+ }
+ };
controller.init();
setupUi();
}
@@ -58,15 +65,14 @@ public class PlaybackControlsDialog extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
isPlayingVideo = getArguments() != null && getArguments().getBoolean(ARGUMENT_IS_PLAYING_VIDEO);
- dialog = new MaterialDialog.Builder(getContext())
- .title(R.string.audio_controls)
- .customView(R.layout.audio_controls, true)
- .neutralText(R.string.close_label)
- .onNeutral((dialog1, which) -> {
- final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
- final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
+ dialog = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.audio_controls)
+ .setView(R.layout.audio_controls)
+ .setPositiveButton(R.string.close_label, (dialog1, which) -> {
+ final SeekBar left = dialog.findViewById(R.id.volume_left);
+ final SeekBar right = dialog.findViewById(R.id.volume_right);
UserPreferences.setVolume(left.getProgress(), right.getProgress());
- }).build();
+ }).create();
return dialog;
}
@@ -109,6 +115,7 @@ public class PlaybackControlsDialog extends DialogFragment {
controller.setPlaybackSpeed(playbackSpeed);
String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
+ PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(playbackSpeed);
if (isPlayingVideo) {
UserPreferences.setVideoPlaybackSpeed(speedPref);
} else {
@@ -135,7 +142,7 @@ public class PlaybackControlsDialog extends DialogFragment {
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
- barPlaybackSpeed.setProgress((int) ((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
+ barPlaybackSpeed.setProgress(Math.round((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
@@ -206,9 +213,11 @@ public class PlaybackControlsDialog extends DialogFragment {
}
private float getCurrentSpeed() {
- if (isPlayingVideo) {
- return UserPreferences.getVideoPlaybackSpeed();
+ Playable media = null;
+ if (controller != null) {
+ media = controller.getMedia();
}
- return UserPreferences.getPlaybackSpeed();
+
+ return PlaybackSpeedUtils.getCurrentPlaybackSpeed(media);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
index c1008a380..11256f2de 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -4,7 +4,8 @@ import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.content.ContextCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -16,10 +17,6 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
-import com.afollestad.materialdialogs.DialogAction;
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.afollestad.materialdialogs.internal.MDButton;
-
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
@@ -48,7 +45,7 @@ public class ProxyDialog {
private final Context context;
- private MaterialDialog dialog;
+ private AlertDialog dialog;
private Spinner spType;
private EditText etHost;
@@ -64,54 +61,53 @@ public class ProxyDialog {
this.context = context;
}
- public Dialog createDialog() {
- dialog = new MaterialDialog.Builder(context)
- .title(R.string.pref_proxy_title)
- .customView(R.layout.proxy_settings, true)
- .positiveText(R.string.proxy_test_label)
- .negativeText(R.string.cancel_label)
- .onPositive((dialog1, which) -> {
- if(!testSuccessful) {
- dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
- test();
- return;
- }
- String type = (String) ((Spinner) dialog1.findViewById(R.id.spType)).getSelectedItem();
- ProxyConfig proxy;
- if(Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) {
- proxy = ProxyConfig.direct();
- } else {
- String host = etHost.getText().toString();
- String port = etPort.getText().toString();
- String username = etUsername.getText().toString();
- if(TextUtils.isEmpty(username)) {
- username = null;
- }
- String password = etPassword.getText().toString();
- if(TextUtils.isEmpty(password)) {
- password = null;
- }
- int portValue = 0;
- if(!TextUtils.isEmpty(port)) {
- portValue = Integer.valueOf(port);
- }
- if (Proxy.Type.valueOf(type) == Proxy.Type.SOCKS) {
- proxy = ProxyConfig.socks(host, portValue, username, password);
- } else {
- proxy = ProxyConfig.http(host, portValue, username, password);
- }
- }
- UserPreferences.setProxyConfig(proxy);
- AntennapodHttpClient.reinit();
- dialog.dismiss();
- })
- .onNegative((dialog1, which) -> dialog1.dismiss())
- .autoDismiss(false)
- .build();
- View view = dialog.getCustomView();
- spType = view.findViewById(R.id.spType);
+ public Dialog show() {
+ View content = View.inflate(context, R.layout.proxy_settings, null);
+ dialog = new AlertDialog.Builder(context)
+ .setTitle(R.string.pref_proxy_title)
+ .setView(content)
+ .setNegativeButton(R.string.cancel_label, null)
+ .setPositiveButton(R.string.proxy_test_label, null)
+ .show();
+ // To prevent cancelling the dialog on button click
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((view) -> {
+ if (!testSuccessful) {
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ test();
+ return;
+ }
+ String type = (String) ((Spinner) content.findViewById(R.id.spType)).getSelectedItem();
+ ProxyConfig proxy;
+ if (Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) {
+ proxy = ProxyConfig.direct();
+ } else {
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ if(TextUtils.isEmpty(username)) {
+ username = null;
+ }
+ String password = etPassword.getText().toString();
+ if(TextUtils.isEmpty(password)) {
+ password = null;
+ }
+ int portValue = 0;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ if (Proxy.Type.valueOf(type) == Proxy.Type.SOCKS) {
+ proxy = ProxyConfig.socks(host, portValue, username, password);
+ } else {
+ proxy = ProxyConfig.http(host, portValue, username, password);
+ }
+ }
+ UserPreferences.setProxyConfig(proxy);
+ AntennapodHttpClient.reinit();
+ dialog.dismiss();
+ });
- List<String> types= new ArrayList<>();
+ spType = content.findViewById(R.id.spType);
+ List<String> types = new ArrayList<>();
types.add(Proxy.Type.DIRECT.name());
types.add(Proxy.Type.HTTP.name());
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -123,22 +119,22 @@ public class ProxyDialog {
spType.setAdapter(adapter);
ProxyConfig proxyConfig = UserPreferences.getProxyConfig();
spType.setSelection(adapter.getPosition(proxyConfig.type.name()));
- etHost = view.findViewById(R.id.etHost);
+ etHost = content.findViewById(R.id.etHost);
if(!TextUtils.isEmpty(proxyConfig.host)) {
etHost.setText(proxyConfig.host);
}
etHost.addTextChangedListener(requireTestOnChange);
- etPort = view.findViewById(R.id.etPort);
+ etPort = content.findViewById(R.id.etPort);
if(proxyConfig.port > 0) {
etPort.setText(String.valueOf(proxyConfig.port));
}
etPort.addTextChangedListener(requireTestOnChange);
- etUsername = view.findViewById(R.id.etUsername);
+ etUsername = content.findViewById(R.id.etUsername);
if(!TextUtils.isEmpty(proxyConfig.username)) {
etUsername.setText(proxyConfig.username);
}
etUsername.addTextChangedListener(requireTestOnChange);
- etPassword = view.findViewById(R.id.etPassword);
+ etPassword = content.findViewById(R.id.etPassword);
if(!TextUtils.isEmpty(proxyConfig.password)) {
etPassword.setText(proxyConfig.username);
}
@@ -159,7 +155,7 @@ public class ProxyDialog {
enableSettings(false);
}
});
- txtvMessage = view.findViewById(R.id.txtvMessage);
+ txtvMessage = content.findViewById(R.id.txtvMessage);
checkValidity();
return dialog;
}
@@ -230,14 +226,12 @@ public class ProxyDialog {
private void setTestRequired(boolean required) {
if(required) {
testSuccessful = false;
- MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
- button.setText(context.getText(R.string.proxy_test_label));
- button.setEnabled(true);
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.proxy_test_label);
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
} else {
testSuccessful = true;
- MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
- button.setText(context.getText(android.R.string.ok));
- button.setEnabled(true);
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(android.R.string.ok);
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
index 24656ed29..7cb274708 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -2,19 +2,17 @@ package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Uri;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import android.util.Log;
-import com.afollestad.materialdialogs.MaterialDialog;
-
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
+import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.util.IntentUtils;
public class RatingDialog {
@@ -59,14 +57,10 @@ public class RatingDialog {
private static void rateNow() {
Context context = mContext.get();
- if(context == null) {
+ if (context == null) {
return;
}
- final String appPackage = "de.danoeh.antennapod";
- final Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=" + appPackage);
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
+ IntentUtils.openInBrowser(context, "https://play.google.com/store/apps/details?id=de.danoeh.antennapod");
saveRated();
}
@@ -102,21 +96,18 @@ public class RatingDialog {
}
@Nullable
- private static MaterialDialog createDialog() {
+ private static AlertDialog createDialog() {
Context context = mContext.get();
- if(context == null) {
+ if (context == null) {
return null;
}
- return new MaterialDialog.Builder(context)
- .title(R.string.rating_title)
- .content(R.string.rating_message)
- .positiveText(R.string.rating_now_label)
- .negativeText(R.string.rating_never_label)
- .neutralText(R.string.rating_later_label)
- .onPositive((dialog, which) -> rateNow())
- .onNegative((dialog, which) -> saveRated())
- .onNeutral((dialog, which) -> resetStartDate())
- .cancelListener(dialog1 -> resetStartDate())
- .build();
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.rating_title)
+ .setMessage(R.string.rating_message)
+ .setPositiveButton(R.string.rating_now_label, (dialog, which) -> rateNow())
+ .setNegativeButton(R.string.rating_never_label, (dialog, which) -> saveRated())
+ .setNeutralButton(R.string.rating_later_label, (dialog, which) -> resetStartDate())
+ .setOnCancelListener(dialog1 -> resetStartDate())
+ .create();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java
index 31a544582..699c6f492 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java
@@ -3,10 +3,12 @@ package de.danoeh.antennapod.dialog;
import android.app.Activity;
import android.text.InputType;
-import com.afollestad.materialdialogs.MaterialDialog;
-
import java.lang.ref.WeakReference;
+import android.view.View;
+import android.widget.EditText;
+import androidx.appcompat.app.AlertDialog;
+import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -25,20 +27,24 @@ public class RenameFeedDialog {
if(activity == null) {
return;
}
- new MaterialDialog.Builder(activity)
- .title(de.danoeh.antennapod.core.R.string.rename_feed_label)
- .inputType(InputType.TYPE_CLASS_TEXT)
- .input(feed.getTitle(), feed.getTitle(), true, (dialog, input) -> {
- feed.setCustomTitle(input.toString());
+
+ View content = View.inflate(activity, R.layout.edit_text_dialog, null);
+ EditText editText = content.findViewById(R.id.text);
+ editText.setText(feed.getTitle());
+ AlertDialog dialog = new AlertDialog.Builder(activity)
+ .setView(content)
+ .setTitle(de.danoeh.antennapod.core.R.string.rename_feed_label)
+ .setPositiveButton(android.R.string.ok, (d, input) -> {
+ feed.setCustomTitle(editText.getText().toString());
DBWriter.setFeedCustomTitle(feed);
- dialog.dismiss();
})
- .neutralText(de.danoeh.antennapod.core.R.string.reset)
- .onNeutral((dialog, which) -> dialog.getInputEditText().setText(feed.getFeedTitle()))
- .negativeText(de.danoeh.antennapod.core.R.string.cancel_label)
- .onNegative((dialog, which) -> dialog.dismiss())
- .autoDismiss(false)
+ .setNeutralButton(de.danoeh.antennapod.core.R.string.reset, null)
+ .setNegativeButton(de.danoeh.antennapod.core.R.string.cancel_label, null)
.show();
+
+ // To prevent cancelling the dialog on button click
+ dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(
+ (view) -> editText.setText(feed.getFeedTitle()));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index dc056a3f9..8d176c708 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -3,7 +3,6 @@ package de.danoeh.antennapod.dialog;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
-import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
@@ -12,9 +11,7 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
-import com.afollestad.materialdialogs.DialogAction;
-import com.afollestad.materialdialogs.MaterialDialog;
-
+import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
@@ -26,7 +23,7 @@ public abstract class SleepTimerDialog {
private final Context context;
- private MaterialDialog dialog;
+ private AlertDialog dialog;
private EditText etxtTime;
private Spinner spTimeUnit;
private CheckBox cbShakeToReset;
@@ -38,40 +35,38 @@ public abstract class SleepTimerDialog {
this.context = context;
}
- public MaterialDialog createNewDialog() {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.set_sleeptimer_label);
- builder.customView(R.layout.time_dialog, false);
- builder.positiveText(R.string.set_sleeptimer_label);
- builder.negativeText(R.string.cancel_label);
- builder.onNegative((dialog, which) -> dialog.dismiss());
- builder.onPositive((dialog, which) -> {
- try {
- savePreferences();
- long input = SleepTimerPreferences.timerMillis();
- onTimerSet(input, cbShakeToReset.isChecked(), cbVibrate.isChecked());
- dialog.dismiss();
- } catch (NumberFormatException e) {
- e.printStackTrace();
- Toast toast = Toast.makeText(context, R.string.time_dialog_invalid_input,
- Toast.LENGTH_LONG);
- toast.show();
- }
- });
- dialog = builder.build();
-
- View view = dialog.getView();
- 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);
+ public AlertDialog createNewDialog() {
+ View content = View.inflate(context, R.layout.time_dialog, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.set_sleeptimer_label);
+ builder.setView(content);
+ builder.setNegativeButton(R.string.cancel_label, (dialog, which) -> dialog.dismiss());
+ builder.setPositiveButton(R.string.set_sleeptimer_label, (dialog, which) -> {
+ try {
+ savePreferences();
+ long input = SleepTimerPreferences.timerMillis();
+ onTimerSet(input, cbShakeToReset.isChecked(), cbVibrate.isChecked());
+ dialog.dismiss();
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ Toast toast = Toast.makeText(context, R.string.time_dialog_invalid_input,
+ Toast.LENGTH_LONG);
+ toast.show();
+ }
+ });
+ dialog = builder.create();
+
+ etxtTime = content.findViewById(R.id.etxtTime);
+ spTimeUnit = content.findViewById(R.id.spTimeUnit);
+ cbShakeToReset = content.findViewById(R.id.cbShakeToReset);
+ cbVibrate = content.findViewById(R.id.cbVibrate);
+ chAutoEnable = content.findViewById(R.id.chAutoEnable);
etxtTime.setText(SleepTimerPreferences.lastTimerValue());
etxtTime.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
- checkInputLength(s.length());
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(s.length() > 0);
}
@Override
@@ -109,16 +104,6 @@ public abstract class SleepTimerDialog {
return dialog;
}
- private void checkInputLength(int length) {
- if (length > 0) {
- Log.d(TAG, "Length is larger than 0, enabling confirm button");
- dialog.getActionButton(DialogAction.POSITIVE).setEnabled(true);
- } else {
- Log.d(TAG, "Length is smaller than 0, disabling confirm button");
- dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
- }
- }
-
public abstract void onTimerSet(long millis, boolean shakeToReset, boolean vibrate);
private void savePreferences() {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
index bf3faf89a..ef624ebe6 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -1,37 +1,21 @@
package de.danoeh.antennapod.dialog;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
import android.os.Build;
-import android.support.v7.app.AlertDialog;
-import android.util.Log;
-import android.view.View;
-
-import com.afollestad.materialdialogs.DialogAction;
-import com.afollestad.materialdialogs.MaterialDialog;
+import androidx.appcompat.app.AlertDialog;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import java.util.Arrays;
import java.util.List;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.IntentUtils;
-
public class VariableSpeedDialog {
- private static final String TAG = VariableSpeedDialog.class.getSimpleName();
-
- private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
- Uri.parse("market://details?id=com.falconware.prestissimo"));
-
private VariableSpeedDialog() {
}
public static void showDialog(final Context context) {
- if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
- || UserPreferences.useSonic()
+ if (UserPreferences.useSonic()
|| UserPreferences.useExoplayer()
|| Build.VERSION.SDK_INT >= 23) {
showSpeedSelectorDialog(context);
@@ -45,38 +29,17 @@ public class VariableSpeedDialog {
}
private static void showGetPluginDialog(final Context context, boolean showSpeedSelector) {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.no_playback_plugin_title);
- builder.content(R.string.no_playback_plugin_or_sonic_msg);
- builder.positiveText(R.string.enable_sonic);
- builder.negativeText(R.string.download_plugin_label);
- builder.neutralText(R.string.close_label);
- builder.onPositive((dialog, which) -> {
- if (Build.VERSION.SDK_INT >= 16) { // just to be safe
- UserPreferences.enableSonic();
- if(showSpeedSelector) {
- showSpeedSelectorDialog(context);
- }
- }
- });
- builder.onNegative((dialog, which) -> {
- try {
- context.startActivity(playStoreIntent);
- } catch (ActivityNotFoundException e) {
- // this is usually thrown on an emulator if the Android market is not installed
- Log.e(TAG, Log.getStackTraceString(e));
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.no_playback_plugin_title);
+ builder.setMessage(R.string.no_playback_plugin_or_sonic_msg);
+ builder.setPositiveButton(R.string.enable_sonic, (dialog, which) -> {
+ UserPreferences.enableSonic();
+ if (showSpeedSelector) {
+ showSpeedSelectorDialog(context);
}
});
- builder.forceStacking(true);
- MaterialDialog dialog = builder.show();
- if (Build.VERSION.SDK_INT < 16) {
- View pos = dialog.getActionButton(DialogAction.POSITIVE);
- pos.setEnabled(false);
- }
- if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) {
- View pos = dialog.getActionButton(DialogAction.NEGATIVE);
- pos.setEnabled(false);
- }
+ builder.setNeutralButton(R.string.close_label, null);
+ builder.show();
}
private static void showSpeedSelectorDialog(final Context context) {
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
index ca9ed83d7..6535df5ef 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.discovery;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
import de.mfietz.fyydlin.SearchHit;
import org.json.JSONArray;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 3ef010f88..2cfe7c1e8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -2,20 +2,15 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.provider.MediaStore;
-import android.support.v4.app.Fragment;
+import androidx.fragment.app.Fragment;
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.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -51,7 +46,7 @@ public class AddFeedFragment extends Fragment {
View butOpmlImport = root.findViewById(R.id.btn_opml_import);
butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
OpmlImportFromPathActivity.class)));
-
+ root.findViewById(R.id.search_icon).setOnClickListener(view -> performSearch());
return root;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index bb52b26b7..3949a03a9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index bb8f4df9a..2df28b262 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
index 1d9020f0d..47d7a0b86 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -101,7 +101,6 @@ public class CombinedSearchFragment extends Fragment {
inflater.inflate(R.menu.itunes_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_label));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index 705151062..7f70daaec 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -16,7 +16,8 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.DownloadLogEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -27,6 +28,8 @@ 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 static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_ADD_TO_QUEUE;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
@@ -38,10 +41,6 @@ public class CompletedDownloadsFragment extends ListFragment {
private static final String TAG = CompletedDownloadsFragment.class.getSimpleName();
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.DOWNLOADLOG_UPDATE |
- EventDistributor.UNREAD_ITEMS_UPDATE;
-
private List<FeedItem> items = new ArrayList<>();
private DownloadedEpisodesListAdapter listAdapter;
private Disposable disposable;
@@ -56,19 +55,24 @@ public class CompletedDownloadsFragment extends ListFragment {
listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
setListAdapter(listAdapter);
setListShown(false);
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onDestroyView() {
+ EventBus.getDefault().unregister(this);
+ super.onDestroyView();
}
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
loadItems();
}
@Override
public void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
if (disposable != null) {
disposable.dispose();
}
@@ -79,7 +83,7 @@ public class CompletedDownloadsFragment extends ListFragment {
super.onListItemClick(l, v, position, id);
position -= l.getHeaderViewsCount();
long[] ids = FeedItemUtil.getIds(items);
- ((MainActivity) requireActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
+ ((MainActivity) requireActivity()).loadChildFragment(ItemPagerFragment.newInstance(ids, position));
}
@Override
@@ -135,14 +139,15 @@ public class CompletedDownloadsFragment extends ListFragment {
}
};
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
- loadItems();
- }
- }
- };
+ @Subscribe
+ public void onDownloadLogChanged(DownloadLogEvent event) {
+ loadItems();
+ }
+
+ @Subscribe
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ loadItems();
+ }
private void loadItems() {
if (disposable != null) {
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 db9dd9530..5467d71a8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -15,6 +15,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import io.reactivex.Maybe;
@@ -70,7 +71,7 @@ public class CoverFragment extends Fragment {
txtvPodcastTitle.setText(media.getFeedTitle());
txtvEpisodeTitle.setText(media.getEpisodeTitle());
Glide.with(this)
- .load(media.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(media))
.apply(new RequestOptions()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.dontAnimate()
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index 26b115b4b..16337b00d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -4,8 +4,8 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -19,7 +19,7 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.DownloadLogEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
@@ -30,6 +30,8 @@ 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;
/**
* Shows the download log
@@ -45,14 +47,12 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
loadItems();
}
@Override
public void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
if (disposable != null) {
disposable.dispose();
}
@@ -77,6 +77,13 @@ public class DownloadLogFragment extends ListFragment {
adapter = new DownloadLogAdapter(getActivity(), itemAccess);
setListAdapter(adapter);
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onDestroyView() {
+ EventBus.getDefault().unregister(this);
+ super.onDestroyView();
}
private void onFragmentLoaded() {
@@ -133,15 +140,10 @@ public class DownloadLogFragment extends ListFragment {
}
};
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) {
- loadItems();
- }
- }
- };
+ @Subscribe
+ public void onDownloadLogChanged(DownloadLogEvent event) {
+ loadItems();
+ }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
index aa6029c84..b1bcdf404 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
index ca21df661..8cdec9f38 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 1cedb5a91..5dbb703b7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -4,15 +4,13 @@ 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;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SearchView;
-import android.support.v7.widget.SimpleItemAnimator;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.appcompat.widget.SearchView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -23,8 +21,20 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-import com.joanzapata.iconify.Iconify;
+
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.core.event.PlayerStatusEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
@@ -32,22 +42,16 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
-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.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
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.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.dialog.FilterDialog;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EmptyViewHandler;
@@ -55,13 +59,6 @@ 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.ArrayList;
-import java.util.List;
-import java.util.Set;
/**
* Shows unread or recently published episodes
@@ -69,11 +66,6 @@ import java.util.Set;
public abstract class EpisodesListFragment extends Fragment {
public static final String TAG = "EpisodesListFragment";
-
- private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE |
- EventDistributor.UNREAD_ITEMS_UPDATE |
- EventDistributor.PLAYER_STATUS_UPDATE;
-
private static final String DEFAULT_PREF_NAME = "PrefAllEpisodesFragment";
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
@@ -107,7 +99,6 @@ public abstract class EpisodesListFragment extends Fragment {
public void onStart() {
super.onStart();
setHasOptionsMenu(true);
- EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
loadItems();
}
@@ -129,7 +120,6 @@ public abstract class EpisodesListFragment extends Fragment {
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
- EventDistributor.getInstance().unregister(contentUpdate);
if (disposable != null) {
disposable.dispose();
}
@@ -149,7 +139,7 @@ public abstract class EpisodesListFragment extends Fragment {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_SCROLL_POSITION, firstItem);
editor.putFloat(PREF_SCROLL_OFFSET, topOffset);
- editor.commit();
+ editor.apply();
}
private void restoreScrollPosition() {
@@ -162,7 +152,7 @@ public abstract class EpisodesListFragment extends Fragment {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_SCROLL_POSITION, 0);
editor.putFloat(PREF_SCROLL_OFFSET, 0.0f);
- editor.commit();
+ editor.apply();
}
}
@@ -179,7 +169,6 @@ public abstract class EpisodesListFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_hint));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@@ -202,10 +191,7 @@ public abstract class EpisodesListFragment extends Fragment {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.refresh_item:
- List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
- if (feeds != null) {
- DBTasks.refreshAllFeeds(getActivity(), feeds);
- }
+ AutoUpdateManager.runImmediate(requireContext());
return true;
case R.id.mark_all_read_item:
ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(),
@@ -262,17 +248,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
FeedItem selectedItem = listAdapter.getSelectedItem();
- // Remove new flag 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 Remove new flag, given there is no UI to undo it otherwise,
- // i.e., there is context menu item for Mark as new
- if (R.id.remove_new_flag_item == item.getItemId()) {
- removeNewFlagWithUndo(selectedItem);
- return true;
- }
-
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
@NonNull
@@ -403,6 +379,20 @@ public abstract class EpisodesListFragment extends Fragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (listAdapter != null) {
+ for (int i = 0; i < listAdapter.getItemCount(); i++) {
+ AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)
+ recyclerView.findViewHolderForAdapterPosition(i);
+ if (holder != null && holder.isCurrentlyPlayingItem()) {
+ holder.notifyPlaybackPositionUpdated(event);
+ break;
+ }
+ }
+ }
+ }
+
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
return true;
}
@@ -412,7 +402,7 @@ public abstract class EpisodesListFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) {
+ if (isMenuInvalidationAllowed && event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
requireActivity().invalidateOptionsMenu();
}
if (update.mediaIds.length > 0) {
@@ -425,17 +415,27 @@ public abstract class EpisodesListFragment extends Fragment {
}
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
- loadItems();
- if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- requireActivity().invalidateOptionsMenu();
- }
- }
+ private void updateUi() {
+ loadItems();
+ if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ requireActivity().invalidateOptionsMenu();
}
- };
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onPlayerStatusChanged(PlayerStatusEvent event) {
+ updateUi();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ updateUi();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ updateUi();
+ }
void loadItems() {
if (disposable != null) {
@@ -453,36 +453,4 @@ public abstract class EpisodesListFragment extends Fragment {
@NonNull
protected abstract List<FeedItem> loadData();
-
- void removeNewFlagWithUndo(FeedItem item) {
- if (item == null) {
- return;
- }
-
- Log.d(TAG, "removeNewFlagWithUndo(" + 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.removed_new_flag_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));
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index 348c73b92..ce2232a55 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.app.Fragment;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -18,16 +18,20 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.ServiceEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
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.feed.util.ImageResourceUtils;
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;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
@@ -67,9 +71,9 @@ public class ExternalPlayerFragment extends Fragment {
if (controller != null && controller.getMedia() != null) {
Intent intent = PlaybackService.getPlayerActivityIntent(getActivity(), controller.getMedia());
- if (Build.VERSION.SDK_INT >= 16 && controller.getMedia().getMediaType() == MediaType.AUDIO) {
- ActivityOptionsCompat options = ActivityOptionsCompat.
- makeSceneTransitionAnimation(getActivity(), imgvCover, "coverTransition");
+ if (controller.getMedia().getMediaType() == MediaType.AUDIO) {
+ ActivityOptionsCompat options = ActivityOptionsCompat
+ .makeSceneTransitionAnimation(getActivity(), imgvCover, "coverTransition");
startActivity(intent, options.toBundle());
} else {
startActivity(intent);
@@ -138,6 +142,7 @@ public class ExternalPlayerFragment extends Fragment {
controller = setupPlaybackController();
controller.init();
loadMediaInfo();
+ EventBus.getDefault().register(this);
}
@Override
@@ -147,6 +152,12 @@ public class ExternalPlayerFragment extends Fragment {
controller.release();
controller = null;
}
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ onPositionObserverUpdate();
}
@Override
@@ -217,7 +228,7 @@ public class ExternalPlayerFragment extends Fragment {
onPositionObserverUpdate();
Glide.with(getActivity())
- .load(media.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(media))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
index 536ebd468..f73735658 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -1,13 +1,12 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
@@ -55,7 +54,8 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment {
emptyView.setTitle(R.string.no_fav_episodes_head_label);
emptyView.setMessage(R.string.no_fav_episodes_label);
- ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
+ ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
+ ItemTouchHelper.LEFT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
new file mode 100644
index 000000000..3b843e150
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
@@ -0,0 +1,226 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.LightingColorFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+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 de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.glide.FastBlurTransformation;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+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 io.reactivex.Maybe;
+import io.reactivex.MaybeOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+
+/**
+ * Displays information about a feed.
+ */
+public class FeedInfoFragment extends Fragment {
+
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String TAG = "FeedInfoActivity";
+
+ private Feed feed;
+ private Disposable disposable;
+ private ImageView imgvCover;
+ private TextView txtvTitle;
+ private TextView txtvDescription;
+ private TextView lblLanguage;
+ private TextView txtvLanguage;
+ private TextView lblAuthor;
+ private TextView txtvAuthor;
+ private TextView txtvUrl;
+ private TextView txtvAuthorHeader;
+ private ImageView imgvBackground;
+
+ public static FeedInfoFragment newInstance(Feed feed) {
+ FeedInfoFragment fragment = new FeedInfoFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feed.getId());
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ 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) getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
+ Toast t = Toast.makeText(getContext(), R.string.copied_url_msg, Toast.LENGTH_SHORT);
+ t.show();
+ }
+ }
+ };
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ ((MainActivity)getActivity()).getSupportActionBar().setTitle(R.string.feed_info_label);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.feedinfo, null);
+ setHasOptionsMenu(true);
+
+ imgvCover = root.findViewById(R.id.imgvCover);
+ txtvTitle = root.findViewById(R.id.txtvTitle);
+ txtvAuthorHeader = root.findViewById(R.id.txtvAuthor);
+ imgvBackground = root.findViewById(R.id.imgvBackground);
+ root.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
+ root.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
+ // https://github.com/bumptech/glide/issues/529
+ imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
+
+
+ txtvDescription = root.findViewById(R.id.txtvDescription);
+ lblLanguage = root.findViewById(R.id.lblLanguage);
+ txtvLanguage = root.findViewById(R.id.txtvLanguage);
+ lblAuthor = root.findViewById(R.id.lblAuthor);
+ txtvAuthor = root.findViewById(R.id.txtvDetailsAuthor);
+ txtvUrl = root.findViewById(R.id.txtvUrl);
+
+ txtvUrl.setOnClickListener(copyUrlToClipboard);
+ postponeEnterTransition();
+ return root;
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ 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 -> {
+ feed = result;
+ showFeed();
+ }, error -> Log.d(TAG, Log.getStackTraceString(error)),
+ this::startPostponedEnterTransition);
+ }
+
+ private void showFeed() {
+ Log.d(TAG, "Language is " + feed.getLanguage());
+ Log.d(TAG, "Author is " + feed.getAuthor());
+ Log.d(TAG, "URL is " + feed.getDownload_url());
+ Glide.with(getContext())
+ .load(feed.getImageLocation())
+ .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(getContext())
+ .load(feed.getImageLocation())
+ .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());
+
+ String description = HtmlToPlainText.getPlainText(feed.getDescription());
+
+ txtvDescription.setText(description);
+
+ if (!TextUtils.isEmpty(feed.getAuthor())) {
+ txtvAuthor.setText(feed.getAuthor());
+ txtvAuthorHeader.setText(feed.getAuthor());
+ } else {
+ lblAuthor.setVisibility(View.GONE);
+ txtvAuthor.setVisibility(View.GONE);
+ }
+ if (!TextUtils.isEmpty(feed.getLanguage())) {
+ txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage()));
+ } else {
+ lblLanguage.setVisibility(View.GONE);
+ txtvLanguage.setVisibility(View.GONE);
+ }
+ txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}");
+ Iconify.addIcons(txtvUrl);
+
+ getActivity().invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.feedinfo, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
+ menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
+ IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ boolean handled = false;
+ try {
+ handled = FeedMenuHandler.onOptionsItemClicked(getContext(), item, feed);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getContext(), e.getMessage());
+ }
+ return handled || super.onOptionsItemSelected(item);
+ }
+}
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 4e4b40096..f03aef207 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -3,13 +3,8 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.graphics.LightingColorFilter;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -24,6 +19,11 @@ import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.SearchView;
+import androidx.core.view.MenuItemCompat;
+import androidx.fragment.app.ListFragment;
+
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
@@ -37,8 +37,6 @@ import org.greenrobot.eventbus.ThreadMode;
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.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
@@ -47,7 +45,12 @@ import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.core.event.PlayerStatusEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -61,6 +64,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.FeedItemPermutors;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.Optional;
@@ -81,12 +85,6 @@ import io.reactivex.schedulers.Schedulers;
@SuppressLint("ValidFragment")
public class FeedItemlistFragment extends ListFragment {
private static final String TAG = "ItemlistFragment";
-
- private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE
- | EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.PLAYER_STATUS_UPDATE;
-
- public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
private FeedItemlistAdapter adapter;
@@ -140,37 +138,31 @@ public class FeedItemlistFragment extends ListFragment {
}
@Override
- public void onStart() {
- super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
- loadItems();
+ public void onHiddenChanged(boolean hidden) {
+ super.onHiddenChanged(hidden);
+ if (!hidden && getActivity() != null) {
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle("");
+ }
}
@Override
- public void onResume() {
- super.onResume();
- ((MainActivity)getActivity()).getSupportActionBar().setTitle("");
- updateProgressBarVisibility();
- }
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
- @Override
- public void onStop() {
- super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
- EventBus.getDefault().unregister(this);
- if(disposable != null) {
- disposable.dispose();
- }
+ registerForContextMenu(getListView());
+
+ EventBus.getDefault().register(this);
+ loadItems();
}
@Override
public void onDestroyView() {
super.onDestroyView();
- resetViewState();
- }
- private void resetViewState() {
+ EventBus.getDefault().unregister(this);
+ if (disposable != null) {
+ disposable.dispose();
+ }
adapter = null;
listFooter = null;
}
@@ -193,11 +185,11 @@ public class FeedItemlistFragment extends ListFragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_hint));
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
+ menu.findItem(R.id.sort_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.filter_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.episode_actions).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.refresh_item).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
@@ -323,7 +315,7 @@ public class FeedItemlistFragment extends ListFragment {
contextMenu = menu;
lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
+ FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item);
}
@Override
@@ -340,14 +332,7 @@ public class FeedItemlistFragment extends ListFragment {
return super.onContextItemSelected(item);
}
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- registerForContextMenu(getListView());
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
@Override
@@ -358,7 +343,7 @@ public class FeedItemlistFragment extends ListFragment {
position -= l.getHeaderViewsCount();
MainActivity activity = (MainActivity) getActivity();
long[] ids = FeedItemUtil.getIds(feed.getItems());
- activity.loadChildFragment(ItemFragment.newInstance(ids, position));
+ activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
activity.getSupportActionBar().setTitle(feed.getTitle());
}
@@ -390,26 +375,43 @@ public class FeedItemlistFragment extends ListFragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isUpdatingFeed != event.update.feedIds.length > 0) {
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeed)) {
updateProgressBarVisibility();
}
- if(adapter != null && update.mediaIds.length > 0) {
+ if (adapter != null && update.mediaIds.length > 0) {
adapter.notifyDataSetChanged();
}
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (adapter != null) {
+ adapter.notifyCurrentlyPlayingItemChanged(event, getListView());
+ }
+ }
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EVENTS & arg) != 0) {
- Log.d(TAG, "Received contentUpdate Intent. arg " + arg);
- refreshHeaderView();
- loadItems();
- updateProgressBarVisibility();
- }
+ private void updateUi() {
+ refreshHeaderView();
+ loadItems();
+ updateProgressBarVisibility();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onPlayerStatusChanged(PlayerStatusEvent event) {
+ updateUi();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ updateUi();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ if (event.contains(feed)) {
+ updateUi();
}
- };
+ }
private void updateProgressBarVisibility() {
if (isUpdatingFeed != updateRefreshMenuItemChecker.isRefreshing()) {
@@ -421,8 +423,9 @@ public class FeedItemlistFragment extends ListFragment {
}
- private void onFragmentLoaded() {
- if(!isVisible()) {
+ private void displayList() {
+ if (getView() == null) {
+ Log.e(TAG, "Required root view is not yet created. Stop binding data to UI.");
return;
}
if (adapter == null) {
@@ -506,10 +509,8 @@ public class FeedItemlistFragment extends ListFragment {
imgvCover.setOnClickListener(v -> showFeedInfo());
butShowSettings.setOnClickListener(v -> {
if (feed != null) {
- Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class);
- startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID,
- feed.getId());
- startActivity(startIntent);
+ FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed);
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP);
}
});
headerCreated = true;
@@ -517,10 +518,8 @@ public class FeedItemlistFragment extends ListFragment {
private void showFeedInfo() {
if (feed != null) {
- Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
- startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
- feed.getId());
- startActivity(startIntent);
+ FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP);
}
}
@@ -626,7 +625,7 @@ public class FeedItemlistFragment extends ListFragment {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result.orElse(null);
- onFragmentLoaded();
+ displayList();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@@ -638,6 +637,11 @@ public class FeedItemlistFragment extends ListFragment {
FeedItemFilter filter = feed.getItemFilter();
feed.setItems(filter.filter(feed.getItems()));
}
+ if (feed != null && feed.getSortOrder() != null) {
+ List<FeedItem> feedItems = feed.getItems();
+ FeedItemPermutors.getPermutor(feed.getSortOrder()).reorder(feedItems);
+ feed.setItems(feedItems);
+ }
return Optional.ofNullable(feed);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
index 4fb3d90f5..b745313aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -1,49 +1,134 @@
package de.danoeh.antennapod.fragment;
-import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.SwitchPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceFragmentCompat;
+import android.util.Log;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedFilter;
import de.danoeh.antennapod.core.feed.FeedPreferences;
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.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.EpisodeFilterDialog;
-import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel;
+import io.reactivex.Maybe;
+import io.reactivex.MaybeOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
-import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID;
+import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
public class FeedSettingsFragment extends PreferenceFragmentCompat {
private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
+ private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
+ private static final DecimalFormat decimalFormat = new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String TAG = "FeedSettingsFragment";
+
private Feed feed;
+ private Disposable disposable;
private FeedPreferences feedPreferences;
+ public static FeedSettingsFragment newInstance(Feed feed) {
+ FeedSettingsFragment fragment = new FeedSettingsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feed.getId());
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
+ postponeEnterTransition();
long feedId = getArguments().getLong(EXTRA_FEED_ID);
- ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId)
+ 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 -> {
feed = result;
feedPreferences = feed.getPreferences();
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
setupAutoDownloadPreference();
setupKeepUpdatedPreference();
setupAutoDeletePreference();
setupAuthentificationPreference();
setupEpisodeFilterPreference();
+ setupPlaybackSpeedPreference();
updateAutoDeleteSummary();
updateAutoDownloadEnabled();
- }).dispose();
+ updatePlaybackSpeedPreference();
+ }, error -> Log.d(TAG, Log.getStackTraceString(error)),
+ this::startPostponedEnterTransition);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label);
+ if (feed != null) {
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(null);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ private void setupPlaybackSpeedPreference() {
+ ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
+
+ String[] speeds = UserPreferences.getPlaybackSpeedArray();
+
+ String[] values = new String[speeds.length + 1];
+ values[0] = decimalFormat.format(SPEED_USE_GLOBAL);
+
+ String[] entries = new String[speeds.length + 1];
+ entries[0] = getString(R.string.feed_auto_download_global);
+
+ System.arraycopy(speeds, 0, values, 1, speeds.length);
+ System.arraycopy(speeds, 0, entries, 1, speeds.length);
+
+ feedPlaybackSpeedPreference.setEntryValues(values);
+ feedPlaybackSpeedPreference.setEntries(entries);
+
+ feedPlaybackSpeedPreference.setOnPreferenceChangeListener((preference, newValue) -> {
+ feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) newValue));
+ feed.savePreferences();
+ updatePlaybackSpeedPreference();
+ return false;
+ });
}
private void setupEpisodeFilterPreference() {
@@ -95,8 +180,15 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
});
}
+ private void updatePlaybackSpeedPreference() {
+ ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
+
+ float speedValue = feedPreferences.getFeedPlaybackSpeed();
+ feedPlaybackSpeedPreference.setValue(decimalFormat.format(speedValue));
+ }
+
private void updateAutoDeleteSummary() {
- ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");
+ ListPreference autoDeletePreference = findPreference("autoDelete");
switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL:
@@ -170,7 +262,7 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
}
@Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
+ public void onConfirmButtonPressed(DialogInterface dialog) {
DBWriter.setFeedsItemsAutoDownload(feed, autoDownload);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
index 9c16cfe56..aa26610aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -100,7 +100,6 @@ public class FyydSearchFragment extends Fragment {
inflater.inflate(R.menu.itunes_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_fyyd_label));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 5cf2c5eeb..85978b761 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
@@ -12,8 +11,8 @@ import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -96,13 +95,7 @@ public class ItemDescriptionFragment extends Fragment {
if (Timeline.isTimecodeLink(url)) {
onTimecodeLinkSelected(url);
} else {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- e.printStackTrace();
- return true;
- }
+ IntentUtils.openInBrowser(getContext(), url);
}
return true;
}
@@ -151,7 +144,6 @@ public class ItemDescriptionFragment extends Fragment {
}
};
- @SuppressWarnings("deprecation")
@SuppressLint("NewApi")
@Override
public boolean onContextItemSelected(MenuItem item) {
@@ -159,11 +151,7 @@ public class ItemDescriptionFragment extends Fragment {
if (selectedURL != null) {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- getActivity().startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), selectedURL);
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
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 3a48c5431..9a88441e0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -3,122 +3,97 @@ package de.danoeh.antennapod.fragment;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
+import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.GestureDetectorCompat;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import android.widget.Button;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-
+import androidx.annotation.AttrRes;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.util.List;
-
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
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.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.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 io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.ArrayUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.List;
/**
* Displays information about a FeedItem and actions.
*/
-public class ItemFragment extends Fragment implements OnSwipeGesture {
+public class ItemFragment extends Fragment {
private static final String TAG = "ItemFragment";
-
- private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE;
-
- private static final String ARG_FEEDITEMS = "feeditems";
- private static final String ARG_FEEDITEM_POS = "feeditem_pos";
-
- private GestureDetectorCompat headerGestureDetector;
- private GestureDetectorCompat webviewGestureDetector;
+ private static final String ARG_FEEDITEM = "feeditem";
/**
* Creates a new instance of an ItemFragment
*
- * @param feeditem The ID of the FeedItem that should be displayed.
+ * @param feeditem The ID of the FeedItem to show
* @return The ItemFragment instance
*/
public static ItemFragment newInstance(long feeditem) {
- return newInstance(new long[] { feeditem }, 0);
- }
-
- /**
- * Creates a new instance of an ItemFragment
- *
- * @param feeditems The IDs of the FeedItems that belong to the same list
- * @param feedItemPos The position of the FeedItem that is currently shown
- * @return The ItemFragment instance
- */
- public static ItemFragment newInstance(long[] feeditems, int feedItemPos) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
- args.putLongArray(ARG_FEEDITEMS, feeditems);
- args.putInt(ARG_FEEDITEM_POS, feedItemPos);
+ args.putLong(ARG_FEEDITEM, feeditem);
fragment.setArguments(args);
return fragment;
}
private boolean itemsLoaded = false;
- private long[] feedItems;
- private int feedItemPos;
+ private long itemId;
private FeedItem item;
private String webviewData;
private List<Downloader> downloaderList;
@@ -132,9 +107,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
private ImageView imgvCover;
private ProgressBar progbarDownload;
private ProgressBar progbarLoading;
- private IconButton butAction1;
- private IconButton butAction2;
- private Menu popupMenu;
+ private Button butAction1;
+ private Button butAction2;
private Disposable disposable;
@@ -146,20 +120,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setRetainInstance(true);
- setHasOptionsMenu(true);
- feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
- feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
-
- headerGestureDetector = new GestureDetectorCompat(getActivity(), new SwipeGestureDetector(this));
- webviewGestureDetector = new GestureDetectorCompat(getActivity(), new SwipeGestureDetector(this) {
- // necessary for the longclick context menu to work properly
- @Override
- public boolean onDown(MotionEvent e) {
- return false;
- }
- });
+ itemId = getArguments().getLong(ARG_FEEDITEM);
}
@Override
@@ -169,11 +131,6 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
root = layout.findViewById(R.id.content_root);
- LinearLayout header = root.findViewById(R.id.header);
- if(feedItems.length > 0) {
- header.setOnTouchListener((v, event) -> headerGestureDetector.onTouchEvent(event));
- }
-
txtvPodcast = layout.findViewById(R.id.txtvPodcast);
txtvPodcast.setOnClickListener(v -> openPodcast());
txtvTitle = layout.findViewById(R.id.txtvTitle);
@@ -204,17 +161,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
webvDescription.getSettings().setLayoutAlgorithm(
WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webvDescription.getSettings().setLoadWithOverviewMode(true);
- if(feedItems.length > 0) {
webvDescription.setOnLongClickListener(webViewLongClickListener);
- }
- webvDescription.setOnTouchListener((v, event) -> webviewGestureDetector.onTouchEvent(event));
+
webvDescription.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- if(IntentUtils.isCallable(getActivity(), intent)) {
- startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), url);
return true;
}
});
@@ -264,6 +216,12 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
@Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ load();
+ }
+
+ @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@@ -271,9 +229,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
- load();
}
@Override
@@ -288,7 +244,6 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
}
@@ -304,68 +259,6 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
}
- @Override
- public boolean onSwipeLeftToRight() {
- return swipeFeedItem(-1);
- }
-
- @Override
- public boolean onSwipeRightToLeft() {
- return swipeFeedItem(+1);
- }
-
- private boolean swipeFeedItem(int position) {
- Log.d(TAG, String.format("onSwipe() shift: %s", position));
- feedItemPos = (feedItemPos + position) % feedItems.length;
- if (feedItemPos < 0) {
- feedItemPos = feedItems.length - 1;
- }
- load();
- return true;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded() || item == null) {
- return;
- }
- super.onCreateOptionsMenu(menu, inflater);
- if (Flavors.FLAVOR == Flavors.PLAY) {
- ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
- }
- inflater.inflate(R.menu.feeditem_options, menu);
- popupMenu = menu;
- if (item.hasMedia()) {
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null);
- } else {
- // these are already available via button1 and button2
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null,
- R.id.mark_read_item, R.id.visit_website_item);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- switch(menuItem.getItemId()) {
- case R.id.open_podcast:
- openPodcast();
- return true;
- default:
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
- }
- }
-
- private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
- @Override
- public void setItemVisibility(int id, boolean visible) {
- MenuItem item = popupMenu.findItem(id);
- if (item != null) {
- item.setVisible(visible);
- }
- }
- };
-
-
private void onFragmentLoaded() {
if (webviewData != null) {
webvDescription.loadDataWithBaseURL("https://127.0.0.1", webviewData, "text/html", "utf-8", "about:blank");
@@ -378,7 +271,6 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
Log.d(TAG, "updateAppearance item is null");
return;
}
- getActivity().supportInvalidateOptionsMenu();
txtvPodcast.setText(item.getFeed().getTitle());
txtvTitle.setText(item.getTitle());
@@ -388,7 +280,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
Glide.with(getActivity())
- .load(item.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(item))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
@@ -409,53 +301,59 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
FeedMedia media = item.getMedia();
- String butAction1Icon = null;
- int butAction1Text = 0;
- String butAction2Icon = null;
- int butAction2Text = 0;
+ @AttrRes int butAction1Icon = 0;
+ @StringRes int butAction1Text = 0;
+ @AttrRes int butAction2Icon = 0;
+ @StringRes int butAction2Text = 0;
if (media == null) {
if (!item.isPlayed()) {
- butAction1Icon = "{fa-check 24sp}";
+ butAction1Icon = R.attr.navigation_accept;
butAction1Text = R.string.mark_read_label;
}
if (item.getLink() != null) {
- butAction2Icon = "{md-web 24sp}";
+ butAction2Icon = R.attr.location_web_site;
butAction2Text = R.string.visit_website_label;
}
} else {
- if(media.getDuration() > 0) {
+ if (media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
}
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
if (!media.isDownloaded()) {
- butAction2Icon = "{md-settings-input-antenna 24sp}";
+ butAction2Icon = R.attr.action_stream;
butAction2Text = R.string.stream_label;
} else {
- butAction2Icon = "{md-delete 24sp}";
+ butAction2Icon = R.attr.content_discard;
butAction2Text = R.string.delete_label;
}
if (isDownloading) {
- butAction1Icon = "{md-cancel 24sp}";
+ butAction1Icon = R.attr.navigation_cancel;
butAction1Text = R.string.cancel_label;
} else if (media.isDownloaded()) {
- butAction1Icon = "{md-play-arrow 24sp}";
+ butAction1Icon = R.attr.av_play;
butAction1Text = R.string.play_label;
} else {
- butAction1Icon = "{md-file-download 24sp}";
+ butAction1Icon = R.attr.av_download;
butAction1Text = R.string.download_label;
}
}
- if(butAction1Icon != null && butAction1Text != 0) {
- butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
- Iconify.addIcons(butAction1);
+ if (butAction1Icon != 0 && butAction1Text != 0) {
+ butAction1.setText(butAction1Text);
+ butAction1.setTransformationMethod(null);
+ TypedValue typedValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(butAction1Icon, typedValue, true);
+ butAction1.setCompoundDrawablesWithIntrinsicBounds(typedValue.resourceId, 0, 0, 0);
butAction1.setVisibility(View.VISIBLE);
} else {
butAction1.setVisibility(View.INVISIBLE);
}
- if(butAction2Icon != null && butAction2Text != 0) {
- butAction2.setText(butAction2Icon +"\u0020\u0020" + getActivity().getString(butAction2Text));
- Iconify.addIcons(butAction2);
+ if (butAction2Icon != 0 && butAction2Text != 0) {
+ butAction2.setText(butAction2Text);
+ butAction2.setTransformationMethod(null);
+ TypedValue typedValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(butAction2Icon, typedValue, true);
+ butAction2.setCompoundDrawablesWithIntrinsicBounds(typedValue.resourceId, 0, 0, 0);
butAction2.setVisibility(View.VISIBLE);
} else {
butAction2.setVisibility(View.INVISIBLE);
@@ -485,11 +383,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
if (selectedURL != null) {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- getActivity().startActivity(intent);
- }
+ IntentUtils.openInBrowser(getContext(), selectedURL);
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
@@ -541,8 +435,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- for(FeedItem item : event.items) {
- if(feedItems[feedItemPos] == item.getId()) {
+ for (FeedItem item : event.items) {
+ if (this.item.getId() == item.getId()) {
load();
return;
}
@@ -565,18 +459,13 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
}
-
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
- load();
- }
- }
- };
+ @Subscribe
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ load();
+ }
private void load() {
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
progbarLoading.setVisibility(View.VISIBLE);
@@ -593,7 +482,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Nullable
private FeedItem loadInBackground() {
- FeedItem feedItem = DBReader.getFeedItem(feedItems[feedItemPos]);
+ FeedItem feedItem = DBReader.getFeedItem(itemId);
Context context = getContext();
if (feedItem != null && context != null) {
Timeline t = new Timeline(context, feedItem);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
new file mode 100644
index 000000000..74530e424
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
@@ -0,0 +1,193 @@
+package de.danoeh.antennapod.fragment;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.CastEnabledActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.util.Flavors;
+import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Displays information about a list of FeedItems.
+ */
+public class ItemPagerFragment extends Fragment {
+ private static final String ARG_FEEDITEMS = "feeditems";
+ private static final String ARG_FEEDITEM_POS = "feeditem_pos";
+
+ /**
+ * Creates a new instance of an ItemPagerFragment.
+ *
+ * @param feeditem The ID of the FeedItem that should be displayed.
+ * @return The ItemFragment instance
+ */
+ public static ItemPagerFragment newInstance(long feeditem) {
+ return newInstance(new long[] { feeditem }, 0);
+ }
+
+ /**
+ * Creates a new instance of an ItemPagerFragment.
+ *
+ * @param feeditems The IDs of the FeedItems that belong to the same list
+ * @param feedItemPos The position of the FeedItem that is currently shown
+ * @return The ItemFragment instance
+ */
+ public static ItemPagerFragment newInstance(long[] feeditems, int feedItemPos) {
+ ItemPagerFragment fragment = new ItemPagerFragment();
+ Bundle args = new Bundle();
+ args.putLongArray(ARG_FEEDITEMS, feeditems);
+ args.putInt(ARG_FEEDITEM_POS, feedItemPos);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ private long[] feedItems;
+ private int feedItemPos;
+ private FeedItem item;
+ private Disposable disposable;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+
+ feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
+ feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
+ }
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View layout = inflater.inflate(R.layout.feeditem_pager_fragment, container, false);
+
+ ViewPager pager = layout.findViewById(R.id.pager);
+ // FragmentStatePagerAdapter documentation:
+ // > When using FragmentStatePagerAdapter the host ViewPager must have a valid ID set.
+ // When opening multiple ItemPagerFragments by clicking "item" -> "visit podcast" -> "item" -> etc,
+ // the ID is no longer unique and FragmentStatePagerAdapter does not display any pages.
+ int newId = ViewCompat.generateViewId();
+ pager.setId(newId);
+ pager.setAdapter(new ItemPagerAdapter());
+ pager.setCurrentItem(feedItemPos);
+ loadItem(feedItems[feedItemPos]);
+ pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ loadItem(feedItems[position]);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+
+ }
+ });
+
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ private void loadItem(long itemId) {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ disposable = Observable.fromCallable(() -> DBReader.getFeedItem(itemId))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ item = result;
+ getActivity().invalidateOptionsMenu();
+ }, Throwable::printStackTrace);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if (!isAdded() || item == null) {
+ return;
+ }
+ super.onCreateOptionsMenu(menu, inflater);
+ if (Flavors.FLAVOR == Flavors.PLAY) {
+ ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ inflater.inflate(R.menu.feeditem_options, menu);
+
+ FeedItemMenuHandler.MenuInterface popupMenuInterface = (id, visible) -> {
+ MenuItem item = menu.findItem(id);
+ if (item != null) {
+ item.setVisible(visible);
+ }
+ };
+
+ if (item.hasMedia()) {
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item);
+ } else {
+ // these are already available via button1 and button2
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item,
+ R.id.mark_read_item, R.id.visit_website_item);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ switch (menuItem.getItemId()) {
+ case R.id.open_podcast:
+ openPodcast();
+ return true;
+ default:
+ return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.getItemId(), item);
+ }
+ }
+
+ private void openPodcast() {
+ Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
+ ((MainActivity) getActivity()).loadChildFragment(fragment);
+ }
+
+ private class ItemPagerAdapter extends FragmentStatePagerAdapter {
+
+ ItemPagerAdapter() {
+ super(getFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
+ }
+
+ @NonNull
+ @Override
+ public Fragment getItem(int position) {
+ return ItemFragment.newInstance(feedItems[position]);
+ }
+
+ @Override
+ public int getCount() {
+ return feedItems.length;
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index 80767bef2..4b1544e47 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -2,10 +2,11 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
-import android.support.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
+import androidx.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -18,34 +19,18 @@ import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.afollestad.materialdialogs.MaterialDialog;
-
import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
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;
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
@@ -134,9 +119,9 @@ public class ItunesSearchFragment extends Fragment {
progressBar.setVisibility(View.GONE);
gridView.setVisibility(View.VISIBLE);
String prefix = getString(R.string.error_msg_prefix);
- new MaterialDialog.Builder(getActivity())
- .content(prefix + " " + error.getMessage())
- .neutralText(android.R.string.ok)
+ new AlertDialog.Builder(getActivity())
+ .setMessage(prefix + " " + error.getMessage())
+ .setPositiveButton(android.R.string.ok, null)
.show();
});
});
@@ -165,9 +150,8 @@ public class ItunesSearchFragment extends Fragment {
inflater.inflate(R.menu.itunes_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_itunes_label));
- sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
+ sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index adae4f2a5..2bfdd040b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -1,12 +1,11 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -16,6 +15,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
/**
* Like 'EpisodesFragment' except that it only shows new episodes and
@@ -54,7 +54,8 @@ public class NewEpisodesFragment extends EpisodesListFragment {
emptyView.setTitle(R.string.no_new_episodes_head_label);
emptyView.setMessage(R.string.no_new_episodes_label);
- ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
+ ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
+ ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
@@ -63,7 +64,7 @@ public class NewEpisodesFragment extends EpisodesListFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
- removeNewFlagWithUndo(holder.getFeedItem());
+ FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem());
}
@Override
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 e2060481f..a97e3dae8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -12,6 +12,8 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import de.danoeh.antennapod.core.event.PlaybackHistoryEvent;
+import de.danoeh.antennapod.core.event.PlayerStatusEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -24,7 +26,6 @@ import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
-import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.Downloader;
@@ -39,12 +40,8 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class PlaybackHistoryFragment extends ListFragment {
-
public static final String TAG = "PlaybackHistoryFragment";
- private static final int EVENTS = EventDistributor.PLAYBACK_HISTORY_UPDATE |
- EventDistributor.PLAYER_STATUS_UPDATE;
-
private List<FeedItem> playbackHistory;
private FeedItemlistAdapter adapter;
private List<Downloader> downloaderList;
@@ -83,7 +80,6 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
loadItems();
}
@@ -92,7 +88,6 @@ public class PlaybackHistoryFragment extends ListFragment {
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
- EventDistributor.getInstance().unregister(contentUpdate);
if (disposable != null) {
disposable.dispose();
}
@@ -111,7 +106,7 @@ public class PlaybackHistoryFragment extends ListFragment {
super.onListItemClick(l, v, position, id);
position -= l.getHeaderViewsCount();
long[] ids = FeedItemUtil.getIds(playbackHistory);
- ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
+ ((MainActivity) getActivity()).loadChildFragment(ItemPagerFragment.newInstance(ids, position));
}
@Override
@@ -166,16 +161,17 @@ public class PlaybackHistoryFragment extends ListFragment {
}
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onHistoryUpdated(PlaybackHistoryEvent event) {
+ loadItems();
+ getActivity().supportInvalidateOptionsMenu();
+ }
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
- loadItems();
- getActivity().supportInvalidateOptionsMenu();
- }
- }
- };
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onPlayerStatusChanged(PlayerStatusEvent event) {
+ loadItems();
+ getActivity().supportInvalidateOptionsMenu();
+ }
private void onFragmentLoaded() {
adapter.notifyDataSetChanged();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index 9763f8f2d..b36ce6145 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -4,14 +4,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SearchView;
-import android.support.v7.widget.SimpleItemAnimator;
-import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -19,11 +11,26 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.SearchView;
+import androidx.core.view.MenuItemCompat;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
+
+import com.google.android.material.snackbar.Snackbar;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
import java.util.List;
import de.danoeh.antennapod.R;
@@ -33,35 +40,32 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.core.event.PlayerStatusEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
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.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
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.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.core.util.QueueSorter;
import de.danoeh.antennapod.core.util.SortOrder;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-
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;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
@@ -70,13 +74,8 @@ import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REM
* Shows all items in the queue
*/
public class QueueFragment extends Fragment {
-
public static final String TAG = "QueueFragment";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.UNREAD_ITEMS_UPDATE | // sent when playback position is reset
- EventDistributor.PLAYER_STATUS_UPDATE;
-
private TextView infoBar;
private RecyclerView recyclerView;
private QueueRecyclerAdapter recyclerAdapter;
@@ -91,10 +90,12 @@ public class QueueFragment extends Fragment {
private static final String PREFS = "QueueFragment";
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
+ private static final String PREF_SHOW_LOCK_WARNING = "show_lock_warning";
private Disposable disposable;
private LinearLayoutManager layoutManager;
private ItemTouchHelper itemTouchHelper;
+ private SharedPreferences prefs;
@Override
@@ -102,6 +103,7 @@ public class QueueFragment extends Fragment {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
+ prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
@Override
@@ -111,7 +113,6 @@ public class QueueFragment extends Fragment {
onFragmentLoaded(true);
}
loadItems(true);
- EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
}
@@ -124,9 +125,8 @@ public class QueueFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
}
@@ -196,8 +196,8 @@ public class QueueFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (isUpdatingFeeds != update.feedIds.length > 0) {
- getActivity().supportInvalidateOptionsMenu();
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
}
if (recyclerAdapter != null && update.mediaIds.length > 0) {
for (long mediaId : update.mediaIds) {
@@ -209,6 +209,37 @@ public class QueueFragment extends Fragment {
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(PlaybackPositionEvent event) {
+ if (recyclerAdapter != null) {
+ for (int i = 0; i < recyclerAdapter.getItemCount(); i++) {
+ QueueRecyclerAdapter.ViewHolder holder = (QueueRecyclerAdapter.ViewHolder)
+ recyclerView.findViewHolderForAdapterPosition(i);
+ if (holder != null && holder.isCurrentlyPlayingItem()) {
+ holder.notifyPlaybackPositionUpdated(event);
+ break;
+ }
+ }
+ }
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onPlayerStatusChanged(PlayerStatusEvent event) {
+ loadItems(false);
+ if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ // Sent when playback position is reset
+ loadItems(false);
+ if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ }
+
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
@@ -219,15 +250,13 @@ public class QueueFragment extends Fragment {
topOffset = firstItemView.getTop();
}
- SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(PREF_SCROLL_POSITION, firstItem);
- editor.putFloat(PREF_SCROLL_OFFSET, topOffset);
- editor.commit();
+ prefs.edit()
+ .putInt(PREF_SCROLL_POSITION, firstItem)
+ .putFloat(PREF_SCROLL_OFFSET, topOffset)
+ .apply();
}
private void restoreScrollPosition() {
- SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
int position = prefs.getInt(PREF_SCROLL_POSITION, 0);
float offset = prefs.getFloat(PREF_SCROLL_OFFSET, 0.0f);
if (position > 0 || offset > 0) {
@@ -259,7 +288,6 @@ public class QueueFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.search_hint));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@@ -299,25 +327,10 @@ public class QueueFragment extends Fragment {
if (!super.onOptionsItemSelected(item)) {
switch (item.getItemId()) {
case R.id.queue_lock:
- boolean newLockState = !UserPreferences.isQueueLocked();
- UserPreferences.setQueueLocked(newLockState);
- getActivity().supportInvalidateOptionsMenu();
- if (recyclerAdapter != null) {
- recyclerAdapter.setLocked(newLockState);
- }
- if (newLockState) {
- Snackbar.make(getActivity().findViewById(R.id.content), R.string
- .queue_locked, Snackbar.LENGTH_SHORT).show();
- } else {
- Snackbar.make(getActivity().findViewById(R.id.content), R.string
- .queue_unlocked, Snackbar.LENGTH_SHORT).show();
- }
+ toggleQueueLock();
return true;
case R.id.refresh_item:
- List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
- if (feeds != null) {
- DBTasks.refreshAllFeeds(getActivity(), feeds);
- }
+ AutoUpdateManager.runImmediate(requireContext());
return true;
case R.id.clear_queue:
// make sure the user really wants to clear the queue
@@ -335,7 +348,7 @@ public class QueueFragment extends Fragment {
conDialog.createNewDialog().show();
return true;
case R.id.episode_actions:
- ((MainActivity) requireActivity()) .loadChildFragment(
+ ((MainActivity) requireActivity()).loadChildFragment(
EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE));
return true;
case R.id.queue_sort_episode_title_asc:
@@ -377,7 +390,7 @@ public class QueueFragment extends Fragment {
UserPreferences.setQueueKeepSorted(keepSortedNew);
if (keepSortedNew) {
SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder();
- QueueSorter.sort(sortOrder, true);
+ DBWriter.reorderQueue(sortOrder, true);
if (recyclerAdapter != null) {
recyclerAdapter.setLocked(true);
}
@@ -394,6 +407,48 @@ public class QueueFragment extends Fragment {
}
}
+ private void toggleQueueLock() {
+ boolean isLocked = UserPreferences.isQueueLocked();
+ if (isLocked) {
+ setQueueLocked(false);
+ } else {
+ boolean shouldShowLockWarning = prefs.getBoolean(PREF_SHOW_LOCK_WARNING, true);
+ if (!shouldShowLockWarning) {
+ setQueueLocked(true);
+ } else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.lock_queue);
+ builder.setMessage(R.string.queue_lock_warning);
+
+ View view = View.inflate(getContext(), R.layout.checkbox_do_not_show_again, null);
+ CheckBox checkDoNotShowAgain = view.findViewById(R.id.checkbox_do_not_show_again);
+ builder.setView(view);
+
+ builder.setPositiveButton(R.string.lock_queue, (dialog, which) -> {
+ prefs.edit().putBoolean(PREF_SHOW_LOCK_WARNING, !checkDoNotShowAgain.isChecked()).apply();
+ setQueueLocked(true);
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.show();
+ }
+ }
+ }
+
+ private void setQueueLocked(boolean locked) {
+ UserPreferences.setQueueLocked(locked);
+ getActivity().supportInvalidateOptionsMenu();
+ if (recyclerAdapter != null) {
+ recyclerAdapter.setLocked(locked);
+ }
+ if (locked) {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_locked, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(getActivity().findViewById(R.id.content), R.string
+ .queue_unlocked, Snackbar.LENGTH_SHORT).show();
+ }
+ }
+
/**
* This method is called if the user clicks on a sort order menu item.
*
@@ -401,7 +456,7 @@ public class QueueFragment extends Fragment {
*/
private void setSortOrder(SortOrder sortOrder) {
UserPreferences.setQueueKeepSortedOrder(sortOrder);
- QueueSorter.sort(sortOrder, true);
+ DBWriter.reorderQueue(sortOrder, true);
}
@Override
@@ -430,7 +485,7 @@ public class QueueFragment extends Fragment {
DBWriter.moveQueueItemToBottom(selectedItem.getId(), true);
return true;
default:
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
+ return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
}
}
@@ -454,7 +509,8 @@ public class QueueFragment extends Fragment {
registerForContextMenu(recyclerView);
itemTouchHelper = new ItemTouchHelper(
- new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {
+ new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
+ ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
// Position tracking whilst dragging
int dragFrom = -1;
@@ -596,17 +652,19 @@ public class QueueFragment extends Fragment {
private void refreshInfoBar() {
String info = queue.size() + getString(R.string.episodes_suffix);
- if(queue.size() > 0) {
+ if (queue.size() > 0) {
long timeLeft = 0;
- float playbackSpeed = UserPreferences.getPlaybackSpeed();
- for(FeedItem item : queue) {
- if(item.getMedia() != null) {
- timeLeft +=
- (long) ((item.getMedia().getDuration() - item.getMedia().getPosition())
- / playbackSpeed);
+ for (FeedItem item : queue) {
+ float playbackSpeed = 1;
+ if (UserPreferences.timeRespectsSpeed()) {
+ playbackSpeed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(item.getMedia());
+ }
+ if (item.getMedia() != null) {
+ long itemTimeLeft = item.getMedia().getDuration() - item.getMedia().getPosition();
+ timeLeft += itemTimeLeft / playbackSpeed;
}
}
- info += " \u2022 ";
+ info += " • ";
info += getString(R.string.time_left_label);
info += Converter.getDurationStringLocalized(getActivity(), timeLeft);
}
@@ -673,19 +731,6 @@ public class QueueFragment extends Fragment {
}
};
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
- Log.d(TAG, "arg: " + arg);
- loadItems(false);
- if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
- }
- }
- }
- };
-
private void loadItems(final boolean restoreScrollPosition) {
Log.d(TAG, "loadItems()");
if(disposable != null) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
index e4213cc6b..7e217cde4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -2,7 +2,8 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,7 +12,6 @@ import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -110,9 +110,9 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
Log.e(TAG, Log.getStackTraceString(error));
view.setAlpha(1f);
String prefix = getString(R.string.error_msg_prefix);
- new MaterialDialog.Builder(getActivity())
- .content(prefix + " " + error.getMessage())
- .neutralText(android.R.string.ok)
+ new AlertDialog.Builder(getActivity())
+ .setMessage(prefix + " " + error.getMessage())
+ .setPositiveButton(android.R.string.ok, null)
.show();
});
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index 2a7f7d12b..7e8823c27 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
+import androidx.fragment.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
@@ -25,6 +25,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.view.EmptyViewHandler;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Displays all running downloads and provides actions to cancel them
@@ -75,7 +76,7 @@ public class RunningDownloadsFragment extends ListFragment {
setListAdapter(null);
}
- @Subscribe(sticky = true)
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 0892bce0a..d124d6aa2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -2,11 +2,11 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.SearchView;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -20,7 +20,7 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SearchlistAdapter;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -30,6 +30,8 @@ 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;
/**
* Performs a search operation on all feeds or one specific feed and displays the search result.
@@ -76,7 +78,6 @@ public class SearchFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
search();
}
@@ -86,7 +87,6 @@ public class SearchFragment extends ListFragment {
if(disposable != null) {
disposable.dispose();
}
- EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
@@ -103,6 +103,13 @@ public class SearchFragment extends ListFragment {
searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
setListAdapter(searchAdapter);
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ EventBus.getDefault().unregister(this);
}
@Override
@@ -145,15 +152,10 @@ public class SearchFragment extends ListFragment {
MenuItemCompat.setActionView(item, sv);
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE
- | EventDistributor.DOWNLOAD_HANDLED)) != 0) {
- search();
- }
- }
- };
+ @Subscribe
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ search();
+ }
private void onSearchResults(List<SearchResult> results) {
searchResults = results;
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 15c6052a9..aa6d80bb0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -5,8 +5,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.annotation.StringRes;
-import android.support.v4.app.Fragment;
+import androidx.annotation.StringRes;
+import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -18,6 +18,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
import java.util.concurrent.Callable;
import de.danoeh.antennapod.R;
@@ -25,19 +27,29 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+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;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* Fragment for displaying feed subscriptions
@@ -45,17 +57,17 @@ import io.reactivex.schedulers.Schedulers;
public class SubscriptionFragment extends Fragment {
public static final String TAG = "SubscriptionFragment";
-
- private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
private static final String PREFS = "SubscriptionFragment";
private static final String PREF_NUM_COLUMNS = "columns";
private GridView subscriptionGridLayout;
private DBReader.NavDrawerData navDrawerData;
private SubscriptionsAdapter subscriptionAdapter;
+ private FloatingActionButton subscriptionAddButton;
+ private EmptyViewHandler emptyView;
private int mPosition = -1;
+ private boolean isUpdatingFeeds = false;
private Disposable disposable;
private SharedPreferences prefs;
@@ -76,6 +88,8 @@ public class SubscriptionFragment extends Fragment {
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, 3));
registerForContextMenu(subscriptionGridLayout);
+ subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
+ setupEmptyView();
return root;
}
@@ -89,6 +103,8 @@ public class SubscriptionFragment extends Fragment {
menu.findItem(R.id.subscription_num_columns_3).setChecked(columns == 3);
menu.findItem(R.id.subscription_num_columns_4).setChecked(columns == 4);
menu.findItem(R.id.subscription_num_columns_5).setChecked(columns == 5);
+
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
@@ -97,6 +113,9 @@ public class SubscriptionFragment extends Fragment {
return true;
}
switch (item.getItemId()) {
+ case R.id.refresh_item:
+ AutoUpdateManager.runImmediate(requireContext());
+ return true;
case R.id.subscription_num_columns_2:
setColumnNumber(2);
return true;
@@ -120,13 +139,28 @@ public class SubscriptionFragment extends Fragment {
getActivity().invalidateOptionsMenu();
}
+ private void setupEmptyView() {
+ emptyView = new EmptyViewHandler(getContext());
+ emptyView.setIcon(R.attr.ic_folder);
+ emptyView.setTitle(R.string.no_subscriptions_head_label);
+ emptyView.setMessage(R.string.no_subscriptions_label);
+ emptyView.attachToListView(subscriptionGridLayout);
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- subscriptionAdapter = new SubscriptionsAdapter((MainActivity)getActivity(), itemAccess);
+
+ subscriptionAdapter = new SubscriptionsAdapter((MainActivity) getActivity(), itemAccess);
subscriptionGridLayout.setAdapter(subscriptionAdapter);
subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter);
+ subscriptionAddButton.setOnClickListener(view -> {
+ if (getActivity() instanceof MainActivity) {
+ ((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
+ }
+ });
+
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.subscriptions_label);
}
@@ -135,14 +169,14 @@ public class SubscriptionFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
- EventDistributor.getInstance().register(contentUpdate);
+ EventBus.getDefault().register(this);
loadSubscriptions();
}
@Override
public void onStop() {
super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
+ EventBus.getDefault().unregister(this);
if(disposable != null) {
disposable.dispose();
}
@@ -152,12 +186,14 @@ public class SubscriptionFragment extends Fragment {
if(disposable != null) {
disposable.dispose();
}
+ emptyView.hide();
disposable = Observable.fromCallable(DBReader::getNavDrawerData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
navDrawerData = result;
subscriptionAdapter.notifyDataSetChanged();
+ emptyView.updateVisibility();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@@ -268,15 +304,26 @@ public class SubscriptionFragment extends Fragment {
dialog.createNewDialog().show();
}
- private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EVENTS & arg) != 0) {
- Log.d(TAG, "Received contentUpdate Intent.");
- loadSubscriptions();
- }
+ @Subscribe
+ public void onFeedListChanged(FeedListUpdateEvent event) {
+ loadSubscriptions();
+ }
+
+ @Subscribe
+ public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
+ loadSubscriptions();
+ }
+
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
+ getActivity().invalidateOptionsMenu();
}
- };
+ }
+
+ private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
+ () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java
new file mode 100644
index 000000000..461fa9da3
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java
@@ -0,0 +1,5 @@
+package de.danoeh.antennapod.fragment;
+
+public enum TransitionEffect {
+ NONE, FLIP, FADE
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
index 4dc114f9b..380f6741a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
@@ -4,11 +4,11 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
+import com.google.android.material.tabs.TabLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index 49851ebb4..4baa74df6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.Fragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -54,9 +54,8 @@ public abstract class PodcastListFragment extends Fragment {
inflater.inflate(R.menu.gpodder_podcasts, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
- sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
+ sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
index 10bd636dd..ffe69aa9a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -50,7 +50,6 @@ public class SearchListFragment extends PodcastListFragment {
// parent already inflated menu
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
sv.setQuery(query, false);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
index d39829260..92cd4ca84 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import org.apache.commons.lang3.Validate;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
index 1e46b1ac5..cde8fb3df 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
@@ -4,9 +4,9 @@ import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
+import androidx.fragment.app.ListFragment;
+import androidx.core.view.MenuItemCompat;
+import androidx.appcompat.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -40,7 +40,6 @@ public class TagListFragment extends ListFragment {
inflater.inflate(R.menu.gpodder_podcasts, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
sv.setQueryHint(getString(R.string.gpodnet_search_hint));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java
new file mode 100644
index 000000000..62a5eb306
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java
@@ -0,0 +1,65 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.ListFragment;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.adapter.SimpleIconListAdapter;
+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 java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+public class AboutDevelopersFragment extends ListFragment {
+ private Disposable developersLoader;
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setDivider(null);
+ getListView().setSelector(android.R.color.transparent);
+
+ developersLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> {
+ ArrayList<SimpleIconListAdapter.ListItem> developers = new ArrayList<>();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ getContext().getAssets().open("developers.csv")));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String[] info = line.split(";");
+ developers.add(new SimpleIconListAdapter.ListItem(info[0], info[2],
+ "https://avatars2.githubusercontent.com/u/" + info[1] + "?s=60&v=4"));
+ }
+ emitter.onSuccess(developers);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ developers -> setListAdapter(new SimpleIconListAdapter<>(getContext(), developers)),
+ error -> Toast.makeText(getContext(), "Error while loading developers", Toast.LENGTH_LONG).show()
+ );
+
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (developersLoader != null) {
+ developersLoader.dispose();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.developers);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java
new file mode 100644
index 000000000..0fa7bd4bb
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java
@@ -0,0 +1,56 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Bundle;
+import androidx.preference.PreferenceFragmentCompat;
+import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.core.util.IntentUtils;
+
+public class AboutFragment extends PreferenceFragmentCompat {
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_about);
+
+ findPreference("about_version").setSummary(String.format(
+ "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH));
+ findPreference("about_version").setOnPreferenceClickListener((preference) -> {
+ ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getString(R.string.bug_report_title),
+ findPreference("about_version").getSummary());
+ clipboard.setPrimaryClip(clip);
+ Snackbar.make(getView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show();
+ return true;
+ });
+ findPreference("about_developers").setOnPreferenceClickListener((preference) -> {
+ getFragmentManager().beginTransaction().replace(R.id.content, new AboutDevelopersFragment())
+ .addToBackStack(getString(R.string.developers)).commit();
+ return true;
+ });
+ findPreference("about_translators").setOnPreferenceClickListener((preference) -> {
+ getFragmentManager().beginTransaction().replace(R.id.content, new AboutTranslatorsFragment())
+ .addToBackStack(getString(R.string.translators)).commit();
+ return true;
+ });
+ findPreference("about_privacy_policy").setOnPreferenceClickListener((preference) -> {
+ IntentUtils.openInBrowser(getContext(), "https://antennapod.org/privacy.html");
+ return true;
+ });
+ findPreference("about_licenses").setOnPreferenceClickListener((preference) -> {
+ getFragmentManager().beginTransaction().replace(R.id.content, new AboutLicensesFragment())
+ .addToBackStack(getString(R.string.translators)).commit();
+ return true;
+ });
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.about_pref);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java
new file mode 100644
index 000000000..536d11e01
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java
@@ -0,0 +1,126 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.ListFragment;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.adapter.SimpleIconListAdapter;
+import de.danoeh.antennapod.core.util.IntentUtils;
+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 org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+public class AboutLicensesFragment extends ListFragment {
+ private Disposable licensesLoader;
+ private final ArrayList<LicenseItem> licenses = new ArrayList<>();
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setDivider(null);
+
+ licensesLoader = Single.create((SingleOnSubscribe<ArrayList<LicenseItem>>) emitter -> {
+ licenses.clear();
+ InputStream stream = getContext().getAssets().open("licenses.xml");
+ DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ NodeList libraryList = docBuilder.parse(stream).getElementsByTagName("library");
+ for (int i = 0; i < libraryList.getLength(); i++) {
+ NamedNodeMap lib = libraryList.item(i).getAttributes();
+ licenses.add(new LicenseItem(
+ lib.getNamedItem("name").getTextContent(),
+ String.format("By %s, %s license",
+ lib.getNamedItem("author").getTextContent(),
+ lib.getNamedItem("license").getTextContent()),
+ null,
+ lib.getNamedItem("website").getTextContent(),
+ lib.getNamedItem("licenseText").getTextContent()));
+ }
+ emitter.onSuccess(licenses);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ developers -> setListAdapter(new SimpleIconListAdapter<LicenseItem>(getContext(), developers)),
+ error -> Toast.makeText(getContext(), "Error while loading licenses", Toast.LENGTH_LONG).show()
+ );
+
+ }
+
+ private static class LicenseItem extends SimpleIconListAdapter.ListItem {
+ final String licenseUrl;
+ final String licenseTextFile;
+
+ LicenseItem(String title, String subtitle, String imageUrl, String licenseUrl, String licenseTextFile) {
+ super(title, subtitle, imageUrl);
+ this.licenseUrl = licenseUrl;
+ this.licenseTextFile = licenseTextFile;
+ }
+ }
+
+ @Override
+ public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+
+ LicenseItem item = licenses.get(position);
+ CharSequence[] items = {"View website", "View license"};
+ new AlertDialog.Builder(getContext())
+ .setTitle(item.title)
+ .setItems(items, (dialog, which) -> {
+ if (which == 0) {
+ IntentUtils.openInBrowser(getContext(), item.licenseUrl);
+ } else if (which == 1) {
+ showLicenseText(item.licenseTextFile);
+ }
+ }).show();
+ }
+
+ private void showLicenseText(String licenseTextFile) {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ getContext().getAssets().open(licenseTextFile)));
+ StringBuilder licenseText = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ licenseText.append(line).append("\n");
+ }
+
+ new AlertDialog.Builder(getContext())
+ .setMessage(licenseText)
+ .show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (licensesLoader != null) {
+ licensesLoader.dispose();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.licenses);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java
new file mode 100644
index 000000000..914dbb9a2
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java
@@ -0,0 +1,64 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.ListFragment;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.adapter.SimpleIconListAdapter;
+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 java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+public class AboutTranslatorsFragment extends ListFragment {
+ private Disposable translatorsLoader;
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setDivider(null);
+ getListView().setSelector(android.R.color.transparent);
+
+ translatorsLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> {
+ ArrayList<SimpleIconListAdapter.ListItem> translators = new ArrayList<>();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ getContext().getAssets().open("translators.csv")));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String[] info = line.split(";");
+ translators.add(new SimpleIconListAdapter.ListItem(info[0], info[1], null));
+ }
+ emitter.onSuccess(translators);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ translators -> setListAdapter(new SimpleIconListAdapter<>(getContext(), translators)),
+ error -> Toast.makeText(getContext(), "Error while loading translators", Toast.LENGTH_LONG).show()
+ );
+
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (translatorsLoader != null) {
+ translatorsLoader.dispose();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.translators);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
index a04615a00..fa17fed0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java
@@ -1,29 +1,42 @@
package de.danoeh.antennapod.fragment.preferences;
+import android.Manifest;
import android.app.Activity;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.Build;
import android.os.Bundle;
-import android.support.v7.preference.CheckBoxPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import android.support.v7.preference.PreferenceScreen;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
import android.util.Log;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "AutoDnldPrefFragment";
+
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
+ private static final String PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt";
+
private CheckBoxPreference[] selectedNetworks;
+ private Preference prefPermissionRequestPromptOnAndroid10 = null;
+
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_autodownload);
@@ -35,6 +48,12 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.pref_automatic_download_title);
+ }
+
+ @Override
public void onResume() {
super.onResume();
checkAutodownloadItemVisibility(UserPreferences.isEnableAutodownload());
@@ -175,10 +194,65 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat {
}
private void setSelectedNetworksEnabled(boolean b) {
+ if (showPermissionRequestPromptOnAndroid10IfNeeded(b)) {
+ return;
+ }
+
if (selectedNetworks != null) {
for (Preference p : selectedNetworks) {
p.setEnabled(b);
}
}
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
+ return;
+ }
+ if (permissions.length > 0 && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION) &&
+ grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ buildAutodownloadSelectedNetworksPreference();
+ }
+ }
+
+ private boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
+ return false;
+ }
+
+ // Cases Android 10(Q) or later
+ if (prefPermissionRequestPromptOnAndroid10 != null) {
+ getPreferenceScreen().removePreference(prefPermissionRequestPromptOnAndroid10);
+ prefPermissionRequestPromptOnAndroid10 = null;
+ }
+
+ if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+
+ // Case location permission not yet granted, permission-specific UI is needed
+ if (!wifiFilterEnabled) {
+ // Don't show the UI when WiFi filter disabled.
+ // it still return true, so that the caller knows
+ // it does not have required permission, and will not invoke codes that require so.
+ return true;
+ }
+
+ Preference pref = new Preference(requireActivity());
+ pref.setKey(PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT);
+ pref.setTitle(R.string.autodl_wifi_filter_permission_title);
+ pref.setSummary(R.string.autodl_wifi_filter_permission_message);
+ pref.setIcon(R.drawable.ic_warning_red);
+ pref.setOnPreferenceClickListener(preference -> {
+ requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
+ return true;
+ });
+ pref.setPersistent(false);
+ getPreferenceScreen().addPreference(pref);
+ prefPermissionRequestPromptOnAndroid10 = pref;
+ return true;
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
index 491922056..c6ae8e20c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
@@ -3,12 +3,13 @@ package de.danoeh.antennapod.fragment.preferences;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
import android.text.Html;
import android.text.format.DateUtils;
import android.widget.Toast;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
@@ -30,6 +31,12 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.gpodnet_main_label);
+ }
+
+ @Override
public void onResume() {
super.onResume();
GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
index 229274b76..51f31eb92 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment.preferences;
import android.os.Bundle;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
@@ -14,6 +14,12 @@ public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat {
setupIntegrationsScreen();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.integrations_label);
+ }
+
private void setupIntegrationsScreen() {
findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder);
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 dcba5fe89..5fd38d663 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
@@ -1,27 +1,15 @@
package de.danoeh.antennapod.fragment.preferences;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
-import android.support.v4.content.FileProvider;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import android.util.Log;
-import android.widget.Toast;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.PreferenceFragmentCompat;
import com.bytehamster.lib.preferencesearch.SearchConfiguration;
import com.bytehamster.lib.preferencesearch.SearchPreference;
-import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AboutActivity;
+import de.danoeh.antennapod.activity.BugReportActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.activity.StatisticsActivity;
-
-import java.util.List;
+import de.danoeh.antennapod.core.util.IntentUtils;
public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "MainPreferencesFragment";
@@ -31,9 +19,9 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_SCREEN_NETWORK = "prefScreenNetwork";
private static final String PREF_SCREEN_INTEGRATIONS = "prefScreenIntegrations";
private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
- private static final String PREF_KNOWN_ISSUES = "prefKnownIssues";
private static final String PREF_FAQ = "prefFaq";
- private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport";
+ private static final String PREF_VIEW_MAILING_LIST = "prefViewMailingList";
+ private static final String PREF_SEND_BUG_REPORT = "prefSendBugReport";
private static final String STATISTICS = "statistics";
private static final String PREF_ABOUT = "prefAbout";
@@ -44,6 +32,12 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
setupSearch();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label);
+ }
+
private void setupMainScreen() {
findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_user_interface);
@@ -68,59 +62,32 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
findPreference(PREF_ABOUT).setOnPreferenceClickListener(
preference -> {
- startActivity(new Intent(getActivity(), AboutActivity.class));
+ getFragmentManager().beginTransaction().replace(R.id.content, new AboutFragment())
+ .addToBackStack(getString(R.string.about_pref)).commit();
return true;
}
);
findPreference(STATISTICS).setOnPreferenceClickListener(
preference -> {
- startActivity(new Intent(getActivity(), StatisticsActivity.class));
+ getFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment())
+ .addToBackStack(getString(R.string.statistics_label)).commit();
return true;
}
);
- findPreference(PREF_KNOWN_ISSUES).setOnPreferenceClickListener(preference -> {
- openInBrowser("https://github.com/AntennaPod/AntennaPod/labels/bug");
+ findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
+ IntentUtils.openInBrowser(getContext(), "https://antennapod.org/faq.html");
return true;
});
- findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
- openInBrowser("https://antennapod.org/faq.html");
+ findPreference(PREF_VIEW_MAILING_LIST).setOnPreferenceClickListener(preference -> {
+ IntentUtils.openInBrowser(getContext(), "https://groups.google.com/forum/#!forum/antennapod");
return true;
});
- findPreference(PREF_SEND_CRASH_REPORT).setOnPreferenceClickListener(preference -> {
- Context context = getActivity().getApplicationContext();
- Intent emailIntent = new Intent(Intent.ACTION_SEND);
- emailIntent.setType("text/plain");
- emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
- emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
- // the attachment
- Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority),
- CrashReportWriter.getFile());
- emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- String intentTitle = getActivity().getString(R.string.send_email);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
+ findPreference(PREF_SEND_BUG_REPORT).setOnPreferenceClickListener(preference -> {
+ startActivity(new Intent(getActivity(), BugReportActivity.class));
return true;
});
}
- private void openInBrowser(String url) {
- try {
- Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(myIntent);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
- Log.e(TAG, Log.getStackTraceString(e));
- }
- }
-
private void setupSearch() {
SearchPreference searchPreference = (SearchPreference) findPreference("searchPreference");
SearchConfiguration config = searchPreference.getSearchConfiguration();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
index ac2436e25..1ca8f63aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
@@ -4,12 +4,9 @@ import android.app.TimePickerDialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceFragmentCompat;
import android.text.format.DateFormat;
-import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -31,6 +28,12 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.network_pref);
+ }
+
+ @Override
public void onResume() {
super.onResume();
setUpdateIntervalText();
@@ -59,7 +62,7 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
ProxyDialog dialog = new ProxyDialog(getActivity());
- dialog.createDialog().show();
+ dialog.show();
return true;
});
}
@@ -101,13 +104,10 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
private void showUpdateIntervalTimePreferencesDialog() {
final Context context = getActivity();
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.pref_autoUpdateIntervallOrTime_title);
- builder.content(R.string.pref_autoUpdateIntervallOrTime_message);
- builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
- builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
- builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
- builder.onPositive((dialog, which) -> {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.pref_autoUpdateIntervallOrTime_title);
+ builder.setMessage(R.string.pref_autoUpdateIntervallOrTime_message);
+ builder.setPositiveButton(R.string.pref_autoUpdateIntervallOrTime_Interval, (dialog, which) -> {
AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
@@ -127,8 +127,9 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
builder1.show();
});
- builder.onNegative((dialog, which) -> {
- int hourOfDay = 7, minute = 0;
+ builder.setNegativeButton(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay, (dialog, which) -> {
+ int hourOfDay = 7;
+ int minute = 0;
int[] updateTime = UserPreferences.getUpdateTimeOfDay();
if (updateTime.length == 2) {
hourOfDay = updateTime[0];
@@ -145,7 +146,7 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
timePickerDialog.show();
});
- builder.onNeutral((dialog, which) -> {
+ builder.setNeutralButton(R.string.pref_autoUpdateIntervallOrTime_Disable, (dialog, which) -> {
UserPreferences.disableAutoUpdate();
setUpdateIntervalText();
});
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
index e1714d4bd..b82bba89b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
@@ -4,10 +4,18 @@ import android.app.Activity;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.PreferenceFragmentCompat;
+
+import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
+import java.util.Map;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MediaplayerActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
@@ -28,9 +36,9 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
}
@Override
- public void onResume() {
- super.onResume();
- checkSonicItemVisibility();
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.playback_pref);
}
private void setupPlaybackScreen() {
@@ -56,6 +64,43 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
}
+
+ buildEnqueueLocationPreference();
+ }
+
+ private void buildEnqueueLocationPreference() {
+ final Resources res = requireActivity().getResources();
+ final Map<String, String> options = new ArrayMap<>();
+ {
+ String[] keys = res.getStringArray(R.array.enqueue_location_values);
+ String[] values = res.getStringArray(R.array.enqueue_location_options);
+ for (int i = 0; i < keys.length; i++) {
+ options.put(keys[i], values[i]);
+ }
+ }
+
+ ListPreference pref = requirePreference(UserPreferences.PREF_ENQUEUE_LOCATION);
+ pref.setSummary(res.getString(R.string.pref_enqueue_location_sum, options.get(pref.getValue())));
+
+ pref.setOnPreferenceChangeListener((preference, newValue) -> {
+ if (!(newValue instanceof String)) {
+ return false;
+ }
+ String newValStr = (String)newValue;
+ pref.setSummary(res.getString(R.string.pref_enqueue_location_sum, options.get(newValStr)));
+ return true;
+ });
+ }
+
+ @NonNull
+ private <T extends Preference> T requirePreference(@NonNull CharSequence key) {
+ // Possibly put it to a common method in abstract base class
+ T result = findPreference(key);
+ if (result == null) {
+ throw new IllegalArgumentException("Preference with key '" + key + "' is not found");
+
+ }
+ return result;
}
private void buildSmartMarkAsPlayedPreference() {
@@ -79,14 +124,4 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
}
pref.setEntries(entries);
}
-
-
-
- private void checkSonicItemVisibility() {
- if (Build.VERSION.SDK_INT < 16) {
- ListPreference p = (ListPreference) findPreference(UserPreferences.PREF_MEDIA_PLAYER);
- p.setEntries(R.array.media_player_options_no_sonic);
- p.setEntryValues(R.array.media_player_values_no_sonic);
- }
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
new file mode 100644
index 000000000..7e1fdf2b9
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
@@ -0,0 +1,180 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.RadioButton;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.adapter.StatisticsListAdapter;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import io.reactivex.Completable;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Displays the 'statistics' screen
+ */
+public class StatisticsFragment extends Fragment {
+ private static final String TAG = StatisticsFragment.class.getSimpleName();
+ private static final String PREF_NAME = "StatisticsActivityPrefs";
+ private static final String PREF_COUNT_ALL = "countAll";
+
+ private Disposable disposable;
+ private RecyclerView feedStatisticsList;
+ private ProgressBar progressBar;
+ private StatisticsListAdapter listAdapter;
+ private boolean countAll = false;
+ private SharedPreferences prefs;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
+ setHasOptionsMenu(true);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ @NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.statistics_activity, container, false);
+ feedStatisticsList = root.findViewById(R.id.statistics_list);
+ progressBar = root.findViewById(R.id.progressBar);
+ listAdapter = new StatisticsListAdapter(getContext());
+ listAdapter.setCountAll(countAll);
+ feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
+ feedStatisticsList.setAdapter(listAdapter);
+ return root;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
+ refreshStatistics();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.statistics, menu);
+ menu.findItem(R.id.statistics_reset).setEnabled(!countAll);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.statistics_mode) {
+ selectStatisticsMode();
+ return true;
+ }
+ if (item.getItemId() == R.id.statistics_reset) {
+ confirmResetStatistics();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void selectStatisticsMode() {
+ View contentView = View.inflate(getContext(), R.layout.statistics_mode_select_dialog, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setView(contentView);
+ builder.setTitle(R.string.statistics_mode);
+
+ if (countAll) {
+ ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true);
+ } else {
+ ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true);
+ }
+
+ builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked();
+ listAdapter.setCountAll(countAll);
+ prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply();
+ refreshStatistics();
+ getActivity().invalidateOptionsMenu();
+ });
+
+ builder.show();
+ }
+
+ private void confirmResetStatistics() {
+ if (!countAll) {
+ ConfirmationDialog conDialog = new ConfirmationDialog(
+ getActivity(),
+ R.string.statistics_reset_data,
+ R.string.statistics_reset_data_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ dialog.dismiss();
+ doResetStatistics();
+ }
+ };
+ conDialog.createNewDialog().show();
+ }
+ }
+
+ private void doResetStatistics() {
+ progressBar.setVisibility(View.VISIBLE);
+ feedStatisticsList.setVisibility(View.GONE);
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ disposable = Completable.fromFuture(DBWriter.resetStatistics())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::refreshStatistics, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+
+ private void refreshStatistics() {
+ progressBar.setVisibility(View.VISIBLE);
+ feedStatisticsList.setVisibility(View.GONE);
+ loadStatistics();
+ }
+
+ private void loadStatistics() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ listAdapter.update(result);
+ progressBar.setVisibility(View.GONE);
+ feedStatisticsList.setVisibility(View.VISIBLE);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
index b4226b546..2c1590c47 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -4,6 +4,7 @@ import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -11,15 +12,19 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.FileProvider;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.FileProvider;
+import androidx.documentfile.provider.DocumentFile;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceFragmentCompat;
import android.util.Log;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
import de.danoeh.antennapod.activity.ImportExportActivity;
import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
import de.danoeh.antennapod.asynctask.ExportWorker;
import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.core.export.html.HtmlWriter;
@@ -45,6 +50,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
+ private static final int CHOOSE_OPML_EXPORT_PATH = 1;
+ private static final String DEFAULT_OPML_OUTPUT_NAME = "antennapod-feeds.opml";
+ private static final String CONTENT_TYPE_OPML = "text/x-opml";
+ private static final int CHOOSE_HTML_EXPORT_PATH = 2;
+ private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds.html";
+ private static final String CONTENT_TYPE_HTML = "text/html";
private Disposable disposable;
@Override
@@ -54,11 +65,25 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
@Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.storage_pref);
+ }
+
+ @Override
public void onResume() {
super.onResume();
setDataFolderText();
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
private void setupStorageScreen() {
final Activity activity = getActivity();
@@ -69,9 +94,16 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
);
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new OpmlWriter()));
+ preference -> {
+ openOpmlExportPathPicker();
+ return true;
+ }
+ );
findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
- preference -> export(new HtmlWriter()));
+ preference -> {
+ openHtmlExportPathPicker();
+ return true;
+ });
findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
preference -> {
activity.startActivity(new Intent(activity, OpmlImportFromPathActivity.class));
@@ -129,52 +161,65 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
}
private boolean export(ExportWriter exportWriter) {
+ return export(exportWriter, null);
+ }
+
+ private boolean export(ExportWriter exportWriter, final Uri uri) {
Context context = getActivity();
final ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage(context.getString(R.string.exporting_label));
progressDialog.setIndeterminate(true);
progressDialog.show();
- final AlertDialog.Builder alert = new AlertDialog.Builder(context)
- .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- alert.setTitle(R.string.export_success_title);
- String message = context.getString(R.string.export_success_sum, output.toString());
- alert.setMessage(message);
- alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ if (uri == null) {
+ Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
context.getString(R.string.provider_authority), output);
- Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_SUBJECT,
- context.getResources().getText(R.string.opml_export_label));
- sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
- sendIntent.setType("text/plain");
- sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- context.startActivity(Intent.createChooser(sendIntent,
- context.getResources().getText(R.string.send_label)));
- });
- alert.create().show();
- }, error -> {
- alert.setTitle(R.string.export_error_label);
- alert.setMessage(error.getMessage());
- alert.show();
- }, progressDialog::dismiss);
+ showExportSuccessDialog(context.getString(R.string.export_success_sum, output.toString()), fileUri);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ } else {
+ Observable<DocumentFile> observable = new DocumentFileExportWorker(exportWriter, context, uri).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
+ showExportSuccessDialog(context.getString(R.string.export_success_sum, output.getUri()), output.getUri());
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
return true;
}
- public void unsubscribeExportSubscription() {
- if (disposable != null) {
- disposable.dispose();
- }
+ private void showExportSuccessDialog(final String message, final Uri streamUri) {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_success_title);
+ alert.setMessage(message);
+ alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.opml_export_label));
+ sendIntent.putExtra(Intent.EXTRA_STREAM, streamUri);
+ sendIntent.setType("text/plain");
+ sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ List<ResolveInfo> resInfoList = getContext().getPackageManager()
+ .queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ getContext().grantUriPermission(packageName, streamUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ getContext().startActivity(Intent.createChooser(sendIntent, getString(R.string.send_label)));
+ });
+ alert.create().show();
+ }
+
+ private void showExportErrorDialog(final Throwable error) {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_error_label);
+ alert.setMessage(error.getMessage());
+ alert.show();
}
@SuppressLint("NewApi")
@@ -184,22 +229,22 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
- if(dir != null) {
+ if (dir != null) {
path = new File(dir);
} else {
path = getActivity().getExternalFilesDir(null);
}
String message = null;
- final Context context= getActivity().getApplicationContext();
- if(!path.exists()) {
+ final Context context = getActivity().getApplicationContext();
+ if (!path.exists()) {
message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
- } else if(!path.canRead()) {
+ } else if (!path.canRead()) {
message = String.format(context.getString(R.string.folder_not_readable_error), dir);
- } else if(!path.canWrite()) {
+ } else if (!path.canWrite()) {
message = String.format(context.getString(R.string.folder_not_writable_error), dir);
}
- if(message == null) {
+ if (message == null) {
Log.d(TAG, "Setting data folder: " + dir);
UserPreferences.setDataFolder(dir);
setDataFolderText();
@@ -210,6 +255,16 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
ab.show();
}
}
+
+ if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_OPML_EXPORT_PATH) {
+ Uri uri = data.getData();
+ export(new OpmlWriter(), uri);
+ }
+
+ if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_HTML_EXPORT_PATH) {
+ Uri uri = data.getData();
+ export(new HtmlWriter(), uri);
+ }
}
private void setDataFolderText() {
@@ -231,6 +286,50 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
+ private void openOpmlExportPathPicker() {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(CONTENT_TYPE_OPML)
+ .putExtra(Intent.EXTRA_TITLE, DEFAULT_OPML_OUTPUT_NAME);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ startActivityForResult(intentPickAction, CHOOSE_OPML_EXPORT_PATH);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
+
+ // If we are using a SDK lower than API 21 or the implicit intent failed
+ // fallback to the legacy export process
+ export(new OpmlWriter());
+ }
+
+ private void openHtmlExportPathPicker() {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(CONTENT_TYPE_HTML)
+ .putExtra(Intent.EXTRA_TITLE, DEFAULT_HTML_OUTPUT_NAME);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ startActivityForResult(intentPickAction, CHOOSE_HTML_EXPORT_PATH);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
+
+ // If we are using a SDK lower than API 21 or the implicit intent failed
+ // fallback to the legacy export process
+ export(new HtmlWriter());
+ }
+
private void showChooseDataFolderDialog() {
ChooseDataFolderDialog.showDialog(
getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
index e1d44f7d3..191999cf7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java
@@ -4,13 +4,14 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.PreferenceFragmentCompat;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceFragmentCompat;
import android.widget.ListView;
import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import org.apache.commons.lang3.ArrayUtils;
@@ -25,6 +26,12 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat {
setupInterfaceScreen();
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.user_interface_label);
+ }
+
private void setupInterfaceScreen() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index 156657a00..60eaf14a5 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -1,11 +1,11 @@
package de.danoeh.antennapod.menuhandler;
import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.annotation.Nullable;
+import android.os.Handler;
+import androidx.annotation.NonNull;
+import com.google.android.material.snackbar.Snackbar;
+import androidx.fragment.app.Fragment;
import android.util.Log;
-import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -18,7 +18,6 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ShareUtils;
/**
@@ -51,35 +50,21 @@ public class FeedItemMenuHandler {
* @param mi An instance of MenuInterface that the method uses to change a
* MenuItem's visibility
* @param selectedItem The FeedItem for which the menu is supposed to be prepared
- * @param showExtendedMenu True if MenuItems that let the user share information about
- * the FeedItem and visit its website should be set visible. This
- * parameter should be set to false if the menu space is limited.
- * @param queueAccess Used for testing if the queue contains the selected item; only used for
- * move to top/bottom in the queue
* @return Returns true if selectedItem is not null.
*/
public static boolean onPrepareMenu(MenuInterface mi,
- FeedItem selectedItem,
- boolean showExtendedMenu,
- @Nullable LongList queueAccess) {
+ FeedItem selectedItem) {
if (selectedItem == null) {
return false;
}
boolean hasMedia = selectedItem.getMedia() != null;
boolean isPlaying = hasMedia && selectedItem.getState() == FeedItem.State.PLAYING;
- boolean keepSorted = UserPreferences.isQueueKeepSorted();
if (!isPlaying) {
mi.setItemVisibility(R.id.skip_episode_item, false);
}
boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE);
- if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId() || keepSorted) {
- mi.setItemVisibility(R.id.move_to_top_item, false);
- }
- if (queueAccess == null || queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == selectedItem.getId() || keepSorted) {
- mi.setItemVisibility(R.id.move_to_bottom_item, false);
- }
if (!isInQueue) {
mi.setItemVisibility(R.id.remove_from_queue_item, false);
}
@@ -87,12 +72,12 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.add_to_queue_item, false);
}
- if (!showExtendedMenu || !ShareUtils.hasLinkToShare(selectedItem)) {
+ if (!ShareUtils.hasLinkToShare(selectedItem)) {
mi.setItemVisibility(R.id.visit_website_item, false);
mi.setItemVisibility(R.id.share_link_item, false);
mi.setItemVisibility(R.id.share_link_with_position_item, false);
}
- if (!showExtendedMenu || !hasMedia || selectedItem.getMedia().getDownload_url() == null) {
+ if (!hasMedia || selectedItem.getMedia().getDownload_url() == null) {
mi.setItemVisibility(R.id.share_download_url_item, false);
mi.setItemVisibility(R.id.share_download_url_with_position_item, false);
}
@@ -104,6 +89,7 @@ public class FeedItemMenuHandler {
boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
mi.setItemVisibility(R.id.share_file, fileDownloaded);
+ mi.setItemVisibility(R.id.remove_new_flag_item, selectedItem.isNew());
if (selectedItem.isPlayed()) {
mi.setItemVisibility(R.id.mark_read_item, false);
} else {
@@ -114,7 +100,7 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.reset_position, false);
}
- if(!UserPreferences.isEnableAutodownload()) {
+ if(!UserPreferences.isEnableAutodownload() || fileDownloaded) {
mi.setItemVisibility(R.id.activate_auto_download, false);
mi.setItemVisibility(R.id.deactivate_auto_download, false);
} else if(selectedItem.getAutoDownload()) {
@@ -141,10 +127,8 @@ public class FeedItemMenuHandler {
*/
public static boolean onPrepareMenu(MenuInterface mi,
FeedItem selectedItem,
- boolean showExtendedMenu,
- LongList queueAccess,
int... excludeIds) {
- boolean rc = onPrepareMenu(mi, selectedItem, showExtendedMenu, queueAccess);
+ boolean rc = onPrepareMenu(mi, selectedItem);
if (rc && excludeIds != null) {
for (int id : excludeIds) {
mi.setItemVisibility(id, false);
@@ -153,8 +137,16 @@ public class FeedItemMenuHandler {
return rc;
}
- public static boolean onMenuItemClicked(Context context, int menuItemId,
- FeedItem selectedItem) {
+ /**
+ * Default menu handling for the given FeedItem.
+ *
+ * A Fragment instance, (rather than the more generic Context), is needed as a parameter
+ * to support some UI operations, e.g., creating a Snackbar.
+ */
+ public static boolean onMenuItemClicked(@NonNull Fragment fragment, int menuItemId,
+ @NonNull FeedItem selectedItem) {
+
+ @NonNull Context context = fragment.requireContext();
switch (menuItemId) {
case R.id.skip_episode_item:
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
@@ -162,9 +154,12 @@ public class FeedItemMenuHandler {
case R.id.remove_item:
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
break;
+ case R.id.remove_new_flag_item:
+ removeNewFlagWithUndo(fragment, selectedItem);
+ break;
case R.id.mark_read_item:
selectedItem.setPlayed(true);
- DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, false);
+ DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, true);
if(GpodnetPreferences.loggedIn()) {
FeedMedia media = selectedItem.getMedia();
// not all items have media, Gpodder only cares about those that do
@@ -216,14 +211,7 @@ public class FeedItemMenuHandler {
DBWriter.setFeedItemAutoDownload(selectedItem, false);
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(FeedItemUtil.getLinkWithFallback(selectedItem));
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(context, intent)) {
- context.startActivity(intent);
- } else {
- Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
- Toast.LENGTH_SHORT).show();
- }
+ IntentUtils.openInBrowser(context, FeedItemUtil.getLinkWithFallback(selectedItem));
break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
@@ -249,4 +237,39 @@ public class FeedItemMenuHandler {
return true;
}
+ /**
+ * Remove new flag with additional UI logic to allow undo with Snackbar.
+ *
+ * Undo is useful for Remove new flag, given there is no UI to undo it otherwise
+ * ,i.e., there is (context) menu item for add new flag
+ */
+ public static void removeNewFlagWithUndo(@NonNull Fragment fragment, FeedItem item) {
+ if (item == null) {
+ return;
+ }
+
+ Log.d(TAG, "removeNewFlagWithUndo(" + item.getId() + ")");
+ // 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(fragment.requireContext().getMainLooper());
+ final Runnable r = () -> {
+ FeedMedia media = item.getMedia();
+ if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
+ DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), media.getId());
+ }
+ };
+
+ Snackbar snackbar = Snackbar.make(fragment.getView(), fragment.getString(R.string.removed_new_flag_label),
+ Snackbar.LENGTH_LONG);
+ snackbar.setAction(fragment.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));
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 3949119fc..e32deba27 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -2,31 +2,28 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.v7.app.AlertDialog;
-import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.widget.Toast;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
+import androidx.annotation.NonNull;
+
+import org.apache.commons.lang3.StringUtils;
+
import java.util.Set;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItemFilter;
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.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
+import de.danoeh.antennapod.core.util.SortOrder;
import de.danoeh.antennapod.dialog.FilterDialog;
+import de.danoeh.antennapod.dialog.IntraFeedSortDialog;
/**
* Handles interactions with the FeedItemMenu.
@@ -50,6 +47,10 @@ public class FeedMenuHandler {
Log.d(TAG, "Preparing options menu");
menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged());
+ if (StringUtils.isBlank(selectedFeed.getLink())) {
+ menu.findItem(R.id.visit_website_item).setVisible(false);
+ menu.findItem(R.id.share_link_item).setVisible(false);
+ }
return true;
}
@@ -68,6 +69,9 @@ public class FeedMenuHandler {
case R.id.refresh_complete_item:
DBTasks.forceRefreshCompleteFeed(context, selectedFeed);
break;
+ case R.id.sort_items:
+ showSortDialog(context, selectedFeed);
+ break;
case R.id.filter_items:
showFilterDialog(context, selectedFeed);
break;
@@ -86,14 +90,7 @@ public class FeedMenuHandler {
conDialog.createNewDialog().show();
break;
case R.id.visit_website_item:
- Uri uri = Uri.parse(selectedFeed.getLink());
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(context, intent)) {
- context.startActivity(intent);
- } else {
- Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
- Toast.LENGTH_SHORT).show();
- }
+ IntentUtils.openInBrowser(context, selectedFeed.getLink());
break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
@@ -118,4 +115,17 @@ public class FeedMenuHandler {
filterDialog.openDialog();
}
+
+
+ private static void showSortDialog(Context context, Feed selectedFeed) {
+ IntraFeedSortDialog sortDialog = new IntraFeedSortDialog(context, selectedFeed.getSortOrder()) {
+ @Override
+ protected void updateSort(@NonNull SortOrder sortOrder) {
+ selectedFeed.setSortOrder(sortOrder);
+ DBWriter.setFeedItemSortOrder(selectedFeed.getId(), sortOrder);
+ }
+ };
+ sortDialog.openDialog();
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index 7b9fcad9b..64eb72ee3 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -2,14 +2,8 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
-import android.widget.EditText;
-
-import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
/**
@@ -17,18 +11,6 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
*/
public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuItemUtils {
- public static void adjustTextColor(Context context, SearchView sv) {
- if(Build.VERSION.SDK_INT < 14) {
- EditText searchEditText = sv.findViewById(R.id.search_src_text);
- if (UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark
- || UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
- searchEditText.setTextColor(Color.WHITE);
- } else {
- searchEditText.setTextColor(Color.BLACK);
- }
- }
- }
-
@SuppressWarnings("ResourceType")
public static void refreshLockItem(Context context, Menu menu) {
final MenuItem queueLock = menu.findItem(de.danoeh.antennapod.R.id.queue_lock);
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
index b810cbfa6..007457c24 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java
@@ -4,8 +4,8 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
index 50e76838c..a58986241 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.preferences;
import android.app.AlertDialog;
import android.content.Context;
-import android.support.v7.preference.Preference;
+import androidx.preference.Preference;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.View;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 1879dcbf8..d0321ddd2 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -3,8 +3,12 @@ package de.danoeh.antennapod.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
+
import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
+import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
public class PreferenceUpgrader {
@@ -21,7 +25,7 @@ public class PreferenceUpgrader {
if (oldVersion != newVersion) {
NotificationUtils.createChannels(context);
- UserPreferences.restartUpdateAlarm();
+ AutoUpdateManager.restartUpdateAlarm();
upgrade(oldVersion);
upgraderPrefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply();
@@ -29,6 +33,9 @@ public class PreferenceUpgrader {
}
private static void upgrade(int oldVersion) {
+ if (oldVersion == -1) {
+ return;
+ }
if (oldVersion < 1070196) {
// migrate episode cleanup value (unit changed from days to hours)
int oldValueInDays = UserPreferences.getEpisodeCleanupValue();
@@ -62,5 +69,21 @@ public class PreferenceUpgrader {
break;
}
}
+ if (oldVersion < 1070400) {
+ int theme = UserPreferences.getTheme();
+ if (theme == R.style.Theme_AntennaPod_Light) {
+ prefs.edit().putString(UserPreferences.PREF_THEME, "system").apply();
+ }
+
+ UserPreferences.setQueueLocked(false);
+ prefs.edit().putBoolean(UserPreferences.PREF_STREAM_OVER_DOWNLOAD, false).apply();
+
+ if (!prefs.contains(UserPreferences.PREF_ENQUEUE_LOCATION)) {
+ final String keyOldPrefEnqueueFront = "prefQueueAddToFront";
+ boolean enqueueAtFront = prefs.getBoolean(keyOldPrefEnqueueFront, false);
+ EnqueueLocation enqueueLocation = enqueueAtFront ? EnqueueLocation.FRONT : EnqueueLocation.BACK;
+ UserPreferences.setEnqueueLocation(enqueueLocation);
+ }
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
index 03958508d..5fa6588d9 100644
--- a/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
+++ b/app/src/main/java/de/danoeh/antennapod/spa/SPAUtil.java
@@ -46,7 +46,7 @@ public class SPAUtil {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, true);
- editor.commit();
+ editor.apply();
return true;
} else {
@@ -63,7 +63,7 @@ public class SPAUtil {
SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(c.getApplicationContext()).edit();
editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, false);
- editor.commit();
+ editor.apply();
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java b/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
index e79389fb3..4c116fa2d 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/AspectRatioVideoView.java
@@ -88,7 +88,7 @@ public class AspectRatioVideoView extends VideoView {
mVideoWidth = videoWidth;
mVideoHeight = videoHeight;
- /**
+ /*
* If this isn't set the video is stretched across the
* SurfaceHolders display surface (i.e. the SurfaceHolder
* as the same size and the video is drawn to fit this
diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
index 8b886e699..0bfd0247f 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
@@ -2,14 +2,14 @@ package de.danoeh.antennapod.view;
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.support.annotation.AttrRes;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
+import android.widget.AbsListView;
+import androidx.annotation.AttrRes;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
-import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -54,28 +54,31 @@ public class EmptyViewHandler {
emptyView.setVisibility(View.GONE);
}
- public void attachToListView(ListView listView) {
+ public void attachToListView(AbsListView listView) {
if (layoutAdded) {
- throw new IllegalStateException("Can not attach to ListView multiple times");
+ throw new IllegalStateException("Can not attach EmptyView multiple times");
}
+ addToParentView(listView);
layoutAdded = true;
- ((ViewGroup) listView.getParent()).addView(emptyView);
listView.setEmptyView(emptyView);
}
public void attachToRecyclerView(RecyclerView recyclerView) {
if (layoutAdded) {
- throw new IllegalStateException("Can not attach to ListView multiple times");
+ throw new IllegalStateException("Can not attach EmptyView multiple times");
}
+ addToParentView(recyclerView);
layoutAdded = true;
this.recyclerView = recyclerView;
- ViewGroup parent = ((ViewGroup) recyclerView.getParent());
- parent.addView(emptyView);
updateAdapter(recyclerView.getAdapter());
+ }
+ private void addToParentView(View view) {
+ ViewGroup parent = ((ViewGroup) view.getParent());
+ parent.addView(emptyView);
if (parent instanceof RelativeLayout) {
RelativeLayout.LayoutParams layoutParams =
- (RelativeLayout.LayoutParams)emptyView.getLayoutParams();
+ (RelativeLayout.LayoutParams) emptyView.getLayoutParams();
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
emptyView.setLayoutParams(layoutParams);
}
@@ -99,7 +102,7 @@ public class EmptyViewHandler {
}
};
- private void updateVisibility() {
+ public void updateVisibility() {
boolean empty;
if (adapter == null) {
empty = true;
diff --git a/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java
new file mode 100644
index 000000000..d1b2abf23
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java
@@ -0,0 +1,121 @@
+package de.danoeh.antennapod.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatImageView;
+import io.reactivex.annotations.Nullable;
+
+public class PieChartView extends AppCompatImageView {
+ private PieChartDrawable drawable;
+
+ public PieChartView(Context context) {
+ super(context);
+ setup();
+ }
+
+ public PieChartView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup();
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private void setup() {
+ drawable = new PieChartDrawable();
+ setImageDrawable(drawable);
+ }
+
+ /**
+ * Set array od names, array of values and array of colors.
+ */
+ public void setData(float[] dataValues) {
+ drawable.dataValues = dataValues;
+ drawable.valueSum = 0;
+ for (float datum : dataValues) {
+ drawable.valueSum += datum;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = getMeasuredWidth();
+ setMeasuredDimension(width, width / 2);
+ }
+
+ private static class PieChartDrawable extends Drawable {
+ private static final float MIN_DEGREES = 10f;
+ private static final float PADDING_DEGREES = 3f;
+ private static final float STROKE_SIZE = 15f;
+ private static final int[] COLOR_VALUES = new int[]{0xFF3775E6, 0xffe51c23, 0xffff9800, 0xff259b24, 0xff9c27b0,
+ 0xff0099c6, 0xffdd4477, 0xff66aa00, 0xffb82e2e, 0xff316395,
+ 0xff994499, 0xff22aa99, 0xffaaaa11, 0xff6633cc, 0xff0073e6};
+ private float[] dataValues;
+ private float valueSum;
+ private final Paint paint;
+
+ private PieChartDrawable() {
+ paint = new Paint();
+ paint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeJoin(Paint.Join.ROUND);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ paint.setStrokeWidth(STROKE_SIZE);
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (valueSum == 0) {
+ return;
+ }
+ float radius = getBounds().height() - STROKE_SIZE;
+ float center = getBounds().width() / 2.f;
+ RectF arcBounds = new RectF(center - radius, STROKE_SIZE, center + radius, STROKE_SIZE + radius * 2);
+
+ float startAngle = 180;
+ for (int i = 0; i < dataValues.length; i++) {
+ float datum = dataValues[i];
+ float sweepAngle = (180f - PADDING_DEGREES) * (datum / valueSum);
+ if (sweepAngle < MIN_DEGREES) {
+ break;
+ }
+ paint.setColor(COLOR_VALUES[i % COLOR_VALUES.length]);
+ float padding = i == 0 ? PADDING_DEGREES / 2 : PADDING_DEGREES;
+ canvas.drawArc(arcBounds, startAngle + padding, sweepAngle - padding, false, paint);
+ startAngle = startAngle + sweepAngle;
+ }
+
+ paint.setColor(Color.GRAY);
+ float sweepAngle = 360 - startAngle - PADDING_DEGREES / 2;
+ if (sweepAngle > PADDING_DEGREES) {
+ canvas.drawArc(arcBounds, startAngle + PADDING_DEGREES, sweepAngle - PADDING_DEGREES, false, paint);
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
index 45c3a35bd..5bd335532 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.view;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
/**
* AdapterDataObserver that relays all events to the method anythingChanged().
diff --git a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
index 7ce33e11f..f82309c4a 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.view;
import android.content.Context;
-import android.support.v7.widget.AppCompatImageView;
+import androidx.appcompat.widget.AppCompatImageView;
import android.util.AttributeSet;
/**
diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
deleted file mode 100644
index fe11a645c..000000000
--- a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.danoeh.antennapod.viewmodel;
-
-import android.arch.lifecycle.ViewModel;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.Maybe;
-
-public class FeedSettingsViewModel extends ViewModel {
- private Feed feed;
-
- public Maybe<Feed> getFeed(long feedId) {
- if (feed == null) {
- return loadFeed(feedId);
- } else {
- return Maybe.just(feed);
- }
- }
-
- private Maybe<Feed> loadFeed(long feedId) {
- return Maybe.create(emitter -> {
- Feed feed = DBReader.getFeed(feedId);
- if (feed != null) {
- this.feed = feed;
- emitter.onSuccess(feed);
- } else {
- emitter.onComplete();
- }
- });
- }
-}