summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod/activity
diff options
context:
space:
mode:
authorByteHamster <ByteHamster@users.noreply.github.com>2024-03-31 18:40:15 +0200
committerGitHub <noreply@github.com>2024-03-31 18:40:15 +0200
commitedb440a5a9a05e24c344a71b272b9238217e9c55 (patch)
tree13623ca7d0dac052ac35d693aac940d0727c87f9 /app/src/main/java/de/danoeh/antennapod/activity
parent4e47691e70e85736c7eeb30ce02c73176e565a86 (diff)
downloadAntennaPod-edb440a5a9a05e24c344a71b272b9238217e9c55.zip
Restructure related UI classes together (#7044)
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/activity')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java128
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java713
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PlaybackSpeedDialogActivity.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java194
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java815
7 files changed, 17 insertions, 1896 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
deleted file mode 100644
index e379b5eb2..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-import com.google.android.material.snackbar.Snackbar;
-
-import androidx.annotation.NonNull;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ShareCompat;
-import androidx.core.content.FileProvider;
-
-
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.TextView;
-
-
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.error.CrashReportWriter;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.storage.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 {
- private static final String TAG = "BugReportActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(ThemeSwitcher.getTheme(this));
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- setContentView(R.layout.bug_report);
-
- String stacktrace = "No crash report recorded";
- try {
- File crashFile = CrashReportWriter.getFile();
- if (crashFile.exists()) {
- stacktrace = IOUtils.toString(new FileInputStream(crashFile), Charset.forName("UTF-8"));
- } else {
- Log.d(TAG, stacktrace);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- TextView crashDetailsTextView = findViewById(R.id.crash_report_logs);
- crashDetailsTextView.setText(CrashReportWriter.getSystemInfo() + "\n\n" + stacktrace);
-
- 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), crashDetailsTextView.getText());
- clipboard.setPrimaryClip(clip);
- if (Build.VERSION.SDK_INT < 32) {
- Snackbar.make(findViewById(android.R.id.content), R.string.copied_to_clipboard,
- Snackbar.LENGTH_SHORT).show();
- }
- });
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.bug_report_options, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == R.id.export_logcat) {
- MaterialAlertDialogBuilder alertBuilder = new MaterialAlertDialogBuilder(this);
- alertBuilder.setMessage(R.string.confirm_export_log_dialog_message);
- alertBuilder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- exportLog();
- dialog.dismiss();
- });
- alertBuilder.setNegativeButton(R.string.cancel_label, null);
- alertBuilder.show();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void exportLog() {
- try {
- File filename = new File(UserPreferences.getDataFolder(null), "full-logs.txt");
- String cmd = "logcat -d -f " + filename.getAbsolutePath();
- Runtime.getRuntime().exec(cmd);
- //share file
- try {
- String authority = getString(R.string.provider_authority);
- Uri fileUri = FileProvider.getUriForFile(this, authority, filename);
-
- new ShareCompat.IntentBuilder(this)
- .setType("text/*")
- .addStream(fileUri)
- .setChooserTitle(R.string.share_file_label)
- .startChooser();
- } catch (Exception e) {
- e.printStackTrace();
- int strResId = R.string.log_file_share_exception;
- Snackbar.make(findViewById(android.R.id.content), strResId, Snackbar.LENGTH_LONG)
- .show();
- }
- } catch (IOException e) {
- e.printStackTrace();
- Snackbar.make(findViewById(android.R.id.content), e.getMessage(), Snackbar.LENGTH_LONG).show();
- }
- }
-
-
-}
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 32884c9c9..fd4007736 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -40,23 +40,23 @@ import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueueSink;
import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.dialog.rating.RatingDialogManager;
+import de.danoeh.antennapod.ui.screen.rating.RatingDialogManager;
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.MessageEvent;
-import de.danoeh.antennapod.fragment.AddFeedFragment;
-import de.danoeh.antennapod.fragment.AllEpisodesFragment;
-import de.danoeh.antennapod.fragment.AudioPlayerFragment;
-import de.danoeh.antennapod.fragment.CompletedDownloadsFragment;
-import de.danoeh.antennapod.fragment.DownloadLogFragment;
-import de.danoeh.antennapod.fragment.FeedItemlistFragment;
-import de.danoeh.antennapod.fragment.InboxFragment;
-import de.danoeh.antennapod.fragment.NavDrawerFragment;
-import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
-import de.danoeh.antennapod.fragment.QueueFragment;
-import de.danoeh.antennapod.fragment.SearchFragment;
-import de.danoeh.antennapod.fragment.SubscriptionFragment;
-import de.danoeh.antennapod.fragment.TransitionEffect;
+import de.danoeh.antennapod.ui.screen.AddFeedFragment;
+import de.danoeh.antennapod.ui.screen.AllEpisodesFragment;
+import de.danoeh.antennapod.ui.screen.playback.audio.AudioPlayerFragment;
+import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
+import de.danoeh.antennapod.ui.screen.download.DownloadLogFragment;
+import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment;
+import de.danoeh.antennapod.ui.screen.InboxFragment;
+import de.danoeh.antennapod.ui.screen.drawer.NavDrawerFragment;
+import de.danoeh.antennapod.ui.screen.PlaybackHistoryFragment;
+import de.danoeh.antennapod.ui.screen.queue.QueueFragment;
+import de.danoeh.antennapod.ui.screen.SearchFragment;
+import de.danoeh.antennapod.ui.screen.subscriptions.SubscriptionFragment;
+import de.danoeh.antennapod.ui.TransitionEffect;
import de.danoeh.antennapod.model.download.DownloadStatus;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
@@ -65,8 +65,8 @@ import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.common.ThemeUtils;
import de.danoeh.antennapod.ui.discovery.DiscoveryFragment;
-import de.danoeh.antennapod.ui.home.HomeFragment;
-import de.danoeh.antennapod.view.LockableBottomSheetBehavior;
+import de.danoeh.antennapod.ui.screen.home.HomeFragment;
+import de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
deleted file mode 100644
index 1f3963d46..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ /dev/null
@@ -1,713 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.LightingColorFilter;
-import android.os.Bundle;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Toast;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import androidx.appcompat.app.AppCompatActivity;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
-import com.google.android.material.snackbar.Snackbar;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
-import de.danoeh.antennapod.net.download.service.feed.remote.Downloader;
-import de.danoeh.antennapod.net.download.service.feed.remote.HttpDownloader;
-import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestCreator;
-import de.danoeh.antennapod.net.discovery.FeedUrlNotFoundException;
-import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
-import de.danoeh.antennapod.playback.service.PlaybackServiceInterface;
-import de.danoeh.antennapod.core.util.DownloadErrorLabel;
-import de.danoeh.antennapod.databinding.EditTextDialogBinding;
-import de.danoeh.antennapod.databinding.OnlinefeedviewHeaderBinding;
-import de.danoeh.antennapod.event.EpisodeDownloadEvent;
-import de.danoeh.antennapod.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.event.PlayerStatusEvent;
-import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.model.download.DownloadRequest;
-import de.danoeh.antennapod.model.download.DownloadResult;
-import de.danoeh.antennapod.storage.database.DBReader;
-import de.danoeh.antennapod.storage.database.DBWriter;
-import de.danoeh.antennapod.net.discovery.CombinedSearcher;
-import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
-import de.danoeh.antennapod.net.discovery.PodcastSearcherRegistry;
-import de.danoeh.antennapod.parser.feed.FeedHandler;
-import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
-import de.danoeh.antennapod.model.download.DownloadError;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.net.common.UrlChecker;
-import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
-import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
-import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.playback.RemoteMedia;
-import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException;
-import de.danoeh.antennapod.ui.common.ThemeUtils;
-import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
-import de.danoeh.antennapod.ui.preferences.screen.synchronization.AuthenticationDialog;
-import io.reactivex.Maybe;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.observers.DisposableMaybeObserver;
-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;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import static de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter.ARG_FEEDURL;
-import static de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter.ARG_STARTED_FROM_SEARCH;
-import static de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter.ARG_WAS_MANUAL_URL;
-
-/**
- * Downloads a feed from a feed URL and parses it. Subclasses can display the
- * feed object that was parsed. This activity MUST be started with a given URL
- * or an Exception will be thrown.
- * <p/>
- * If the feed cannot be downloaded or parsed, an error dialog will be displayed
- * and the activity will finish as soon as the error dialog is closed.
- */
-public class OnlineFeedViewActivity extends AppCompatActivity {
-
- private static final int RESULT_ERROR = 2;
- private static final String TAG = "OnlineFeedViewActivity";
- private static final String PREFS = "OnlineFeedViewActivityPreferences";
- private static final String PREF_LAST_AUTO_DOWNLOAD = "lastAutoDownload";
- private static final int DESCRIPTION_MAX_LINES_COLLAPSED = 4;
-
- private volatile List<Feed> feeds;
- private String selectedDownloadUrl;
- private Downloader downloader;
- private String username = null;
- private String password = null;
-
- private boolean isPaused;
- private boolean didPressSubscribe = false;
- private boolean isFeedFoundBySearch = false;
-
- private Dialog dialog;
-
- private Disposable download;
- private Disposable parser;
- private Disposable updater;
-
- private OnlinefeedviewHeaderBinding headerBinding;
- private OnlinefeedviewActivityBinding viewBinding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(ThemeSwitcher.getTranslucentTheme(this));
- super.onCreate(savedInstanceState);
-
- viewBinding = OnlinefeedviewActivityBinding.inflate(getLayoutInflater());
- setContentView(viewBinding.getRoot());
-
- viewBinding.transparentBackground.setOnClickListener(v -> finish());
- viewBinding.closeButton.setOnClickListener(view -> finish());
- viewBinding.card.setOnClickListener(null);
- viewBinding.card.setCardBackgroundColor(ThemeUtils.getColorFromAttr(this, R.attr.colorSurface));
- headerBinding = OnlinefeedviewHeaderBinding.inflate(getLayoutInflater());
-
- String feedUrl = null;
- if (getIntent().hasExtra(ARG_FEEDURL)) {
- feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
- } else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)) {
- feedUrl = getIntent().getStringExtra(Intent.EXTRA_TEXT);
- } else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
- feedUrl = getIntent().getDataString();
- }
-
- if (feedUrl == null) {
- Log.e(TAG, "feedUrl is null.");
- showNoPodcastFoundError();
- } else {
- Log.d(TAG, "Activity was started with url " + feedUrl);
- setLoadingLayout();
- // Remove subscribeonandroid.com from feed URL in order to subscribe to the actual feed URL
- if (feedUrl.contains("subscribeonandroid.com")) {
- feedUrl = feedUrl.replaceFirst("((www.)?(subscribeonandroid.com/))", "");
- }
- if (savedInstanceState != null) {
- username = savedInstanceState.getString("username");
- password = savedInstanceState.getString("password");
- }
- lookupUrlAndDownload(feedUrl);
- }
- }
-
- private void showNoPodcastFoundError() {
- runOnUiThread(() -> new MaterialAlertDialogBuilder(OnlineFeedViewActivity.this)
- .setNeutralButton(android.R.string.ok, (dialog, which) -> finish())
- .setTitle(R.string.error_label)
- .setMessage(R.string.null_value_podcast_error)
- .setOnDismissListener(dialog1 -> {
- setResult(RESULT_ERROR);
- finish();
- })
- .show());
- }
-
- /**
- * Displays a progress indicator.
- */
- private void setLoadingLayout() {
- viewBinding.progressBar.setVisibility(View.VISIBLE);
- viewBinding.feedDisplayContainer.setVisibility(View.GONE);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- isPaused = false;
- EventBus.getDefault().register(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- isPaused = true;
- EventBus.getDefault().unregister(this);
- if (downloader != null && !downloader.isFinished()) {
- downloader.cancel();
- }
- if(dialog != null && dialog.isShowing()) {
- dialog.dismiss();
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if(updater != null) {
- updater.dispose();
- }
- if(download != null) {
- download.dispose();
- }
- if(parser != null) {
- parser.dispose();
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString("username", username);
- outState.putString("password", password);
- }
-
- private void resetIntent(String url) {
- Intent intent = new Intent();
- intent.putExtra(ARG_FEEDURL, url);
- setIntent(intent);
- }
-
- @Override
- public void finish() {
- super.finish();
- overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
- }
-
- private void lookupUrlAndDownload(String url) {
- download = PodcastSearcherRegistry.lookupUrl(url)
- .subscribeOn(Schedulers.io())
- .observeOn(Schedulers.io())
- .subscribe(this::startFeedDownload,
- error -> {
- if (error instanceof FeedUrlNotFoundException) {
- tryToRetrieveFeedUrlBySearch((FeedUrlNotFoundException) error);
- } else {
- showNoPodcastFoundError();
- Log.e(TAG, Log.getStackTraceString(error));
- }
- });
- }
-
- private void tryToRetrieveFeedUrlBySearch(FeedUrlNotFoundException error) {
- Log.d(TAG, "Unable to retrieve feed url, trying to retrieve feed url from search");
- String url = searchFeedUrlByTrackName(error.getTrackName(), error.getArtistName());
- if (url != null) {
- Log.d(TAG, "Successfully retrieve feed url");
- isFeedFoundBySearch = true;
- startFeedDownload(url);
- } else {
- showNoPodcastFoundError();
- Log.d(TAG, "Failed to retrieve feed url");
- }
- }
-
- private String searchFeedUrlByTrackName(String trackName, String artistName) {
- CombinedSearcher searcher = new CombinedSearcher();
- String query = trackName + " " + artistName;
- List<PodcastSearchResult> results = searcher.search(query).blockingGet();
- for (PodcastSearchResult result : results) {
- if (result.feedUrl != null && result.author != null
- && result.author.equalsIgnoreCase(artistName) && result.title.equalsIgnoreCase(trackName)) {
- return result.feedUrl;
-
- }
- }
- return null;
- }
-
- private void startFeedDownload(String url) {
- Log.d(TAG, "Starting feed download");
- selectedDownloadUrl = UrlChecker.prepareUrl(url);
- DownloadRequest request = DownloadRequestCreator.create(new Feed(selectedDownloadUrl, null))
- .withAuthentication(username, password)
- .withInitiatedByUser(true)
- .build();
-
- download = Observable.fromCallable(() -> {
- feeds = DBReader.getFeedList();
- downloader = new HttpDownloader(request);
- downloader.call();
- return downloader.getResult();
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(status -> checkDownloadResult(status, request.getDestination()),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
-
- private void checkDownloadResult(@NonNull DownloadResult status, String destination) {
- if (status.isSuccessful()) {
- parseFeed(destination);
- } else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
- if (!isFinishing() && !isPaused) {
- if (username != null && password != null) {
- Toast.makeText(this, R.string.download_error_unauthorized, Toast.LENGTH_LONG).show();
- }
- dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this,
- R.string.authentication_notification_title,
- downloader.getDownloadRequest().getSource()).create();
- dialog.show();
- }
- } else {
- showErrorDialog(getString(DownloadErrorLabel.from(status.getReason())), status.getReasonDetailed());
- }
- }
-
- @Subscribe
- public void onFeedListChanged(FeedListUpdateEvent event) {
- updater = Observable.fromCallable(DBReader::getFeedList)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- feeds -> {
- OnlineFeedViewActivity.this.feeds = feeds;
- handleUpdatedFeedStatus();
- }, error -> Log.e(TAG, Log.getStackTraceString(error))
- );
- }
-
- @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
- public void onEventMainThread(EpisodeDownloadEvent event) {
- handleUpdatedFeedStatus();
- }
-
- private void parseFeed(String destination) {
- Log.d(TAG, "Parsing feed");
- parser = Maybe.fromCallable(() -> doParseFeed(destination))
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableMaybeObserver<FeedHandlerResult>() {
- @Override
- public void onSuccess(@NonNull FeedHandlerResult result) {
- showFeedInformation(result.feed, result.alternateFeedUrls);
- }
-
- @Override
- public void onComplete() {
- // Ignore null result: We showed the discovery dialog.
- }
-
- @Override
- public void onError(@NonNull Throwable error) {
- showErrorDialog(error.getMessage(), "");
- Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
- }
- });
- }
-
- /**
- * Try to parse the feed.
- * @return The FeedHandlerResult if successful.
- * Null if unsuccessful but we started another attempt.
- * @throws Exception If unsuccessful but we do not know a resolution.
- */
- @Nullable
- private FeedHandlerResult doParseFeed(String destination) throws Exception {
- FeedHandler handler = new FeedHandler();
- Feed feed = new Feed(selectedDownloadUrl, null);
- feed.setLocalFileUrl(destination);
- File destinationFile = new File(destination);
- try {
- return handler.parseFeed(feed);
- } catch (UnsupportedFeedtypeException e) {
- Log.d(TAG, "Unsupported feed type detected");
- if ("html".equalsIgnoreCase(e.getRootElement())) {
- boolean dialogShown = showFeedDiscoveryDialog(destinationFile, selectedDownloadUrl);
- if (dialogShown) {
- return null; // Should not display an error message
- } else {
- throw new UnsupportedFeedtypeException(getString(R.string.download_error_unsupported_type_html));
- }
- } else {
- throw e;
- }
- } catch (Exception e) {
- Log.e(TAG, Log.getStackTraceString(e));
- throw e;
- } finally {
- boolean rc = destinationFile.delete();
- Log.d(TAG, "Deleted feed source file. Result: " + rc);
- }
- }
-
- /**
- * Called when feed parsed successfully.
- * This method is executed on the GUI thread.
- */
- private void showFeedInformation(final Feed feed, Map<String, String> alternateFeedUrls) {
- viewBinding.progressBar.setVisibility(View.GONE);
- viewBinding.feedDisplayContainer.setVisibility(View.VISIBLE);
- if (isFeedFoundBySearch) {
- int resId = R.string.no_feed_url_podcast_found_by_search;
- Snackbar.make(findViewById(android.R.id.content), resId, Snackbar.LENGTH_LONG).show();
- }
-
- viewBinding.backgroundImage.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
-
- viewBinding.listView.addHeaderView(headerBinding.getRoot());
- viewBinding.listView.setSelector(android.R.color.transparent);
- viewBinding.listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
-
- if (StringUtils.isNotBlank(feed.getImageUrl())) {
- Glide.with(this)
- .load(feed.getImageUrl())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .fitCenter()
- .dontAnimate())
- .into(viewBinding.coverImage);
- Glide.with(this)
- .load(feed.getImageUrl())
- .apply(new RequestOptions()
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .transform(new FastBlurTransformation())
- .dontAnimate())
- .into(viewBinding.backgroundImage);
- }
-
- viewBinding.titleLabel.setText(feed.getTitle());
- viewBinding.authorLabel.setText(feed.getAuthor());
- headerBinding.txtvDescription.setText(HtmlToPlainText.getPlainText(feed.getDescription()));
-
- viewBinding.subscribeButton.setOnClickListener(v -> {
- if (feedInFeedlist()) {
- openFeed();
- } else {
- FeedDatabaseWriter.updateFeed(this, feed, false);
- didPressSubscribe = true;
- handleUpdatedFeedStatus();
- }
- });
-
- viewBinding.stopPreviewButton.setOnClickListener(v -> {
- PlaybackPreferences.writeNoMediaPlaying();
- IntentUtils.sendLocalBroadcast(this, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
- });
-
- if (UserPreferences.isEnableAutodownload()) {
- SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE);
- viewBinding.autoDownloadCheckBox.setChecked(preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true));
- }
-
- headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
- headerBinding.txtvDescription.setOnClickListener(v -> {
- if (headerBinding.txtvDescription.getMaxLines() > DESCRIPTION_MAX_LINES_COLLAPSED) {
- headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
- } else {
- headerBinding.txtvDescription.setMaxLines(2000);
- }
- });
-
- if (alternateFeedUrls.isEmpty()) {
- viewBinding.alternateUrlsSpinner.setVisibility(View.GONE);
- } else {
- viewBinding.alternateUrlsSpinner.setVisibility(View.VISIBLE);
-
- final List<String> alternateUrlsList = new ArrayList<>();
- final List<String> alternateUrlsTitleList = new ArrayList<>();
-
- alternateUrlsList.add(feed.getDownloadUrl());
- alternateUrlsTitleList.add(feed.getTitle());
-
-
- alternateUrlsList.addAll(alternateFeedUrls.keySet());
- for (String url : alternateFeedUrls.keySet()) {
- alternateUrlsTitleList.add(alternateFeedUrls.get(url));
- }
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- R.layout.alternate_urls_item, alternateUrlsTitleList) {
- @Override
- public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- // reusing the old view causes a visual bug on Android <= 10
- return super.getDropDownView(position, null, parent);
- }
- };
-
- adapter.setDropDownViewResource(R.layout.alternate_urls_dropdown_item);
- viewBinding.alternateUrlsSpinner.setAdapter(adapter);
- viewBinding.alternateUrlsSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- selectedDownloadUrl = alternateUrlsList.get(position);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
- });
- }
- handleUpdatedFeedStatus();
- }
-
- private void openFeed() {
- // feed.getId() is always 0, we have to retrieve the id from the feed list from the database
- MainActivityStarter mainActivityStarter = new MainActivityStarter(this);
- mainActivityStarter.withOpenFeed(getFeedId());
- if (getIntent().getBooleanExtra(ARG_STARTED_FROM_SEARCH, false)) {
- mainActivityStarter.withAddToBackStack();
- }
- finish();
- startActivity(mainActivityStarter.getIntent());
- }
-
- private void handleUpdatedFeedStatus() {
- if (DownloadServiceInterface.get().isDownloadingEpisode(selectedDownloadUrl)) {
- viewBinding.subscribeButton.setEnabled(false);
- viewBinding.subscribeButton.setText(R.string.subscribing_label);
- } else if (feedInFeedlist()) {
- viewBinding.subscribeButton.setEnabled(true);
- viewBinding.subscribeButton.setText(R.string.open_podcast);
- if (didPressSubscribe) {
- didPressSubscribe = false;
-
- Feed feed1 = DBReader.getFeed(getFeedId());
- FeedPreferences feedPreferences = feed1.getPreferences();
- if (UserPreferences.isEnableAutodownload()) {
- boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked();
- feedPreferences.setAutoDownload(autoDownload);
-
- SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE);
- SharedPreferences.Editor editor = preferences.edit();
- editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload);
- editor.apply();
- }
- if (username != null) {
- feedPreferences.setUsername(username);
- feedPreferences.setPassword(password);
- }
- DBWriter.setFeedPreferences(feedPreferences);
-
- openFeed();
- }
- } else {
- viewBinding.subscribeButton.setEnabled(true);
- viewBinding.subscribeButton.setText(R.string.subscribe_label);
- if (UserPreferences.isEnableAutodownload()) {
- viewBinding.autoDownloadCheckBox.setVisibility(View.VISIBLE);
- }
- }
- }
-
- private boolean feedInFeedlist() {
- return getFeedId() != 0;
- }
-
- private long getFeedId() {
- if (feeds == null) {
- return 0;
- }
- for (Feed f : feeds) {
- if (f.getDownloadUrl().equals(selectedDownloadUrl)) {
- return f.getId();
- }
- }
- return 0;
- }
-
- @UiThread
- private void showErrorDialog(String errorMsg, String details) {
- if (!isFinishing() && !isPaused) {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
- builder.setTitle(R.string.error_label);
- if (errorMsg != null) {
- String total = errorMsg + "\n\n" + details;
- SpannableString errorMessage = new SpannableString(total);
- errorMessage.setSpan(new ForegroundColorSpan(0x88888888),
- errorMsg.length(), total.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- builder.setMessage(errorMessage);
- } else {
- builder.setMessage(R.string.download_error_error_unknown);
- }
- builder.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.cancel());
- if (getIntent().getBooleanExtra(ARG_WAS_MANUAL_URL, false)) {
- builder.setNeutralButton(R.string.edit_url_menu, (dialog, which) -> editUrl());
- }
- builder.setOnCancelListener(dialog -> {
- setResult(RESULT_ERROR);
- finish();
- });
- if (dialog != null && dialog.isShowing()) {
- dialog.dismiss();
- }
- dialog = builder.show();
- }
- }
-
- private void editUrl() {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
- builder.setTitle(R.string.edit_url_menu);
- final EditTextDialogBinding dialogBinding = EditTextDialogBinding.inflate(getLayoutInflater());
- if (downloader != null) {
- dialogBinding.urlEditText.setText(downloader.getDownloadRequest().getSource());
- }
- builder.setView(dialogBinding.getRoot());
- builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- setLoadingLayout();
- lookupUrlAndDownload(dialogBinding.urlEditText.getText().toString());
- });
- builder.setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel());
- builder.setOnCancelListener(dialog1 -> {
- setResult(RESULT_ERROR);
- finish();
- });
- builder.show();
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void playbackStateChanged(PlayerStatusEvent event) {
- boolean isPlayingPreview =
- PlaybackPreferences.getCurrentlyPlayingMediaType() == RemoteMedia.PLAYABLE_TYPE_REMOTE_MEDIA;
- viewBinding.stopPreviewButton.setVisibility(isPlayingPreview ? View.VISIBLE : View.GONE);
- }
-
- /**
- *
- * @return true if a FeedDiscoveryDialog is shown, false otherwise (e.g., due to no feed found).
- */
- private boolean showFeedDiscoveryDialog(File feedFile, String baseUrl) {
- FeedDiscoverer fd = new FeedDiscoverer();
- final Map<String, String> urlsMap;
- try {
- urlsMap = fd.findLinks(feedFile, baseUrl);
- if (urlsMap == null || urlsMap.isEmpty()) {
- return false;
- }
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
-
- if (isPaused || isFinishing()) {
- return false;
- }
-
- final List<String> titles = new ArrayList<>();
-
- final List<String> urls = new ArrayList<>(urlsMap.keySet());
- for (String url : urls) {
- titles.add(urlsMap.get(url));
- }
-
- if (urls.size() == 1) {
- // Skip dialog and display the item directly
- resetIntent(urls.get(0));
- startFeedDownload(urls.get(0));
- return true;
- }
-
- final ArrayAdapter<String> adapter = new ArrayAdapter<>(OnlineFeedViewActivity.this,
- R.layout.ellipsize_start_listitem, R.id.txtvTitle, titles);
- DialogInterface.OnClickListener onClickListener = (dialog, which) -> {
- String selectedUrl = urls.get(which);
- dialog.dismiss();
- resetIntent(selectedUrl);
- startFeedDownload(selectedUrl);
- };
-
- MaterialAlertDialogBuilder ab = new MaterialAlertDialogBuilder(OnlineFeedViewActivity.this)
- .setTitle(R.string.feeds_label)
- .setCancelable(true)
- .setOnCancelListener(dialog -> finish())
- .setAdapter(adapter, onClickListener);
-
- runOnUiThread(() -> {
- if(dialog != null && dialog.isShowing()) {
- dialog.dismiss();
- }
- dialog = ab.show();
- });
- return true;
- }
-
- private class FeedViewAuthenticationDialog extends AuthenticationDialog {
-
- private final String feedUrl;
-
- FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) {
- super(context, titleRes, true, username, password);
- this.feedUrl = feedUrl;
- }
-
- @Override
- protected void onCancelled() {
- super.onCancelled();
- finish();
- }
-
- @Override
- protected void onConfirmed(String username, String password) {
- OnlineFeedViewActivity.this.username = username;
- OnlineFeedViewActivity.this.password = password;
- startFeedDownload(feedUrl);
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PlaybackSpeedDialogActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PlaybackSpeedDialogActivity.java
deleted file mode 100644
index 37f13272a..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/PlaybackSpeedDialogActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-
-public class PlaybackSpeedDialogActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(ThemeSwitcher.getTranslucentTheme(this));
- super.onCreate(savedInstanceState);
- VariableSpeedDialog speedDialog = new InnerVariableSpeedDialog();
- speedDialog.show(getSupportFragmentManager(), null);
- }
-
- public static class InnerVariableSpeedDialog extends VariableSpeedDialog {
- @Override
- public void onDismiss(@NonNull DialogInterface dialog) {
- super.onDismiss(dialog);
- getActivity().finish();
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
deleted file mode 100644
index aa3b05715..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.MenuItem;
-
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-
-import androidx.appcompat.app.ActionBar;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.preference.PreferenceFragmentCompat;
-
-import com.bytehamster.lib.preferencesearch.SearchPreferenceResult;
-import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener;
-
-import com.google.android.material.snackbar.Snackbar;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-
-import de.danoeh.antennapod.event.MessageEvent;
-import de.danoeh.antennapod.fragment.preferences.ImportExportPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.DownloadsPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.SwipePreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.UserInterfacePreferencesFragment;
-import de.danoeh.antennapod.ui.preferences.screen.AutoDownloadPreferencesFragment;
-import de.danoeh.antennapod.ui.preferences.screen.NotificationPreferencesFragment;
-import de.danoeh.antennapod.ui.preferences.screen.synchronization.SynchronizationPreferencesFragment;
-import de.danoeh.antennapod.ui.preferences.databinding.SettingsActivityBinding;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-/**
- * PreferenceActivity for API 11+. In order to change the behavior of the preference UI, see
- * PreferenceController.
- */
-public class PreferenceActivity extends AppCompatActivity implements SearchPreferenceResultListener {
- private static final String FRAGMENT_TAG = "tag_preferences";
- public static final String OPEN_AUTO_DOWNLOAD_SETTINGS = "OpenAutoDownloadSettings";
- private SettingsActivityBinding binding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(ThemeSwitcher.getTheme(this));
- super.onCreate(savedInstanceState);
-
- ActionBar ab = getSupportActionBar();
- if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- }
-
- binding = SettingsActivityBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG) == null) {
- getSupportFragmentManager().beginTransaction()
- .replace(binding.settingsContainer.getId(), new MainPreferencesFragment(), FRAGMENT_TAG)
- .commit();
- }
- Intent intent = getIntent();
- if (intent.getBooleanExtra(OPEN_AUTO_DOWNLOAD_SETTINGS, false)) {
- openScreen(R.xml.preferences_autodownload);
- }
- }
-
- private PreferenceFragmentCompat getPreferenceScreen(int screen) {
- PreferenceFragmentCompat prefFragment = null;
-
- if (screen == R.xml.preferences_user_interface) {
- prefFragment = new UserInterfacePreferencesFragment();
- } else if (screen == R.xml.preferences_downloads) {
- prefFragment = new DownloadsPreferencesFragment();
- } else if (screen == R.xml.preferences_import_export) {
- prefFragment = new ImportExportPreferencesFragment();
- } else if (screen == R.xml.preferences_autodownload) {
- prefFragment = new AutoDownloadPreferencesFragment();
- } else if (screen == R.xml.preferences_synchronization) {
- prefFragment = new SynchronizationPreferencesFragment();
- } else if (screen == R.xml.preferences_playback) {
- prefFragment = new PlaybackPreferencesFragment();
- } else if (screen == R.xml.preferences_notifications) {
- prefFragment = new NotificationPreferencesFragment();
- } else if (screen == R.xml.preferences_swipe) {
- prefFragment = new SwipePreferencesFragment();
- }
- return prefFragment;
- }
-
- public static int getTitleOfPage(int preferences) {
- if (preferences == R.xml.preferences_downloads) {
- return R.string.downloads_pref;
- } else if (preferences == R.xml.preferences_autodownload) {
- return R.string.pref_automatic_download_title;
- } else if (preferences == R.xml.preferences_playback) {
- return R.string.playback_pref;
- } else if (preferences == R.xml.preferences_import_export) {
- return R.string.import_export_pref;
- } else if (preferences == R.xml.preferences_user_interface) {
- return R.string.user_interface_label;
- } else if (preferences == R.xml.preferences_synchronization) {
- return R.string.synchronization_pref;
- } else if (preferences == R.xml.preferences_notifications) {
- return R.string.notification_pref_fragment;
- } else if (preferences == R.xml.feed_settings) {
- return R.string.feed_settings_label;
- } else if (preferences == R.xml.preferences_swipe) {
- return R.string.swipeactions_label;
- }
- return R.string.settings_label;
- }
-
- public PreferenceFragmentCompat openScreen(int screen) {
- PreferenceFragmentCompat fragment = getPreferenceScreen(screen);
- if (screen == R.xml.preferences_notifications && Build.VERSION.SDK_INT >= 26) {
- Intent intent = new Intent();
- intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
- startActivity(intent);
- } else {
- getSupportFragmentManager().beginTransaction()
- .replace(binding.settingsContainer.getId(), fragment)
- .addToBackStack(getString(getTitleOfPage(screen))).commit();
- }
-
-
- return fragment;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
- finish();
- } else {
- InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
- View view = getCurrentFocus();
- //If no view currently has focus, create a new one, just so we can grab a window token from it
- if (view == null) {
- view = new View(this);
- }
- imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
- getSupportFragmentManager().popBackStack();
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void onSearchResultClicked(SearchPreferenceResult result) {
- int screen = result.getResourceFile();
- if (screen == R.xml.feed_settings) {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
- builder.setTitle(R.string.feed_settings_label);
- builder.setMessage(R.string.pref_feed_settings_dialog_msg);
- builder.setPositiveButton(android.R.string.ok, null);
- builder.show();
- } else if (screen == R.xml.preferences_notifications) {
- openScreen(screen);
- } else {
- PreferenceFragmentCompat fragment = openScreen(result.getResourceFile());
- result.highlight(fragment);
- }
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- EventBus.getDefault().register(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- EventBus.getDefault().unregister(this);
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(MessageEvent event) {
- Log.d(FRAGMENT_TAG, "onEvent(" + event + ")");
- Snackbar s = Snackbar.make(binding.getRoot(), event.message, Snackbar.LENGTH_LONG);
- if (event.action != null) {
- s.setAction(event.actionText, v -> event.action.accept(this));
- }
- s.show();
- }
-}
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 43da309d7..4ea33ca3e 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java
@@ -7,7 +7,7 @@ import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable;
-import de.danoeh.antennapod.error.CrashReportWriter;
+import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.storage.database.PodDBAdapter;
import io.reactivex.Completable;
import io.reactivex.android.schedulers.AndroidSchedulers;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
deleted file mode 100644
index 313d97248..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ /dev/null
@@ -1,815 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Intent;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.media.AudioManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.ScaleAnimation;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import androidx.annotation.Nullable;
-import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
-import com.bumptech.glide.Glide;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.dialog.MediaPlayerErrorDialog;
-import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import de.danoeh.antennapod.event.MessageEvent;
-import de.danoeh.antennapod.event.playback.BufferUpdateEvent;
-import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
-import de.danoeh.antennapod.event.PlayerErrorEvent;
-import de.danoeh.antennapod.event.playback.PlaybackServiceEvent;
-import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
-import de.danoeh.antennapod.fragment.ChaptersFragment;
-import de.danoeh.antennapod.playback.service.PlaybackController;
-import de.danoeh.antennapod.playback.service.PlaybackService;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.database.DBReader;
-import de.danoeh.antennapod.storage.database.DBWriter;
-import de.danoeh.antennapod.ui.common.Converter;
-import de.danoeh.antennapod.core.util.FeedItemUtil;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.ShareUtils;
-import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
-import de.danoeh.antennapod.databinding.VideoplayerActivityBinding;
-import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
-import de.danoeh.antennapod.dialog.ShareDialog;
-import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
-import de.danoeh.antennapod.dialog.SleepTimerDialog;
-import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.model.playback.Playable;
-import de.danoeh.antennapod.playback.base.PlayerStatus;
-import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
-import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
-import de.danoeh.antennapod.ui.episodes.TimeSpeedConverter;
-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;
-
-/**
- * Activity for playing video files.
- */
-public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.OnSeekBarChangeListener {
- private static final String TAG = "VideoplayerActivity";
-
- /**
- * True if video controls are currently visible.
- */
- private boolean videoControlsShowing = true;
- private boolean videoSurfaceCreated = false;
- private boolean destroyingDueToReload = false;
- private long lastScreenTap = 0;
- private final Handler videoControlsHider = new Handler(Looper.getMainLooper());
- private VideoplayerActivityBinding viewBinding;
- private PlaybackController controller;
- private boolean showTimeLeft = false;
- private boolean isFavorite = false;
- private boolean switchToAudioOnly = false;
- private Disposable disposable;
- private float prog;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
- // has to be called before setting layout content
- supportRequestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
- setTheme(R.style.Theme_AntennaPod_VideoPlayer);
- super.onCreate(savedInstanceState);
-
- Log.d(TAG, "onCreate()");
-
- getWindow().setFormat(PixelFormat.TRANSPARENT);
- viewBinding = VideoplayerActivityBinding.inflate(LayoutInflater.from(this));
- setContentView(viewBinding.getRoot());
- setupView();
- getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000));
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- switchToAudioOnly = false;
- if (PlaybackService.isCasting()) {
- Intent intent = PlaybackService.getPlayerActivityIntent(this);
- if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
- destroyingDueToReload = true;
- finish();
- startActivity(intent);
- }
- }
- }
-
- @Override
- protected void onStop() {
- if (controller != null) {
- controller.release();
- controller = null; // prevent leak
- }
- if (disposable != null) {
- disposable.dispose();
- }
- EventBus.getDefault().unregister(this);
- super.onStop();
- if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
- videoControlsHider.removeCallbacks(hideVideoControls);
- }
- // Controller released; we will not receive buffering updates
- viewBinding.progressBar.setVisibility(View.GONE);
- }
-
- @Override
- public void onUserLeaveHint() {
- if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
- compatEnterPictureInPicture();
- }
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- controller = newPlaybackController();
- controller.init();
- loadMediaInfo();
- onPositionObserverUpdate();
- EventBus.getDefault().register(this);
- }
-
- @Override
- protected void onPause() {
- if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
- if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
- controller.pause();
- }
- }
- super.onPause();
- }
-
- @Override
- public void onTrimMemory(int level) {
- super.onTrimMemory(level);
- Glide.get(this).trimMemory(level);
- }
-
- @Override
- public void onLowMemory() {
- super.onLowMemory();
- Glide.get(this).clearMemory();
- }
-
- private PlaybackController newPlaybackController() {
- return new PlaybackController(this) {
- @Override
- protected void updatePlayButtonShowsPlay(boolean showPlay) {
- viewBinding.playButton.setIsShowPlay(showPlay);
- if (showPlay) {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setupVideoAspectRatio();
- if (videoSurfaceCreated && controller != null) {
- Log.d(TAG, "Videosurface already created, setting videosurface now");
- controller.setVideoSurface(viewBinding.videoView.getHolder());
- }
- }
- }
-
- @Override
- public void loadMediaInfo() {
- VideoplayerActivity.this.loadMediaInfo();
- }
-
- @Override
- public void onPlaybackEnd() {
- finish();
- }
- };
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- @SuppressWarnings("unused")
- public void bufferUpdate(BufferUpdateEvent event) {
- if (event.hasStarted()) {
- viewBinding.progressBar.setVisibility(View.VISIBLE);
- } else if (event.hasEnded()) {
- viewBinding.progressBar.setVisibility(View.INVISIBLE);
- } else {
- viewBinding.sbPosition.setSecondaryProgress((int) (event.getProgress() * viewBinding.sbPosition.getMax()));
- }
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- @SuppressWarnings("unused")
- public void sleepTimerUpdate(SleepTimerUpdatedEvent event) {
- if (event.isCancelled() || event.wasJustEnabled()) {
- supportInvalidateOptionsMenu();
- }
- }
-
- protected void loadMediaInfo() {
- Log.d(TAG, "loadMediaInfo()");
- if (controller == null || controller.getMedia() == null) {
- return;
- }
- if (controller.getStatus() == PlayerStatus.PLAYING && !controller.isPlayingVideoLocally()) {
- Log.d(TAG, "Closing, no longer video");
- destroyingDueToReload = true;
- finish();
- new MainActivityStarter(this).withOpenPlayer().start();
- return;
- }
- showTimeLeft = UserPreferences.shouldShowRemainingTime();
- onPositionObserverUpdate();
- checkFavorite();
- Playable media = controller.getMedia();
- if (media != null) {
- getSupportActionBar().setSubtitle(media.getEpisodeTitle());
- getSupportActionBar().setTitle(media.getFeedTitle());
- }
- }
-
- protected void setupView() {
- showTimeLeft = UserPreferences.shouldShowRemainingTime();
- Log.d("timeleft", showTimeLeft ? "true" : "false");
- viewBinding.durationLabel.setOnClickListener(v -> {
- showTimeLeft = !showTimeLeft;
- Playable media = controller.getMedia();
- if (media == null) {
- return;
- }
-
- TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
- String length;
- if (showTimeLeft) {
- int remainingTime = converter.convert(media.getDuration() - media.getPosition());
- length = "-" + Converter.getDurationStringLong(remainingTime);
- } else {
- int duration = converter.convert(media.getDuration());
- length = Converter.getDurationStringLong(duration);
- }
- viewBinding.durationLabel.setText(length);
-
- UserPreferences.setShowRemainTimeSetting(showTimeLeft);
- Log.d("timeleft on click", showTimeLeft ? "true" : "false");
- });
-
- viewBinding.sbPosition.setOnSeekBarChangeListener(this);
- viewBinding.rewindButton.setOnClickListener(v -> onRewind());
- viewBinding.rewindButton.setOnLongClickListener(v -> {
- SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this,
- SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null);
- return true;
- });
- viewBinding.playButton.setIsVideoScreen(true);
- viewBinding.playButton.setOnClickListener(v -> onPlayPause());
- viewBinding.fastForwardButton.setOnClickListener(v -> onFastForward());
- viewBinding.fastForwardButton.setOnLongClickListener(v -> {
- SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this,
- SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null);
- return false;
- });
- // To suppress touches directly below the slider
- viewBinding.bottomControlsContainer.setOnTouchListener((view, motionEvent) -> true);
- viewBinding.bottomControlsContainer.setFitsSystemWindows(true);
- viewBinding.videoView.getHolder().addCallback(surfaceHolderCallback);
- viewBinding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-
- setupVideoControlsToggler();
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- viewBinding.videoPlayerContainer.setOnTouchListener(onVideoviewTouched);
- viewBinding.videoPlayerContainer.getViewTreeObserver().addOnGlobalLayoutListener(() ->
- viewBinding.videoView.setAvailableSize(
- viewBinding.videoPlayerContainer.getWidth(), viewBinding.videoPlayerContainer.getHeight()));
- }
-
- private final Runnable hideVideoControls = () -> {
- if (videoControlsShowing) {
- Log.d(TAG, "Hiding video controls");
- getSupportActionBar().hide();
- hideVideoControls(true);
- videoControlsShowing = false;
- }
- };
-
- private final View.OnTouchListener onVideoviewTouched = (v, event) -> {
- if (event.getAction() != MotionEvent.ACTION_DOWN) {
- return false;
- }
- if (PictureInPictureUtil.isInPictureInPictureMode(this)) {
- return true;
- }
- videoControlsHider.removeCallbacks(hideVideoControls);
-
- if (System.currentTimeMillis() - lastScreenTap < 300) {
- if (event.getX() > v.getMeasuredWidth() / 2.0f) {
- onFastForward();
- showSkipAnimation(true);
- } else {
- onRewind();
- showSkipAnimation(false);
- }
- if (videoControlsShowing) {
- getSupportActionBar().hide();
- hideVideoControls(false);
- videoControlsShowing = false;
- }
- return true;
- }
-
- toggleVideoControlsVisibility();
- if (videoControlsShowing) {
- setupVideoControlsToggler();
- }
-
- lastScreenTap = System.currentTimeMillis();
- return true;
- };
-
- private void showSkipAnimation(boolean isForward) {
- AnimationSet skipAnimation = new AnimationSet(true);
- skipAnimation.addAnimation(new ScaleAnimation(1f, 2f, 1f, 2f,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
- skipAnimation.addAnimation(new AlphaAnimation(1f, 0f));
- skipAnimation.setFillAfter(false);
- skipAnimation.setDuration(800);
-
- FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) viewBinding.skipAnimationImage.getLayoutParams();
- if (isForward) {
- viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_forward_video_white);
- params.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
- } else {
- viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_rewind_video_white);
- params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
- }
-
- viewBinding.skipAnimationImage.setVisibility(View.VISIBLE);
- viewBinding.skipAnimationImage.setLayoutParams(params);
- viewBinding.skipAnimationImage.startAnimation(skipAnimation);
- skipAnimation.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- }
-
- @Override
- public void onAnimationEnd(Animation animation) {
- viewBinding.skipAnimationImage.setVisibility(View.GONE);
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) {
-
- }
- });
- }
-
- private void setupVideoControlsToggler() {
- videoControlsHider.removeCallbacks(hideVideoControls);
- videoControlsHider.postDelayed(hideVideoControls, 2500);
- }
-
- private void setupVideoAspectRatio() {
- if (videoSurfaceCreated && controller != null) {
- Pair<Integer, Integer> videoSize = controller.getVideoSize();
- if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) {
- Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second);
- viewBinding.videoView.setVideoSize(videoSize.first, videoSize.second);
- } else {
- Log.e(TAG, "Could not determine video size");
- }
- }
- }
-
- private void toggleVideoControlsVisibility() {
- if (videoControlsShowing) {
- getSupportActionBar().hide();
- hideVideoControls(true);
- } else {
- getSupportActionBar().show();
- showVideoControls();
- }
- videoControlsShowing = !videoControlsShowing;
- }
-
- void onRewind() {
- if (controller == null) {
- return;
- }
- int curr = controller.getPosition();
- controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
- setupVideoControlsToggler();
- }
-
- void onPlayPause() {
- if (controller == null) {
- return;
- }
- controller.playPause();
- setupVideoControlsToggler();
- }
-
- void onFastForward() {
- if (controller == null) {
- return;
- }
- int curr = controller.getPosition();
- controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000);
- setupVideoControlsToggler();
- }
-
- private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- holder.setFixedSize(width, height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.d(TAG, "Videoview holder created");
- videoSurfaceCreated = true;
- if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
- controller.setVideoSurface(holder);
- }
- setupVideoAspectRatio();
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.d(TAG, "Videosurface was destroyed");
- videoSurfaceCreated = false;
- if (controller != null && !destroyingDueToReload && !switchToAudioOnly) {
- controller.notifyVideoSurfaceAbandoned();
- }
- }
- };
-
- private void showVideoControls() {
- viewBinding.bottomControlsContainer.setVisibility(View.VISIBLE);
- viewBinding.controlsContainer.setVisibility(View.VISIBLE);
- final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in);
- if (animation != null) {
- viewBinding.bottomControlsContainer.startAnimation(animation);
- viewBinding.controlsContainer.startAnimation(animation);
- }
- viewBinding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
- }
-
- private void hideVideoControls(boolean showAnimation) {
- if (showAnimation) {
- final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
- if (animation != null) {
- viewBinding.bottomControlsContainer.startAnimation(animation);
- viewBinding.controlsContainer.startAnimation(animation);
- }
- }
- 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);
- viewBinding.bottomControlsContainer.setFitsSystemWindows(true);
-
- viewBinding.bottomControlsContainer.setVisibility(View.GONE);
- viewBinding.controlsContainer.setVisibility(View.GONE);
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(PlaybackPositionEvent event) {
- onPositionObserverUpdate();
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onPlaybackServiceChanged(PlaybackServiceEvent event) {
- if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) {
- finish();
- }
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onMediaPlayerError(PlayerErrorEvent event) {
- MediaPlayerErrorDialog.show(this, event);
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(MessageEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
- final MaterialAlertDialogBuilder errorDialog = new MaterialAlertDialogBuilder(this);
- errorDialog.setMessage(event.message);
- if (event.action != null) {
- errorDialog.setPositiveButton(event.actionText, (dialog, which) -> event.action.accept(this));
- }
- errorDialog.show();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- requestCastButton(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.mediaplayer, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- if (controller == null) {
- return false;
- }
- Playable media = controller.getMedia();
- boolean isFeedMedia = (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);
-
- boolean isItemAndHasLink = isFeedMedia && ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
- boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownloadUrl() != null;
- menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
-
- menu.findItem(R.id.add_to_favorites_item).setVisible(false);
- menu.findItem(R.id.remove_from_favorites_item).setVisible(false);
- if (isFeedMedia) {
- menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
- menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
- }
-
- menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive());
- menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive());
-
- menu.findItem(R.id.player_switch_to_audio_only).setVisible(true);
-
- menu.findItem(R.id.audio_controls).setVisible(controller.getAudioTracks().size() >= 2);
- menu.findItem(R.id.playback_speed).setVisible(true);
- menu.findItem(R.id.player_show_chapters).setVisible(true);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.player_switch_to_audio_only) {
- switchToAudioOnly = true;
- finish();
- return true;
- } else if (item.getItemId() == android.R.id.home) {
- Intent intent = new Intent(VideoplayerActivity.this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- finish();
- return true;
- } else if (item.getItemId() == R.id.player_show_chapters) {
- new ChaptersFragment().show(getSupportFragmentManager(), ChaptersFragment.TAG);
- return true;
- }
-
- if (controller == null) {
- return false;
- }
-
- Playable media = controller.getMedia();
- if (media == null) {
- return false;
- }
- final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem
- if (item.getItemId() == R.id.add_to_favorites_item && feedItem != null) {
- DBWriter.addFavoriteItem(feedItem);
- isFavorite = true;
- invalidateOptionsMenu();
- } else if (item.getItemId() == R.id.remove_from_favorites_item && feedItem != null) {
- DBWriter.removeFavoriteItem(feedItem);
- isFavorite = false;
- invalidateOptionsMenu();
- } else if (item.getItemId() == R.id.disable_sleeptimer_item
- || item.getItemId() == R.id.set_sleeptimer_item) {
- new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog");
- } else if (item.getItemId() == R.id.audio_controls) {
- PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance();
- dialog.show(getSupportFragmentManager(), "playback_controls");
- } else if (item.getItemId() == R.id.open_feed_item && feedItem != null) {
- Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId());
- startActivity(intent);
- } else if (item.getItemId() == R.id.visit_website_item) {
- IntentUtils.openInBrowser(VideoplayerActivity.this, getWebsiteLinkWithFallback(media));
- } else if (item.getItemId() == R.id.share_item && feedItem != null) {
- ShareDialog shareDialog = ShareDialog.newInstance(feedItem);
- shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog");
- } else if (item.getItemId() == R.id.playback_speed) {
- new VariableSpeedDialog().show(getSupportFragmentManager(), null);
- } else {
- return false;
- }
- return true;
- }
-
- private static String getWebsiteLinkWithFallback(Playable media) {
- if (media == null) {
- return null;
- } else if (StringUtils.isNotBlank(media.getWebsiteLink())) {
- return media.getWebsiteLink();
- } else if (media instanceof FeedMedia) {
- return FeedItemUtil.getLinkWithFallback(((FeedMedia) media).getItem());
- }
- return null;
- }
-
- void onPositionObserverUpdate() {
- if (controller == null) {
- return;
- }
-
- TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
- int currentPosition = converter.convert(controller.getPosition());
- int duration = converter.convert(controller.getDuration());
- int remainingTime = converter.convert(
- controller.getDuration() - controller.getPosition());
- Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
- if (currentPosition == Playable.INVALID_TIME
- || duration == Playable.INVALID_TIME) {
- Log.w(TAG, "Could not react to position observer update because of invalid time");
- return;
- }
- viewBinding.positionLabel.setText(Converter.getDurationStringLong(currentPosition));
- if (showTimeLeft) {
- viewBinding.durationLabel.setText("-" + Converter.getDurationStringLong(remainingTime));
- } else {
- viewBinding.durationLabel.setText(Converter.getDurationStringLong(duration));
- }
- updateProgressbarPosition(currentPosition, duration);
- }
-
- private void updateProgressbarPosition(int position, int duration) {
- Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
- float progress = ((float) position) / duration;
- viewBinding.sbPosition.setProgress((int) (progress * viewBinding.sbPosition.getMax()));
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (controller == null) {
- return;
- }
- if (fromUser) {
- prog = progress / ((float) seekBar.getMax());
- TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
- int position = converter.convert((int) (prog * controller.getDuration()));
- viewBinding.seekPositionLabel.setText(Converter.getDurationStringLong(position));
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- viewBinding.seekCardView.setScaleX(.8f);
- viewBinding.seekCardView.setScaleY(.8f);
- viewBinding.seekCardView.animate()
- .setInterpolator(new FastOutSlowInInterpolator())
- .alpha(1f).scaleX(1f).scaleY(1f)
- .setDuration(200)
- .start();
- videoControlsHider.removeCallbacks(hideVideoControls);
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- if (controller != null) {
- controller.seekTo((int) (prog * controller.getDuration()));
- }
- viewBinding.seekCardView.setScaleX(1f);
- viewBinding.seekCardView.setScaleY(1f);
- viewBinding.seekCardView.animate()
- .setInterpolator(new FastOutSlowInInterpolator())
- .alpha(0f).scaleX(.8f).scaleY(.8f)
- .setDuration(200)
- .start();
- setupVideoControlsToggler();
- }
-
- private void checkFavorite() {
- FeedItem feedItem = getFeedItem(controller.getMedia());
- if (feedItem == null) {
- return;
- }
- if (disposable != null) {
- disposable.dispose();
- }
- disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- item -> {
- boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
- if (isFavorite != isFav) {
- isFavorite = isFav;
- invalidateOptionsMenu();
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
-
- @Nullable
- private static FeedItem getFeedItem(@Nullable Playable playable) {
- if (playable instanceof FeedMedia) {
- return ((FeedMedia) playable).getItem();
- } else {
- return null;
- }
- }
-
- private void compatEnterPictureInPicture() {
- if (PictureInPictureUtil.supportsPictureInPicture(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- getSupportActionBar().hide();
- hideVideoControls(false);
- enterPictureInPictureMode();
- }
- }
-
- //Hardware keyboard support
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- View currentFocus = getCurrentFocus();
- if (currentFocus instanceof EditText) {
- return super.onKeyUp(keyCode, event);
- }
-
- AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_P: //Fallthrough
- case KeyEvent.KEYCODE_SPACE:
- onPlayPause();
- toggleVideoControlsVisibility();
- return true;
- case KeyEvent.KEYCODE_J: //Fallthrough
- case KeyEvent.KEYCODE_A:
- case KeyEvent.KEYCODE_COMMA:
- onRewind();
- showSkipAnimation(false);
- return true;
- case KeyEvent.KEYCODE_K: //Fallthrough
- case KeyEvent.KEYCODE_D:
- case KeyEvent.KEYCODE_PERIOD:
- onFastForward();
- showSkipAnimation(true);
- return true;
- case KeyEvent.KEYCODE_F: //Fallthrough
- case KeyEvent.KEYCODE_ESCAPE:
- //Exit fullscreen mode
- onBackPressed();
- return true;
- case KeyEvent.KEYCODE_I:
- compatEnterPictureInPicture();
- return true;
- case KeyEvent.KEYCODE_PLUS: //Fallthrough
- case KeyEvent.KEYCODE_W:
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
- return true;
- case KeyEvent.KEYCODE_MINUS: //Fallthrough
- case KeyEvent.KEYCODE_S:
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
- return true;
- case KeyEvent.KEYCODE_M:
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.FLAG_SHOW_UI);
- return true;
- }
- break;
- }
-
- //Go to x% of video:
- if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
- controller.seekTo((int) (0.1f * (keyCode - KeyEvent.KEYCODE_0) * controller.getDuration()));
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-}