summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/danoeh')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java67
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java41
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java162
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java73
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java70
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/TagSettingsDialog.java44
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java66
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java125
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java131
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsDialogFragment.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java93
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java54
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java128
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java201
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java28
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NotificationPreferencesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java (renamed from app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java)52
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/NextcloudAuthenticationFragment.java92
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/SynchronizationPreferencesFragment.java222
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java2
69 files changed, 1480 insertions, 926 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
index aa59e4e96..f7c96a93a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java
@@ -7,7 +7,6 @@ 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.util.Log;
import com.google.android.material.snackbar.Snackbar;
@@ -103,22 +102,21 @@ public class BugReportActivity extends AppCompatActivity {
Runtime.getRuntime().exec(cmd);
//share file
try {
- Intent i = new Intent(Intent.ACTION_SEND);
- i.setType("text/*");
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/*");
String authString = getString(de.danoeh.antennapod.core.R.string.provider_authority);
Uri fileUri = FileProvider.getUriForFile(this, authString, filename);
- i.putExtra(Intent.EXTRA_STREAM, fileUri);
- i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- PackageManager pm = getPackageManager();
- List<ResolveInfo> resInfos = pm.queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfos) {
- String packageName = resolveInfo.activityInfo.packageName;
- grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
+ intent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String chooserTitle = getString(de.danoeh.antennapod.core.R.string.share_file_label);
- startActivity(Intent.createChooser(i, chooserTitle));
+ Intent chooser = Intent.createChooser(intent, chooserTitle);
+ List<ResolveInfo> resInfos = getPackageManager()
+ .queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfos) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ startActivity(chooser);
} catch (Exception e) {
e.printStackTrace();
int strResId = R.string.log_file_share_exception;
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 f07ad6ad5..7dc760e76 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -38,6 +38,7 @@ import com.bumptech.glide.Glide;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
@@ -45,7 +46,7 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.MessageEvent;
+import de.danoeh.antennapod.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
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 4dca1fda7..9148a9949 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -6,7 +6,6 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.LightingColorFilter;
-import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
@@ -19,6 +18,7 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -31,8 +31,8 @@ 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.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.core.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@@ -60,7 +60,6 @@ import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.discovery.PodcastSearcherRegistry;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
import de.danoeh.antennapod.model.playback.RemoteMedia;
import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException;
import io.reactivex.Maybe;
@@ -101,6 +100,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
private Feed feed;
private String selectedDownloadUrl;
private Downloader downloader;
+ private String username = null;
+ private String password = null;
private boolean isPaused;
private boolean didPressSubscribe = false;
@@ -144,12 +145,11 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (feedUrl.contains("subscribeonandroid.com")) {
feedUrl = feedUrl.replaceFirst("((www.)?(subscribeonandroid.com/))", "");
}
- if (savedInstanceState == null) {
- lookupUrlAndDownload(feedUrl, null, null);
- } else {
- lookupUrlAndDownload(feedUrl, savedInstanceState.getString("username"),
- savedInstanceState.getString("password"));
+ if (savedInstanceState != null) {
+ username = savedInstanceState.getString("username");
+ password = savedInstanceState.getString("password");
}
+ lookupUrlAndDownload(feedUrl);
}
}
@@ -210,10 +210,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- if (feed != null && feed.getPreferences() != null) {
- outState.putString("username", feed.getPreferences().getUsername());
- outState.putString("password", feed.getPreferences().getPassword());
- }
+ outState.putString("username", username);
+ outState.putString("password", password);
}
private void resetIntent(String url) {
@@ -242,32 +240,23 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
- private void lookupUrlAndDownload(String url, String username, String password) {
+ private void lookupUrlAndDownload(String url) {
download = PodcastSearcherRegistry.lookupUrl(url)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
- .subscribe(lookedUpUrl -> startFeedDownload(lookedUpUrl, username, password),
+ .subscribe(this::startFeedDownload,
error -> {
showNoPodcastFoundError();
Log.e(TAG, Log.getStackTraceString(error));
});
}
- private void startFeedDownload(String url, String username, String password) {
+ private void startFeedDownload(String url) {
Log.d(TAG, "Starting feed download");
url = URLChecker.prepareURL(url);
feed = new Feed(url, null);
- if (username != null && password != null) {
- feed.setPreferences(new FeedPreferences(0, false, FeedPreferences.AutoDeleteAction.GLOBAL,
- VolumeAdaptionSetting.OFF, username, password));
- }
- String fileUrl;
- try {
- fileUrl = DownloadRequester.getInstance().getDownloadPathForFeed(feed).getAbsolutePath();
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- fileUrl = new File(getCacheDir(), FileNameGenerator.generateFileName(feed.getDownload_url())).toString();
- }
+ String fileUrl = new File(getExternalCacheDir(),
+ FileNameGenerator.generateFileName(feed.getDownload_url())).toString();
feed.setFile_url(fileUrl);
final DownloadRequest request = new DownloadRequest(feed.getFile_url(),
feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED, username, password,
@@ -293,6 +282,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
parseFeed();
} 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();
@@ -458,8 +450,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
final int MAX_LINES_COLLAPSED = 10;
description.setMaxLines(MAX_LINES_COLLAPSED);
description.setOnClickListener(v -> {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
- && description.getMaxLines() > MAX_LINES_COLLAPSED) {
+ if (description.getMaxLines() > MAX_LINES_COLLAPSED) {
description.setMaxLines(MAX_LINES_COLLAPSED);
} else {
description.setMaxLines(2000);
@@ -642,21 +633,17 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (urls.size() == 1) {
// Skip dialog and display the item directly
resetIntent(urls.get(0));
- startFeedDownload(urls.get(0), null, null);
+ startFeedDownload(urls.get(0));
return true;
}
- final ArrayAdapter<String> adapter = new ArrayAdapter<>(OnlineFeedViewActivity.this, R.layout.ellipsize_start_listitem, R.id.txtvTitle, titles);
+ 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);
- FeedPreferences prefs = feed.getPreferences();
- if(prefs != null) {
- startFeedDownload(selectedUrl, prefs.getUsername(), prefs.getPassword());
- } else {
- startFeedDownload(selectedUrl, null, null);
- }
+ startFeedDownload(selectedUrl);
};
AlertDialog.Builder ab = new AlertDialog.Builder(OnlineFeedViewActivity.this)
@@ -679,7 +666,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
private final String feedUrl;
FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) {
- super(context, titleRes, true, null, null);
+ super(context, titleRes, true, username, password);
this.feedUrl = feedUrl;
}
@@ -691,7 +678,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
@Override
protected void onConfirmed(String username, String password) {
- startFeedDownload(feedUrl, username, password);
+ OnlineFeedViewActivity.this.username = username;
+ OnlineFeedViewActivity.this.password = password;
+ startFeedDownload(feedUrl);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index a6810715c..3d0c9d113 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.activity;
+import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
@@ -15,7 +16,9 @@ import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
-import androidx.annotation.NonNull;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
@@ -35,7 +38,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
-import org.apache.commons.lang3.ArrayUtils;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -48,7 +50,6 @@ import java.util.List;
* */
public class OpmlImportActivity extends AppCompatActivity {
private static final String TAG = "OpmlImportBaseActivity";
- private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
@Nullable private Uri uri;
OpmlSelectionBinding viewBinding;
private ArrayAdapter<String> listAdapter;
@@ -198,27 +199,23 @@ public class OpmlImportActivity extends AppCompatActivity {
}
private void requestPermission() {
- String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE };
- ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
+ requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
}
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
- @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, 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();
- }
- }
+ private final ActivityResultLauncher<String> requestPermissionLauncher =
+ registerForActivityResult(new RequestPermission(), isGranted -> {
+ if (isGranted) {
+ 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() {
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 600204554..1fc16ab32 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
+
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@@ -21,13 +22,13 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.databinding.SettingsActivityBinding;
import de.danoeh.antennapod.fragment.preferences.AutoDownloadPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.GpodderPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.ImportExportPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.NetworkPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.NotificationPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.StoragePreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.synchronization.SynchronizationPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.SwipePreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.UserInterfacePreferencesFragment;
@@ -76,8 +77,8 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
prefFragment = new ImportExportPreferencesFragment();
} else if (screen == R.xml.preferences_autodownload) {
prefFragment = new AutoDownloadPreferencesFragment();
- } else if (screen == R.xml.preferences_gpodder) {
- prefFragment = new GpodderPreferencesFragment();
+ } 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) {
@@ -101,8 +102,8 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
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_gpodder) {
- return R.string.gpodnet_main_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) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java
new file mode 100644
index 000000000..4ffed949e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/activity/SelectSubscriptionActivity.java
@@ -0,0 +1,162 @@
+package de.danoeh.antennapod.activity;
+
+import static de.danoeh.antennapod.activity.MainActivity.EXTRA_FEED_ID;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.pm.ShortcutInfoCompat;
+import androidx.core.content.pm.ShortcutManagerCompat;
+import androidx.core.graphics.drawable.IconCompat;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.DataSource;
+import com.bumptech.glide.load.engine.GlideException;
+import com.bumptech.glide.request.RequestListener;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.request.target.Target;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.NavDrawerData;
+import de.danoeh.antennapod.databinding.SubscriptionSelectionActivityBinding;
+import de.danoeh.antennapod.model.feed.Feed;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+public class SelectSubscriptionActivity extends AppCompatActivity {
+
+ private static final String TAG = "SelectSubscription";
+
+ private Disposable disposable;
+ private volatile List<Feed> listItems;
+
+ private SubscriptionSelectionActivityBinding viewBinding;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTranslucentTheme());
+ super.onCreate(savedInstanceState);
+
+ viewBinding = SubscriptionSelectionActivityBinding.inflate(getLayoutInflater());
+ setContentView(viewBinding.getRoot());
+ setSupportActionBar(viewBinding.toolbar);
+ setTitle(R.string.shortcut_select_subscription);
+
+ viewBinding.transparentBackground.setOnClickListener(v -> finish());
+ viewBinding.card.setOnClickListener(null);
+
+ loadSubscriptions();
+
+ final Integer[] checkedPosition = new Integer[1];
+ viewBinding.list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ viewBinding.list.setOnItemClickListener((listView, view1, position, rowId) ->
+ checkedPosition[0] = position
+ );
+ viewBinding.shortcutBtn.setOnClickListener(view -> {
+ if (checkedPosition[0] != null && Intent.ACTION_CREATE_SHORTCUT.equals(
+ getIntent().getAction())) {
+ getBitmapFromUrl(listItems.get(checkedPosition[0]));
+ }
+ });
+
+ }
+
+ public List<Feed> getFeedItems(List<NavDrawerData.DrawerItem> items, List<Feed> result) {
+ for (NavDrawerData.DrawerItem item : items) {
+ if (item.type == NavDrawerData.DrawerItem.Type.TAG) {
+ getFeedItems(((NavDrawerData.TagDrawerItem) item).children, result);
+ } else {
+ Feed feed = ((NavDrawerData.FeedDrawerItem) item).feed;
+ if (!result.contains(feed)) {
+ result.add(feed);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void addShortcut(Feed feed, Bitmap bitmap) {
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra(EXTRA_FEED_ID, feed.getId());
+ String id = "subscription-" + feed.getId();
+ IconCompat icon;
+
+ if (bitmap != null) {
+ icon = IconCompat.createWithAdaptiveBitmap(bitmap);
+ } else {
+ icon = IconCompat.createWithResource(this, R.drawable.ic_folder_shortcut);
+ }
+
+ ShortcutInfoCompat shortcut = new ShortcutInfoCompat.Builder(this, id)
+ .setShortLabel(feed.getTitle())
+ .setLongLabel(feed.getFeedTitle())
+ .setIntent(intent)
+ .setIcon(icon)
+ .build();
+
+ setResult(RESULT_OK, ShortcutManagerCompat.createShortcutResultIntent(this, shortcut));
+ finish();
+ }
+
+ private void getBitmapFromUrl(Feed feed) {
+ int iconSize = (int) (128 * getResources().getDisplayMetrics().density);
+ Glide.with(this)
+ .asBitmap()
+ .load(feed.getImageUrl())
+ .apply(new RequestOptions().override(iconSize, iconSize))
+ .listener(new RequestListener<Bitmap>() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, Object model,
+ Target<Bitmap> target, boolean isFirstResource) {
+ addShortcut(feed, null);
+ return true;
+ }
+
+ @Override
+ public boolean onResourceReady(Bitmap resource, Object model,
+ Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
+ addShortcut(feed, resource);
+ return true;
+ }
+ }).submit();
+ }
+
+ private void loadSubscriptions() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(
+ () -> {
+ NavDrawerData data = DBReader.getNavDrawerData();
+ return getFeedItems(data.items, new ArrayList<>());
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ result -> {
+ listItems = result;
+ ArrayList<String> titles = new ArrayList<>();
+ for (Feed feed: result) {
+ titles.add(feed.getTitle());
+ }
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+ R.layout.simple_list_item_multiple_choice_on_start, titles);
+ viewBinding.list.setAdapter(adapter);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+} \ No newline at end of file
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 d436acf0d..4ff2a5775 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -36,11 +36,13 @@ import androidx.core.view.WindowCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.bumptech.glide.Glide;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
-import de.danoeh.antennapod.core.event.ServiceEvent;
+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.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
@@ -50,7 +52,6 @@ import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
-import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.databinding.VideoplayerActivityBinding;
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
@@ -60,6 +61,8 @@ 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 io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -193,40 +196,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
}
@Override
- public void onBufferStart() {
- viewBinding.progressBar.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onBufferEnd() {
- viewBinding.progressBar.setVisibility(View.INVISIBLE);
- }
-
- @Override
- public void onBufferUpdate(float progress) {
- viewBinding.sbPosition.setSecondaryProgress((int) (progress * viewBinding.sbPosition.getMax()));
- }
-
- @Override
- public void handleError(int code) {
- final AlertDialog.Builder errorDialog = new AlertDialog.Builder(VideoplayerActivity.this);
- errorDialog.setTitle(R.string.error_label);
- errorDialog.setMessage(MediaPlayerError.getErrorString(VideoplayerActivity.this, code));
- errorDialog.setNeutralButton(android.R.string.ok, (dialog, which) -> finish());
- errorDialog.show();
- }
-
- @Override
public void onReloadNotification(int code) {
VideoplayerActivity.this.onReloadNotification(code);
}
@Override
- public void onSleepTimerUpdate() {
- supportInvalidateOptionsMenu();
- }
-
- @Override
protected void updatePlayButtonShowsPlay(boolean showPlay) {
viewBinding.playButton.setIsShowPlay(showPlay);
}
@@ -261,6 +235,26 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
};
}
+ @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) {
@@ -544,12 +538,21 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onPlaybackServiceChanged(ServiceEvent event) {
- if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) {
+ public void onPlaybackServiceChanged(PlaybackServiceEvent event) {
+ if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) {
finish();
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onMediaPlayerError(PlayerErrorEvent event) {
+ final AlertDialog.Builder errorDialog = new AlertDialog.Builder(VideoplayerActivity.this);
+ errorDialog.setTitle(R.string.error_label);
+ errorDialog.setMessage(event.getMessage());
+ errorDialog.setNeutralButton(android.R.string.ok, (dialog, which) -> finish());
+ errorDialog.show();
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
index 3020aba43..674071294 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
@@ -1,21 +1,14 @@
package de.danoeh.antennapod.activity;
-import android.Manifest;
-import android.app.WallpaperManager;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
-import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.content.ContextCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.PlayerWidget;
@@ -51,7 +44,6 @@ public class WidgetConfigActivity extends AppCompatActivity {
finish();
}
- displayDeviceBackground();
opacityTextView = findViewById(R.id.widget_opacity_textView);
opacitySeekBar = findViewById(R.id.widget_opacity_seekBar);
widgetPreview = findViewById(R.id.widgetLayout);
@@ -102,16 +94,6 @@ public class WidgetConfigActivity extends AppCompatActivity {
widgetPreview.findViewById(R.id.butRew).setVisibility(ckRewind.isChecked() ? View.VISIBLE : View.GONE);
}
- 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());
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 2ab96e84d..5ddb6407c 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -95,7 +95,7 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
holder.preview.setVisibility(View.GONE);
holder.description.setTag(Boolean.FALSE);
} else {
- holder.description.setMaxLines(2000);
+ holder.description.setMaxLines(30);
holder.description.setTag(Boolean.TRUE);
holder.preview.setVisibility(item.getMedia() != null ? View.VISIBLE : View.GONE);
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 ff0311ab6..7854f7aa9 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -196,7 +196,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
bindFeedView((NavDrawerData.FeedDrawerItem) item, (FeedHolder) holder);
holder.itemView.setOnCreateContextMenuListener(itemAccess);
} else {
- bindFolderView((NavDrawerData.FolderDrawerItem) item, (FeedHolder) holder);
+ bindTagView((NavDrawerData.TagDrawerItem) item, (FeedHolder) holder);
}
}
if (viewType != VIEW_TYPE_SECTION_DIVIDER) {
@@ -327,16 +327,16 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
}
}
- private void bindFolderView(NavDrawerData.FolderDrawerItem folder, FeedHolder holder) {
+ private void bindTagView(NavDrawerData.TagDrawerItem tag, FeedHolder holder) {
Activity context = activity.get();
if (context == null) {
return;
}
- if (folder.isOpen) {
+ if (tag.isOpen) {
holder.count.setVisibility(View.GONE);
}
Glide.with(context).clear(holder.image);
- holder.image.setImageResource(R.drawable.ic_folder);
+ holder.image.setImageResource(R.drawable.ic_tag);
holder.failure.setVisibility(View.GONE);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
index 5fec5f063..26674b2b2 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
@@ -1,13 +1,12 @@
package de.danoeh.antennapod.adapter;
-import android.content.Context;
-import androidx.appcompat.app.AlertDialog;
-
+import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.StatisticsItem;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateFormatter;
+import de.danoeh.antennapod.fragment.FeedStatisticsDialogFragment;
import de.danoeh.antennapod.view.PieChartView;
import java.util.Date;
@@ -18,10 +17,12 @@ import java.util.List;
*/
public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
+ private final Fragment fragment;
boolean countAll = true;
- public PlaybackStatisticsListAdapter(Context context) {
- super(context);
+ public PlaybackStatisticsListAdapter(Fragment fragment) {
+ super(fragment.getContext());
+ this.fragment = fragment;
}
public void setCountAll(boolean countAll) {
@@ -60,16 +61,9 @@ public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
holder.value.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();
+ FeedStatisticsDialogFragment yourDialogFragment = FeedStatisticsDialogFragment.newInstance(
+ statsItem.feed.getId(), statsItem.feed.getTitle());
+ yourDialogFragment.show(fragment.getChildFragmentManager().beginTransaction(), "DialogFragment");
});
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
index 73f67d016..b637eb31d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
@@ -219,7 +219,7 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
.load();
} else {
new CoverLoader(mainActivityRef.get())
- .withResource(R.drawable.ic_folder)
+ .withResource(R.drawable.ic_tag)
.withPlaceholderView(feedTitle, true)
.withCoverView(imageView)
.load();
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 dedf8e5e6..a2b0e98c3 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
@@ -34,7 +34,7 @@ public class CancelDownloadActionButton extends ItemActionButton {
FeedMedia media = item.getMedia();
DownloadRequester.getInstance().cancelDownload(context, media);
if (UserPreferences.isEnableAutodownload()) {
- item.setAutoDownload(false);
+ item.disableAutoDownload();
DBWriter.setFeedItem(item);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
index a45eb5199..1f4f657b1 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -15,6 +15,5 @@ class ClientConfigurator {
ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
- ClientConfig.castCallbacks = new CastCallbackImpl();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
index 938bb5931..590b7c897 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/DownloadServiceCallbacksImpl.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.config;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import de.danoeh.antennapod.R;
@@ -24,7 +25,8 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
return PendingIntent.getActivity(context,
- R.id.pending_intent_download_service_notification, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ R.id.pending_intent_download_service_notification, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
}
@Override
@@ -33,7 +35,8 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
activityIntent.setAction("request" + request.getFeedfileId());
activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, request);
return PendingIntent.getActivity(context.getApplicationContext(),
- R.id.pending_intent_download_service_auth, activityIntent, PendingIntent.FLAG_ONE_SHOT);
+ R.id.pending_intent_download_service_auth, activityIntent,
+ PendingIntent.FLAG_ONE_SHOT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
}
@Override
@@ -43,15 +46,15 @@ public class DownloadServiceCallbacksImpl implements DownloadServiceCallbacks {
Bundle args = new Bundle();
args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
- return PendingIntent.getActivity(context, R.id.pending_intent_download_service_report,
- intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, R.id.pending_intent_download_service_report, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
}
@Override
public PendingIntent getAutoDownloadReportNotificationContentIntent(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, QueueFragment.TAG);
- return PendingIntent.getActivity(context, R.id.pending_intent_download_service_autodownload_report,
- intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, R.id.pending_intent_download_service_autodownload_report, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
index ee19a0339..595f37e40 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.dialog;
import android.content.Context;
import android.view.View;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
@@ -14,7 +15,6 @@ import de.danoeh.antennapod.model.feed.FeedFilter;
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
*/
public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
-
private final FeedFilter initialFilter;
public EpisodeFilterDialog(Context context, FeedFilter filter) {
@@ -26,8 +26,10 @@ public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
setView(rootView);
final EditText etxtEpisodeFilterText = rootView.findViewById(R.id.etxtEpisodeFilterText);
+ final EditText etxtEpisodeFilterDurationText = rootView.findViewById(R.id.etxtEpisodeFilterDurationText);
final RadioButton radioInclude = rootView.findViewById(R.id.radio_filter_include);
final RadioButton radioExclude = rootView.findViewById(R.id.radio_filter_exclude);
+ final CheckBox checkboxDuration = rootView.findViewById(R.id.checkbox_filter_duration);
if (initialFilter.includeOnly()) {
radioInclude.setChecked(true);
@@ -40,18 +42,31 @@ public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
radioInclude.setChecked(false);
etxtEpisodeFilterText.setText("");
}
+ if (initialFilter.hasMinimalDurationFilter()) {
+ checkboxDuration.setChecked(true);
+ // Store minimal duration in seconds, show in minutes
+ etxtEpisodeFilterDurationText.setText(String.valueOf(initialFilter.getMinimalDurationFilter() / 60));
+ }
setNegativeButton(R.string.cancel_label, null);
setPositiveButton(R.string.confirm_label, (dialog, which) -> {
String includeString = "";
String excludeString = "";
+ int minimalDuration = -1;
if (radioInclude.isChecked()) {
includeString = etxtEpisodeFilterText.getText().toString();
} else {
excludeString = etxtEpisodeFilterText.getText().toString();
}
-
- onConfirmed(new FeedFilter(includeString, excludeString));
+ if (checkboxDuration.isChecked()) {
+ try {
+ // Store minimal duration in seconds
+ minimalDuration = Integer.parseInt(etxtEpisodeFilterDurationText.getText().toString()) * 60;
+ } catch (NumberFormatException e) {
+ // Do not change anything on error
+ }
+ }
+ onConfirmed(new FeedFilter(includeString, excludeString, minimalDuration));
}
);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java
index 96d1b9b67..b89d05f88 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedSortDialog.java
@@ -10,7 +10,7 @@ import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
public class FeedSortDialog {
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 3186cbe2e..5cc1f99c6 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -12,9 +12,13 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.view.PlaybackSpeedSeekBar;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import java.util.Locale;
@@ -22,6 +26,8 @@ import java.util.Locale;
public class PlaybackControlsDialog extends DialogFragment {
private PlaybackController controller;
private AlertDialog dialog;
+ private PlaybackSpeedSeekBar speedSeekBar;
+ private TextView txtvPlaybackSpeed;
public static PlaybackControlsDialog newInstance() {
Bundle arguments = new Bundle();
@@ -42,10 +48,12 @@ public class PlaybackControlsDialog extends DialogFragment {
public void loadMediaInfo() {
setupUi();
setupAudioTracks();
+ updateSpeed(new SpeedChangedEvent(getCurrentPlaybackSpeedMultiplier()));
}
};
controller.init();
setupUi();
+ EventBus.getDefault().register(this);
}
@Override
@@ -53,6 +61,7 @@ public class PlaybackControlsDialog extends DialogFragment {
super.onStop();
controller.release();
controller = null;
+ EventBus.getDefault().unregister(this);
}
@NonNull
@@ -66,12 +75,14 @@ public class PlaybackControlsDialog extends DialogFragment {
}
private void setupUi() {
- final TextView txtvPlaybackSpeed = dialog.findViewById(R.id.txtvPlaybackSpeed);
-
- PlaybackSpeedSeekBar speedSeekBar = dialog.findViewById(R.id.speed_seek_bar);
- speedSeekBar.setController(controller);
- speedSeekBar.setProgressChangedListener(speed
- -> txtvPlaybackSpeed.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
+ txtvPlaybackSpeed = dialog.findViewById(R.id.txtvPlaybackSpeed);
+ speedSeekBar = dialog.findViewById(R.id.speed_seek_bar);
+ speedSeekBar.setProgressChangedListener(speed -> {
+ if (controller != null) {
+ controller.setPlaybackSpeed(speed);
+ }
+ });
+ updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
final CheckBox stereoToMono = dialog.findViewById(R.id.stereo_to_mono);
stereoToMono.setChecked(UserPreferences.stereoToMono());
@@ -100,6 +111,12 @@ public class PlaybackControlsDialog extends DialogFragment {
});
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void updateSpeed(SpeedChangedEvent event) {
+ txtvPlaybackSpeed.setText(String.format(Locale.getDefault(), "%.2fx", event.getNewSpeed()));
+ speedSeekBar.updateSpeed(event.getNewSpeed());
+ }
+
private void setupAudioTracks() {
List<String> audioTracks = controller.getAudioTracks();
int selectedAudioTrack = controller.getSelectedAudioTrack();
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 13258b4ec..ad2ed3499 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -67,6 +67,7 @@ public class ProxyDialog {
.setView(content)
.setNegativeButton(R.string.cancel_label, null)
.setPositiveButton(R.string.proxy_test_label, null)
+ .setNeutralButton(R.string.reset, null)
.show();
// To prevent cancelling the dialog on button click
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((view) -> {
@@ -75,36 +76,19 @@ public class ProxyDialog {
test();
return;
}
- String type = (String) 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.parseInt(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);
+ setProxyConfig();
AntennapodHttpClient.reinit();
dialog.dismiss();
});
+ dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener((view) -> {
+ etHost.getText().clear();
+ etPort.getText().clear();
+ etUsername.getText().clear();
+ etPassword.getText().clear();
+ setProxyConfig();
+ });
+
List<String> types = new ArrayList<>();
types.add(Proxy.Type.DIRECT.name());
types.add(Proxy.Type.HTTP.name());
@@ -144,6 +128,11 @@ public class ProxyDialog {
spType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (position == 0) {
+ dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setVisibility(View.GONE);
+ } else {
+ dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setVisibility(View.VISIBLE);
+ }
enableSettings(position > 0);
setTestRequired(position > 0);
}
@@ -158,6 +147,35 @@ public class ProxyDialog {
return dialog;
}
+ private void setProxyConfig() {
+ String type = (String) 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.parseInt(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);
+ }
+
private final TextWatcher requireTestOnChange = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
index 9fcf8be69..23c032248 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RemoveFeedDialog.java
@@ -19,18 +19,18 @@ import io.reactivex.schedulers.Schedulers;
public class RemoveFeedDialog {
private static final String TAG = "RemoveFeedDialog";
- public static void show(Context context, Feed feed, Runnable onSuccess) {
+ public static void show(Context context, Feed feed) {
List<Feed> feeds = Collections.singletonList(feed);
String message = getMessageId(context, feeds);
- showDialog(context, feeds, message, onSuccess);
+ showDialog(context, feeds, message);
}
- public static void show(Context context, List<Feed> feeds, Runnable onSuccess) {
+ public static void show(Context context, List<Feed> feeds) {
String message = getMessageId(context, feeds);
- showDialog(context, feeds, message, onSuccess);
+ showDialog(context, feeds, message);
}
- private static void showDialog(Context context, List<Feed> feeds, String message, Runnable onSuccess) {
+ private static void showDialog(Context context, List<Feed> feeds, String message) {
ConfirmationDialog dialog = new ConfirmationDialog(context, R.string.remove_feed_label, message) {
@Override
public void onConfirmButtonPressed(DialogInterface clickedDialog) {
@@ -42,20 +42,16 @@ public class RemoveFeedDialog {
progressDialog.setCancelable(false);
progressDialog.show();
- Completable.fromCallable(() -> {
+ Completable.fromAction(() -> {
for (Feed feed : feeds) {
DBWriter.deleteFeed(context, feed.getId()).get();
}
- return null;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
() -> {
Log.d(TAG, "Feed(s) deleted");
- if (onSuccess != null) {
- onSuccess.run();
- }
progressDialog.dismiss();
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
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 691bd65e8..764940e06 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -18,20 +18,17 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-
-import java.util.concurrent.TimeUnit;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
public class SleepTimerDialog extends DialogFragment {
private PlaybackController controller;
- private Disposable timeUpdater;
-
private EditText etxtTime;
private Spinner spTimeUnit;
private LinearLayout timeSetup;
@@ -47,19 +44,11 @@ public class SleepTimerDialog extends DialogFragment {
super.onStart();
controller = new PlaybackController(getActivity()) {
@Override
- public void onSleepTimerUpdate() {
- updateTime();
- }
-
- @Override
public void loadMediaInfo() {
- updateTime();
}
};
controller.init();
- timeUpdater = Observable.interval(1, TimeUnit.SECONDS)
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(tick -> updateTime());
+ EventBus.getDefault().register(this);
}
@Override
@@ -68,9 +57,7 @@ public class SleepTimerDialog extends DialogFragment {
if (controller != null) {
controller.release();
}
- if (timeUpdater != null) {
- timeUpdater.dispose();
- }
+ EventBus.getDefault().unregister(this);
}
@NonNull
@@ -170,13 +157,12 @@ public class SleepTimerDialog extends DialogFragment {
return builder.create();
}
- private void updateTime() {
- if (controller == null) {
- return;
- }
- timeSetup.setVisibility(controller.sleepTimerActive() ? View.GONE : View.VISIBLE);
- timeDisplay.setVisibility(controller.sleepTimerActive() ? View.VISIBLE : View.GONE);
- time.setText(Converter.getDurationStringLong((int) controller.getSleepTimerTimeLeft()));
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ @SuppressWarnings("unused")
+ public void timerUpdated(SleepTimerUpdatedEvent event) {
+ timeDisplay.setVisibility(event.isOver() || event.isCancelled() ? View.GONE : View.VISIBLE);
+ timeSetup.setVisibility(event.isOver() || event.isCancelled() ? View.VISIBLE : View.GONE);
+ time.setText(Converter.getDurationStringLong((int) event.getTimeLeft()));
}
private void closeKeyboard(View content) {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java
index 29172bb5e..9e524188f 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java
@@ -16,7 +16,7 @@ import java.util.HashSet;
import java.util.Set;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup;
import de.danoeh.antennapod.core.preferences.UserPreferences;
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/TagSettingsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TagSettingsDialog.java
index 8ef01590f..8f5f1b802 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/TagSettingsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/TagSettingsDialog.java
@@ -27,7 +27,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class TagSettingsDialog extends DialogFragment {
public static final String TAG = "TagSettingsDialog";
@@ -36,10 +38,10 @@ public class TagSettingsDialog extends DialogFragment {
private EditTagsDialogBinding viewBinding;
private TagSelectionAdapter adapter;
- public static TagSettingsDialog newInstance(FeedPreferences preferences) {
+ public static TagSettingsDialog newInstance(List<FeedPreferences> preferencesList) {
TagSettingsDialog fragment = new TagSettingsDialog();
Bundle args = new Bundle();
- args.putSerializable(ARG_FEED_PREFERENCES, preferences);
+ args.putSerializable(ARG_FEED_PREFERENCES, new ArrayList<>(preferencesList));
fragment.setArguments(args);
return fragment;
}
@@ -47,8 +49,14 @@ public class TagSettingsDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
- FeedPreferences preferences = (FeedPreferences) getArguments().getSerializable(ARG_FEED_PREFERENCES);
- displayedTags = new ArrayList<>(preferences.getTags());
+ ArrayList<FeedPreferences> feedPreferencesList =
+ (ArrayList<FeedPreferences>) getArguments().getSerializable(ARG_FEED_PREFERENCES);
+ Set<String> commonTags = new HashSet<>(feedPreferencesList.get(0).getTags());
+
+ for (FeedPreferences preference : feedPreferencesList) {
+ commonTags.retainAll(preference.getTags());
+ }
+ displayedTags = new ArrayList<>(commonTags);
displayedTags.remove(FeedPreferences.TAG_ROOT);
viewBinding = EditTagsDialogBinding.inflate(getLayoutInflater());
@@ -57,7 +65,7 @@ public class TagSettingsDialog extends DialogFragment {
adapter = new TagSelectionAdapter();
adapter.setHasStableIds(true);
viewBinding.tagsRecycler.setAdapter(adapter);
- viewBinding.rootFolderCheckbox.setChecked(preferences.getTags().contains(FeedPreferences.TAG_ROOT));
+ viewBinding.rootFolderCheckbox.setChecked(commonTags.contains(FeedPreferences.TAG_ROOT));
viewBinding.newTagButton.setOnClickListener(v ->
addTag(viewBinding.newTagEditText.getText().toString().trim()));
@@ -73,17 +81,16 @@ public class TagSettingsDialog extends DialogFragment {
}
});
+ if (feedPreferencesList.size() > 1) {
+ viewBinding.commonTagsInfo.setVisibility(View.VISIBLE);
+ }
+
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
dialog.setView(viewBinding.getRoot());
- dialog.setTitle(R.string.feed_folders_label);
+ dialog.setTitle(R.string.feed_tags_label);
dialog.setPositiveButton(android.R.string.ok, (d, input) -> {
addTag(viewBinding.newTagEditText.getText().toString().trim());
- preferences.getTags().clear();
- preferences.getTags().addAll(displayedTags);
- if (viewBinding.rootFolderCheckbox.isChecked()) {
- preferences.getTags().add(FeedPreferences.TAG_ROOT);
- }
- DBWriter.setFeedPreferences(preferences);
+ updatePreferencesTags(feedPreferencesList, commonTags);
});
dialog.setNegativeButton(R.string.cancel_label, null);
return dialog.create();
@@ -96,7 +103,7 @@ public class TagSettingsDialog extends DialogFragment {
List<NavDrawerData.DrawerItem> items = data.items;
List<String> folders = new ArrayList<String>();
for (NavDrawerData.DrawerItem item : items) {
- if (item.type == NavDrawerData.DrawerItem.Type.FOLDER) {
+ if (item.type == NavDrawerData.DrawerItem.Type.TAG) {
folders.add(item.getTitle());
}
}
@@ -123,6 +130,17 @@ public class TagSettingsDialog extends DialogFragment {
adapter.notifyDataSetChanged();
}
+ private void updatePreferencesTags(List<FeedPreferences> feedPreferencesList, Set<String> commonTags) {
+ if (viewBinding.rootFolderCheckbox.isChecked()) {
+ displayedTags.add(FeedPreferences.TAG_ROOT);
+ }
+ for (FeedPreferences preferences : feedPreferencesList) {
+ preferences.getTags().removeAll(commonTags);
+ preferences.getTags().addAll(displayedTags);
+ DBWriter.setFeedPreferences(preferences);
+ }
+ }
+
public class TagSelectionAdapter extends RecyclerView.Adapter<TagSelectionAdapter.ViewHolder> {
@Override
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 def2e56a7..2bce73b79 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.dialog;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -15,10 +14,14 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.view.ItemOffsetDecoration;
import de.danoeh.antennapod.view.PlaybackSpeedSeekBar;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -47,22 +50,12 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
super.onStart();
controller = new PlaybackController(getActivity()) {
@Override
- public void onPlaybackSpeedChange() {
- updateSpeed();
- }
-
- @Override
public void loadMediaInfo() {
- updateSpeed();
+ updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
}
};
controller.init();
- speedSeekBar.setController(controller);
- }
-
- private void updateSpeed() {
- speedSeekBar.updateSpeed();
- addCurrentSpeedChip.setText(speedFormat.format(controller.getCurrentPlaybackSpeedMultiplier()));
+ EventBus.getDefault().register(this);
}
@Override
@@ -70,6 +63,13 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
super.onStop();
controller.release();
controller = null;
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void updateSpeed(SpeedChangedEvent event) {
+ speedSeekBar.updateSpeed(event.getNewSpeed());
+ addCurrentSpeedChip.setText(speedFormat.format(event.getNewSpeed()));
}
@Nullable
@@ -78,6 +78,11 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
@Nullable Bundle savedInstanceState) {
View root = View.inflate(getContext(), R.layout.speed_select_dialog, null);
speedSeekBar = root.findViewById(R.id.speed_seek_bar);
+ speedSeekBar.setProgressChangedListener(multiplier -> {
+ if (controller != null) {
+ controller.setPlaybackSpeed(multiplier);
+ }
+ });
RecyclerView selectedSpeedsGrid = root.findViewById(R.id.selected_speeds_grid);
selectedSpeedsGrid.setLayoutManager(new GridLayoutManager(getContext(), 3));
selectedSpeedsGrid.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
@@ -112,9 +117,7 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment {
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Chip chip = new Chip(getContext());
- if (Build.VERSION.SDK_INT >= 17) {
- chip.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
- }
+ chip.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
return new ViewHolder(chip);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
index f97c1c7ab..340783208 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.discovery;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
@@ -18,8 +18,8 @@ public class GpodnetPodcastSearcher implements PodcastSearcher {
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
try {
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
- GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
- GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
+ SynchronizationCredentials.getHosturl(), SynchronizationCredentials.getDeviceID(),
+ SynchronizationCredentials.getUsername(), SynchronizationCredentials.getPassword());
List<GpodnetPodcast> gpodnetPodcasts = service.searchPodcasts(query, 0);
List<PodcastSearchResult> results = new ArrayList<>();
for (GpodnetPodcast podcast : gpodnetPodcasts) {
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
index 6e894176f..5f3dd5f61 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
@@ -17,9 +17,12 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class ItunesPodcastSearcher implements PodcastSearcher {
private static final String ITUNES_API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
+ private static final String PATTERN_BY_ID = ".*/podcasts\\.apple\\.com/.*/podcast/.*/id(\\d+).*";
public ItunesPodcastSearcher() {
}
@@ -70,9 +73,12 @@ public class ItunesPodcastSearcher implements PodcastSearcher {
@Override
public Single<String> lookupUrl(String url) {
+ Pattern pattern = Pattern.compile(PATTERN_BY_ID);
+ Matcher matcher = pattern.matcher(url);
+ final String lookupUrl = matcher.find() ? ("https://itunes.apple.com/lookup?id=" + matcher.group(1)) : url;
return Single.create(emitter -> {
OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder().url(url);
+ Request.Builder httpReq = new Request.Builder().url(lookupUrl);
try {
Response response = client.newCall(httpReq.build()).execute();
if (response.isSuccessful()) {
@@ -92,7 +98,7 @@ public class ItunesPodcastSearcher implements PodcastSearcher {
@Override
public boolean urlNeedsLookup(String url) {
- return url.contains("itunes.apple.com");
+ return url.contains("itunes.apple.com") || url.matches(PATTERN_BY_ID);
}
@Override
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 64e7f161e..8c01a4563 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ClipboardManager;
import android.content.Context;
@@ -12,9 +11,14 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.activity.result.contract.ActivityResultContracts.GetContent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.documentfile.provider.DocumentFile;
@@ -48,14 +52,17 @@ import java.util.Collections;
public class AddFeedFragment extends Fragment {
public static final String TAG = "AddFeedFragment";
- private static final int REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH = 1;
- private static final int REQUEST_CODE_ADD_LOCAL_FOLDER = 2;
private static final String KEY_UP_ARROW = "up_arrow";
private AddfeedBinding viewBinding;
private MainActivity activity;
private boolean displayUpArrow;
+ private final ActivityResultLauncher<String> chooseOpmlImportPathLauncher =
+ registerForActivityResult(new GetContent(), this::chooseOpmlImportPathResult);
+ private final ActivityResultLauncher<Uri> addLocalFolderLauncher =
+ registerForActivityResult(new AddLocalFolder(), this::addLocalFolderResult);
+
@Override
@Nullable
public View onCreateView(@NonNull LayoutInflater inflater,
@@ -91,10 +98,7 @@ public class AddFeedFragment extends Fragment {
viewBinding.opmlImportButton.setOnClickListener(v -> {
try {
- Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
- intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
- intentGetContentAction.setType("*/*");
- startActivityForResult(intentGetContentAction, REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH);
+ chooseOpmlImportPathLauncher.launch("*/*");
} catch (ActivityNotFoundException e) {
e.printStackTrace();
((MainActivity) getActivity())
@@ -107,9 +111,7 @@ public class AddFeedFragment extends Fragment {
return;
}
try {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- startActivityForResult(intent, REQUEST_CODE_ADD_LOCAL_FOLDER);
+ addLocalFolderLauncher.launch(null);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
((MainActivity) getActivity())
@@ -157,6 +159,10 @@ public class AddFeedFragment extends Fragment {
}
private void performSearch() {
+ viewBinding.combinedFeedSearchEditText.clearFocus();
+ InputMethodManager in = (InputMethodManager)
+ getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ in.hideSoftInputFromWindow(viewBinding.combinedFeedSearchEditText.getWindowToken(), 0);
String query = viewBinding.combinedFeedSearchEditText.getText().toString();
if (query.matches("http[s]?://.*")) {
addUrl(query);
@@ -171,22 +177,23 @@ public class AddFeedFragment extends Fragment {
setRetainInstance(true);
}
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode != Activity.RESULT_OK || data == null) {
+ private void chooseOpmlImportPathResult(final Uri uri) {
+ if (uri == null) {
return;
}
- Uri uri = data.getData();
-
- if (requestCode == REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH) {
- Intent intent = new Intent(getContext(), OpmlImportActivity.class);
- intent.setData(uri);
- startActivity(intent);
- } else if (requestCode == REQUEST_CODE_ADD_LOCAL_FOLDER) {
- Observable.fromCallable(() -> addLocalFolder(uri))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
+ final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+
+ private void addLocalFolderResult(final Uri uri) {
+ if (uri == null) {
+ return;
+ }
+ Observable.fromCallable(() -> addLocalFolder(uri))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
feed -> {
Fragment fragment = FeedItemlistFragment.newInstance(feed.getId());
((MainActivity) getActivity()).loadChildFragment(fragment);
@@ -195,7 +202,6 @@ public class AddFeedFragment extends Fragment {
((MainActivity) getActivity())
.showSnackbarAbovePlayer(error.getLocalizedMessage(), Snackbar.LENGTH_LONG);
});
- }
}
private Feed addLocalFolder(Uri uri) throws DownloadRequestException {
@@ -219,4 +225,14 @@ public class AddFeedFragment extends Fragment {
DBTasks.forceRefreshFeed(getContext(), fromDatabase, true);
return fromDatabase;
}
+
+ private static class AddLocalFolder extends ActivityResultContracts.OpenDocumentTree {
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull final Context context, @Nullable final Uri input) {
+ return super.createIntent(context, input)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
index 168133c7a..95e2eb1aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
@@ -25,6 +25,14 @@ import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.event.playback.BufferUpdateEvent;
+import de.danoeh.antennapod.event.playback.PlaybackServiceEvent;
+import de.danoeh.antennapod.event.PlayerErrorEvent;
+import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
+import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
+import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -34,25 +42,20 @@ import java.text.NumberFormat;
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.core.event.FavoritesEvent;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
-import de.danoeh.antennapod.core.event.ServiceEvent;
+import de.danoeh.antennapod.event.FavoritesEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.model.feed.Chapter;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
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.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
-import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.model.playback.Playable;
-import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
@@ -224,8 +227,8 @@ public class AudioPlayerFragment extends Fragment implements
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onPlaybackServiceChanged(ServiceEvent event) {
- if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) {
+ public void onPlaybackServiceChanged(PlaybackServiceEvent event) {
+ if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) {
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
@@ -243,14 +246,11 @@ public class AudioPlayerFragment extends Fragment implements
});
}
- protected void updatePlaybackSpeedButton(Playable media) {
- if (butPlaybackSpeed == null || controller == null) {
- return;
- }
- float speed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(media);
- String speedStr = new DecimalFormat("0.00").format(speed);
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void updatePlaybackSpeedButton(SpeedChangedEvent event) {
+ String speedStr = new DecimalFormat("0.00").format(event.getNewSpeed());
txtvPlaybackSpeed.setText(speedStr);
- butPlaybackSpeed.setSpeed(speed);
+ butPlaybackSpeed.setSpeed(event.getNewSpeed());
}
private void loadMediaInfo(boolean includingChapters) {
@@ -282,47 +282,6 @@ public class AudioPlayerFragment extends Fragment implements
private PlaybackController newPlaybackController() {
return new PlaybackController(getActivity()) {
@Override
- public void onBufferStart() {
- progressIndicator.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onBufferEnd() {
- progressIndicator.setVisibility(View.GONE);
- }
-
- @Override
- public void onBufferUpdate(float progress) {
- if (isStreaming()) {
- sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax()));
- } else {
- sbPosition.setSecondaryProgress(0);
- }
- }
-
- @Override
- public void handleError(int code) {
- final AlertDialog.Builder errorDialog = new AlertDialog.Builder(getContext());
- errorDialog.setTitle(R.string.error_label);
- errorDialog.setMessage(MediaPlayerError.getErrorString(getContext(), code));
- errorDialog.setPositiveButton(android.R.string.ok, (dialog, which) ->
- ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED));
- if (!UserPreferences.useExoplayer()) {
- errorDialog.setNeutralButton(R.string.media_player_switch_to_exoplayer, (dialog, which) -> {
- UserPreferences.enableExoplayer();
- ((MainActivity) getActivity()).showSnackbarAbovePlayer(
- R.string.media_player_switched_to_exoplayer, Snackbar.LENGTH_LONG);
- });
- }
- errorDialog.create().show();
- }
-
- @Override
- public void onSleepTimerUpdate() {
- AudioPlayerFragment.this.loadMediaInfo(false);
- }
-
- @Override
protected void updatePlayButtonShowsPlay(boolean showPlay) {
butPlay.setIsShowPlay(showPlay);
}
@@ -336,25 +295,28 @@ public class AudioPlayerFragment extends Fragment implements
public void onPlaybackEnd() {
((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
}
-
- @Override
- public void onPlaybackSpeedChange() {
- updatePlaybackSpeedButton(getMedia());
- }
};
}
private void updateUi(Playable media) {
- if (controller == null) {
+ if (controller == null || media == null) {
return;
}
duration = controller.getDuration();
- updatePosition(new PlaybackPositionEvent(controller.getPosition(), duration));
- updatePlaybackSpeedButton(media);
+ updatePosition(new PlaybackPositionEvent(media.getPosition(), media.getDuration()));
+ updatePlaybackSpeedButton(new SpeedChangedEvent(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media)));
setChapterDividers(media);
setupOptionsMenu(media);
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ @SuppressWarnings("unused")
+ public void sleepTimerUpdate(SleepTimerUpdatedEvent event) {
+ if (event.isCancelled() || event.wasJustEnabled()) {
+ AudioPlayerFragment.this.loadMediaInfo(false);
+ }
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -385,6 +347,20 @@ public class AudioPlayerFragment extends Fragment implements
}
@Subscribe(threadMode = ThreadMode.MAIN)
+ @SuppressWarnings("unused")
+ public void bufferUpdate(BufferUpdateEvent event) {
+ if (event.hasStarted()) {
+ progressIndicator.setVisibility(View.VISIBLE);
+ } else if (event.hasEnded()) {
+ progressIndicator.setVisibility(View.GONE);
+ } else if (controller != null && controller.isStreaming()) {
+ sbPosition.setSecondaryProgress((int) (event.getProgress() * sbPosition.getMax()));
+ } else {
+ sbPosition.setSecondaryProgress(0);
+ }
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void updatePosition(PlaybackPositionEvent event) {
if (controller == null || txtvPosition == null || txtvLength == null || sbPosition == null) {
return;
@@ -419,6 +395,23 @@ public class AudioPlayerFragment extends Fragment implements
AudioPlayerFragment.this.loadMediaInfo(false);
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void mediaPlayerError(PlayerErrorEvent event) {
+ final AlertDialog.Builder errorDialog = new AlertDialog.Builder(getContext());
+ errorDialog.setTitle(R.string.error_label);
+ errorDialog.setMessage(event.getMessage());
+ errorDialog.setPositiveButton(android.R.string.ok, (dialog, which) ->
+ ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED));
+ if (!UserPreferences.useExoplayer()) {
+ errorDialog.setNeutralButton(R.string.media_player_switch_to_exoplayer, (dialog, which) -> {
+ UserPreferences.enableExoplayer();
+ ((MainActivity) getActivity()).showSnackbarAbovePlayer(
+ R.string.media_player_switched_to_exoplayer, Snackbar.LENGTH_LONG);
+ });
+ }
+ errorDialog.create().show();
+ }
+
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (controller == null || txtvLength == null) {
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 de14f220e..04ad6e2bd 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -17,14 +17,14 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import de.danoeh.antennapod.playback.base.PlayerStatus;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.model.feed.Chapter;
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 6c8baef29..933147378 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -23,10 +23,10 @@ import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.adapter.actionbutton.DeleteActionButton;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloadLogEvent;
-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.event.FeedItemEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
import de.danoeh.antennapod.model.feed.FeedItem;
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 8c2203f72..2d448faa8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -45,7 +45,7 @@ import org.greenrobot.eventbus.ThreadMode;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
@@ -110,9 +110,8 @@ public class CoverFragment extends Fragment {
butNextChapter.setColorFilter(colorFilter);
butPrevChapter.setColorFilter(colorFilter);
descriptionIcon.setColorFilter(colorFilter);
- ChaptersFragment chaptersFragment = new ChaptersFragment();
chapterControl.setOnClickListener(v ->
- chaptersFragment.show(getChildFragmentManager(), ChaptersFragment.TAG));
+ new ChaptersFragment().show(getChildFragmentManager(), ChaptersFragment.TAG));
butPrevChapter.setOnClickListener(v -> seekToPrevChapter());
butNextChapter.setOnClickListener(v -> seekToNextChapter());
@@ -156,8 +155,13 @@ public class CoverFragment extends Fragment {
+ "・"
+ "\u00A0"
+ StringUtils.replace(StringUtils.stripToEmpty(pubDateStr), " ", "\u00A0"));
- Intent openFeed = MainActivity.getIntentToOpenFeed(requireContext(), ((FeedMedia) media).getItem().getFeedId());
- txtvPodcastTitle.setOnClickListener(v -> startActivity(openFeed));
+ if (media instanceof FeedMedia) {
+ Intent openFeed = MainActivity.getIntentToOpenFeed(requireContext(),
+ ((FeedMedia) media).getItem().getFeedId());
+ txtvPodcastTitle.setOnClickListener(v -> startActivity(openFeed));
+ } else {
+ txtvPodcastTitle.setOnClickListener(null);
+ }
txtvPodcastTitle.setOnLongClickListener(v -> copyText(media.getFeedTitle()));
txtvEpisodeTitle.setText(media.getEpisodeTitle());
txtvEpisodeTitle.setOnLongClickListener(v -> copyText(media.getEpisodeTitle()));
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
index 034b111e1..230a0ce0d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
@@ -23,7 +23,7 @@ import org.greenrobot.eventbus.EventBus;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
-import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
+import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
import io.reactivex.disposables.Disposable;
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 ddbf6c078..5602dcb78 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -113,7 +113,7 @@ public class DownloadLogFragment extends ListFragment {
if (downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
FeedMedia media = DBReader.getFeedMedia(downloadRequest.getFeedfileId());
FeedItem feedItem = media.getItem();
- feedItem.setAutoDownload(false);
+ feedItem.disableAutoDownload();
DBWriter.setFeedItem(feedItem);
}
} else if (item instanceof DownloadStatus) {
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 7ea76bb8d..37d77d31f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -21,10 +21,10 @@ import android.widget.TextView;
import android.widget.Toast;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
-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.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
@@ -40,7 +40,7 @@ import de.danoeh.antennapod.activity.MainActivity;
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.event.FeedItemEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBWriter;
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 8e070738c..1e24d62f7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -9,21 +9,23 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+
+import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
-import de.danoeh.antennapod.core.event.ServiceEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.playback.PlaybackServiceEvent;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.playback.base.PlayerStatus;
import de.danoeh.antennapod.view.PlayButton;
import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -77,8 +79,8 @@ public class ExternalPlayerFragment extends Fragment {
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
butPlay.setOnClickListener(v -> {
if (controller == null) {
return;
@@ -97,12 +99,6 @@ public class ExternalPlayerFragment extends Fragment {
private PlaybackController setupPlaybackController() {
return new PlaybackController(getActivity()) {
-
- @Override
- public void onPositionObserverUpdate() {
- ExternalPlayerFragment.this.onPositionObserverUpdate();
- }
-
@Override
protected void updatePlayButtonShowsPlay(boolean showPlay) {
butPlay.setIsShowPlay(showPlay);
@@ -140,13 +136,20 @@ public class ExternalPlayerFragment extends Fragment {
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onEventMainThread(PlaybackPositionEvent event) {
- onPositionObserverUpdate();
+ public void onPositionObserverUpdate(PlaybackPositionEvent event) {
+ if (controller == null) {
+ return;
+ } else if (controller.getPosition() == PlaybackService.INVALID_TIME
+ || controller.getDuration() == PlaybackService.INVALID_TIME) {
+ return;
+ }
+ progressBar.setProgress((int)
+ ((double) controller.getPosition() / controller.getDuration() * 100));
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onPlaybackServiceChanged(ServiceEvent event) {
- if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) {
+ public void onPlaybackServiceChanged(PlaybackServiceEvent event) {
+ if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) {
((MainActivity) getActivity()).setPlayerVisible(false);
}
}
@@ -193,7 +196,7 @@ public class ExternalPlayerFragment extends Fragment {
((MainActivity) getActivity()).setPlayerVisible(true);
txtvTitle.setText(media.getEpisodeTitle());
feedName.setText(media.getFeedTitle());
- onPositionObserverUpdate();
+ onPositionObserverUpdate(new PlaybackPositionEvent(media.getPosition(), media.getDuration()));
RequestOptions options = new RequestOptions()
.placeholder(R.color.light_gray)
@@ -218,15 +221,4 @@ public class ExternalPlayerFragment extends Fragment {
((MainActivity) getActivity()).getBottomSheet().setLocked(false);
}
}
-
- private void onPositionObserverUpdate() {
- if (controller == null) {
- return;
- } else if (controller.getPosition() == PlaybackService.INVALID_TIME
- || controller.getDuration() == PlaybackService.INVALID_TIME) {
- return;
- }
- progressBar.setProgress((int)
- ((double) controller.getPosition() / controller.getDuration() * 100));
- }
}
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 986c417fd..d7bfd404d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -18,7 +18,7 @@ import org.greenrobot.eventbus.Subscribe;
import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.FavoritesEvent;
+import de.danoeh.antennapod.event.FavoritesEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
index da7e7e633..ae298cc1c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Context;
@@ -10,62 +9,56 @@ import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.widget.AppCompatDrawableManager;
-import androidx.appcompat.widget.Toolbar;
-import androidx.documentfile.provider.DocumentFile;
-import androidx.fragment.app.Fragment;
import android.text.TextUtils;
-import android.text.format.Formatter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.AppCompatDrawableManager;
+import androidx.appcompat.widget.Toolbar;
+import androidx.documentfile.provider.DocumentFile;
+import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.snackbar.Snackbar;
import com.joanzapata.iconify.Iconify;
-
-import org.apache.commons.lang3.StringUtils;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedFunding;
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.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.StatisticsItem;
-import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
import de.danoeh.antennapod.fragment.preferences.StatisticsFragment;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedFunding;
import de.danoeh.antennapod.view.ToolbarIconTintManager;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.MaybeOnSubscribe;
-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 java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
/**
* Displays information about a feed.
@@ -74,28 +67,22 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
private static final String TAG = "FeedInfoActivity";
- private static final int REQUEST_CODE_ADD_LOCAL_FOLDER = 2;
+ private final ActivityResultLauncher<Uri> addLocalFolderLauncher =
+ registerForActivityResult(new AddLocalFolder(), this::addLocalFolderResult);
private Feed feed;
private Disposable disposable;
- private Disposable disposableStatistics;
private ImageView imgvCover;
private TextView txtvTitle;
private TextView txtvDescription;
- private TextView lblStatistics;
- private TextView txtvPodcastTime;
- private TextView txtvPodcastSpace;
- private TextView txtvPodcastEpisodeCount;
private TextView txtvFundingUrl;
private TextView lblSupport;
- private Button btnvOpenStatistics;
private TextView txtvUrl;
private TextView txtvAuthorHeader;
private ImageView imgvBackground;
private View infoContainer;
private View header;
private Toolbar toolbar;
- private ToolbarIconTintManager iconTintManager;
public static FeedInfoFragment newInstance(Feed feed) {
FeedInfoFragment fragment = new FeedInfoFragment();
@@ -133,7 +120,7 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
AppBarLayout appBar = root.findViewById(R.id.appBar);
CollapsingToolbarLayout collapsingToolbar = root.findViewById(R.id.collapsing_toolbar);
- iconTintManager = new ToolbarIconTintManager(getContext(), toolbar, collapsingToolbar) {
+ ToolbarIconTintManager iconTintManager = new ToolbarIconTintManager(getContext(), toolbar, collapsingToolbar) {
@Override
protected void doTint(Context themedContext) {
toolbar.getMenu().findItem(R.id.visit_website_item)
@@ -157,23 +144,20 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
txtvDescription = root.findViewById(R.id.txtvDescription);
- lblStatistics = root.findViewById(R.id.lblStatistics);
- txtvPodcastSpace = root.findViewById(R.id.txtvPodcastSpaceUsed);
- txtvPodcastEpisodeCount = root.findViewById(R.id.txtvPodcastEpisodeCount);
- txtvPodcastTime = root.findViewById(R.id.txtvPodcastTime);
- btnvOpenStatistics = root.findViewById(R.id.btnvOpenStatistics);
txtvUrl = root.findViewById(R.id.txtvUrl);
lblSupport = root.findViewById(R.id.lblSupport);
txtvFundingUrl = root.findViewById(R.id.txtvFundingUrl);
txtvUrl.setOnClickListener(copyUrlToClipboard);
- btnvOpenStatistics.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatisticsFragment fragment = new StatisticsFragment();
- ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
- }
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ getParentFragmentManager().beginTransaction().replace(R.id.statisticsFragmentContainer,
+ FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
+ .commitAllowingStateLoss();
+
+ root.findViewById(R.id.btnvOpenStatistics).setOnClickListener(view -> {
+ StatisticsFragment fragment = new StatisticsFragment();
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
});
return root;
@@ -195,7 +179,6 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
.subscribe(result -> {
feed = result;
showFeed();
- loadStatistics();
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
@@ -270,53 +253,12 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
refreshToolbarState();
}
- private void loadStatistics() {
- if (disposableStatistics != null) {
- disposableStatistics.dispose();
- }
-
- disposableStatistics =
- Observable.fromCallable(() -> {
- List<StatisticsItem> statisticsData = DBReader.getStatistics();
-
- for (StatisticsItem statisticsItem : statisticsData) {
- if (statisticsItem.feed.getId() == feed.getId()) {
- return statisticsItem;
- }
- }
-
- return null;
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- txtvPodcastTime.setText(Converter.shortLocalizedDuration(
- getContext(), result.timePlayed));
- txtvPodcastSpace.setText(Formatter.formatShortFileSize(
- getContext(), result.totalDownloadSize));
- txtvPodcastEpisodeCount.setText(String.format(Locale.getDefault(),
- "%d%s", result.episodesDownloadCount,
- getString(R.string.episodes_suffix)));
- }, error -> {
- Log.d(TAG, Log.getStackTraceString(error));
- lblStatistics.setVisibility(View.GONE);
- txtvPodcastSpace.setVisibility(View.GONE);
- txtvPodcastTime.setVisibility(View.GONE);
- txtvPodcastEpisodeCount.setVisibility(View.GONE);
- btnvOpenStatistics.setVisibility(View.GONE);
- });
- }
-
@Override
public void onDestroy() {
super.onDestroy();
if (disposable != null) {
disposable.dispose();
}
-
- if (disposableStatistics != null) {
- disposableStatistics.dispose();
- }
}
private void refreshToolbarState() {
@@ -351,9 +293,7 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
alert.setMessage(R.string.reconnect_local_folder_warning);
alert.setPositiveButton(android.R.string.ok, (dialog, which) -> {
try {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- startActivityForResult(intent, REQUEST_CODE_ADD_LOCAL_FOLDER);
+ addLocalFolderLauncher.launch(null);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "No activity found. Should never happen...");
}
@@ -366,16 +306,11 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
return handled;
}
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode != Activity.RESULT_OK || data == null) {
+ private void addLocalFolderResult(final Uri uri) {
+ if (uri == null) {
return;
}
- Uri uri = data.getData();
-
- if (requestCode == REQUEST_CODE_ADD_LOCAL_FOLDER) {
- reconnectLocalFolder(uri);
- }
+ reconnectLocalFolder(uri);
}
private void reconnectLocalFolder(Uri uri) {
@@ -401,4 +336,14 @@ public class FeedInfoFragment extends Fragment implements Toolbar.OnMenuItemClic
error -> ((MainActivity) getActivity())
.showSnackbarAbovePlayer(error.getLocalizedMessage(), Snackbar.LENGTH_LONG));
}
+
+ private static class AddLocalFolder extends ActivityResultContracts.OpenDocumentTree {
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull final Context context, @Nullable final Uri input) {
+ return super.createIntent(context, input)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
}
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 0ee60866d..148cf6582 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -52,13 +52,13 @@ import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
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.FavoritesEvent;
-import de.danoeh.antennapod.core.event.FeedItemEvent;
-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.QueueEvent;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.FavoritesEvent;
+import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.QueueEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
@@ -333,8 +333,8 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
new RenameFeedDialog(getActivity(), feed).show();
return true;
} else if (itemId == R.id.remove_item) {
- RemoveFeedDialog.show(getContext(), feed, () ->
- ((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null));
+ ((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null);
+ RemoveFeedDialog.show(getContext(), feed);
return true;
} else if (itemId == R.id.action_search) {
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(feed.getId(), feed.getTitle()));
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 dbc7f2ae3..0c2103d25 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -7,16 +7,19 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.ListPreference;
+import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.settings.SkipIntroEndingChangedEvent;
-import de.danoeh.antennapod.core.event.settings.SpeedPresetChangedEvent;
-import de.danoeh.antennapod.core.event.settings.VolumeAdaptionChangedEvent;
+import de.danoeh.antennapod.event.settings.SkipIntroEndingChangedEvent;
+import de.danoeh.antennapod.event.settings.SpeedPresetChangedEvent;
+import de.danoeh.antennapod.event.settings.VolumeAdaptionChangedEvent;
+import de.danoeh.antennapod.databinding.PlaybackSpeedFeedSettingDialogBinding;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedFilter;
import de.danoeh.antennapod.model.feed.FeedPreferences;
@@ -35,12 +38,9 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
+import java.util.Collections;
import java.util.Locale;
-import static de.danoeh.antennapod.model.feed.FeedPreferences.SPEED_USE_GLOBAL;
-
public class FeedSettingsFragment extends Fragment {
private static final String TAG = "FeedSettingsFragment";
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
@@ -104,8 +104,6 @@ public class FeedSettingsFragment extends Fragment {
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final String PREF_AUTO_SKIP = "feedAutoSkip";
private static final String PREF_TAGS = "tags";
- private static final DecimalFormat SPEED_FORMAT =
- new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
private Feed feed;
private Disposable disposable;
@@ -164,7 +162,6 @@ public class FeedSettingsFragment extends Fragment {
updateAutoDeleteSummary();
updateVolumeReductionValue();
updateAutoDownloadEnabled();
- updatePlaybackSpeedPreference();
if (feed.isLocalFeed()) {
findPreference(PREF_AUTHENTICATION).setVisible(false);
@@ -205,27 +202,34 @@ public class FeedSettingsFragment extends Fragment {
}
private void setupPlaybackSpeedPreference() {
- ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
-
- final String[] speeds = getResources().getStringArray(R.array.playback_speed_values);
- String[] values = new String[speeds.length + 1];
- values[0] = SPEED_FORMAT.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));
- DBWriter.setFeedPreferences(feedPreferences);
- updatePlaybackSpeedPreference();
- EventBus.getDefault().post(
- new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(), feed.getId()));
- return false;
+ Preference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
+ feedPlaybackSpeedPreference.setOnPreferenceClickListener(preference -> {
+ PlaybackSpeedFeedSettingDialogBinding viewBinding =
+ PlaybackSpeedFeedSettingDialogBinding.inflate(getLayoutInflater());
+ viewBinding.seekBar.setProgressChangedListener(speed ->
+ viewBinding.currentSpeedLabel.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
+ float speed = feedPreferences.getFeedPlaybackSpeed();
+ viewBinding.useGlobalCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ viewBinding.seekBar.setEnabled(!isChecked);
+ viewBinding.seekBar.setAlpha(isChecked ? 0.4f : 1f);
+ viewBinding.currentSpeedLabel.setAlpha(isChecked ? 0.4f : 1f);
+ });
+ viewBinding.useGlobalCheckbox.setChecked(speed == FeedPreferences.SPEED_USE_GLOBAL);
+ viewBinding.seekBar.updateSpeed(speed == FeedPreferences.SPEED_USE_GLOBAL ? 1 : speed);
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.playback_speed)
+ .setView(viewBinding.getRoot())
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ float newSpeed = viewBinding.useGlobalCheckbox.isChecked()
+ ? FeedPreferences.SPEED_USE_GLOBAL : viewBinding.seekBar.getCurrentSpeed();
+ feedPreferences.setFeedPlaybackSpeed(newSpeed);
+ DBWriter.setFeedPreferences(feedPreferences);
+ EventBus.getDefault().post(
+ new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(), feed.getId()));
+ })
+ .setNegativeButton(R.string.cancel_label, null)
+ .show();
+ return true;
});
}
@@ -277,13 +281,6 @@ public class FeedSettingsFragment extends Fragment {
});
}
- private void updatePlaybackSpeedPreference() {
- ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
-
- float speedValue = feedPreferences.getFeedPlaybackSpeed();
- feedPlaybackSpeedPreference.setValue(SPEED_FORMAT.format(speedValue));
- }
-
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = findPreference(PREF_AUTO_DELETE);
@@ -395,7 +392,8 @@ public class FeedSettingsFragment extends Fragment {
private void setupTags() {
findPreference(PREF_TAGS).setOnPreferenceClickListener(preference -> {
- TagSettingsDialog.newInstance(feedPreferences).show(getChildFragmentManager(), TagSettingsDialog.TAG);
+ TagSettingsDialog.newInstance(Collections.singletonList(feedPreferences))
+ .show(getChildFragmentManager(), TagSettingsDialog.TAG);
return true;
});
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsDialogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsDialogFragment.java
new file mode 100644
index 000000000..33710b2c4
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsDialogFragment.java
@@ -0,0 +1,42 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import de.danoeh.antennapod.R;
+
+public class FeedStatisticsDialogFragment extends DialogFragment {
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String EXTRA_FEED_TITLE = "de.danoeh.antennapod.extra.feedTitle";
+
+ public static FeedStatisticsDialogFragment newInstance(long feedId, String feedTitle) {
+ FeedStatisticsDialogFragment fragment = new FeedStatisticsDialogFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feedId);
+ arguments.putString(EXTRA_FEED_TITLE, feedTitle);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.setTitle(getArguments().getString(EXTRA_FEED_TITLE));
+ dialog.setView(R.layout.feed_statistics_dialog);
+ return dialog.create();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ getChildFragmentManager().beginTransaction().replace(R.id.statisticsContainer,
+ FeedStatisticsFragment.newInstance(feedId, true), "feed_statistics_fragment")
+ .commitAllowingStateLoss();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java
new file mode 100644
index 000000000..e85c2a386
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java
@@ -0,0 +1,93 @@
+package de.danoeh.antennapod.fragment;
+
+import android.os.Bundle;
+import android.text.format.Formatter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.StatisticsItem;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.databinding.FeedStatisticsBinding;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.List;
+import java.util.Locale;
+
+public class FeedStatisticsFragment extends Fragment {
+ private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
+ private static final String EXTRA_DETAILED = "de.danoeh.antennapod.extra.detailed";
+
+ private long feedId;
+ private Disposable disposable;
+ private FeedStatisticsBinding viewBinding;
+
+ public static FeedStatisticsFragment newInstance(long feedId, boolean detailed) {
+ FeedStatisticsFragment fragment = new FeedStatisticsFragment();
+ Bundle arguments = new Bundle();
+ arguments.putLong(EXTRA_FEED_ID, feedId);
+ arguments.putBoolean(EXTRA_DETAILED, detailed);
+ fragment.setArguments(arguments);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ feedId = getArguments().getLong(EXTRA_FEED_ID);
+ viewBinding = FeedStatisticsBinding.inflate(inflater);
+
+ if (!getArguments().getBoolean(EXTRA_DETAILED)) {
+ for (int i = 0; i < viewBinding.getRoot().getChildCount(); i++) {
+ View child = viewBinding.getRoot().getChildAt(i);
+ if ("detailed".equals(child.getTag())) {
+ child.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ loadStatistics();
+ return viewBinding.getRoot();
+ }
+
+ private void loadStatistics() {
+ disposable =
+ Observable.fromCallable(() -> {
+ List<StatisticsItem> statisticsData = DBReader.getStatistics();
+ for (StatisticsItem statisticsItem : statisticsData) {
+ if (statisticsItem.feed.getId() == feedId) {
+ return statisticsItem;
+ }
+ }
+ return null;
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::showStats, Throwable::printStackTrace);
+ }
+
+ private void showStats(StatisticsItem s) {
+ viewBinding.startedTotalLabel.setText(String.format(Locale.getDefault(), "%d / %d",
+ s.episodesStarted, s.episodes));
+ viewBinding.timePlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayed));
+ viewBinding.durationPlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayedCountAll));
+ viewBinding.totalDurationLabel.setText(Converter.shortLocalizedDuration(getContext(), s.time));
+ viewBinding.onDeviceLabel.setText(String.format(Locale.getDefault(), "%d", s.episodesDownloadCount));
+ viewBinding.spaceUsedLabel.setText(Formatter.formatShortFileSize(getContext(), s.totalDownloadSize));
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+}
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 31c6da8cd..c261370e2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -14,7 +14,6 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import androidx.core.util.ObjectsCompat;
@@ -42,9 +41,9 @@ import de.danoeh.antennapod.adapter.actionbutton.StreamActionButton;
import de.danoeh.antennapod.adapter.actionbutton.VisitWebsiteActionButton;
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.PlayerStatusEvent;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
@@ -224,17 +223,6 @@ public class ItemFragment extends Fragment {
}
@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);
- }
-
- @Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
@@ -245,6 +233,7 @@ public class ItemFragment extends Fragment {
}
};
controller.init();
+ load();
}
@Override
@@ -398,7 +387,7 @@ public class ItemFragment extends Fragment {
long mediaId = item.getMedia().getId();
if (ArrayUtils.contains(update.mediaIds, mediaId)) {
if (itemsLoaded && getActivity() != null) {
- updateAppearance();
+ updateButtons();
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
index d42300ca7..14f6ae875 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java
@@ -20,7 +20,7 @@ import org.greenrobot.eventbus.ThreadMode;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.event.FeedItemEvent;
+import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
index 826a7e0ab..18defc545 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java
@@ -28,9 +28,9 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.core.event.QueueEvent;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.QueueEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.dialog.TagSettingsDialog;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -50,6 +50,7 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -157,16 +158,16 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS
};
removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
- } else if (itemId == R.id.add_to_folder) {
- TagSettingsDialog.newInstance(feed.getPreferences()).show(getChildFragmentManager(), TagSettingsDialog.TAG);
+ } else if (itemId == R.id.edit_tags) {
+ TagSettingsDialog.newInstance(Collections.singletonList(feed.getPreferences()))
+ .show(getChildFragmentManager(), TagSettingsDialog.TAG);
return true;
} else if (itemId == R.id.rename_item) {
new RenameFeedDialog(getActivity(), feed).show();
return true;
} else if (itemId == R.id.remove_item) {
- RemoveFeedDialog.show(getContext(), feed, () -> {
- ((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null);
- });
+ ((MainActivity) getActivity()).loadFragment(EpisodesFragment.TAG, null);
+ RemoveFeedDialog.show(getContext(), feed);
return true;
}
return super.onContextItemSelected(item);
@@ -318,7 +319,7 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS
((MainActivity) getActivity()).getBottomSheet()
.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
- NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) clickedItem);
+ NavDrawerData.TagDrawerItem folder = ((NavDrawerData.TagDrawerItem) clickedItem);
if (openFolders.contains(folder.name)) {
openFolders.remove(folder.name);
} else {
@@ -388,11 +389,11 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS
for (NavDrawerData.DrawerItem item : items) {
item.setLayer(layer);
flatItems.add(item);
- if (item.type == NavDrawerData.DrawerItem.Type.FOLDER) {
- NavDrawerData.FolderDrawerItem folder = ((NavDrawerData.FolderDrawerItem) item);
+ if (item.type == NavDrawerData.DrawerItem.Type.TAG) {
+ NavDrawerData.TagDrawerItem folder = ((NavDrawerData.TagDrawerItem) item);
folder.isOpen = openFolders.contains(folder.name);
if (folder.isOpen) {
- flatItems.addAll(makeFlatDrawerData(((NavDrawerData.FolderDrawerItem) item).children, layer + 1));
+ flatItems.addAll(makeFlatDrawerData(((NavDrawerData.TagDrawerItem) item).children, layer + 1));
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
index 992b6930c..f3080f655 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java
@@ -1,15 +1,20 @@
package de.danoeh.antennapod.fragment;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+
+import android.widget.AbsListView;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.appcompat.widget.SearchView;
+
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ProgressBar;
@@ -110,6 +115,21 @@ public class OnlineSearchFragment extends Fragment {
TextView txtvPoweredBy = root.findViewById(R.id.search_powered_by);
txtvPoweredBy.setText(getString(R.string.search_powered_by, searchProvider.getName()));
setupToolbar(root.findViewById(R.id.toolbar));
+
+ gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
+ InputMethodManager imm = (InputMethodManager)
+ getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+ }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+ }
+ });
return root;
}
@@ -142,6 +162,11 @@ public class OnlineSearchFragment extends Fragment {
return false;
}
});
+ sv.setOnQueryTextFocusChangeListener((view, hasFocus) -> {
+ if (hasFocus) {
+ showInputMethod(view.findFocus());
+ }
+ });
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
@@ -192,4 +217,11 @@ public class OnlineSearchFragment extends Fragment {
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
+
+ private void showInputMethod(View view) {
+ InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.showSoftInput(view, 0);
+ }
+ }
}
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 5e3d36c03..e1fa5eeb6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -16,11 +16,11 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
-import de.danoeh.antennapod.core.event.FeedItemEvent;
-import de.danoeh.antennapod.core.event.PlaybackHistoryEvent;
-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.event.FeedItemEvent;
+import de.danoeh.antennapod.event.playback.PlaybackHistoryEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
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 1b7d236c6..b308db0f6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -33,11 +33,11 @@ import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
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.QueueEvent;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.QueueEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
@@ -247,8 +247,9 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
() -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
private void refreshToolbarState() {
- toolbar.getMenu().findItem(R.id.queue_lock).setChecked(UserPreferences.isQueueLocked());
boolean keepSorted = UserPreferences.isQueueKeepSorted();
+ toolbar.getMenu().findItem(R.id.queue_lock).setChecked(UserPreferences.isQueueLocked());
+ toolbar.getMenu().findItem(R.id.queue_lock).setVisible(!keepSorted);
toolbar.getMenu().findItem(R.id.queue_sort_random).setVisible(!keepSorted);
toolbar.getMenu().findItem(R.id.queue_keep_sorted).setChecked(keepSorted);
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(),
@@ -635,11 +636,6 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
}
@Override
- public boolean isItemViewSwipeEnabled() {
- return !UserPreferences.isQueueLocked();
- }
-
- @Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
// Check if drag finished
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 14f355b52..8bfcfd1ed 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -25,7 +25,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
-import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
+import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.discovery.PodcastSearchResult;
import io.reactivex.disposables.Disposable;
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 f8326d9c1..e43b6f314 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.fragment;
+
+import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -9,6 +11,7 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -26,10 +29,10 @@ import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.adapter.FeedSearchResultAdapter;
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.event.FeedItemEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.storage.FeedSearcher;
@@ -70,7 +73,6 @@ public class SearchFragment extends Fragment {
private SearchView searchView;
private Handler automaticSearchDebouncer;
private long lastQueryChange = 0;
-
/**
* Create a new SearchFragment that searches all feeds.
*/
@@ -153,6 +155,22 @@ public class SearchFragment extends Fragment {
if (getArguments().getString(ARG_QUERY, null) != null) {
search();
}
+ searchView.setOnQueryTextFocusChangeListener((view, hasFocus) -> {
+ if (hasFocus) {
+ showInputMethod(view.findFocus());
+ }
+ });
+ recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
+ InputMethodManager imm = (InputMethodManager)
+ getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(recyclerView.getWindowToken(), 0);
+ }
+ }
+ });
return layout;
}
@@ -320,4 +338,11 @@ public class SearchFragment extends Fragment {
List<Feed> feeds = FeedSearcher.searchFeeds(getContext(), query);
return new Pair<>(items, feeds);
}
+
+ private void showInputMethod(View view) {
+ InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.showSoftInput(view, 0);
+ }
+ }
}
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 ea6c2ca0d..c4ac25455 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -33,6 +33,7 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
@@ -42,8 +43,8 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsRecyclerAdapter;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
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.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
@@ -250,8 +251,8 @@ public class SubscriptionFragment extends Fragment
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onViewCreated(@NonNull View v, Bundle savedInstanceState) {
+ super.onViewCreated(v, savedInstanceState);
subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity());
subscriptionAdapter.setOnSelectModeListener(this);
subscriptionRecycler.setAdapter(subscriptionAdapter);
@@ -293,9 +294,9 @@ public class SubscriptionFragment extends Fragment
NavDrawerData data = DBReader.getNavDrawerData();
List<NavDrawerData.DrawerItem> items = data.items;
for (NavDrawerData.DrawerItem item : items) {
- if (item.type == NavDrawerData.DrawerItem.Type.FOLDER
+ if (item.type == NavDrawerData.DrawerItem.Type.TAG
&& item.getTitle().equals(displayedFolder)) {
- return ((NavDrawerData.FolderDrawerItem) item).children;
+ return ((NavDrawerData.TagDrawerItem) item).children;
}
}
return items;
@@ -344,14 +345,15 @@ public class SubscriptionFragment extends Fragment
R.string.remove_all_new_flags_confirmation_msg,
() -> DBWriter.removeFeedNewFlag(feed.getId()));
return true;
- } else if (itemId == R.id.add_to_folder) {
- TagSettingsDialog.newInstance(feed.getPreferences()).show(getChildFragmentManager(), TagSettingsDialog.TAG);
+ } else if (itemId == R.id.edit_tags) {
+ TagSettingsDialog.newInstance(Collections.singletonList(feed.getPreferences()))
+ .show(getChildFragmentManager(), TagSettingsDialog.TAG);
return true;
} else if (itemId == R.id.rename_item) {
new RenameFeedDialog(getActivity(), feed).show();
return true;
} else if (itemId == R.id.remove_item) {
- RemoveFeedDialog.show(getContext(), feed, null);
+ RemoveFeedDialog.show(getContext(), feed);
return true;
} else if (itemId == R.id.multi_select) {
speedDialView.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
index f160b2241..e3dfe8ade 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
@@ -3,19 +3,23 @@ package de.danoeh.antennapod.fragment.actions;
import android.util.Log;
import androidx.annotation.PluralsRes;
+import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer;
import com.google.android.material.snackbar.Snackbar;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.databinding.PlaybackSpeedFeedSettingDialogBinding;
import de.danoeh.antennapod.dialog.RemoveFeedDialog;
+import de.danoeh.antennapod.dialog.TagSettingsDialog;
import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceListDialog;
import de.danoeh.antennapod.fragment.preferences.dialog.PreferenceSwitchDialog;
import de.danoeh.antennapod.model.feed.Feed;
@@ -33,7 +37,7 @@ public class FeedMultiSelectActionHandler {
public void handleAction(int id) {
if (id == R.id.remove_item) {
- RemoveFeedDialog.show(activity, selectedItems, null);
+ RemoveFeedDialog.show(activity, selectedItems);
} else if (id == R.id.keep_updated) {
keepUpdatedPrefHandler();
} else if (id == R.id.autodownload) {
@@ -42,6 +46,8 @@ public class FeedMultiSelectActionHandler {
autoDeleteEpisodesPrefHandler();
} else if (id == R.id.playback_speed) {
playbackSpeedPrefHandler();
+ } else if (id == R.id.edit_tags) {
+ editFeedPrefTags();
} else {
Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + id);
}
@@ -64,25 +70,26 @@ public class FeedMultiSelectActionHandler {
new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
private void playbackSpeedPrefHandler() {
- final String[] speeds = activity.getResources().getStringArray(R.array.playback_speed_values);
- String[] values = new String[speeds.length + 1];
- values[0] = SPEED_FORMAT.format(FeedPreferences.SPEED_USE_GLOBAL);
-
- String[] entries = new String[speeds.length + 1];
- entries[0] = activity.getString(R.string.feed_auto_download_global);
-
- System.arraycopy(speeds, 0, values, 1, speeds.length);
- System.arraycopy(speeds, 0, entries, 1, speeds.length);
-
- PreferenceListDialog preferenceListDialog = new PreferenceListDialog(activity,
- activity.getString(R.string.playback_speed));
- preferenceListDialog.openDialog(entries);
- preferenceListDialog.setOnPreferenceChangedListener(pos -> {
- saveFeedPreferences(feedPreferences -> {
- feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) values[pos]));
- });
-
+ PlaybackSpeedFeedSettingDialogBinding viewBinding =
+ PlaybackSpeedFeedSettingDialogBinding.inflate(activity.getLayoutInflater());
+ viewBinding.seekBar.setProgressChangedListener(speed ->
+ viewBinding.currentSpeedLabel.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
+ viewBinding.useGlobalCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ viewBinding.seekBar.setEnabled(!isChecked);
+ viewBinding.seekBar.setAlpha(isChecked ? 0.4f : 1f);
+ viewBinding.currentSpeedLabel.setAlpha(isChecked ? 0.4f : 1f);
});
+ viewBinding.seekBar.updateSpeed(1.0f);
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.playback_speed)
+ .setView(viewBinding.getRoot())
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ float newSpeed = viewBinding.useGlobalCheckbox.isChecked()
+ ? FeedPreferences.SPEED_USE_GLOBAL : viewBinding.seekBar.getCurrentSpeed();
+ saveFeedPreferences(feedPreferences -> feedPreferences.setFeedPlaybackSpeed(newSpeed));
+ })
+ .setNegativeButton(R.string.cancel_label, null)
+ .show();
}
private void autoDeleteEpisodesPrefHandler() {
@@ -136,4 +143,13 @@ public class FeedMultiSelectActionHandler {
}
showMessage(R.plurals.updated_feeds_batch_label, selectedItems.size());
}
+
+ private void editFeedPrefTags() {
+ ArrayList<FeedPreferences> preferencesList = new ArrayList<>();
+ for (Feed feed : selectedItems) {
+ preferencesList.add(feed.getPreferences());
+ }
+ TagSettingsDialog.newInstance(preferencesList).show(activity.getSupportFragmentManager(),
+ TagSettingsDialog.TAG);
+ }
}
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 c813cbf7a..c2c5adc9a 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
@@ -15,7 +15,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.gpodnet.PodcastListAdapter;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
@@ -76,8 +76,8 @@ public abstract class PodcastListFragment extends Fragment {
disposable = Observable.fromCallable(
() -> {
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
- GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
- GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
+ SynchronizationCredentials.getHosturl(), SynchronizationCredentials.getDeviceID(),
+ SynchronizationCredentials.getUsername(), SynchronizationCredentials.getPassword());
return loadPodcastData(service);
})
.subscribeOn(Schedulers.io())
@@ -101,7 +101,7 @@ public abstract class PodcastListFragment extends Fragment {
}, error -> {
gridView.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
- txtvError.setText(getString(R.string.error_msg_prefix) + error.getMessage());
+ txtvError.setText(error.getMessage());
txtvError.setVisibility(View.VISIBLE);
butRetry.setVisibility(View.VISIBLE);
Log.e(TAG, Log.getStackTraceString(error));
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 f961e30bb..abdfab941 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
@@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.gpodnet.TagListAdapter;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
@@ -51,8 +51,8 @@ public class TagListFragment extends ListFragment {
disposable = Observable.fromCallable(
() -> {
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
- GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
- GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
+ SynchronizationCredentials.getHosturl(), SynchronizationCredentials.getDeviceID(),
+ SynchronizationCredentials.getUsername(), SynchronizationCredentials.getPassword());
return service.getTopTags(COUNT);
})
.subscribeOn(Schedulers.io())
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
deleted file mode 100644
index 4fb734e17..000000000
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package de.danoeh.antennapod.fragment.preferences;
-
-import android.app.Activity;
-import android.os.Bundle;
-import androidx.core.text.HtmlCompat;
-import androidx.preference.PreferenceFragmentCompat;
-
-import android.text.Spanned;
-import android.text.format.DateUtils;
-import com.google.android.material.snackbar.Snackbar;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.event.SyncServiceEvent;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.sync.SyncService;
-import de.danoeh.antennapod.dialog.AuthenticationDialog;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
- private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
- private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
- private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
- private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync";
- private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- addPreferencesFromResource(R.xml.preferences_gpodder);
- setupGpodderScreen();
- }
-
- @Override
- public void onStart() {
- super.onStart();
- ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.gpodnet_main_label);
- updateGpodnetPreferenceScreen();
- EventBus.getDefault().register(this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- EventBus.getDefault().unregister(this);
- ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle("");
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
- public void syncStatusChanged(SyncServiceEvent event) {
- updateGpodnetPreferenceScreen();
- if (!GpodnetPreferences.loggedIn()) {
- return;
- }
- if (event.getMessageResId() == R.string.sync_status_error
- || event.getMessageResId() == R.string.sync_status_success) {
- updateLastGpodnetSyncReport(SyncService.isLastSyncSuccessful(getContext()),
- SyncService.getLastSyncAttempt(getContext()));
- } else {
- ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle(event.getMessageResId());
- }
- }
-
- private void setupGpodderScreen() {
- final Activity activity = getActivity();
-
- findPreference(PREF_GPODNET_LOGIN).setOnPreferenceClickListener(preference -> {
- new GpodderAuthenticationFragment().show(getChildFragmentManager(), GpodderAuthenticationFragment.TAG);
- return true;
- });
- findPreference(PREF_GPODNET_SETLOGIN_INFORMATION)
- .setOnPreferenceClickListener(preference -> {
- AuthenticationDialog dialog = new AuthenticationDialog(activity,
- R.string.pref_gpodnet_setlogin_information_title, false, GpodnetPreferences.getUsername(),
- null) {
-
- @Override
- protected void onConfirmed(String username, String password) {
- GpodnetPreferences.setPassword(password);
- }
- };
- dialog.show();
- return true;
- });
- findPreference(PREF_GPODNET_SYNC).setOnPreferenceClickListener(preference -> {
- SyncService.syncImmediately(getActivity().getApplicationContext());
- return true;
- });
- findPreference(PREF_GPODNET_FORCE_FULL_SYNC).setOnPreferenceClickListener(preference -> {
- SyncService.fullSync(getContext());
- return true;
- });
- findPreference(PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(preference -> {
- GpodnetPreferences.logout();
- Snackbar.make(getView(), R.string.pref_gpodnet_logout_toast, Snackbar.LENGTH_LONG).show();
- updateGpodnetPreferenceScreen();
- return true;
- });
- }
-
- private void updateGpodnetPreferenceScreen() {
- final boolean loggedIn = GpodnetPreferences.loggedIn();
- findPreference(PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
- findPreference(PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
- findPreference(PREF_GPODNET_SYNC).setEnabled(loggedIn);
- findPreference(PREF_GPODNET_FORCE_FULL_SYNC).setEnabled(loggedIn);
- findPreference(PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
- if (loggedIn) {
- String format = getActivity().getString(R.string.pref_gpodnet_login_status);
- String summary = String.format(format, GpodnetPreferences.getUsername(),
- GpodnetPreferences.getDeviceID());
- Spanned formattedSummary = HtmlCompat.fromHtml(summary, HtmlCompat.FROM_HTML_MODE_LEGACY);
- findPreference(PREF_GPODNET_LOGOUT).setSummary(formattedSummary);
- updateLastGpodnetSyncReport(SyncService.isLastSyncSuccessful(getContext()),
- SyncService.getLastSyncAttempt(getContext()));
- } else {
- findPreference(PREF_GPODNET_LOGOUT).setSummary(null);
- }
- }
-
- private void updateLastGpodnetSyncReport(boolean successful, long lastTime) {
- String status = String.format("%1$s (%2$s)", getString(successful
- ? R.string.gpodnetsync_pref_report_successful : R.string.gpodnetsync_pref_report_failed),
- DateUtils.getRelativeDateTimeString(getContext(),
- lastTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME));
- ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle(status);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
index f6aa45e93..b72d1eb32 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -12,6 +12,13 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
+
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.activity.result.contract.ActivityResultContracts.GetContent;
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import androidx.preference.PreferenceFragmentCompat;
@@ -54,13 +61,19 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds-%s.html";
private static final String CONTENT_TYPE_HTML = "text/html";
private static final String DEFAULT_FAVORITES_OUTPUT_NAME = "antennapod-favorites-%s.html";
- private static final int REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH = 1;
- private static final int REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH = 2;
- private static final int REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH = 3;
- private static final int REQUEST_CODE_RESTORE_DATABASE = 4;
- private static final int REQUEST_CODE_BACKUP_DATABASE = 5;
- private static final int REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH = 6;
private static final String DATABASE_EXPORT_FILENAME = "AntennaPodBackup-%s.db";
+ private final ActivityResultLauncher<Intent> chooseOpmlExportPathLauncher =
+ registerForActivityResult(new StartActivityForResult(), this::chooseOpmlExportPathResult);
+ private final ActivityResultLauncher<Intent> chooseHtmlExportPathLauncher =
+ registerForActivityResult(new StartActivityForResult(), this::chooseHtmlExportPathResult);
+ private final ActivityResultLauncher<Intent> chooseFavoritesExportPathLauncher =
+ registerForActivityResult(new StartActivityForResult(), this::chooseFavoritesExportPathResult);
+ private final ActivityResultLauncher<Intent> restoreDatabaseLauncher =
+ registerForActivityResult(new StartActivityForResult(), this::restoreDatabaseResult);
+ private final ActivityResultLauncher<String> backupDatabaseLauncher =
+ registerForActivityResult(new BackupDatabase(), this::backupDatabaseResult);
+ private final ActivityResultLauncher<String> chooseOpmlImportPathLauncher =
+ registerForActivityResult(new GetContent(), this::chooseOpmlImportPathResult);
private Disposable disposable;
private ProgressDialog progressDialog;
@@ -95,23 +108,20 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
preference -> {
openExportPathPicker(CONTENT_TYPE_OPML, dateStampFilename(DEFAULT_OPML_OUTPUT_NAME),
- REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH, new OpmlWriter());
+ chooseOpmlExportPathLauncher, new OpmlWriter());
return true;
}
);
findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
preference -> {
openExportPathPicker(CONTENT_TYPE_HTML, dateStampFilename(DEFAULT_HTML_OUTPUT_NAME),
- REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH, new HtmlWriter());
+ chooseHtmlExportPathLauncher, new HtmlWriter());
return true;
});
findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
preference -> {
try {
- Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
- intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
- intentGetContentAction.setType("*/*");
- startActivityForResult(intentGetContentAction, REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH);
+ chooseOpmlImportPathLauncher.launch("*/*");
} catch (ActivityNotFoundException e) {
Log.e(TAG, "No activity found. Should never happen...");
}
@@ -130,7 +140,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
findPreference(PREF_FAVORITE_EXPORT).setOnPreferenceClickListener(
preference -> {
openExportPathPicker(CONTENT_TYPE_HTML, dateStampFilename(DEFAULT_FAVORITES_OUTPUT_NAME),
- REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH, new FavoritesWriter());
+ chooseFavoritesExportPathLauncher, new FavoritesWriter());
return true;
});
}
@@ -160,12 +170,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private void exportDatabase() {
if (Build.VERSION.SDK_INT >= 19) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
- .addCategory(Intent.CATEGORY_OPENABLE)
- .setType("application/x-sqlite3")
- .putExtra(Intent.EXTRA_TITLE, dateStampFilename(DATABASE_EXPORT_FILENAME));
-
- startActivityForResult(intent, REQUEST_CODE_BACKUP_DATABASE);
+ backupDatabaseLauncher.launch(dateStampFilename(DATABASE_EXPORT_FILENAME));
} else {
File sd = Environment.getExternalStorageDirectory();
File backupDB = new File(sd, dateStampFilename(DATABASE_EXPORT_FILENAME));
@@ -190,18 +195,10 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
// add a button
builder.setNegativeButton(R.string.no, null);
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- if (Build.VERSION.SDK_INT >= 19) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.setType("*/*");
- startActivityForResult(intent, REQUEST_CODE_RESTORE_DATABASE);
- } else {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType("*/*");
- startActivityForResult(Intent.createChooser(intent,
- getString(R.string.import_select_file)), REQUEST_CODE_RESTORE_DATABASE);
- }
- }
- );
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.setType("*/*");
+ restoreDatabaseLauncher.launch(intent);
+ });
// create and show the alert dialog
builder.show();
@@ -227,15 +224,14 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
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);
- }
+ Intent chooserIntent = Intent.createChooser(sendIntent, getString(R.string.send_label));
+ 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)));
+ getContext().startActivity(chooserIntent);
});
alert.create().show();
}
@@ -249,64 +245,97 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
alert.show();
}
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode != Activity.RESULT_OK || data == null) {
+ private void chooseOpmlExportPathResult(final ActivityResult result) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
return;
}
- Uri uri = data.getData();
+ final Uri uri = result.getData().getData();
+ exportWithWriter(new OpmlWriter(), uri);
+ }
- if (requestCode == REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH) {
- exportWithWriter(new OpmlWriter(), uri);
- } else if (requestCode == REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH) {
- exportWithWriter(new HtmlWriter(), uri);
- } else if (requestCode == REQUEST_CODE_CHOOSE_FAVORITES_EXPORT_PATH) {
- exportWithWriter(new FavoritesWriter(), uri);
- } else if (requestCode == REQUEST_CODE_RESTORE_DATABASE) {
- progressDialog.show();
- disposable = Completable.fromAction(() -> DatabaseExporter.importBackup(uri, getContext()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(() -> {
- showDatabaseImportSuccessDialog();
- UserPreferences.unsetUsageCountingDate();
- progressDialog.dismiss();
- }, this::showExportErrorDialog);
- } else if (requestCode == REQUEST_CODE_BACKUP_DATABASE) {
- progressDialog.show();
- disposable = Completable.fromAction(() -> DatabaseExporter.exportToDocument(uri, getContext()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(() -> {
- Snackbar.make(getView(), R.string.export_success_title, Snackbar.LENGTH_LONG).show();
- progressDialog.dismiss();
- }, this::showExportErrorDialog);
- } else if (requestCode == REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH) {
- Intent intent = new Intent(getContext(), OpmlImportActivity.class);
- intent.setData(uri);
- startActivity(intent);
+ private void chooseHtmlExportPathResult(final ActivityResult result) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
}
+ final Uri uri = result.getData().getData();
+ exportWithWriter(new HtmlWriter(), uri);
}
- private void openExportPathPicker(String contentType, String title, int requestCode, ExportWriter writer) {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
- Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
- .addCategory(Intent.CATEGORY_OPENABLE)
- .setType(contentType)
- .putExtra(Intent.EXTRA_TITLE, title);
+ private void chooseFavoritesExportPathResult(final ActivityResult result) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
+ }
+ final Uri uri = result.getData().getData();
+ exportWithWriter(new FavoritesWriter(), uri);
+ }
- // Creates an implicit intent to launch a file manager which lets
- // the user choose a specific directory to export to.
- try {
- startActivityForResult(intentPickAction, requestCode);
- return;
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "No activity found. Should never happen...");
- }
+ private void restoreDatabaseResult(final ActivityResult result) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
+ }
+ final Uri uri = result.getData().getData();
+ progressDialog.show();
+ disposable = Completable.fromAction(() -> DatabaseExporter.importBackup(uri, getContext()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ showDatabaseImportSuccessDialog();
+ UserPreferences.unsetUsageCountingDate();
+ progressDialog.dismiss();
+ }, this::showExportErrorDialog);
+ }
+
+ private void backupDatabaseResult(final Uri uri) {
+ if (uri == null) {
+ return;
+ }
+ progressDialog.show();
+ disposable = Completable.fromAction(() -> DatabaseExporter.exportToDocument(uri, getContext()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ Snackbar.make(getView(), R.string.export_success_title, Snackbar.LENGTH_LONG).show();
+ progressDialog.dismiss();
+ }, this::showExportErrorDialog);
+ }
+
+ private void chooseOpmlImportPathResult(final Uri uri) {
+ if (uri == null) {
+ return;
+ }
+ final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+
+ private void openExportPathPicker(String contentType, String title,
+ final ActivityResultLauncher<Intent> result, ExportWriter writer) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(contentType)
+ .putExtra(Intent.EXTRA_TITLE, title);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ result.launch(intentPickAction);
+ 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
exportWithWriter(writer, null);
}
+
+ private static class BackupDatabase extends ActivityResultContracts.CreateDocument {
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull final Context context, @NonNull final String input) {
+ return super.createIntent(context, input)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType("application/x-sqlite3");
+ }
+ }
}
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 cc09acbca..891d3737b 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,6 +1,8 @@
package de.danoeh.antennapod.fragment.preferences;
import android.content.Intent;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
@@ -17,12 +19,11 @@ import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.fragment.preferences.about.AboutFragment;
public class MainPreferencesFragment extends PreferenceFragmentCompat {
- private static final String TAG = "MainPreferencesFragment";
private static final String PREF_SCREEN_USER_INTERFACE = "prefScreenInterface";
private static final String PREF_SCREEN_PLAYBACK = "prefScreenPlayback";
private static final String PREF_SCREEN_NETWORK = "prefScreenNetwork";
- private static final String PREF_SCREEN_GPODDER = "prefScreenGpodder";
+ private static final String PREF_SCREEN_SYNCHRONIZATION = "prefScreenSynchronization";
private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
private static final String PREF_DOCUMENTATION = "prefDocumentation";
private static final String PREF_VIEW_FORUM = "prefViewForum";
@@ -43,15 +44,26 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
// and afterwards remove the following lines. Please keep in mind that AntennaPod is licensed under the GPL.
// This means that your application needs to be open-source under the GPL, too.
// It must also include a prominent copyright notice.
- String packageName = getContext().getPackageName();
- if (!"de.danoeh.antennapod".equals(packageName) && !"de.danoeh.antennapod.debug".equals(packageName)) {
+ int packageHash = getContext().getPackageName().hashCode();
+ if (packageHash != 1790437538 && packageHash != -1190467065) {
findPreference(PREF_CATEGORY_PROJECT).setVisible(false);
Preference copyrightNotice = new Preference(getContext());
+ copyrightNotice.setIcon(R.drawable.ic_info_white);
+ copyrightNotice.getIcon().mutate()
+ .setColorFilter(new PorterDuffColorFilter(0xffcc0000, PorterDuff.Mode.MULTIPLY));
copyrightNotice.setSummary("This application is based on AntennaPod."
+ " The AntennaPod team does NOT provide support for this unofficial version."
+ " If you can read this message, the developers of this modification"
+ " violate the GNU General Public License (GPL).");
findPreference(PREF_CATEGORY_PROJECT).getParent().addPreference(copyrightNotice);
+ } else if (packageHash == -1190467065) {
+ Preference debugNotice = new Preference(getContext());
+ debugNotice.setIcon(R.drawable.ic_info_white);
+ debugNotice.getIcon().mutate()
+ .setColorFilter(new PorterDuffColorFilter(0xffcc0000, PorterDuff.Mode.MULTIPLY));
+ debugNotice.setOrder(-1);
+ debugNotice.setSummary("This is a development version of AntennaPod and not meant for daily use");
+ findPreference(PREF_CATEGORY_PROJECT).getParent().addPreference(debugNotice);
}
}
@@ -74,8 +86,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_network);
return true;
});
- findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
- ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder);
+ findPreference(PREF_SCREEN_SYNCHRONIZATION).setOnPreferenceClickListener(preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_synchronization);
return true;
});
findPreference(PREF_SCREEN_STORAGE).setOnPreferenceClickListener(preference -> {
@@ -142,8 +154,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_network))
.addBreadcrumb(R.string.automation)
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_autodownload));
- config.index(R.xml.preferences_gpodder)
- .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_gpodder));
+ config.index(R.xml.preferences_synchronization)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_synchronization));
config.index(R.xml.preferences_notifications)
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_notifications));
config.index(R.xml.feed_settings)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NotificationPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NotificationPreferencesFragment.java
index 94e151f7a..ba17cedb2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NotificationPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NotificationPreferencesFragment.java
@@ -4,11 +4,10 @@ import android.os.Bundle;
import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.sync.SynchronizationSettings;
public class NotificationPreferencesFragment extends PreferenceFragmentCompat {
- private static final String TAG = "NotificationPrefFragment";
private static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications";
@Override
@@ -24,7 +23,6 @@ public class NotificationPreferencesFragment extends PreferenceFragmentCompat {
}
private void setUpScreen() {
- final boolean loggedIn = GpodnetPreferences.loggedIn();
- findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(loggedIn);
+ findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(SynchronizationSettings.isProviderConnected());
}
}
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 1fa1fed58..7fa2ed4d1 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
@@ -10,13 +10,12 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.preferences.UsageStatistics;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import de.danoeh.antennapod.preferences.PreferenceControllerFlavorHelper;
import java.util.Map;
import org.greenrobot.eventbus.EventBus;
@@ -31,7 +30,6 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
addPreferencesFromResource(R.xml.preferences_playback);
setupPlaybackScreen();
- PreferenceControllerFlavorHelper.setupFlavoredUI(this);
buildSmartMarkAsPlayedPreference();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java
index 208ede8cc..04324f709 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java
@@ -68,7 +68,7 @@ public class PlaybackStatisticsFragment extends Fragment {
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 PlaybackStatisticsListAdapter(getContext());
+ listAdapter = new PlaybackStatisticsListAdapter(this);
listAdapter.setCountAll(countAll);
feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
feedStatisticsList.setAdapter(listAdapter);
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 04b9677e2..ff974179e 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
@@ -10,8 +10,8 @@ import androidx.preference.PreferenceFragmentCompat;
import android.widget.ListView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.event.PlayerStatusEvent;
-import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
+import de.danoeh.antennapod.event.PlayerStatusEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
import de.danoeh.antennapod.dialog.FeedSortDialog;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java
index c0bf3e0ea..9dfe6840c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.fragment.preferences;
+package de.danoeh.antennapod.fragment.preferences.synchronization;
import android.app.Dialog;
import android.content.Context;
@@ -15,30 +15,35 @@ import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.ViewFlipper;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
+
import com.google.android.material.button.MaterialButton;
import com.google.android.material.textfield.TextInputLayout;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.sync.SyncService;
-import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
-import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice;
+import de.danoeh.antennapod.core.sync.SynchronizationProviderViewData;
+import de.danoeh.antennapod.core.sync.SynchronizationSettings;
import de.danoeh.antennapod.core.util.FileNameGenerator;
import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
+import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
-import java.util.List;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
/**
* Guides the user through the authentication process.
*/
@@ -83,23 +88,24 @@ public class GpodderAuthenticationFragment extends DialogFragment {
final RadioGroup serverRadioGroup = view.findViewById(R.id.serverRadioGroup);
final EditText serverUrlText = view.findViewById(R.id.serverUrlText);
- if (!GpodnetService.DEFAULT_BASE_HOST.equals(GpodnetPreferences.getHosturl())) {
- serverUrlText.setText(GpodnetPreferences.getHosturl());
+ if (!GpodnetService.DEFAULT_BASE_HOST.equals(SynchronizationCredentials.getHosturl())) {
+ serverUrlText.setText(SynchronizationCredentials.getHosturl());
}
final TextInputLayout serverUrlTextInput = view.findViewById(R.id.serverUrlTextInput);
serverRadioGroup.setOnCheckedChangeListener((group, checkedId) -> {
serverUrlTextInput.setVisibility(checkedId == R.id.customServerRadio ? View.VISIBLE : View.GONE);
});
selectHost.setOnClickListener(v -> {
+ SynchronizationCredentials.clear(getContext());
if (serverRadioGroup.getCheckedRadioButtonId() == R.id.customServerRadio) {
- GpodnetPreferences.setHosturl(serverUrlText.getText().toString());
+ SynchronizationCredentials.setHosturl(serverUrlText.getText().toString());
} else {
- GpodnetPreferences.setHosturl(GpodnetService.DEFAULT_BASE_HOST);
+ SynchronizationCredentials.setHosturl(GpodnetService.DEFAULT_BASE_HOST);
}
service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
- GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
- GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
- getDialog().setTitle(GpodnetPreferences.getHosturl());
+ SynchronizationCredentials.getHosturl(), SynchronizationCredentials.getDeviceID(),
+ SynchronizationCredentials.getUsername(), SynchronizationCredentials.getPassword());
+ getDialog().setTitle(SynchronizationCredentials.getHosturl());
advance();
});
}
@@ -116,7 +122,7 @@ public class GpodderAuthenticationFragment extends DialogFragment {
createAccount.setPaintFlags(createAccount.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
createAccount.setOnClickListener(v -> IntentUtils.openInBrowser(getContext(), "https://gpodder.net/register/"));
- if (GpodnetPreferences.getHosturl().startsWith("http://")) {
+ if (SynchronizationCredentials.getHosturl().startsWith("http://")) {
createAccountWarning.setVisibility(View.VISIBLE);
}
password.setOnEditorActionListener((v, actionID, event) ->
@@ -265,15 +271,8 @@ public class GpodderAuthenticationFragment extends DialogFragment {
});
}
- private void writeLoginCredentials() {
- GpodnetPreferences.setUsername(username);
- GpodnetPreferences.setPassword(password);
- GpodnetPreferences.setDeviceID(selectedDevice.getId());
- }
-
private void advance() {
if (currentStep < STEP_FINISH) {
-
View view = viewFlipper.getChildAt(currentStep + 1);
if (currentStep == STEP_DEFAULT) {
setupHostView(view);
@@ -289,7 +288,10 @@ public class GpodderAuthenticationFragment extends DialogFragment {
if (selectedDevice == null) {
throw new IllegalStateException("Device must not be null here");
} else {
- writeLoginCredentials();
+ SynchronizationSettings.setSelectedSyncProvider(SynchronizationProviderViewData.GPODDER_NET);
+ SynchronizationCredentials.setUsername(username);
+ SynchronizationCredentials.setPassword(password);
+ SynchronizationCredentials.setDeviceID(selectedDevice.getId());
setupFinishView(view);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/NextcloudAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/NextcloudAuthenticationFragment.java
new file mode 100644
index 000000000..2e9260c1d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/NextcloudAuthenticationFragment.java
@@ -0,0 +1,92 @@
+package de.danoeh.antennapod.fragment.preferences.synchronization;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.core.sync.SyncService;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
+import de.danoeh.antennapod.core.sync.SynchronizationProviderViewData;
+import de.danoeh.antennapod.core.sync.SynchronizationSettings;
+import de.danoeh.antennapod.databinding.NextcloudAuthDialogBinding;
+import de.danoeh.antennapod.net.sync.nextcloud.NextcloudLoginFlow;
+
+/**
+ * Guides the user through the authentication process.
+ */
+public class NextcloudAuthenticationFragment extends DialogFragment
+ implements NextcloudLoginFlow.AuthenticationCallback {
+ public static final String TAG = "NextcloudAuthenticationFragment";
+ private NextcloudAuthDialogBinding viewBinding;
+ private NextcloudLoginFlow nextcloudLoginFlow;
+ private boolean shouldDismiss = false;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
+ dialog.setTitle(R.string.gpodnetauth_login_butLabel);
+ dialog.setNegativeButton(R.string.cancel_label, null);
+ dialog.setCancelable(false);
+ this.setCancelable(false);
+
+ viewBinding = NextcloudAuthDialogBinding.inflate(getLayoutInflater());
+ dialog.setView(viewBinding.getRoot());
+
+ viewBinding.loginButton.setOnClickListener(v -> {
+ viewBinding.errorText.setVisibility(View.GONE);
+ viewBinding.loginButton.setVisibility(View.GONE);
+ viewBinding.loginProgressContainer.setVisibility(View.VISIBLE);
+ nextcloudLoginFlow = new NextcloudLoginFlow(AntennapodHttpClient.getHttpClient(),
+ viewBinding.serverUrlText.getText().toString(), getContext(), this);
+ nextcloudLoginFlow.start();
+ });
+
+ return dialog.create();
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (nextcloudLoginFlow != null) {
+ nextcloudLoginFlow.cancel();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (shouldDismiss) {
+ dismiss();
+ }
+ }
+
+ @Override
+ public void onNextcloudAuthenticated(String server, String username, String password) {
+ SynchronizationSettings.setSelectedSyncProvider(SynchronizationProviderViewData.NEXTCLOUD_GPODDER);
+ SynchronizationCredentials.clear(getContext());
+ SynchronizationCredentials.setPassword(password);
+ SynchronizationCredentials.setHosturl(server);
+ SynchronizationCredentials.setUsername(username);
+ SyncService.fullSync(getContext());
+ if (isVisible()) {
+ dismiss();
+ } else {
+ shouldDismiss = true;
+ }
+ }
+
+ @Override
+ public void onNextcloudAuthError(String errorMessage) {
+ viewBinding.loginProgressContainer.setVisibility(View.GONE);
+ viewBinding.errorText.setVisibility(View.VISIBLE);
+ viewBinding.errorText.setText(errorMessage);
+ viewBinding.loginButton.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/SynchronizationPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/SynchronizationPreferencesFragment.java
new file mode 100644
index 000000000..8cb7f45db
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/SynchronizationPreferencesFragment.java
@@ -0,0 +1,222 @@
+package de.danoeh.antennapod.fragment.preferences.synchronization;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.text.Spanned;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.text.HtmlCompat;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.google.android.material.snackbar.Snackbar;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.event.SyncServiceEvent;
+import de.danoeh.antennapod.core.sync.SynchronizationCredentials;
+import de.danoeh.antennapod.core.sync.SyncService;
+import de.danoeh.antennapod.core.sync.SynchronizationProviderViewData;
+import de.danoeh.antennapod.core.sync.SynchronizationSettings;
+import de.danoeh.antennapod.dialog.AuthenticationDialog;
+
+public class SynchronizationPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String PREFERENCE_SYNCHRONIZATION_DESCRIPTION = "preference_synchronization_description";
+ private static final String PREFERENCE_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
+ private static final String PREFERENCE_SYNC = "pref_synchronization_sync";
+ private static final String PREFERENCE_FORCE_FULL_SYNC = "pref_synchronization_force_full_sync";
+ private static final String PREFERENCE_LOGOUT = "pref_synchronization_logout";
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_synchronization);
+ setupScreen();
+ updateScreen();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.synchronization_pref);
+ updateScreen();
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventBus.getDefault().unregister(this);
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle("");
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
+ public void syncStatusChanged(SyncServiceEvent event) {
+ if (!SynchronizationSettings.isProviderConnected()) {
+ return;
+ }
+ updateScreen();
+ if (event.getMessageResId() == R.string.sync_status_error
+ || event.getMessageResId() == R.string.sync_status_success) {
+ updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful(),
+ SynchronizationSettings.getLastSyncAttempt());
+ } else {
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle(event.getMessageResId());
+ }
+ }
+
+ private void setupScreen() {
+ final Activity activity = getActivity();
+ findPreference(PREFERENCE_GPODNET_SETLOGIN_INFORMATION)
+ .setOnPreferenceClickListener(preference -> {
+ AuthenticationDialog dialog = new AuthenticationDialog(activity,
+ R.string.pref_gpodnet_setlogin_information_title,
+ false, SynchronizationCredentials.getUsername(), null) {
+ @Override
+ protected void onConfirmed(String username, String password) {
+ SynchronizationCredentials.setPassword(password);
+ }
+ };
+ dialog.show();
+ return true;
+ });
+ findPreference(PREFERENCE_SYNC).setOnPreferenceClickListener(preference -> {
+ SyncService.syncImmediately(getActivity().getApplicationContext());
+ return true;
+ });
+ findPreference(PREFERENCE_FORCE_FULL_SYNC).setOnPreferenceClickListener(preference -> {
+ SyncService.fullSync(getContext());
+ return true;
+ });
+ findPreference(PREFERENCE_LOGOUT).setOnPreferenceClickListener(preference -> {
+ SynchronizationCredentials.clear(getContext());
+ Snackbar.make(getView(), R.string.pref_synchronization_logout_toast, Snackbar.LENGTH_LONG).show();
+ SynchronizationSettings.setSelectedSyncProvider(null);
+ updateScreen();
+ return true;
+ });
+ }
+
+ private void updateScreen() {
+ final boolean loggedIn = SynchronizationSettings.isProviderConnected();
+ Preference preferenceHeader = findPreference(PREFERENCE_SYNCHRONIZATION_DESCRIPTION);
+ if (loggedIn) {
+ SynchronizationProviderViewData selectedProvider =
+ SynchronizationProviderViewData.fromIdentifier(getSelectedSyncProviderKey());
+ preferenceHeader.setTitle("");
+ preferenceHeader.setSummary(selectedProvider.getSummaryResource());
+ preferenceHeader.setIcon(selectedProvider.getIconResource());
+ preferenceHeader.setOnPreferenceClickListener(null);
+ } else {
+ preferenceHeader.setTitle(R.string.synchronization_choose_title);
+ preferenceHeader.setSummary(R.string.synchronization_summary_unchoosen);
+ preferenceHeader.setIcon(R.drawable.ic_cloud);
+ preferenceHeader.setOnPreferenceClickListener((preference) -> {
+ chooseProviderAndLogin();
+ return true;
+ });
+ }
+
+ Preference gpodnetSetLoginPreference = findPreference(PREFERENCE_GPODNET_SETLOGIN_INFORMATION);
+ gpodnetSetLoginPreference.setVisible(isProviderSelected(SynchronizationProviderViewData.GPODDER_NET));
+ gpodnetSetLoginPreference.setEnabled(loggedIn);
+ findPreference(PREFERENCE_SYNC).setEnabled(loggedIn);
+ findPreference(PREFERENCE_FORCE_FULL_SYNC).setEnabled(loggedIn);
+ findPreference(PREFERENCE_LOGOUT).setEnabled(loggedIn);
+ if (loggedIn) {
+ String summary = getString(R.string.synchronization_login_status,
+ SynchronizationCredentials.getUsername(), SynchronizationCredentials.getHosturl());
+ Spanned formattedSummary = HtmlCompat.fromHtml(summary, HtmlCompat.FROM_HTML_MODE_LEGACY);
+ findPreference(PREFERENCE_LOGOUT).setSummary(formattedSummary);
+ updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful(),
+ SynchronizationSettings.getLastSyncAttempt());
+ } else {
+ findPreference(PREFERENCE_LOGOUT).setSummary(null);
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle(null);
+ }
+ }
+
+ private void chooseProviderAndLogin() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.dialog_choose_sync_service_title);
+
+ SynchronizationProviderViewData[] providers = SynchronizationProviderViewData.values();
+ ListAdapter adapter = new ArrayAdapter<SynchronizationProviderViewData>(
+ getContext(), R.layout.alertdialog_sync_provider_chooser, providers) {
+
+ ViewHolder holder;
+
+ class ViewHolder {
+ ImageView icon;
+ TextView title;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ if (convertView == null) {
+ convertView = inflater.inflate(
+ R.layout.alertdialog_sync_provider_chooser, null);
+
+ holder = new ViewHolder();
+ holder.icon = (ImageView) convertView.findViewById(R.id.icon);
+ holder.title = (TextView) convertView.findViewById(R.id.title);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+ SynchronizationProviderViewData synchronizationProviderViewData = getItem(position);
+ holder.title.setText(synchronizationProviderViewData.getSummaryResource());
+ holder.icon.setImageResource(synchronizationProviderViewData.getIconResource());
+ return convertView;
+ }
+ };
+
+ builder.setAdapter(adapter, (dialog, which) -> {
+ switch (providers[which]) {
+ case GPODDER_NET:
+ new GpodderAuthenticationFragment()
+ .show(getChildFragmentManager(), GpodderAuthenticationFragment.TAG);
+ break;
+ case NEXTCLOUD_GPODDER:
+ new NextcloudAuthenticationFragment()
+ .show(getChildFragmentManager(), NextcloudAuthenticationFragment.TAG);
+ break;
+ default:
+ break;
+ }
+ updateScreen();
+ });
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private boolean isProviderSelected(@NonNull SynchronizationProviderViewData provider) {
+ String selectedSyncProviderKey = getSelectedSyncProviderKey();
+ return provider.getIdentifier().equals(selectedSyncProviderKey);
+ }
+
+ private String getSelectedSyncProviderKey() {
+ return SynchronizationSettings.getSelectedSyncProviderKey();
+ }
+
+ private void updateLastSyncReport(boolean successful, long lastTime) {
+ String status = String.format("%1$s (%2$s)", getString(successful
+ ? R.string.gpodnetsync_pref_report_successful : R.string.gpodnetsync_pref_report_failed),
+ DateUtils.getRelativeDateTimeString(getContext(),
+ lastTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME));
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setSubtitle(status);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java b/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
index 50c7c1ae5..adf133856 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/swipeactions/SwipeActions.java
@@ -201,12 +201,12 @@ public class SwipeActions extends ItemTouchHelper.SimpleCallback implements Life
@Override
public float getSwipeEscapeVelocity(float defaultValue) {
- return swipeOutEnabled ? defaultValue : Float.MAX_VALUE;
+ return swipeOutEnabled ? defaultValue * 1.5f : Float.MAX_VALUE;
}
@Override
public float getSwipeVelocityThreshold(float defaultValue) {
- return swipeOutEnabled ? defaultValue : 0;
+ return swipeOutEnabled ? defaultValue * 0.6f : 0;
}
@Override
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 c272af7d5..23fdb86de 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -13,12 +13,12 @@ import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.sync.SyncService;
+import de.danoeh.antennapod.core.sync.SynchronizationSettings;
+import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
@@ -151,7 +151,7 @@ public class FeedItemMenuHandler {
} else if (menuItemId == R.id.mark_read_item) {
selectedItem.setPlayed(true);
DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, true);
- if (GpodnetPreferences.loggedIn()) {
+ if (SynchronizationSettings.isProviderConnected()) {
FeedMedia media = selectedItem.getMedia();
// not all items have media, Gpodder only cares about those that do
if (media != null) {
@@ -161,17 +161,17 @@ public class FeedItemMenuHandler {
.position(media.getDuration() / 1000)
.total(media.getDuration() / 1000)
.build();
- SyncService.enqueueEpisodeAction(context, actionPlay);
+ SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, actionPlay);
}
}
} else if (menuItemId == R.id.mark_unread_item) {
selectedItem.setPlayed(false);
DBWriter.markItemPlayed(selectedItem, FeedItem.UNPLAYED, false);
- if (GpodnetPreferences.loggedIn() && selectedItem.getMedia() != null) {
+ if (selectedItem.getMedia() != null) {
EpisodeAction actionNew = new EpisodeAction.Builder(selectedItem, EpisodeAction.NEW)
.currentTimestamp()
.build();
- SyncService.enqueueEpisodeAction(context, actionNew);
+ SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, actionNew);
}
} else if (menuItemId == R.id.add_to_queue_item) {
DBWriter.addQueueItem(context, selectedItem);
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 84c738632..af35bbac9 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -108,9 +108,12 @@ public class PreferenceUpgrader {
}
}
if (oldVersion < 2040000) {
- SharedPreferences prefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE);
- prefs.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + QueueFragment.TAG,
+ SharedPreferences swipePrefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE);
+ swipePrefs.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + QueueFragment.TAG,
SwipeAction.REMOVE_FROM_QUEUE + "," + SwipeAction.REMOVE_FROM_QUEUE).apply();
}
+ if (oldVersion < 2050000) {
+ prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true).apply();
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
index 1075117dd..2ea15005a 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
@@ -22,7 +22,7 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
Log.d(TAG, "Received intent");
ClientConfig.initialize(context);
- if (NetworkUtils.autodownloadNetworkAvailable()) {
+ if (NetworkUtils.isAutoDownloadAllowed()) {
Log.d(TAG, "auto-dl network available, starting auto-download");
DBTasks.autodownloadUndownloadedItems(context);
} else { // if new network is Wi-Fi, finish ongoing downloads,
diff --git a/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java b/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java
index c75164a74..33f0d47b8 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/PlaybackSpeedSeekBar.java
@@ -9,11 +9,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.util.playback.PlaybackController;
public class PlaybackSpeedSeekBar extends FrameLayout {
private SeekBar seekBar;
- private PlaybackController controller;
private Consumer<Float> progressChangedListener;
public PlaybackSpeedSeekBar(@NonNull Context context) {
@@ -40,15 +38,9 @@ public class PlaybackSpeedSeekBar extends FrameLayout {
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (controller != null) {
- float playbackSpeed = (progress + 10) / 20.0f;
- controller.setPlaybackSpeed(playbackSpeed);
-
- if (progressChangedListener != null) {
- progressChangedListener.accept(playbackSpeed);
- }
- } else if (fromUser) {
- seekBar.post(() -> updateSpeed());
+ float playbackSpeed = (progress + 10) / 20.0f;
+ if (progressChangedListener != null) {
+ progressChangedListener.accept(playbackSpeed);
}
}
@@ -62,21 +54,23 @@ public class PlaybackSpeedSeekBar extends FrameLayout {
});
}
- public void updateSpeed() {
- if (controller != null) {
- seekBar.setProgress(Math.round((20 * controller.getCurrentPlaybackSpeedMultiplier()) - 10));
- }
- }
-
- public void setController(PlaybackController controller) {
- this.controller = controller;
- updateSpeed();
- if (progressChangedListener != null && controller != null) {
- progressChangedListener.accept(controller.getCurrentPlaybackSpeedMultiplier());
- }
+ public void updateSpeed(float speedMultiplier) {
+ seekBar.setProgress(Math.round((20 * speedMultiplier) - 10));
}
public void setProgressChangedListener(Consumer<Float> progressChangedListener) {
this.progressChangedListener = progressChangedListener;
}
+
+ public float getCurrentSpeed() {
+ return (seekBar.getProgress() + 10) / 20.0f;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ seekBar.setEnabled(enabled);
+ findViewById(R.id.butDecSpeed).setEnabled(enabled);
+ findViewById(R.id.butIncSpeed).setEnabled(enabled);
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
index cd3af5003..8d1810ecb 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
@@ -21,7 +21,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.CoverLoader;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.core.util.DateFormatter;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;