Delete local feed episodes (#6400)
This commit is contained in:
parent
fa75317bce
commit
346365b8d0
|
@ -41,6 +41,7 @@ import static de.test.antennapod.EspressoTestUtils.clickPreference;
|
|||
import static de.test.antennapod.EspressoTestUtils.waitForView;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@LargeTest
|
||||
|
@ -199,6 +200,22 @@ public class PreferencesTest {
|
|||
.until(() -> autoDelete == UserPreferences.isAutoDelete());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoDeleteLocal() {
|
||||
clickPreference(R.string.downloads_pref);
|
||||
final boolean initialAutoDelete = UserPreferences.isAutoDeleteLocal();
|
||||
assertFalse(initialAutoDelete);
|
||||
|
||||
onView(withText(R.string.pref_auto_local_delete_title)).perform(click());
|
||||
onView(withText(R.string.yes)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.isAutoDeleteLocal());
|
||||
|
||||
onView(withText(R.string.pref_auto_local_delete_title)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> !UserPreferences.isAutoDeleteLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaybackSpeeds() {
|
||||
clickPreference(R.string.playback_pref);
|
||||
|
|
|
@ -4,10 +4,14 @@ import android.content.Context;
|
|||
import android.view.View;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.view.LocalDeleteModal;
|
||||
|
||||
public class DeleteActionButton extends ItemActionButton {
|
||||
|
||||
|
@ -33,11 +37,17 @@ public class DeleteActionButton extends ItemActionButton {
|
|||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
DBWriter.deleteFeedMediaOfItem(context, media.getId());
|
||||
|
||||
LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(context, Collections.singletonList(item),
|
||||
() -> DBWriter.deleteFeedMediaOfItem(context, media.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVisibility() {
|
||||
return (item.getMedia() != null && item.getMedia().isDownloaded()) ? View.VISIBLE : View.INVISIBLE;
|
||||
if (item.getMedia() != null && (item.getMedia().isDownloaded() || item.getFeed().isLocalFeed())) {
|
||||
return View.VISIBLE;
|
||||
}
|
||||
|
||||
return View.INVISIBLE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,8 +197,8 @@ public class AddFeedFragment extends Fragment {
|
|||
}
|
||||
|
||||
private Feed addLocalFolder(Uri uri) {
|
||||
getActivity().getContentResolver()
|
||||
.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
getActivity().getContentResolver().takePersistableUriPermission(uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
DocumentFile documentFile = DocumentFile.fromTreeUri(getContext(), uri);
|
||||
if (documentFile == null) {
|
||||
throw new IllegalArgumentException("Unable to retrieve document tree");
|
||||
|
|
|
@ -367,7 +367,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
swipeActions.detach();
|
||||
if (feed.isLocalFeed()) {
|
||||
speedDialBinding.fabSD.removeActionItemById(R.id.download_batch);
|
||||
speedDialBinding.fabSD.removeActionItemById(R.id.delete_batch);
|
||||
}
|
||||
speedDialBinding.fabSD.removeActionItemById(R.id.remove_all_inbox_item);
|
||||
speedDialBinding.fabSD.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -172,7 +172,6 @@ public class FeedSettingsFragment extends Fragment {
|
|||
|
||||
if (feed.isLocalFeed()) {
|
||||
findPreference(PREF_AUTHENTICATION).setVisible(false);
|
||||
findPreference(PREF_AUTO_DELETE).setVisible(false);
|
||||
findPreference(PREF_CATEGORY_AUTO_DOWNLOAD).setVisible(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterfa
|
|||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.view.LocalDeleteModal;
|
||||
|
||||
public class EpisodeMultiSelectActionHandler {
|
||||
private static final String TAG = "EpisodeSelectHandler";
|
||||
|
@ -41,7 +42,7 @@ public class EpisodeMultiSelectActionHandler {
|
|||
} else if (actionId == R.id.download_batch) {
|
||||
downloadChecked(items);
|
||||
} else if (actionId == R.id.delete_batch) {
|
||||
deleteChecked(items);
|
||||
LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(activity, items, () -> deleteChecked(items));
|
||||
} else {
|
||||
Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=" + actionId);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,12 @@ package de.danoeh.antennapod.fragment.preferences;
|
|||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
|
@ -17,9 +21,12 @@ import java.io.File;
|
|||
public class DownloadsPreferencesFragment extends PreferenceFragmentCompat
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final String PREF_SCREEN_AUTODL = "prefAutoDownloadSettings";
|
||||
private static final String PREF_AUTO_DELETE_LOCAL = "prefAutoDeleteLocal";
|
||||
private static final String PREF_PROXY = "prefProxy";
|
||||
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
||||
|
||||
private boolean blockAutoDeleteLocal = true;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_downloads);
|
||||
|
@ -63,6 +70,14 @@ public class DownloadsPreferencesFragment extends PreferenceFragmentCompat
|
|||
});
|
||||
return true;
|
||||
});
|
||||
findPreference(PREF_AUTO_DELETE_LOCAL).setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (blockAutoDeleteLocal && newValue == Boolean.TRUE) {
|
||||
showAutoDeleteEnableDialog();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setDataFolderText() {
|
||||
|
@ -78,4 +93,16 @@ public class DownloadsPreferencesFragment extends PreferenceFragmentCompat
|
|||
FeedUpdateManager.restartUpdateAlarm(getContext(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAutoDeleteEnableDialog() {
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.pref_auto_local_delete_dialog_body)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
blockAutoDeleteLocal = false;
|
||||
((TwoStatePreference) findPreference(PREF_AUTO_DELETE_LOCAL)).setChecked(true);
|
||||
blockAutoDeleteLocal = true;
|
||||
})
|
||||
.setNegativeButton(R.string.cancel_label, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,14 @@ package de.danoeh.antennapod.fragment.swipeactions;
|
|||
|
||||
import android.content.Context;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
||||
import de.danoeh.antennapod.view.LocalDeleteModal;
|
||||
|
||||
public class DeleteSwipeAction implements SwipeAction {
|
||||
|
||||
|
@ -31,14 +35,16 @@ public class DeleteSwipeAction implements SwipeAction {
|
|||
|
||||
@Override
|
||||
public void performAction(FeedItem item, Fragment fragment, FeedItemFilter filter) {
|
||||
if (!item.isDownloaded()) {
|
||||
if (!item.isDownloaded() && !item.getFeed().isLocalFeed()) {
|
||||
return;
|
||||
}
|
||||
DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), item.getMedia().getId());
|
||||
LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(
|
||||
fragment.requireContext(), Collections.singletonList(item),
|
||||
() -> DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), item.getMedia().getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willRemove(FeedItemFilter filter, FeedItem item) {
|
||||
return filter.showDownloaded && item.isDownloaded();
|
||||
return filter.showDownloaded && (item.isDownloaded() || item.getFeed().isLocalFeed());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ import androidx.fragment.app.Fragment;
|
|||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.FeedUtil;
|
||||
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackServiceInterface;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
|
@ -29,6 +31,7 @@ import de.danoeh.antennapod.dialog.ShareDialog;
|
|||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.net.sync.model.EpisodeAction;
|
||||
import de.danoeh.antennapod.view.LocalDeleteModal;
|
||||
|
||||
/**
|
||||
* Handles interactions with the FeedItemMenu.
|
||||
|
@ -56,6 +59,7 @@ public class FeedItemMenuHandler {
|
|||
final boolean isPlaying = hasMedia && PlaybackStatus.isPlaying(selectedItem.getMedia());
|
||||
final boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE);
|
||||
final boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
|
||||
final boolean isLocalFile = hasMedia && selectedItem.getFeed().isLocalFeed();
|
||||
final boolean isFavorite = selectedItem.isTagged(FeedItem.TAG_FAVORITE);
|
||||
|
||||
setItemVisibility(menu, R.id.skip_episode_item, isPlaying);
|
||||
|
@ -80,7 +84,7 @@ public class FeedItemMenuHandler {
|
|||
|
||||
setItemVisibility(menu, R.id.add_to_favorites_item, !isFavorite);
|
||||
setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite);
|
||||
setItemVisibility(menu, R.id.remove_item, fileDownloaded);
|
||||
setItemVisibility(menu, R.id.remove_item, fileDownloaded || isLocalFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -148,7 +152,8 @@ public class FeedItemMenuHandler {
|
|||
if (menuItemId == R.id.skip_episode_item) {
|
||||
context.sendBroadcast(MediaButtonReceiver.createIntent(context, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||
} else if (menuItemId == R.id.remove_item) {
|
||||
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
|
||||
LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(context, Arrays.asList(selectedItem),
|
||||
() -> DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId()));
|
||||
} else if (menuItemId == R.id.remove_inbox_item) {
|
||||
removeNewFlagWithUndo(fragment, selectedItem);
|
||||
} else if (menuItemId == R.id.mark_read_item) {
|
||||
|
@ -225,7 +230,8 @@ public class FeedItemMenuHandler {
|
|||
final Handler h = new Handler(fragment.requireContext().getMainLooper());
|
||||
final Runnable r = () -> {
|
||||
FeedMedia media = item.getMedia();
|
||||
if (media != null && FeedItemUtil.hasAlmostEnded(media) && UserPreferences.isAutoDelete()) {
|
||||
boolean shouldAutoDelete = FeedUtil.shouldAutoDeleteItemsOnThatFeed(item.getFeed());
|
||||
if (media != null && FeedItemUtil.hasAlmostEnded(media) && shouldAutoDelete) {
|
||||
DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), media.getId());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package de.danoeh.antennapod.view;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import de.danoeh.antennapod.ui.i18n.R;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
|
||||
public class LocalDeleteModal {
|
||||
public static void showLocalFeedDeleteWarningIfNecessary(Context context, Iterable<FeedItem> items,
|
||||
Runnable deleteCommand) {
|
||||
boolean anyLocalFeed = false;
|
||||
for (FeedItem item : items) {
|
||||
if (item.getFeed().isLocalFeed()) {
|
||||
anyLocalFeed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyLocalFeed) {
|
||||
deleteCommand.run();
|
||||
return;
|
||||
}
|
||||
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.delete_episode_label)
|
||||
.setMessage(R.string.delete_local_feed_warning_body)
|
||||
.setPositiveButton(R.string.delete_label, (dialog, which) -> deleteCommand.run())
|
||||
.setNegativeButton(R.string.cancel_label, null)
|
||||
.show();
|
||||
}
|
||||
}
|
|
@ -33,6 +33,12 @@
|
|||
android:key="prefAutoDelete"
|
||||
android:summary="@string/pref_auto_delete_sum"
|
||||
android:title="@string/pref_auto_delete_title"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefAutoDeleteLocal"
|
||||
android:summary="@string/pref_auto_local_delete_sum"
|
||||
android:title="@string/pref_auto_local_delete_title"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
|
|
|
@ -37,7 +37,6 @@ import de.danoeh.antennapod.model.download.DownloadError;
|
|||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.model.playback.MediaType;
|
||||
import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils;
|
||||
import de.danoeh.antennapod.parser.media.id3.ID3ReaderException;
|
||||
|
@ -124,13 +123,9 @@ public class LocalFeedUpdater {
|
|||
feed.setImageUrl(getImageUrl(allFiles, folderUri));
|
||||
|
||||
feed.getPreferences().setAutoDownload(false);
|
||||
feed.getPreferences().setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NEVER);
|
||||
feed.setDescription(context.getString(R.string.local_feed_description));
|
||||
feed.setAuthor(context.getString(R.string.local_folder));
|
||||
|
||||
if (newItems.isEmpty()) {
|
||||
throw new IOException("Empty folder. Make sure that the folder is accessible and contains media files.");
|
||||
}
|
||||
DBTasks.updateFeed(context, feed, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
|||
import de.danoeh.antennapod.core.storage.FeedSearcher;
|
||||
import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.FeedUtil;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
|
@ -1103,7 +1104,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||
FeedPreferences.AutoDeleteAction action =
|
||||
item.getFeed().getPreferences().getCurrentAutoDelete();
|
||||
boolean shouldAutoDelete = action == FeedPreferences.AutoDeleteAction.ALWAYS
|
||||
|| (action == FeedPreferences.AutoDeleteAction.GLOBAL && UserPreferences.isAutoDelete());
|
||||
|| (action == FeedPreferences.AutoDeleteAction.GLOBAL
|
||||
&& FeedUtil.shouldAutoDeleteItemsOnThatFeed(item.getFeed()));
|
||||
if (shouldAutoDelete && (!item.isTagged(FeedItem.TAG_FAVORITE)
|
||||
|| !UserPreferences.shouldFavoriteKeepEpisode())) {
|
||||
DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId());
|
||||
|
|
|
@ -2,15 +2,22 @@ package de.danoeh.antennapod.core.storage;
|
|||
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
import de.danoeh.antennapod.core.event.DownloadLogEvent;
|
||||
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
|
||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackServiceInterface;
|
||||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -25,7 +32,6 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.event.DownloadLogEvent;
|
||||
import de.danoeh.antennapod.event.FavoritesEvent;
|
||||
import de.danoeh.antennapod.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.event.FeedListUpdateEvent;
|
||||
|
@ -94,7 +100,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> deleteFeedMediaOfItem(@NonNull final Context context,
|
||||
final long mediaId) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final FeedMedia media = DBReader.getFeedMedia(mediaId);
|
||||
if (media != null) {
|
||||
boolean result = deleteFeedMediaSynchronous(context, media);
|
||||
|
@ -106,10 +112,10 @@ public class DBWriter {
|
|||
});
|
||||
}
|
||||
|
||||
private static boolean deleteFeedMediaSynchronous(
|
||||
@NonNull Context context, @NonNull FeedMedia media) {
|
||||
private static boolean deleteFeedMediaSynchronous(@NonNull Context context, @NonNull FeedMedia media) {
|
||||
Log.i(TAG, String.format(Locale.US, "Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s",
|
||||
media.getId(), media.getEpisodeTitle(), media.isDownloaded()));
|
||||
boolean localDelete = false;
|
||||
if (media.isDownloaded()) {
|
||||
// delete downloaded media file
|
||||
File mediaFile = new File(media.getFile_url());
|
||||
|
@ -125,23 +131,38 @@ public class DBWriter {
|
|||
adapter.open();
|
||||
adapter.setMedia(media);
|
||||
adapter.close();
|
||||
|
||||
if (media.getId() == PlaybackPreferences.getCurrentlyPlayingFeedMediaId()) {
|
||||
PlaybackPreferences.writeNoMediaPlaying();
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
|
||||
|
||||
NotificationManagerCompat nm = NotificationManagerCompat.from(context);
|
||||
nm.cancel(R.id.notification_playing);
|
||||
} else if (media.getFile_url().startsWith("content://")) {
|
||||
// Local feed
|
||||
DocumentFile documentFile = DocumentFile.fromSingleUri(
|
||||
context, Uri.parse(media.getFile_url()));
|
||||
if (documentFile == null || !documentFile.exists() || !documentFile.delete()) {
|
||||
EventBus.getDefault().post(new MessageEvent(context.getString(R.string.delete_local_failed)));
|
||||
return false;
|
||||
}
|
||||
localDelete = true;
|
||||
}
|
||||
|
||||
if (media.getId() == PlaybackPreferences.getCurrentlyPlayingFeedMediaId()) {
|
||||
PlaybackPreferences.writeNoMediaPlaying();
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
|
||||
|
||||
NotificationManagerCompat nm = NotificationManagerCompat.from(context);
|
||||
nm.cancel(R.id.notification_playing);
|
||||
}
|
||||
|
||||
if (localDelete) {
|
||||
// Do full update of this feed to get rid of the item
|
||||
LocalFeedUpdater.updateFeed(media.getItem().getFeed(), context.getApplicationContext(), null);
|
||||
} else {
|
||||
// Gpodder: queue delete action for synchronization
|
||||
FeedItem item = media.getItem();
|
||||
EpisodeAction action = new EpisodeAction.Builder(item, EpisodeAction.DELETE)
|
||||
.currentTimestamp()
|
||||
.build();
|
||||
SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, action);
|
||||
|
||||
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
||||
}
|
||||
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -152,7 +173,7 @@ public class DBWriter {
|
|||
* @param feedId ID of the Feed that should be deleted.
|
||||
*/
|
||||
public static Future<?> deleteFeed(final Context context, final long feedId) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final Feed feed = DBReader.getFeed(feedId);
|
||||
if (feed == null) {
|
||||
return;
|
||||
|
@ -183,7 +204,7 @@ public class DBWriter {
|
|||
*/
|
||||
@NonNull
|
||||
public static Future<?> deleteFeedItems(@NonNull Context context, @NonNull List<FeedItem> items) {
|
||||
return dbExec.submit(() -> deleteFeedItemsSynchronous(context, items));
|
||||
return runOnDbThread(() -> deleteFeedItemsSynchronous(context, items));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,7 +256,7 @@ public class DBWriter {
|
|||
* Deletes the entire playback history.
|
||||
*/
|
||||
public static Future<?> clearPlaybackHistory() {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.clearPlaybackHistory();
|
||||
|
@ -248,7 +269,7 @@ public class DBWriter {
|
|||
* Deletes the entire download log.
|
||||
*/
|
||||
public static Future<?> clearDownloadLog() {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.clearDownloadLog();
|
||||
|
@ -281,7 +302,7 @@ public class DBWriter {
|
|||
* @param date PlaybackCompletionDate for <code>media</code>
|
||||
*/
|
||||
public static Future<?> addItemToPlaybackHistory(final FeedMedia media, Date date) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
Log.d(TAG, "Adding item to playback history");
|
||||
media.setPlaybackCompletionDate(date);
|
||||
|
||||
|
@ -300,7 +321,7 @@ public class DBWriter {
|
|||
* @param status The DownloadStatus object.
|
||||
*/
|
||||
public static Future<?> addDownloadStatus(final DownloadResult status) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setDownloadStatus(status);
|
||||
|
@ -322,7 +343,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> addQueueItemAt(final Context context, final long itemId,
|
||||
final int index, final boolean performAutoDownload) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader.getQueue(adapter);
|
||||
|
@ -393,7 +414,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> addQueueItem(final Context context, final boolean performAutoDownload,
|
||||
final boolean markAsUnplayed, final long... itemIds) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
if (itemIds.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
@ -476,7 +497,7 @@ public class DBWriter {
|
|||
* Removes all FeedItem objects from the queue.
|
||||
*/
|
||||
public static Future<?> clearQueue() {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.clearQueue();
|
||||
|
@ -495,12 +516,12 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> removeQueueItem(final Context context,
|
||||
final boolean performAutoDownload, final FeedItem item) {
|
||||
return dbExec.submit(() -> removeQueueItemSynchronous(context, performAutoDownload, item.getId()));
|
||||
return runOnDbThread(() -> removeQueueItemSynchronous(context, performAutoDownload, item.getId()));
|
||||
}
|
||||
|
||||
public static Future<?> removeQueueItem(final Context context, final boolean performAutoDownload,
|
||||
final long... itemIds) {
|
||||
return dbExec.submit(() -> removeQueueItemSynchronous(context, performAutoDownload, itemIds));
|
||||
return runOnDbThread(() -> removeQueueItemSynchronous(context, performAutoDownload, itemIds));
|
||||
}
|
||||
|
||||
private static void removeQueueItemSynchronous(final Context context,
|
||||
|
@ -562,7 +583,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
public static Future<?> addFavoriteItem(final FeedItem item) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance().open();
|
||||
adapter.addFavoriteItem(item);
|
||||
adapter.close();
|
||||
|
@ -573,7 +594,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
public static Future<?> removeFavoriteItem(final FeedItem item) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance().open();
|
||||
adapter.removeFavoriteItem(item);
|
||||
adapter.close();
|
||||
|
@ -590,7 +611,7 @@ public class DBWriter {
|
|||
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
|
||||
*/
|
||||
public static Future<?> moveQueueItemToTop(final long itemId, final boolean broadcastUpdate) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
LongList queueIdList = DBReader.getQueueIDList();
|
||||
int index = queueIdList.indexOf(itemId);
|
||||
if (index >= 0) {
|
||||
|
@ -609,7 +630,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> moveQueueItemToBottom(final long itemId,
|
||||
final boolean broadcastUpdate) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
LongList queueIdList = DBReader.getQueueIDList();
|
||||
int index = queueIdList.indexOf(itemId);
|
||||
if (index >= 0) {
|
||||
|
@ -632,7 +653,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> moveQueueItem(final int from,
|
||||
final int to, final boolean broadcastUpdate) {
|
||||
return dbExec.submit(() -> moveQueueItemHelper(from, to, broadcastUpdate));
|
||||
return runOnDbThread(() -> moveQueueItemHelper(from, to, broadcastUpdate));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -669,7 +690,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
public static Future<?> resetPagedFeedPage(Feed feed) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.resetPagedFeedPage(feed);
|
||||
|
@ -699,7 +720,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> markItemPlayed(final int played, final boolean broadcastUpdate,
|
||||
final long... itemIds) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItemRead(played, itemIds);
|
||||
|
@ -729,7 +750,7 @@ public class DBWriter {
|
|||
final int played,
|
||||
final long mediaId,
|
||||
final boolean resetMediaPosition) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItemRead(played, itemId, mediaId,
|
||||
|
@ -746,7 +767,7 @@ public class DBWriter {
|
|||
* @param feedId ID of the Feed.
|
||||
*/
|
||||
public static Future<?> removeFeedNewFlag(final long feedId) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED, feedId);
|
||||
|
@ -760,7 +781,7 @@ public class DBWriter {
|
|||
* Sets the 'read'-attribute of all NEW FeedItems to UNPLAYED.
|
||||
*/
|
||||
public static Future<?> removeAllNewFlags() {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED);
|
||||
|
@ -771,7 +792,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
static Future<?> addNewFeed(final Context context, final Feed... feeds) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feeds);
|
||||
|
@ -789,7 +810,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
static Future<?> setCompleteFeed(final Feed... feeds) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feeds);
|
||||
|
@ -798,7 +819,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
public static Future<?> setItemList(final List<FeedItem> items) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.storeFeedItemlist(items);
|
||||
|
@ -814,7 +835,7 @@ public class DBWriter {
|
|||
* @param media The FeedMedia object.
|
||||
*/
|
||||
public static Future<?> setFeedMedia(final FeedMedia media) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setMedia(media);
|
||||
|
@ -828,7 +849,7 @@ public class DBWriter {
|
|||
* @param media The FeedMedia object.
|
||||
*/
|
||||
public static Future<?> setFeedMediaPlaybackInformation(final FeedMedia media) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedMediaPlaybackInformation(media);
|
||||
|
@ -843,7 +864,7 @@ public class DBWriter {
|
|||
* @param item The FeedItem object.
|
||||
*/
|
||||
public static Future<?> setFeedItem(final FeedItem item) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setSingleFeedItem(item);
|
||||
|
@ -857,7 +878,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> updateFeedDownloadURL(final String original, final String updated) {
|
||||
Log.d(TAG, "updateFeedDownloadURL(original: " + original + ", updated: " + updated + ")");
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedDownloadUrl(original, updated);
|
||||
|
@ -871,7 +892,7 @@ public class DBWriter {
|
|||
* @param preferences The FeedPreferences object.
|
||||
*/
|
||||
public static Future<?> setFeedPreferences(final FeedPreferences preferences) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedPreferences(preferences);
|
||||
|
@ -901,7 +922,7 @@ public class DBWriter {
|
|||
*/
|
||||
public static Future<?> setFeedLastUpdateFailed(final long feedId,
|
||||
final boolean lastUpdateFailed) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedLastUpdateFailed(feedId, lastUpdateFailed);
|
||||
|
@ -911,7 +932,7 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
public static Future<?> setFeedCustomTitle(Feed feed) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedCustomTitle(feed.getId(), feed.getCustomTitle());
|
||||
|
@ -930,10 +951,10 @@ public class DBWriter {
|
|||
public static Future<?> reorderQueue(@Nullable SortOrder sortOrder, final boolean broadcastUpdate) {
|
||||
if (sortOrder == null) {
|
||||
Log.w(TAG, "reorderQueue() - sortOrder is null. Do nothing.");
|
||||
return dbExec.submit(() -> { });
|
||||
return runOnDbThread(() -> { });
|
||||
}
|
||||
final Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(sortOrder);
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader.getQueue(adapter);
|
||||
|
@ -960,7 +981,7 @@ public class DBWriter {
|
|||
public static Future<?> setFeedItemsFilter(final long feedId,
|
||||
final Set<String> filterValues) {
|
||||
Log.d(TAG, "setFeedItemsFilter() called with: " + "feedId = [" + feedId + "], filterValues = [" + filterValues + "]");
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItemFilter(feedId, filterValues);
|
||||
|
@ -974,7 +995,7 @@ public class DBWriter {
|
|||
*
|
||||
*/
|
||||
public static Future<?> setFeedItemSortOrder(long feedId, @Nullable SortOrder sortOrder) {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItemSortOrder(feedId, sortOrder);
|
||||
|
@ -988,11 +1009,24 @@ public class DBWriter {
|
|||
*/
|
||||
@NonNull
|
||||
public static Future<?> resetStatistics() {
|
||||
return dbExec.submit(() -> {
|
||||
return runOnDbThread(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.resetAllMediaPlayedDuration();
|
||||
adapter.close();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit to the DB thread only if caller is not already on the DB thread. Otherwise,
|
||||
* just execute synchronously
|
||||
*/
|
||||
private static Future<?> runOnDbThread(Runnable runnable) {
|
||||
if ("DatabaseExecutor".equals(Thread.currentThread().getName())) {
|
||||
runnable.run();
|
||||
return Futures.immediateFuture(null);
|
||||
} else {
|
||||
return dbExec.submit(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
|
||||
public abstract class FeedUtil {
|
||||
public static boolean shouldAutoDeleteItemsOnThatFeed(Feed feed) {
|
||||
if (!UserPreferences.isAutoDelete()) {
|
||||
return false;
|
||||
}
|
||||
return !feed.isLocalFeed() || UserPreferences.isAutoDeleteLocal();
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ public class UserPreferences {
|
|||
public static final String PREF_SKIP_KEEPS_EPISODE = "prefSkipKeepsEpisode";
|
||||
private static final String PREF_FAVORITE_KEEPS_EPISODE = "prefFavoriteKeepsEpisode";
|
||||
private static final String PREF_AUTO_DELETE = "prefAutoDelete";
|
||||
private static final String PREF_AUTO_DELETE_LOCAL = "prefAutoDeleteLocal";
|
||||
public static final String PREF_SMART_MARK_AS_PLAYED_SECS = "prefSmartMarkAsPlayedSecs";
|
||||
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
|
||||
public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
|
||||
|
@ -366,6 +367,10 @@ public class UserPreferences {
|
|||
return prefs.getBoolean(PREF_AUTO_DELETE, false);
|
||||
}
|
||||
|
||||
public static boolean isAutoDeleteLocal() {
|
||||
return prefs.getBoolean(PREF_AUTO_DELETE_LOCAL, false);
|
||||
}
|
||||
|
||||
public static int getSmartMarkAsPlayedSecs() {
|
||||
return Integer.parseInt(prefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30"));
|
||||
}
|
||||
|
|
|
@ -216,6 +216,7 @@
|
|||
<string name="stream_label">Stream</string>
|
||||
<string name="delete_label">Delete</string>
|
||||
<string name="delete_failed">Unable to delete file. Rebooting the device could help.</string>
|
||||
<string name="delete_local_failed">Unable to delete file. Try re-connecting the local folder from the podcast info screen.</string>
|
||||
<string name="delete_episode_label">Delete episode</string>
|
||||
<plurals name="deleted_multi_episode_batch_label">
|
||||
<item quantity="one">1 downloaded episode deleted.</item>
|
||||
|
@ -259,6 +260,7 @@
|
|||
<string name="skip_episode_label">Skip episode</string>
|
||||
<string name="reset_position">Reset playback position</string>
|
||||
<string name="no_items_selected">No items selected</string>
|
||||
<string name="delete_local_feed_warning_body">Deleting removes the episode from AntennaPod and deletes the media file from your device storage. It cannot be downloaded again through AntennaPod.</string>
|
||||
|
||||
<!-- Download messages and labels -->
|
||||
<string name="download_successful">successful</string>
|
||||
|
@ -401,6 +403,9 @@
|
|||
<string name="pref_followQueue_sum">Jump to next queue item when playback completes</string>
|
||||
<string name="pref_auto_delete_sum">Delete episode when playback completes</string>
|
||||
<string name="pref_auto_delete_title">Auto delete</string>
|
||||
<string name="pref_auto_local_delete_title">Auto delete from local folders</string>
|
||||
<string name="pref_auto_local_delete_sum">Include local folders in Auto delete functionality</string>
|
||||
<string name="pref_auto_local_delete_dialog_body">Note that for local folders this will remove episodes from AntennaPod and delete their media files from your device storage. They cannot be downloaded again through AntennaPod. Enable auto delete?</string>
|
||||
<string name="pref_smart_mark_as_played_sum">Mark episodes as played even if less than a certain amount of seconds of playing time is still left</string>
|
||||
<string name="pref_smart_mark_as_played_title">Smart mark as played</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Keep episodes when they are skipped</string>
|
||||
|
|
Loading…
Reference in New Issue