summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorByteHamster <ByteHamster@users.noreply.github.com>2024-05-09 11:44:26 +0200
committerGitHub <noreply@github.com>2024-05-09 11:44:26 +0200
commit084723ad76f93822b9a15b24bb55a1fefa155dce (patch)
tree8c847b937facfae38808f313f427b01d611f7068
parent53ce6cd71a766847dfdf345ecd7b96a6dbca8015 (diff)
downloadAntennaPod-084723ad76f93822b9a15b24bb55a1fefa155dce.zip
Add episodes without subscribing (#7098)
-rw-r--r--app/src/main/java/de/danoeh/antennapod/actionbutton/ItemActionButton.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemListAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemViewHolder.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeMultiSelectActionHandler.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/episodeslist/FeedItemMenuHandler.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/AllEpisodesFragment.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/PlaybackHistoryFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/download/CompletedDownloadsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemPagerFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedInfoFragment.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedItemlistFragment.java141
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/home/sections/DownloadsSection.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/FeedItemlistDescriptionAdapter.java112
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/OnlineFeedViewActivity.java365
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java18
-rw-r--r--app/src/main/res/layout/alternate_urls_dropdown_item.xml8
-rw-r--r--app/src/main/res/layout/alternate_urls_item.xml9
-rw-r--r--app/src/main/res/layout/feedinfo.xml6
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml14
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml56
-rw-r--r--app/src/main/res/layout/itemdescription_listitem.xml51
-rw-r--r--app/src/main/res/layout/onlinefeedview_activity.xml172
-rw-r--r--app/src/main/res/layout/onlinefeedview_header.xml36
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java16
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedItemFilter.java10
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java9
-rw-r--r--net/discovery/src/main/java/de/danoeh/antennapod/net/discovery/ItunesTopListLoader.java3
-rw-r--r--net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/episode/MediaDownloadedHandler.java3
-rw-r--r--net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/feed/FeedUpdateWorker.java6
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java4
-rw-r--r--playback/service/src/main/java/de/danoeh/antennapod/playback/service/PlaybackService.java4
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java9
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java5
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBWriter.java44
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedDatabaseWriter.java3
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleaner.java46
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java30
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java5
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java3
-rw-r--r--storage/database/src/test/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleanerTest.java104
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java3
-rw-r--r--storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java3
-rw-r--r--ui/common/src/main/res/drawable/bg_message_info.xml17
-rw-r--r--ui/common/src/main/res/drawable/bg_rounded_corners.xml6
-rw-r--r--ui/common/src/main/res/drawable/ic_close.xml11
-rw-r--r--ui/common/src/main/res/values/colors.xml1
-rw-r--r--ui/common/src/main/res/values/dimens.xml2
-rw-r--r--ui/i18n/src/main/res/values/strings.xml5
50 files changed, 677 insertions, 817 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/actionbutton/ItemActionButton.java
index 84b246167..54714be3d 100644
--- a/app/src/main/java/de/danoeh/antennapod/actionbutton/ItemActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/actionbutton/ItemActionButton.java
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import android.view.View;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.playback.service.PlaybackStatus;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
@@ -48,6 +49,8 @@ public abstract class ItemActionButton {
return new PlayActionButton(item);
} else if (isDownloadingMedia) {
return new CancelDownloadActionButton(item);
+ } else if (item.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
+ return new StreamActionButton(item);
} else if (UserPreferences.isStreamOverDownload()) {
return new StreamActionButton(item);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemListAdapter.java b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemListAdapter.java
index 5082f25ff..db7991261 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemListAdapter.java
@@ -12,6 +12,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.ui.SelectableAdapter;
@@ -32,13 +33,13 @@ import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHolder>
implements View.OnCreateContextMenuListener {
- private final WeakReference<MainActivity> mainActivityRef;
+ private final WeakReference<FragmentActivity> mainActivityRef;
private List<FeedItem> episodes = new ArrayList<>();
private FeedItem longPressedItem;
int longPressedPosition = 0; // used to init actionMode
private int dummyViews = 0;
- public EpisodeItemListAdapter(MainActivity mainActivity) {
+ public EpisodeItemListAdapter(FragmentActivity mainActivity) {
super(mainActivity);
this.mainActivityRef = new WeakReference<>(mainActivity);
setHasStableIds(true);
@@ -86,9 +87,18 @@ public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHol
holder.bind(item);
holder.itemView.setOnClickListener(v -> {
- MainActivity activity = mainActivityRef.get();
- if (activity != null && !inActionMode()) {
- activity.loadChildFragment(ItemPagerFragment.newInstance(episodes, item));
+ if (!inActionMode()) {
+ if (mainActivityRef.get() instanceof MainActivity) {
+ ((MainActivity) mainActivityRef.get())
+ .loadChildFragment(ItemPagerFragment.newInstance(episodes, item));
+ } else {
+ ItemPagerFragment fragment = ItemPagerFragment.newInstance(episodes, item);
+ mainActivityRef.get().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragmentContainer, fragment, "Items")
+ .addToBackStack("Items")
+ .commitAllowingStateLoss();
+ }
} else {
toggleSelection(holder.getBindingAdapterPosition());
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemViewHolder.java
index dd1a10450..c5868a945 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeItemViewHolder.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.ui.episodeslist;
+import android.app.Activity;
import android.os.Build;
import android.text.Layout;
import android.text.format.Formatter;
@@ -17,7 +18,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.elevation.SurfaceColors;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.ui.CoverLoader;
import de.danoeh.antennapod.actionbutton.ItemActionButton;
import de.danoeh.antennapod.playback.service.PlaybackStatus;
@@ -62,10 +62,10 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
private final View leftPadding;
public final CardView coverHolder;
- private final MainActivity activity;
+ private final Activity activity;
private FeedItem item;
- public EpisodeItemViewHolder(MainActivity activity, ViewGroup parent) {
+ public EpisodeItemViewHolder(Activity activity, ViewGroup parent) {
super(LayoutInflater.from(activity).inflate(R.layout.feeditemlist_item, parent, false));
this.activity = activity;
container = itemView.findViewById(R.id.container);
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeMultiSelectActionHandler.java
index 76ed47de5..a655982cb 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeMultiSelectActionHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/EpisodeMultiSelectActionHandler.java
@@ -1,29 +1,28 @@
package de.danoeh.antennapod.ui.episodeslist;
+import android.app.Activity;
import android.util.Log;
import androidx.annotation.PluralsRes;
-import com.google.android.material.snackbar.Snackbar;
-
import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.event.MessageEvent;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import de.danoeh.antennapod.storage.database.DBWriter;
import de.danoeh.antennapod.storage.database.LongList;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.ui.view.LocalDeleteModal;
+import org.greenrobot.eventbus.EventBus;
public class EpisodeMultiSelectActionHandler {
private static final String TAG = "EpisodeSelectHandler";
- private final MainActivity activity;
+ private final Activity activity;
private final int actionId;
private int totalNumItems = 0;
- private Snackbar snackbar = null;
- public EpisodeMultiSelectActionHandler(MainActivity activity, int actionId) {
+ public EpisodeMultiSelectActionHandler(Activity activity, int actionId) {
this.activity = activity;
this.actionId = actionId;
}
@@ -116,12 +115,7 @@ public class EpisodeMultiSelectActionHandler {
totalNumItems += numItems;
activity.runOnUiThread(() -> {
String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems);
- if (snackbar != null) {
- snackbar.setText(text);
- snackbar.show(); // Resets the timeout
- } else {
- snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG);
- }
+ EventBus.getDefault().post(new MessageEvent(text));
});
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/FeedItemMenuHandler.java
index e1974940c..720e0ccbc 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/FeedItemMenuHandler.java
@@ -16,6 +16,7 @@ import java.util.Arrays;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueueSink;
import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
import de.danoeh.antennapod.playback.service.PlaybackServiceInterface;
@@ -84,6 +85,10 @@ 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 || isLocalFile);
+
+ if (selectedItem.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
+ setItemVisibility(menu, R.id.mark_read_item, false);
+ }
return true;
}
@@ -158,7 +163,8 @@ public class FeedItemMenuHandler {
} else if (menuItemId == R.id.mark_read_item) {
selectedItem.setPlayed(true);
DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, true);
- if (!selectedItem.getFeed().isLocalFeed() && SynchronizationSettings.isProviderConnected()) {
+ if (!selectedItem.getFeed().isLocalFeed() && selectedItem.getFeed().getState() == Feed.STATE_SUBSCRIBED
+ && SynchronizationSettings.isProviderConnected()) {
FeedMedia media = selectedItem.getMedia();
// not all items have media, Gpodder only cares about those that do
if (media != null) {
@@ -174,7 +180,8 @@ public class FeedItemMenuHandler {
} else if (menuItemId == R.id.mark_unread_item) {
selectedItem.setPlayed(false);
DBWriter.markItemPlayed(selectedItem, FeedItem.UNPLAYED, false);
- if (!selectedItem.getFeed().isLocalFeed() && selectedItem.getMedia() != null) {
+ if (!selectedItem.getFeed().isLocalFeed() && selectedItem.getMedia() != null
+ && selectedItem.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
EpisodeAction actionNew = new EpisodeAction.Builder(selectedItem, EpisodeAction.NEW)
.currentTimestamp()
.build();
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/AllEpisodesFragment.java
index eb49c94d9..6e48ade39 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/AllEpisodesFragment.java
@@ -66,7 +66,12 @@ public class AllEpisodesFragment extends EpisodesListFragment {
@Override
protected FeedItemFilter getFilter() {
- return new FeedItemFilter(UserPreferences.getPrefFilterAllEpisodes());
+ FeedItemFilter filter = new FeedItemFilter(UserPreferences.getPrefFilterAllEpisodes());
+ if (filter.showIsFavorite) {
+ return new FeedItemFilter(filter, FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
+ } else {
+ return filter;
+ }
}
@Override
@@ -91,6 +96,7 @@ public class AllEpisodesFragment extends EpisodesListFragment {
ArrayList<String> filter = new ArrayList<>(getFilter().getValuesList());
if (filter.contains(FeedItemFilter.IS_FAVORITE)) {
filter.remove(FeedItemFilter.IS_FAVORITE);
+ filter.remove(FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
} else {
filter.add(FeedItemFilter.IS_FAVORITE);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/PlaybackHistoryFragment.java
index a02f86bd2..abdf043b1 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/PlaybackHistoryFragment.java
@@ -23,7 +23,8 @@ import java.util.List;
public class PlaybackHistoryFragment extends EpisodesListFragment {
public static final String TAG = "PlaybackHistoryFragment";
- private static final FeedItemFilter FILTER_HISTORY = new FeedItemFilter(FeedItemFilter.IS_IN_HISTORY);
+ private static final FeedItemFilter FILTER_HISTORY = new FeedItemFilter(
+ FeedItemFilter.IS_IN_HISTORY, FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
@NonNull
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/download/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/download/CompletedDownloadsFragment.java
index 001c2b465..0d82b7133 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/download/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/download/CompletedDownloadsFragment.java
@@ -285,7 +285,7 @@ public class CompletedDownloadsFragment extends Fragment
disposable = Observable.fromCallable(() -> {
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
List<FeedItem> downloadedItems = DBReader.getEpisodes(0, Integer.MAX_VALUE,
- new FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder);
+ new FeedItemFilter(FeedItemFilter.DOWNLOADED, FeedItemFilter.INCLUDE_NOT_SUBSCRIBED), sortOrder);
List<String> mediaUrls = new ArrayList<>();
if (runningDownloads == null) {
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemFragment.java
index e31004a57..a5ee78a58 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemFragment.java
@@ -38,6 +38,7 @@ import de.danoeh.antennapod.actionbutton.PlayLocalActionButton;
import de.danoeh.antennapod.actionbutton.StreamActionButton;
import de.danoeh.antennapod.actionbutton.VisitWebsiteActionButton;
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.playback.service.PlaybackStatus;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
@@ -49,6 +50,7 @@ import de.danoeh.antennapod.storage.preferences.UsageStatistics;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
import de.danoeh.antennapod.ui.common.Converter;
import de.danoeh.antennapod.ui.common.DateFormatter;
import de.danoeh.antennapod.ui.common.CircularProgressBar;
@@ -114,6 +116,7 @@ public class ItemFragment extends Fragment {
private ItemActionButton actionButton1;
private ItemActionButton actionButton2;
private View noMediaLabel;
+ private View nonSubscribedWarningLabel;
private Disposable disposable;
private PlaybackController controller;
@@ -164,6 +167,7 @@ public class ItemFragment extends Fragment {
butAction1Text = layout.findViewById(R.id.butAction1Text);
butAction2Text = layout.findViewById(R.id.butAction2Text);
noMediaLabel = layout.findViewById(R.id.noMediaLabel);
+ nonSubscribedWarningLabel = layout.findViewById(R.id.nonSubscribedWarningLabel);
butAction1.setOnClickListener(v -> {
if (actionButton1 instanceof StreamActionButton && !UserPreferences.isStreamOverDownload()
@@ -287,6 +291,11 @@ public class ItemFragment extends Fragment {
txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate()));
}
+ if (item.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
+ nonSubscribedWarningLabel.setVisibility(View.VISIBLE);
+ nonSubscribedWarningLabel.setOnClickListener(v -> openPodcast());
+ }
+
float radius = 8 * getResources().getDisplayMetrics().density;
RequestOptions options = new RequestOptions()
.error(ImagePlaceholder.getDrawable(getContext(), radius))
@@ -366,8 +375,13 @@ public class ItemFragment extends Fragment {
if (item == null) {
return;
}
- Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
- ((MainActivity) getActivity()).loadChildFragment(fragment);
+ if (item.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
+ Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
+ ((MainActivity) getActivity()).loadChildFragment(fragment);
+ } else {
+ startActivity(new OnlineFeedviewActivityStarter(getContext(), item.getFeed().getDownloadUrl())
+ .getIntent());
+ }
}
@Subscribe(threadMode = ThreadMode.MAIN)
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemPagerFragment.java
index e7f345617..951e5affb 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/episode/ItemPagerFragment.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.ui.screen.episode;
+import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -13,7 +14,8 @@ import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
-import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -173,8 +175,12 @@ public class ItemPagerFragment extends Fragment implements MaterialToolbar.OnMen
if (item == null) {
return;
}
- Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
- ((MainActivity) getActivity()).loadChildFragment(fragment);
+ if (item.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
+ Intent intent = MainActivity.getIntentToOpenFeed(getContext(), item.getFeedId());
+ startActivity(intent);
+ } else {
+ startActivity(new OnlineFeedviewActivityStarter(getContext(), item.getFeed().getDownloadUrl()).getIntent());
+ }
}
private class ItemPagerAdapter extends FragmentStateAdapter {
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedInfoFragment.java
index aabb0852e..f73b69d75 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedInfoFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedInfoFragment.java
@@ -122,7 +122,6 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
viewBinding.header.butFilter.setVisibility(View.INVISIBLE);
// https://github.com/bumptech/glide/issues/529
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
-
viewBinding.urlLabel.setOnClickListener(copyUrlToClipboard);
long feedId = getArguments().getLong(EXTRA_FEED_ID);
@@ -237,6 +236,25 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
viewBinding.supportUrl.setText(str.toString());
}
+ if (feed.getState() == Feed.STATE_SUBSCRIBED) {
+ long feedId = getArguments().getLong(EXTRA_FEED_ID);
+ getParentFragmentManager().beginTransaction().replace(R.id.statisticsFragmentContainer,
+ FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
+ .commitAllowingStateLoss();
+
+ viewBinding.statisticsButton.setOnClickListener(view -> {
+ StatisticsFragment fragment = new StatisticsFragment();
+ ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
+ });
+ } else {
+ viewBinding.statisticsButton.setVisibility(View.GONE);
+ viewBinding.statisticsFragmentContainer.setVisibility(View.GONE);
+ viewBinding.statisticsHeadingLabel.setVisibility(View.GONE);
+ viewBinding.supportHeadingLabel.setVisibility(View.GONE);
+ viewBinding.supportUrl.setVisibility(View.GONE);
+ viewBinding.descriptionHeadingLabel.setVisibility(View.GONE);
+ }
+
refreshToolbarState();
}
@@ -249,13 +267,14 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
}
private void refreshToolbarState() {
+ boolean isSubscribed = feed != null && feed.getState() == Feed.STATE_SUBSCRIBED;
viewBinding.toolbar.getMenu().findItem(R.id.reconnect_local_folder).setVisible(
- feed != null && feed.isLocalFeed());
- viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(feed != null && !feed.isLocalFeed());
- viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(feed != null
+ isSubscribed && feed.isLocalFeed());
+ viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(isSubscribed && !feed.isLocalFeed());
+ viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(isSubscribed
&& feed.getLink() != null
&& IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
- viewBinding.toolbar.getMenu().findItem(R.id.edit_feed_url_item).setVisible(feed != null && !feed.isLocalFeed());
+ viewBinding.toolbar.getMenu().findItem(R.id.edit_feed_url_item).setVisible(isSubscribed && !feed.isLocalFeed());
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedItemlistFragment.java
index 3c6931794..fbfb9fa0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/feed/FeedItemlistFragment.java
@@ -12,52 +12,23 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
-
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.snackbar.Snackbar;
-
-import de.danoeh.antennapod.ui.CoverLoader;
-import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
-import de.danoeh.antennapod.ui.screen.SearchFragment;
-import de.danoeh.antennapod.ui.TransitionEffect;
-import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
-import de.danoeh.antennapod.ui.screen.download.DownloadLogFragment;
-import de.danoeh.antennapod.ui.screen.feed.preferences.FeedSettingsFragment;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.ui.episodeslist.EpisodeItemListAdapter;
-import de.danoeh.antennapod.event.FeedEvent;
-import de.danoeh.antennapod.ui.MenuItemUtils;
-import de.danoeh.antennapod.storage.database.DBReader;
-import de.danoeh.antennapod.storage.database.DBWriter;
-import de.danoeh.antennapod.ui.common.IntentUtils;
-import de.danoeh.antennapod.ui.share.ShareUtils;
-import de.danoeh.antennapod.ui.episodeslist.MoreContentListFooterUtil;
import de.danoeh.antennapod.databinding.FeedItemListFragmentBinding;
-import de.danoeh.antennapod.ui.screen.download.DownloadLogDetailsDialog;
-import de.danoeh.antennapod.ui.FeedItemFilterDialog;
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
import de.danoeh.antennapod.event.FavoritesEvent;
+import de.danoeh.antennapod.event.FeedEvent;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
@@ -65,21 +36,48 @@ import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.QueueEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
-import de.danoeh.antennapod.ui.episodeslist.EpisodeMultiSelectActionHandler;
-import de.danoeh.antennapod.ui.swipeactions.SwipeActions;
-import de.danoeh.antennapod.ui.episodeslist.FeedItemMenuHandler;
import de.danoeh.antennapod.model.download.DownloadResult;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.database.DBWriter;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
+import de.danoeh.antennapod.ui.CoverLoader;
+import de.danoeh.antennapod.ui.FeedItemFilterDialog;
+import de.danoeh.antennapod.ui.MenuItemUtils;
+import de.danoeh.antennapod.ui.TransitionEffect;
+import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
+import de.danoeh.antennapod.ui.cleaner.HtmlToPlainText;
+import de.danoeh.antennapod.ui.common.IntentUtils;
+import de.danoeh.antennapod.ui.episodeslist.EpisodeItemListAdapter;
import de.danoeh.antennapod.ui.episodeslist.EpisodeItemViewHolder;
+import de.danoeh.antennapod.ui.episodeslist.EpisodeMultiSelectActionHandler;
+import de.danoeh.antennapod.ui.episodeslist.FeedItemMenuHandler;
+import de.danoeh.antennapod.ui.episodeslist.MoreContentListFooterUtil;
+import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
+import de.danoeh.antennapod.ui.screen.SearchFragment;
+import de.danoeh.antennapod.ui.screen.download.DownloadLogDetailsDialog;
+import de.danoeh.antennapod.ui.screen.download.DownloadLogFragment;
+import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
+import de.danoeh.antennapod.ui.screen.feed.preferences.FeedSettingsFragment;
+import de.danoeh.antennapod.ui.share.ShareUtils;
+import de.danoeh.antennapod.ui.swipeactions.SwipeActions;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
/**
* Displays a list of FeedItems.
@@ -100,7 +98,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
private boolean displayUpArrow;
private long feedID;
private Feed feed;
- private boolean headerCreated = false;
private Disposable disposable;
private FeedItemListFragmentBinding viewBinding;
@@ -145,12 +142,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
if (savedInstanceState != null) {
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
}
- ((MainActivity) getActivity()).setupToolbarToggle(viewBinding.toolbar, displayUpArrow);
+ if (getActivity() instanceof MainActivity) {
+ ((MainActivity) getActivity()).setupToolbarToggle(viewBinding.toolbar, displayUpArrow);
+ viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
+ } else {
+ viewBinding.toolbar.setNavigationIcon(R.drawable.ic_close);
+ viewBinding.toolbar.setNavigationOnClickListener(view -> getActivity().finish());
+ }
updateToolbar();
setupLoadMoreScrollListener();
+ setupHeaderView();
- viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
- adapter = new FeedItemListAdapter((MainActivity) getActivity());
+ adapter = new FeedItemListAdapter(getActivity());
adapter.setOnSelectModeListener(this);
viewBinding.recyclerView.setAdapter(adapter);
swipeActions = new SwipeActions(this, TAG).attachTo(viewBinding.recyclerView);
@@ -198,7 +201,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
Snackbar.LENGTH_SHORT);
return false;
}
- new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), menuItem.getItemId())
+ new EpisodeMultiSelectActionHandler(getActivity(), menuItem.getItemId())
.handleAction(adapter.getSelectedItems());
adapter.endSelectMode();
return true;
@@ -249,6 +252,13 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
if (feed.isLocalFeed()) {
viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(false);
}
+ if (feed.getState() == Feed.STATE_NOT_SUBSCRIBED) {
+ viewBinding.toolbar.getMenu().findItem(R.id.sort_items).setVisible(false);
+ viewBinding.toolbar.getMenu().findItem(R.id.refresh_item).setVisible(false);
+ viewBinding.toolbar.getMenu().findItem(R.id.rename_item).setVisible(false);
+ viewBinding.toolbar.getMenu().findItem(R.id.remove_feed).setVisible(false);
+ viewBinding.toolbar.getMenu().findItem(R.id.action_search).setVisible(false);
+ }
}
@Override
@@ -263,8 +273,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
@Override
public boolean onMenuItemClick(MenuItem item) {
if (feed == null) {
- ((MainActivity) getActivity()).showSnackbarAbovePlayer(
- R.string.please_wait_for_data, Toast.LENGTH_LONG);
+ EventBus.getDefault().post(getString(R.string.please_wait_for_data));
return true;
}
if (item.getItemId() == R.id.visit_website_item) {
@@ -443,7 +452,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
private void refreshHeaderView() {
- setupHeaderView();
if (viewBinding == null || feed == null) {
Log.e(TAG, "Unable to refresh header view");
return;
@@ -454,7 +462,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
} else {
viewBinding.header.txtvFailure.setVisibility(View.GONE);
}
- if (!feed.getPreferences().getKeepUpdated()) {
+ if (!feed.getPreferences().getKeepUpdated() && feed.getState() == Feed.STATE_SUBSCRIBED) {
viewBinding.header.txtvUpdatesDisabled.setText(R.string.updates_disabled_label);
viewBinding.header.txtvUpdatesDisabled.setVisibility(View.VISIBLE);
} else {
@@ -462,7 +470,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
viewBinding.header.txtvTitle.setText(feed.getTitle());
viewBinding.header.txtvAuthor.setText(feed.getAuthor());
- if (feed.getItemFilter() != null) {
+ viewBinding.header.descriptionContainer.setVisibility(View.GONE);
+ if (feed.getState() != Feed.STATE_SUBSCRIBED) {
+ viewBinding.header.descriptionContainer.setVisibility(View.VISIBLE);
+ viewBinding.header.headerDescriptionLabel.setText(HtmlToPlainText.getPlainText(feed.getDescription()));
+ } else if (feed.getItemFilter() != null) {
FeedItemFilter filter = feed.getItemFilter();
if (filter.getValues().length > 0) {
viewBinding.header.txtvInformation.setText(R.string.filtered_label);
@@ -475,17 +487,30 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
} else {
viewBinding.header.txtvInformation.setVisibility(View.GONE);
}
- }
+ boolean isSubscribed = feed.getState() == Feed.STATE_SUBSCRIBED;
+ viewBinding.header.butShowInfo.setVisibility(isSubscribed ? View.VISIBLE : View.GONE);
+ viewBinding.header.butFilter.setVisibility(isSubscribed ? View.VISIBLE : View.GONE);
+ viewBinding.header.butShowSettings.setVisibility(isSubscribed ? View.VISIBLE : View.GONE);
+ viewBinding.header.butSubscribe.setVisibility(isSubscribed ? View.GONE : View.VISIBLE);
- private void setupHeaderView() {
- if (feed == null || headerCreated) {
- return;
+ if (!isSubscribed && feed.getLastRefreshAttempt() < System.currentTimeMillis() - 1000L * 3600 * 24) {
+ FeedUpdateManager.getInstance().runOnce(getContext(), feed, true);
}
+ }
+ private void setupHeaderView() {
// https://github.com/bumptech/glide/issues/529
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff666666, 0x000000));
viewBinding.header.butShowInfo.setOnClickListener(v -> showFeedInfo());
viewBinding.header.imgvCover.setOnClickListener(v -> showFeedInfo());
+ viewBinding.header.headerDescriptionLabel.setOnClickListener(v -> showFeedInfo());
+ viewBinding.header.butSubscribe.setOnClickListener(view -> {
+ DBWriter.setFeedState(getContext(), feed, Feed.STATE_SUBSCRIBED);
+ MainActivityStarter mainActivityStarter = new MainActivityStarter(getContext());
+ mainActivityStarter.withOpenFeed(feed.getId());
+ getActivity().finish();
+ startActivity(mainActivityStarter.getIntent());
+ });
viewBinding.header.butShowSettings.setOnClickListener(v -> {
if (feed != null) {
FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed);
@@ -495,7 +520,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
viewBinding.header.butFilter.setOnClickListener(v ->
FeedItemFilterDialog.newInstance(feed).show(getChildFragmentManager(), null));
viewBinding.header.txtvFailure.setOnClickListener(v -> showErrorDetails());
- headerCreated = true;
}
private void showErrorDetails() {
@@ -516,9 +540,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
private void showFeedInfo() {
- if (feed != null) {
- FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
+ if (feed == null) {
+ return;
+ }
+ FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
+ if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
+ } else {
+ getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragmentContainer, fragment, "Info")
+ .addToBackStack("Info")
+ .commitAllowingStateLoss();
}
}
@@ -625,7 +658,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
private class FeedItemListAdapter extends EpisodeItemListAdapter {
- public FeedItemListAdapter(MainActivity mainActivity) {
+ public FeedItemListAdapter(FragmentActivity mainActivity) {
super(mainActivity);
}
@@ -648,7 +681,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
- if (!inActionMode()) {
+ if (!inActionMode() && feed.getState() == Feed.STATE_SUBSCRIBED) {
menu.findItem(R.id.multi_select).setVisible(true);
}
MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected);
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/home/sections/DownloadsSection.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/home/sections/DownloadsSection.java
index cc3288e2f..06de7803a 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/home/sections/DownloadsSection.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/home/sections/DownloadsSection.java
@@ -39,6 +39,8 @@ import java.util.List;
public class DownloadsSection extends HomeSection {
public static final String TAG = "DownloadsSection";
private static final int NUM_EPISODES = 2;
+ private static final FeedItemFilter FILTER_DOWNLOADED = new FeedItemFilter(
+ FeedItemFilter.DOWNLOADED, FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
private EpisodeItemListAdapter adapter;
private List<FeedItem> items;
private Disposable disposable;
@@ -52,7 +54,7 @@ public class DownloadsSection extends HomeSection {
viewBinding.recyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) requireActivity()).getRecycledViewPool());
- adapter = new EpisodeItemListAdapter((MainActivity) requireActivity()) {
+ adapter = new EpisodeItemListAdapter(requireActivity()) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
@@ -124,8 +126,7 @@ public class DownloadsSection extends HomeSection {
disposable.dispose();
}
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
- disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, NUM_EPISODES,
- new FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder))
+ disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, NUM_EPISODES, FILTER_DOWNLOADED, sortOrder))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(downloads -> {
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/FeedItemlistDescriptionAdapter.java
deleted file mode 100644
index f46d786cf..000000000
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/FeedItemlistDescriptionAdapter.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package de.danoeh.antennapod.ui.screen.onlinefeedview;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.model.playback.MediaType;
-import de.danoeh.antennapod.net.common.NetworkUtils;
-import de.danoeh.antennapod.model.playback.RemoteMedia;
-import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.playback.service.PlaybackService;
-import de.danoeh.antennapod.playback.service.PlaybackServiceStarter;
-import de.danoeh.antennapod.ui.common.DateFormatter;
-import de.danoeh.antennapod.model.playback.Playable;
-import de.danoeh.antennapod.ui.cleaner.HtmlToPlainText;
-import de.danoeh.antennapod.ui.StreamingConfirmationDialog;
-
-import java.util.List;
-
-/**
- * List adapter for showing a list of FeedItems with their title and description.
- */
-public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
- private static final int MAX_LINES_COLLAPSED = 2;
-
- public FeedItemlistDescriptionAdapter(Context context, int resource, List<FeedItem> objects) {
- super(context, resource, objects);
- }
-
- @NonNull
- @Override
- public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- Holder holder;
-
- FeedItem item = getItem(position);
-
- // Inflate layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false);
- holder.title = convertView.findViewById(R.id.txtvTitle);
- holder.pubDate = convertView.findViewById(R.id.txtvPubDate);
- holder.description = convertView.findViewById(R.id.txtvDescription);
- holder.preview = convertView.findViewById(R.id.butPreview);
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- holder.title.setText(item.getTitle());
- holder.pubDate.setText(DateFormatter.formatAbbrev(getContext(), item.getPubDate()));
- if (item.getDescription() != null) {
- String description = HtmlToPlainText.getPlainText(item.getDescription())
- .replaceAll("\n", " ")
- .replaceAll("\\s+", " ")
- .trim();
- holder.description.setText(description);
- holder.description.setMaxLines(MAX_LINES_COLLAPSED);
- }
- holder.description.setTag(Boolean.FALSE); // not expanded
- holder.preview.setVisibility(View.GONE);
- holder.preview.setOnClickListener(v -> {
- if (item.getMedia() == null) {
- return;
- }
- Playable playable = new RemoteMedia(item);
- if (!NetworkUtils.isStreamingAllowed()) {
- new StreamingConfirmationDialog(getContext(), playable).show();
- return;
- }
-
- new PlaybackServiceStarter(getContext(), playable)
- .callEvenIfRunning(true)
- .start();
-
- if (playable.getMediaType() == MediaType.VIDEO) {
- getContext().startActivity(PlaybackService.getPlayerActivityIntent(getContext(), playable));
- }
- });
- convertView.setOnClickListener(v -> {
- if (holder.description.getTag() == Boolean.TRUE) {
- holder.description.setMaxLines(MAX_LINES_COLLAPSED);
- holder.preview.setVisibility(View.GONE);
- holder.description.setTag(Boolean.FALSE);
- } else {
- holder.description.setMaxLines(30);
- holder.description.setTag(Boolean.TRUE);
-
- holder.preview.setVisibility(item.getMedia() != null ? View.VISIBLE : View.GONE);
- holder.preview.setText(R.string.preview_episode);
- }
- });
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView pubDate;
- TextView description;
- Button preview;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/OnlineFeedViewActivity.java
index 7b8558c3d..be601027c 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/onlinefeedview/OnlineFeedViewActivity.java
@@ -4,8 +4,6 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.LightingColorFilter;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
@@ -13,68 +11,45 @@ import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.appcompat.app.AppCompatActivity;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
-import com.google.android.material.snackbar.Snackbar;
-
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.net.download.service.feed.remote.Downloader;
-import de.danoeh.antennapod.net.download.service.feed.remote.HttpDownloader;
-import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestCreator;
-import de.danoeh.antennapod.net.discovery.FeedUrlNotFoundException;
-import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
-import de.danoeh.antennapod.playback.service.PlaybackServiceInterface;
-import de.danoeh.antennapod.ui.screen.download.DownloadErrorLabel;
import de.danoeh.antennapod.databinding.EditTextDialogBinding;
-import de.danoeh.antennapod.databinding.OnlinefeedviewHeaderBinding;
-import de.danoeh.antennapod.event.EpisodeDownloadEvent;
-import de.danoeh.antennapod.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.event.PlayerStatusEvent;
-import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
+import de.danoeh.antennapod.model.download.DownloadError;
import de.danoeh.antennapod.model.download.DownloadRequest;
import de.danoeh.antennapod.model.download.DownloadResult;
-import de.danoeh.antennapod.storage.database.DBReader;
-import de.danoeh.antennapod.storage.database.DBWriter;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.net.common.UrlChecker;
import de.danoeh.antennapod.net.discovery.CombinedSearcher;
+import de.danoeh.antennapod.net.discovery.FeedUrlNotFoundException;
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
import de.danoeh.antennapod.net.discovery.PodcastSearcherRegistry;
+import de.danoeh.antennapod.net.download.service.feed.remote.Downloader;
+import de.danoeh.antennapod.net.download.service.feed.remote.HttpDownloader;
+import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestCreator;
import de.danoeh.antennapod.parser.feed.FeedHandler;
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
-import de.danoeh.antennapod.model.download.DownloadError;
-import de.danoeh.antennapod.ui.common.IntentUtils;
-import de.danoeh.antennapod.net.common.UrlChecker;
-import de.danoeh.antennapod.ui.cleaner.HtmlToPlainText;
-import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.playback.RemoteMedia;
import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.database.DBWriter;
+import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
+import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
+import de.danoeh.antennapod.ui.common.ThemeSwitcher;
import de.danoeh.antennapod.ui.common.ThemeUtils;
-import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
import de.danoeh.antennapod.ui.preferences.screen.synchronization.AuthenticationDialog;
+import de.danoeh.antennapod.ui.screen.download.DownloadErrorLabel;
+import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
-import io.reactivex.observers.DisposableMaybeObserver;
import io.reactivex.schedulers.Schedulers;
-import org.apache.commons.lang3.StringUtils;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
import java.io.File;
import java.io.IOException;
@@ -95,30 +70,16 @@ import static de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStart
* and the activity will finish as soon as the error dialog is closed.
*/
public class OnlineFeedViewActivity extends AppCompatActivity {
-
- private static final int RESULT_ERROR = 2;
private static final String TAG = "OnlineFeedViewActivity";
- private static final String PREFS = "OnlineFeedViewActivityPreferences";
- private static final String PREF_LAST_AUTO_DOWNLOAD = "lastAutoDownload";
- private static final int DESCRIPTION_MAX_LINES_COLLAPSED = 4;
-
- private volatile List<Feed> feeds;
private String selectedDownloadUrl;
private Downloader downloader;
private String username = null;
private String password = null;
-
private boolean isPaused;
- private boolean didPressSubscribe = false;
private boolean isFeedFoundBySearch = false;
-
private Dialog dialog;
-
private Disposable download;
private Disposable parser;
- private Disposable updater;
-
- private OnlinefeedviewHeaderBinding headerBinding;
private OnlinefeedviewActivityBinding viewBinding;
@Override
@@ -128,12 +89,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
viewBinding = OnlinefeedviewActivityBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
-
viewBinding.transparentBackground.setOnClickListener(v -> finish());
- viewBinding.closeButton.setOnClickListener(view -> finish());
viewBinding.card.setOnClickListener(null);
viewBinding.card.setCardBackgroundColor(ThemeUtils.getColorFromAttr(this, R.attr.colorSurface));
- headerBinding = OnlinefeedviewHeaderBinding.inflate(getLayoutInflater());
String feedUrl = null;
if (getIntent().hasExtra(ARG_FEEDURL)) {
@@ -149,7 +107,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
showNoPodcastFoundError();
} else {
Log.d(TAG, "Activity was started with url " + feedUrl);
- setLoadingLayout();
// Remove subscribeonandroid.com from feed URL in order to subscribe to the actual feed URL
if (feedUrl.contains("subscribeonandroid.com")) {
feedUrl = feedUrl.replaceFirst("((www.)?(subscribeonandroid.com/))", "");
@@ -167,33 +124,20 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
.setNeutralButton(android.R.string.ok, (dialog, which) -> finish())
.setTitle(R.string.error_label)
.setMessage(R.string.null_value_podcast_error)
- .setOnDismissListener(dialog1 -> {
- setResult(RESULT_ERROR);
- finish();
- })
+ .setOnDismissListener(dialog1 -> finish())
.show());
}
- /**
- * Displays a progress indicator.
- */
- private void setLoadingLayout() {
- viewBinding.progressBar.setVisibility(View.VISIBLE);
- viewBinding.feedDisplayContainer.setVisibility(View.GONE);
- }
-
@Override
protected void onStart() {
super.onStart();
isPaused = false;
- EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
isPaused = true;
- EventBus.getDefault().unregister(this);
if (downloader != null && !downloader.isFinished()) {
downloader.cancel();
}
@@ -205,9 +149,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
@Override
public void onDestroy() {
super.onDestroy();
- if(updater != null) {
- updater.dispose();
- }
if(download != null) {
download.dispose();
}
@@ -239,7 +180,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
download = PodcastSearcherRegistry.lookupUrl(url)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
- .subscribe(this::startFeedDownload,
+ .subscribe(this::downloadIfNotAlreadySubscribed,
error -> {
if (error instanceof FeedUrlNotFoundException) {
tryToRetrieveFeedUrlBySearch((FeedUrlNotFoundException) error);
@@ -256,7 +197,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (url != null) {
Log.d(TAG, "Successfully retrieve feed url");
isFeedFoundBySearch = true;
- startFeedDownload(url);
+ downloadIfNotAlreadySubscribed(url);
} else {
showNoPodcastFoundError();
Log.d(TAG, "Failed to retrieve feed url");
@@ -277,6 +218,28 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
return null;
}
+ private Feed downloadIfNotAlreadySubscribed(String url) {
+ download = Maybe.fromCallable(() -> {
+ List<Feed> feeds = DBReader.getFeedList();
+ for (Feed f : feeds) {
+ if (f.getDownloadUrl().equals(url)) {
+ return f;
+ }
+ }
+ return null;
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(subscribedFeed -> {
+ if (subscribedFeed.getState() == Feed.STATE_SUBSCRIBED) {
+ openFeed(subscribedFeed.getId());
+ } else {
+ showFeedFragment(subscribedFeed.getId());
+ }
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)), () -> startFeedDownload(url));
+ return null;
+ }
+
private void startFeedDownload(String url) {
Log.d(TAG, "Starting feed download");
selectedDownloadUrl = UrlChecker.prepareUrl(url);
@@ -286,7 +249,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
.build();
download = Observable.fromCallable(() -> {
- feeds = DBReader.getFeedList();
downloader = new HttpDownloader(request);
downloader.call();
return downloader.getResult();
@@ -315,46 +277,25 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
}
- @Subscribe
- public void onFeedListChanged(FeedListUpdateEvent event) {
- updater = Observable.fromCallable(DBReader::getFeedList)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- feeds -> {
- OnlineFeedViewActivity.this.feeds = feeds;
- handleUpdatedFeedStatus();
- }, error -> Log.e(TAG, Log.getStackTraceString(error))
- );
- }
-
- @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
- public void onEventMainThread(EpisodeDownloadEvent event) {
- handleUpdatedFeedStatus();
- }
-
private void parseFeed(String destination) {
Log.d(TAG, "Parsing feed");
- parser = Maybe.fromCallable(() -> doParseFeed(destination))
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableMaybeObserver<FeedHandlerResult>() {
- @Override
- public void onSuccess(@NonNull FeedHandlerResult result) {
- showFeedInformation(result.feed, result.alternateFeedUrls);
- }
-
- @Override
- public void onComplete() {
- // Ignore null result: We showed the discovery dialog.
- }
-
- @Override
- public void onError(@NonNull Throwable error) {
- showErrorDialog(error.getMessage(), "");
- Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
- }
- });
+ parser = Observable.fromCallable(() -> {
+ FeedHandlerResult handlerResult = doParseFeed(destination);
+ Feed feed = handlerResult.feed;
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ feed.setLastRefreshAttempt(System.currentTimeMillis());
+ FeedDatabaseWriter.updateFeed(this, feed, false);
+ Feed feedFromDb = DBReader.getFeed(feed.getId(), false, 0, Integer.MAX_VALUE);
+ feedFromDb.getPreferences().setKeepUpdated(false);
+ DBWriter.setFeedPreferences(feedFromDb.getPreferences());
+ return feed.getId();
+ })
+ .subscribeOn(Schedulers.computation())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::showFeedFragment, error -> {
+ error.printStackTrace();
+ showErrorDialog(error.getMessage(), "");
+ });
}
/**
@@ -392,123 +333,23 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
}
- /**
- * Called when feed parsed successfully.
- * This method is executed on the GUI thread.
- */
- private void showFeedInformation(final Feed feed, Map<String, String> alternateFeedUrls) {
- viewBinding.progressBar.setVisibility(View.GONE);
- viewBinding.feedDisplayContainer.setVisibility(View.VISIBLE);
+ private void showFeedFragment(long id) {
if (isFeedFoundBySearch) {
- int resId = R.string.no_feed_url_podcast_found_by_search;
- Snackbar.make(findViewById(android.R.id.content), resId, Snackbar.LENGTH_LONG).show();
- }
-
- viewBinding.backgroundImage.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
-
- viewBinding.listView.addHeaderView(headerBinding.getRoot());
- viewBinding.listView.setSelector(android.R.color.transparent);
- viewBinding.listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
-
- if (StringUtils.isNotBlank(feed.getImageUrl())) {
- Glide.with(this)
- .load(feed.getImageUrl())
- .apply(new RequestOptions()
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .fitCenter()
- .dontAnimate())
- .into(viewBinding.coverImage);
- Glide.with(this)
- .load(feed.getImageUrl())
- .apply(new RequestOptions()
- .placeholder(R.color.image_readability_tint)
- .error(R.color.image_readability_tint)
- .transform(new FastBlurTransformation())
- .dontAnimate())
- .into(viewBinding.backgroundImage);
- }
-
- viewBinding.titleLabel.setText(feed.getTitle());
- viewBinding.authorLabel.setText(feed.getAuthor());
- headerBinding.txtvDescription.setText(HtmlToPlainText.getPlainText(feed.getDescription()));
-
- viewBinding.subscribeButton.setOnClickListener(v -> {
- if (feedInFeedlist()) {
- openFeed();
- } else {
- FeedDatabaseWriter.updateFeed(this, feed, false);
- didPressSubscribe = true;
- handleUpdatedFeedStatus();
- }
- });
-
- viewBinding.stopPreviewButton.setOnClickListener(v -> {
- PlaybackPreferences.writeNoMediaPlaying();
- IntentUtils.sendLocalBroadcast(this, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
- });
-
- if (UserPreferences.isEnableAutodownload()) {
- SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE);
- viewBinding.autoDownloadCheckBox.setChecked(preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true));
+ Toast.makeText(this, R.string.no_feed_url_podcast_found_by_search, Toast.LENGTH_LONG).show();
}
- headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
- headerBinding.txtvDescription.setOnClickListener(v -> {
- if (headerBinding.txtvDescription.getMaxLines() > DESCRIPTION_MAX_LINES_COLLAPSED) {
- headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
- } else {
- headerBinding.txtvDescription.setMaxLines(2000);
- }
- });
-
- if (alternateFeedUrls.isEmpty()) {
- viewBinding.alternateUrlsSpinner.setVisibility(View.GONE);
- } else {
- viewBinding.alternateUrlsSpinner.setVisibility(View.VISIBLE);
-
- final List<String> alternateUrlsList = new ArrayList<>();
- final List<String> alternateUrlsTitleList = new ArrayList<>();
-
- alternateUrlsList.add(feed.getDownloadUrl());
- alternateUrlsTitleList.add(feed.getTitle());
-
-
- alternateUrlsList.addAll(alternateFeedUrls.keySet());
- for (String url : alternateFeedUrls.keySet()) {
- alternateUrlsTitleList.add(alternateFeedUrls.get(url));
- }
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- R.layout.alternate_urls_item, alternateUrlsTitleList) {
- @Override
- public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- // reusing the old view causes a visual bug on Android <= 10
- return super.getDropDownView(position, null, parent);
- }
- };
-
- adapter.setDropDownViewResource(R.layout.alternate_urls_dropdown_item);
- viewBinding.alternateUrlsSpinner.setAdapter(adapter);
- viewBinding.alternateUrlsSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- selectedDownloadUrl = alternateUrlsList.get(position);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
- });
- }
- handleUpdatedFeedStatus();
+ viewBinding.progressBar.setVisibility(View.GONE);
+ FeedItemlistFragment fragment = FeedItemlistFragment.newInstance(id);
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragmentContainer, fragment, FeedItemlistFragment.TAG)
+ .commitAllowingStateLoss();
}
- private void openFeed() {
+ private void openFeed(long feedId) {
// feed.getId() is always 0, we have to retrieve the id from the feed list from the database
MainActivityStarter mainActivityStarter = new MainActivityStarter(this);
- mainActivityStarter.withOpenFeed(getFeedId());
+ mainActivityStarter.withOpenFeed(feedId);
if (getIntent().getBooleanExtra(ARG_STARTED_FROM_SEARCH, false)) {
mainActivityStarter.withAddToBackStack();
}
@@ -516,60 +357,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
startActivity(mainActivityStarter.getIntent());
}
- private void handleUpdatedFeedStatus() {
- if (DownloadServiceInterface.get().isDownloadingEpisode(selectedDownloadUrl)) {
- viewBinding.subscribeButton.setEnabled(false);
- viewBinding.subscribeButton.setText(R.string.subscribing_label);
- } else if (feedInFeedlist()) {
- viewBinding.subscribeButton.setEnabled(true);
- viewBinding.subscribeButton.setText(R.string.open_podcast);
- if (didPressSubscribe) {
- didPressSubscribe = false;
-
- Feed feed1 = DBReader.getFeed(getFeedId(), false, 0, 0);
- FeedPreferences feedPreferences = feed1.getPreferences();
- if (UserPreferences.isEnableAutodownload()) {
- boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked();
- feedPreferences.setAutoDownload(autoDownload);
-
- SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE);
- SharedPreferences.Editor editor = preferences.edit();
- editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload);
- editor.apply();
- }
- if (username != null) {
- feedPreferences.setUsername(username);
- feedPreferences.setPassword(password);
- }
- DBWriter.setFeedPreferences(feedPreferences);
-
- openFeed();
- }
- } else {
- viewBinding.subscribeButton.setEnabled(true);
- viewBinding.subscribeButton.setText(R.string.subscribe_label);
- if (UserPreferences.isEnableAutodownload()) {
- viewBinding.autoDownloadCheckBox.setVisibility(View.VISIBLE);
- }
- }
- }
-
- private boolean feedInFeedlist() {
- return getFeedId() != 0;
- }
-
- private long getFeedId() {
- if (feeds == null) {
- return 0;
- }
- for (Feed f : feeds) {
- if (f.getDownloadUrl().equals(selectedDownloadUrl)) {
- return f.getId();
- }
- }
- return 0;
- }
-
@UiThread
private void showErrorDialog(String errorMsg, String details) {
if (!isFinishing() && !isPaused) {
@@ -589,7 +376,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
builder.setNeutralButton(R.string.edit_url_menu, (dialog, which) -> editUrl());
}
builder.setOnCancelListener(dialog -> {
- setResult(RESULT_ERROR);
finish();
});
if (dialog != null && dialog.isShowing()) {
@@ -608,24 +394,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
builder.setView(dialogBinding.getRoot());
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- setLoadingLayout();
lookupUrlAndDownload(dialogBinding.urlEditText.getText().toString());
});
builder.setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel());
builder.setOnCancelListener(dialog1 -> {
- setResult(RESULT_ERROR);
finish();
});
builder.show();
}
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void playbackStateChanged(PlayerStatusEvent event) {
- boolean isPlayingPreview =
- PlaybackPreferences.getCurrentlyPlayingMediaType() == RemoteMedia.PLAYABLE_TYPE_REMOTE_MEDIA;
- viewBinding.stopPreviewButton.setVisibility(isPlayingPreview ? View.VISIBLE : View.GONE);
- }
-
/**
*
* @return true if a FeedDiscoveryDialog is shown, false otherwise (e.g., due to no feed found).
@@ -657,7 +434,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (urls.size() == 1) {
// Skip dialog and display the item directly
resetIntent(urls.get(0));
- startFeedDownload(urls.get(0));
+ downloadIfNotAlreadySubscribed(urls.get(0));
return true;
}
@@ -667,7 +444,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
String selectedUrl = urls.get(which);
dialog.dismiss();
resetIntent(selectedUrl);
- startFeedDownload(selectedUrl);
+ downloadIfNotAlreadySubscribed(selectedUrl);
};
MaterialAlertDialogBuilder ab = new MaterialAlertDialogBuilder(OnlineFeedViewActivity.this)
@@ -704,7 +481,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
protected void onConfirmed(String username, String password) {
OnlineFeedViewActivity.this.username = username;
OnlineFeedViewActivity.this.password = password;
- startFeedDownload(feedUrl);
+ downloadIfNotAlreadySubscribed(feedUrl);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
index e66ed6d3e..7aa9da503 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
@@ -25,8 +25,10 @@ import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.elevation.SurfaceColors;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.playback.service.PlaybackController;
import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
+import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
import de.danoeh.antennapod.ui.episodes.PlaybackSpeedUtils;
import de.danoeh.antennapod.ui.episodes.TimeSpeedConverter;
@@ -497,14 +499,25 @@ public class AudioPlayerFragment extends Fragment implements
return true;
} else if (itemId == R.id.open_feed_item) {
if (feedItem != null) {
- Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feedItem.getFeedId());
- startActivity(intent);
+ openFeed(feedItem.getFeed());
}
return true;
}
return false;
}
+ private void openFeed(Feed feed) {
+ if (feed == null) {
+ return;
+ }
+ if (feed.getState() == Feed.STATE_SUBSCRIBED) {
+ Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feed.getId());
+ startActivity(intent);
+ } else {
+ startActivity(new OnlineFeedviewActivityStarter(getContext(), feed.getDownloadUrl()).getIntent());
+ }
+ }
+
public void fadePlayerToToolbar(float slideOffset) {
float playerFadeProgress = Math.max(0.0f, Math.min(0.2f, slideOffset - 0.2f)) / 0.2f;
View player = getView().findViewById(R.id.playerFragment);
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java
index 073d5b0be..d4931380e 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java
@@ -32,6 +32,8 @@ import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
import de.danoeh.antennapod.ui.screen.chapter.ChaptersFragment;
import de.danoeh.antennapod.playback.service.PlaybackController;
@@ -122,9 +124,7 @@ public class CoverFragment extends Fragment {
+ "\u00A0"
+ StringUtils.replace(StringUtils.stripToEmpty(pubDateStr), " ", "\u00A0"));
if (media instanceof FeedMedia) {
- Intent openFeed = MainActivity.getIntentToOpenFeed(requireContext(),
- ((FeedMedia) media).getItem().getFeedId());
- viewBinding.txtvPodcastTitle.setOnClickListener(v -> startActivity(openFeed));
+ viewBinding.txtvPodcastTitle.setOnClickListener(v -> openFeed(((FeedMedia) media).getItem().getFeed()));
} else {
viewBinding.txtvPodcastTitle.setOnClickListener(null);
}
@@ -164,6 +164,18 @@ public class CoverFragment extends Fragment {
updateChapterControlVisibility();
}
+ private void openFeed(Feed feed) {
+ if (feed == null) {
+ return;
+ }
+ if (feed.getState() == Feed.STATE_SUBSCRIBED) {
+ Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feed.getId());
+ startActivity(intent);
+ } else {
+ startActivity(new OnlineFeedviewActivityStarter(getContext(), feed.getDownloadUrl()).getIntent());
+ }
+ }
+
private void updateChapterControlVisibility() {
boolean chapterControlVisible = false;
if (media.getChapters() != null) {
diff --git a/app/src/main/res/layout/alternate_urls_dropdown_item.xml b/app/src/main/res/layout/alternate_urls_dropdown_item.xml
deleted file mode 100644
index 3c4dcc7fc..000000000
--- a/app/src/main/res/layout/alternate_urls_dropdown_item.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<CheckedTextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingVertical="8dp"
- style="?android:attr/spinnerDropDownItemStyle" />
diff --git a/app/src/main/res/layout/alternate_urls_item.xml b/app/src/main/res/layout/alternate_urls_item.xml
deleted file mode 100644
index 54e05b49d..000000000
--- a/app/src/main/res/layout/alternate_urls_item.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLines="3"
- android:textAlignment="inherit"
- style="?android:attr/spinnerItemStyle" />
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index d1acc1e37..7b7937b9d 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -65,13 +65,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:paddingTop="16dp"
android:paddingHorizontal="@dimen/additional_horizontal_spacing">
<TextView
android:id="@+id/statisticsHeadingLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:textSize="18sp"
android:layout_marginBottom="8dp"
android:text="@string/statistics_label"
@@ -89,6 +89,7 @@
android:layout_height="wrap_content"
android:minWidth="0dp"
android:minHeight="0dp"
+ android:layout_marginBottom="16dp"
android:text="@string/statistics_view_all"
style="@style/Widget.MaterialComponents.Button.TextButton" />
@@ -96,7 +97,6 @@
android:id="@+id/supportHeadingLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:layout_marginBottom="4dp"
android:text="@string/support_funding_label"
android:textColor="?android:attr/textColorPrimary"
@@ -119,7 +119,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
- android:layout_marginTop="16dp"
android:layout_marginBottom="4dp"
android:text="@string/description_label"
android:textColor="?android:attr/textColorPrimary"
@@ -129,7 +128,6 @@
android:id="@+id/descriptionLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/design_time_lorem_ipsum"
android:textIsSelectable="true"
tools:background="@android:color/holo_green_dark" />
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index 37db9067c..df95b8c15 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -175,6 +175,20 @@
</LinearLayout>
<TextView
+ android:id="@+id/nonSubscribedWarningLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="8dp"
+ android:layout_marginBottom="8dp"
+ android:paddingHorizontal="16dp"
+ android:paddingVertical="8dp"
+ android:background="@drawable/bg_message_info"
+ android:textColor="?attr/colorAccent"
+ android:visibility="gone"
+ android:foreground="?attr/selectableItemBackground"
+ android:text="@string/state_deleted_not_subscribed" />
+
+ <TextView
android:id="@+id/noMediaLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index d28f7dae8..f44a3233e 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -28,6 +28,14 @@
android:layout_width="148dp"
android:layout_height="match_parent" />
+ <Button
+ android:id="@+id/butSubscribe"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/subscribe_label"
+ android:visibility="gone"
+ tools:visibility="visible" />
+
<ImageButton
android:id="@+id/butShowInfo"
android:layout_width="40dp"
@@ -187,4 +195,52 @@
</LinearLayout>
+ <LinearLayout
+ android:id="@+id/descriptionContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="16dp"
+ android:background="?android:attr/colorBackground"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="16dp"
+ android:paddingHorizontal="16dp"
+ android:paddingVertical="8dp"
+ android:background="@drawable/bg_message_info"
+ android:textColor="?attr/colorAccent"
+ android:text="@string/state_deleted_not_subscribed" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:text="@string/description_label"
+ style="@style/TextAppearance.Material3.TitleMedium" />
+
+ <TextView
+ android:id="@+id/headerDescriptionLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:lineHeight="20dp"
+ android:maxLines="3"
+ android:layout_marginBottom="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ style="@style/AntennaPod.TextView.ListItemBody"
+ tools:text="@string/design_time_lorem_ipsum" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/preview_episodes"
+ android:layout_marginBottom="8dp"
+ style="@style/TextAppearance.Material3.TitleMedium" />
+
+ </LinearLayout>
+
</LinearLayout>
diff --git a/app/src/main/res/layout/itemdescription_listitem.xml b/app/src/main/res/layout/itemdescription_listitem.xml
deleted file mode 100644
index c3f8c24b8..000000000
--- a/app/src/main/res/layout/itemdescription_listitem.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingHorizontal="20dp"
- android:paddingVertical="16dp">
-
- <TextView
- android:id="@+id/txtvPubDate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:lines="1"
- style="@android:style/TextAppearance.Small"
- tools:text="22 Jan 2016"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginVertical="12dp"
- android:ellipsize="end"
- android:maxLines="2"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- tools:text="Feed item title"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvDescription"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:maxLines="2"
- style="@style/AntennaPod.TextView.ListItemBody"
- tools:text="Feed item description"
- tools:background="@android:color/holo_green_dark" />
-
- <Button
- android:id="@+id/butPreview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/preview_episode"
- android:layout_gravity="end|right"
- style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
-
-</LinearLayout>
diff --git a/app/src/main/res/layout/onlinefeedview_activity.xml b/app/src/main/res/layout/onlinefeedview_activity.xml
index 88b87da1a..a121c9e0e 100644
--- a/app/src/main/res/layout/onlinefeedview_activity.xml
+++ b/app/src/main/res/layout/onlinefeedview_activity.xml
@@ -2,7 +2,6 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/transparentBackground"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -11,169 +10,22 @@
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="24dp"
+ android:layout_marginHorizontal="16dp"
+ android:layout_marginVertical="56dp"
android:elevation="16dp"
app:cardCornerRadius="8dp">
- <FrameLayout
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <ProgressBar
- android:id="@+id/progressBar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="?android:attr/progressBarStyle" />
-
- <LinearLayout
- android:id="@+id/feed_display_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/feeditemlist_header_height"
- android:layout_marginBottom="12dp"
- android:background="@color/feed_image_bg">
-
- <ImageView
- android:id="@+id/backgroundImage"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerCrop" />
-
- <ImageView
- android:id="@+id/coverImage"
- android:layout_width="@dimen/thumbnail_length_onlinefeedview"
- android:layout_height="@dimen/thumbnail_length_onlinefeedview"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginBottom="12dp"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginTop="24dp"
- android:background="@drawable/bg_rounded_corners"
- android:clipToOutline="true"
- android:importantForAccessibility="no"
- tools:src="@tools:sample/avatars" />
-
- <TextView
- android:id="@+id/titleLabel"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginTop="24dp"
- android:layout_marginRight="24dp"
- android:layout_marginEnd="24dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_toRightOf="@id/coverImage"
- android:layout_toEndOf="@id/coverImage"
- android:ellipsize="end"
- android:maxLines="2"
- android:shadowColor="@color/black"
- android:shadowRadius="3"
- android:textColor="@color/white"
- android:textSize="20sp"
- android:textFontWeight="800"
- tools:text="Podcast title" />
-
- <TextView
- android:id="@+id/author_label"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_below="@id/titleLabel"
- android:layout_marginBottom="16dp"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_toRightOf="@id/coverImage"
- android:layout_toEndOf="@id/coverImage"
- android:ellipsize="end"
- android:lines="1"
- android:shadowColor="@color/black"
- android:shadowRadius="3"
- android:textColor="@color/white"
- android:textSize="@dimen/text_size_small"
- tools:text="Podcast author" />
-
- <ImageButton
- android:id="@+id/closeButton"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_alignParentRight="true"
- android:layout_marginTop="12dp"
- android:layout_marginRight="12dp"
- android:background="@android:color/transparent"
- android:src="@drawable/ic_close_white" />
-
- </RelativeLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="16dp"
- android:orientation="vertical">
-
- <Spinner
- android:id="@+id/alternate_urls_spinner"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:dropDownWidth="match_parent"
- android:padding="8dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_micro" />
-
- <Button
- android:id="@+id/subscribeButton"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:text="@string/subscribe_label" />
-
- <CheckBox
- android:id="@+id/autoDownloadCheckBox"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:checked="true"
- android:layout_marginTop="8dp"
- android:text="@string/auto_download_label"
- android:visibility="gone"
- tools:visibility="visible" />
-
- <Button
- android:id="@+id/stopPreviewButton"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:text="@string/stop_preview"
- android:visibility="gone"
- tools:visibility="visible" />
-
- </LinearLayout>
-
- <ListView
- android:id="@+id/listView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="16dp"
- android:clipToPadding="false" />
-
- </LinearLayout>
-
- </FrameLayout>
+ android:layout_height="match_parent" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ style="?android:attr/progressBarStyle" />
</androidx.cardview.widget.CardView>
diff --git a/app/src/main/res/layout/onlinefeedview_header.xml b/app/src/main/res/layout/onlinefeedview_header.xml
deleted file mode 100644
index 6d740c772..000000000
--- a/app/src/main/res/layout/onlinefeedview_header.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="20dp"
- android:paddingRight="20dp"
- android:layout_marginBottom="8dp">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:text="@string/description_label"
- style="@style/TextAppearance.Material3.TitleMedium" />
-
- <TextView
- android:id="@+id/txtvDescription"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:ellipsize="end"
- android:lineHeight="20dp"
- style="@style/AntennaPod.TextView.ListItemBody"
- tools:text="@string/design_time_lorem_ipsum" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:text="@string/episodes_label"
- style="@style/TextAppearance.Material3.TitleMedium" />
-
-</LinearLayout>
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
index 15d256c24..634d3440d 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
@@ -15,6 +15,8 @@ import org.apache.commons.lang3.StringUtils;
public class Feed {
public static final int FEEDFILETYPE_FEED = 0;
+ public static final int STATE_SUBSCRIBED = 0;
+ public static final int STATE_NOT_SUBSCRIBED = 1;
public static final String TYPE_RSS2 = "rss";
public static final String TYPE_ATOM1 = "atom";
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
@@ -101,6 +103,7 @@ public class Feed {
*/
@Nullable
private SortOrder sortOrder;
+ private int state;
/**
* This constructor is used for restoring a feed from the database.
@@ -109,7 +112,7 @@ public class Feed {
String description, String paymentLinks, String author, String language,
String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, long lastRefreshAttempt, boolean paged, String nextPageLink,
- String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed) {
+ String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed, int state) {
this.localFileUrl = fileUrl;
this.downloadUrl = downloadUrl;
this.lastRefreshAttempt = lastRefreshAttempt;
@@ -135,6 +138,7 @@ public class Feed {
}
setSortOrder(sortOrder);
this.lastUpdateFailed = lastUpdateFailed;
+ this.state = state;
}
/**
@@ -144,7 +148,7 @@ public class Feed {
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, long lastRefreshAttempt) {
this(id, lastModified, title, null, link, description, paymentLink, author, language, type, feedIdentifier,
- imageUrl, fileUrl, downloadUrl, lastRefreshAttempt, false, null, null, null, false);
+ imageUrl, fileUrl, downloadUrl, lastRefreshAttempt, false, null, null, null, false, STATE_SUBSCRIBED);
}
/**
@@ -468,4 +472,12 @@ public class Feed {
public boolean isLocalFeed() {
return downloadUrl.startsWith(PREFIX_LOCAL_FOLDER);
}
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItemFilter.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItemFilter.java
index 95a7a6110..1faeda012 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItemFilter.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedItemFilter.java
@@ -24,6 +24,7 @@ public class FeedItemFilter implements Serializable {
public final boolean showIsFavorite;
public final boolean showNotFavorite;
public final boolean showInHistory;
+ public final boolean includeNotSubscribed;
public static final String PLAYED = "played";
public static final String UNPLAYED = "unplayed";
@@ -39,6 +40,7 @@ public class FeedItemFilter implements Serializable {
public static final String DOWNLOADED = "downloaded";
public static final String NOT_DOWNLOADED = "not_downloaded";
public static final String IS_IN_HISTORY = "is_in_history";
+ public static final String INCLUDE_NOT_SUBSCRIBED = "include_not_subscribed";
public static FeedItemFilter unfiltered() {
return new FeedItemFilter("");
@@ -48,6 +50,10 @@ public class FeedItemFilter implements Serializable {
this(TextUtils.split(properties, ","));
}
+ public FeedItemFilter(FeedItemFilter filter, String... additionalProperties) {
+ this(TextUtils.join(",", filter.getValues()) + "," + TextUtils.join(",", additionalProperties));
+ }
+
public FeedItemFilter(String... properties) {
this.properties = properties;
@@ -66,6 +72,7 @@ public class FeedItemFilter implements Serializable {
showNotFavorite = hasProperty(NOT_FAVORITE);
showNew = hasProperty(NEW);
showInHistory = hasProperty(IS_IN_HISTORY);
+ includeNotSubscribed = hasProperty(INCLUDE_NOT_SUBSCRIBED);
}
private boolean hasProperty(String property) {
@@ -112,6 +119,9 @@ public class FeedItemFilter implements Serializable {
} else if (showInHistory && item.getMedia() != null
&& item.getMedia().getPlaybackCompletionDate().getTime() == 0) {
return false;
+ } else if (!includeNotSubscribed && item.getFeed() != null
+ && item.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
+ return false;
}
return true;
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java b/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java
index 434d474a7..2d584adef 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java
@@ -12,6 +12,7 @@ public class SubscriptionsFilter {
private final String[] properties;
private boolean showIfCounterGreaterZero = false;
+ private boolean hideNonSubscribedFeeds = true;
private boolean showAutoDownloadEnabled = false;
private boolean showAutoDownloadDisabled = false;
@@ -67,10 +68,6 @@ public class SubscriptionsFilter {
* Run a list of feed items through the filter.
*/
public List<Feed> filter(List<Feed> items, Map<Long, Integer> feedCounters) {
- if (properties.length == 0) {
- return items;
- }
-
List<Feed> result = new ArrayList<>();
for (Feed item : items) {
@@ -95,6 +92,10 @@ public class SubscriptionsFilter {
continue;
}
+ if (hideNonSubscribedFeeds && item.getState() != Feed.STATE_SUBSCRIBED) {
+ continue;
+ }
+
// If the item reaches here, it meets all criteria (except counter > 0)
result.add(item);
}
diff --git a/net/discovery/src/main/java/de/danoeh/antennapod/net/discovery/ItunesTopListLoader.java b/net/discovery/src/main/java/de/danoeh/antennapod/net/discovery/ItunesTopListLoader.java
index 128aad593..c837a14ef 100644
--- a/net/discovery/src/main/java/de/danoeh/antennapod/net/discovery/ItunesTopListLoader.java
+++ b/net/discovery/src/main/java/de/danoeh/antennapod/net/discovery/ItunesTopListLoader.java
@@ -58,7 +58,8 @@ public class ItunesTopListLoader {
List<PodcastSearchResult> suggestedPodcasts, List<Feed> subscribedFeeds, int limit) {
Set<String> subscribedPodcastsSet = new HashSet<>();
for (Feed subscribedFeed : subscribedFeeds) {
- if (subscribedFeed.getTitle() != null && subscribedFeed.getAuthor() != null) {
+ if (subscribedFeed.getTitle() != null && subscribedFeed.getAuthor() != null
+ && subscribedFeed.getState() == Feed.STATE_SUBSCRIBED) {
subscribedPodcastsSet.add(subscribedFeed.getTitle().trim() + " - " + subscribedFeed.getAuthor().trim());
}
}
diff --git a/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/episode/MediaDownloadedHandler.java b/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/episode/MediaDownloadedHandler.java
index 96c1549e2..cf9ec17e1 100644
--- a/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/episode/MediaDownloadedHandler.java
+++ b/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/episode/MediaDownloadedHandler.java
@@ -7,6 +7,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueueSink;
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
import org.greenrobot.eventbus.EventBus;
@@ -104,7 +105,7 @@ public class MediaDownloadedHandler implements Runnable {
FeedMedia.FEEDFILETYPE_FEEDMEDIA, false, DownloadError.ERROR_DB_ACCESS_ERROR, e.getMessage());
}
- if (item != null) {
+ if (item != null && item.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
EpisodeAction action = new EpisodeAction.Builder(item, EpisodeAction.DOWNLOAD)
.currentTimestamp()
.build();
diff --git a/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/feed/FeedUpdateWorker.java b/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/feed/FeedUpdateWorker.java
index 9e363b585..b5174dfcb 100644
--- a/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/feed/FeedUpdateWorker.java
+++ b/net/download/service/src/main/java/de/danoeh/antennapod/net/download/service/feed/FeedUpdateWorker.java
@@ -35,6 +35,7 @@ import de.danoeh.antennapod.model.download.DownloadRequest;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestBuilder;
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
+import de.danoeh.antennapod.storage.database.NonSubscribedFeedsCleaner;
import de.danoeh.antennapod.ui.notifications.NotificationUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -69,7 +70,7 @@ public class FeedUpdateWorker extends Worker {
Iterator<Feed> itr = toUpdate.iterator();
while (itr.hasNext()) {
Feed feed = itr.next();
- if (!feed.getPreferences().getKeepUpdated()) {
+ if (!feed.getPreferences().getKeepUpdated() || feed.getState() != Feed.STATE_SUBSCRIBED) {
itr.remove();
continue;
}
@@ -99,8 +100,9 @@ public class FeedUpdateWorker extends Worker {
}
refreshFeeds(toUpdate, force);
- notificationManager.cancel(R.id.notification_updating_feeds);
+ NonSubscribedFeedsCleaner.deleteOldNonSubscribedFeeds(getApplicationContext());
AutoDownloadManager.getInstance().autodownloadUndownloadedItems(getApplicationContext());
+ notificationManager.cancel(R.id.notification_updating_feeds);
return Result.success();
}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
index ad235130a..e617dfc78 100644
--- a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.net.sync.serviceinterface;
import android.content.Context;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.storage.preferences.SynchronizationSettings;
import de.danoeh.antennapod.model.feed.FeedMedia;
@@ -62,7 +63,8 @@ public class SynchronizationQueueSink {
if (!SynchronizationSettings.isProviderConnected()) {
return;
}
- if (media.getItem() == null || media.getItem().getFeed().isLocalFeed()) {
+ if (media.getItem() == null || media.getItem().getFeed().isLocalFeed()
+ || media.getItem().getFeed().getState() != Feed.STATE_SUBSCRIBED) {
return;
}
if (media.getStartPosition() < 0 || (!completed && media.getStartPosition() >= media.getPosition())) {
diff --git a/playback/service/src/main/java/de/danoeh/antennapod/playback/service/PlaybackService.java b/playback/service/src/main/java/de/danoeh/antennapod/playback/service/PlaybackService.java
index 5fa89dd43..7d20124cf 100644
--- a/playback/service/src/main/java/de/danoeh/antennapod/playback/service/PlaybackService.java
+++ b/playback/service/src/main/java/de/danoeh/antennapod/playback/service/PlaybackService.java
@@ -436,7 +436,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.UNPLAYED))));
List<Feed> feeds = DBReader.getFeedList();
for (Feed feed : feeds) {
- mediaItems.add(createBrowsableMediaItemForFeed(feed));
+ if (feed.getState() == Feed.STATE_SUBSCRIBED) {
+ mediaItems.add(createBrowsableMediaItemForFeed(feed));
+ }
}
return mediaItems;
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
index 432990379..272df5048 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
@@ -356,7 +356,9 @@ public final class DBReader {
try (FeedCursor cursor = new FeedCursor(adapter.getFeedCursor(feedId))) {
if (cursor.moveToNext()) {
feed = cursor.getFeed();
- FeedItemFilter filter = filtered ? feed.getItemFilter() : FeedItemFilter.unfiltered();
+ FeedItemFilter filter = (filtered && feed.getItemFilter() != null)
+ ? feed.getItemFilter() : FeedItemFilter.unfiltered();
+ filter = new FeedItemFilter(filter, FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
List<FeedItem> items = getFeedItemList(feed, filter, feed.getSortOrder(), offset, limit);
for (FeedItem item : items) {
item.setFeed(feed);
@@ -668,9 +670,10 @@ public final class DBReader {
final Map<Long, Integer> feedCounters = adapter.getFeedCounters(feedCounter);
List<Feed> feeds = getFeedList();
- if (subscriptionsFilter != null) {
- feeds = subscriptionsFilter.filter(feeds, feedCounters);
+ if (subscriptionsFilter == null) {
+ subscriptionsFilter = new SubscriptionsFilter("");
}
+ feeds = subscriptionsFilter.filter(feeds, feedCounters);
Comparator<Feed> comparator;
switch (feedOrder) {
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
index 19a02972d..be09a5132 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBUpgrader.java
@@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.media.MediaMetadataRetriever;
import android.util.Log;
+import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import static de.danoeh.antennapod.model.feed.FeedPreferences.SPEED_USE_GLOBAL;
@@ -338,6 +339,10 @@ class DBUpgrader {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_SKIP_SILENCE + " INTEGER");
}
+ if (oldVersion < 3050000) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_STATE + " INTEGER DEFAULT " + Feed.STATE_SUBSCRIBED);
+ }
}
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBWriter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBWriter.java
index 5f684b398..11e1ad751 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBWriter.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBWriter.java
@@ -14,6 +14,7 @@ import androidx.documentfile.provider.DocumentFile;
import com.google.common.util.concurrent.Futures;
import de.danoeh.antennapod.event.DownloadLogEvent;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.net.download.serviceinterface.AutoDownloadManager;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
@@ -141,12 +142,13 @@ public class DBWriter {
// Do full update of this feed to get rid of the item
FeedUpdateManager.getInstance().runOnce(context, media.getItem().getFeed());
} 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);
+ if (media.getItem().getFeed().getState() == Feed.STATE_SUBSCRIBED) {
+ 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()));
}
@@ -174,7 +176,7 @@ public class DBWriter {
adapter.removeFeed(feed);
adapter.close();
- if (!feed.isLocalFeed()) {
+ if (!feed.isLocalFeed() && feed.getState() == Feed.STATE_SUBSCRIBED) {
SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownloadUrl());
}
EventBus.getDefault().post(new FeedListUpdateEvent(feed));
@@ -786,7 +788,7 @@ public class DBWriter {
adapter.close();
for (Feed feed : feeds) {
- if (!feed.isLocalFeed()) {
+ if (!feed.isLocalFeed() && feed.getState() == Feed.STATE_SUBSCRIBED) {
SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.getDownloadUrl());
}
}
@@ -928,6 +930,32 @@ public class DBWriter {
});
}
+ public static Future<?> setFeedState(Context context, Feed feed, int newState) {
+ int oldState = feed.getState();
+ return runOnDbThread(() -> {
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ adapter.setFeedState(feed.getId(), newState);
+ feed.setState(newState);
+ if (oldState == Feed.STATE_NOT_SUBSCRIBED && newState == Feed.STATE_SUBSCRIBED) {
+ feed.getPreferences().setKeepUpdated(true);
+ DBWriter.setFeedPreferences(feed.getPreferences());
+ FeedUpdateManager.getInstance().runOnceOrAsk(context, feed);
+ SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.getDownloadUrl());
+ DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(),
+ SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
+ for (FeedItem item : feed.getItems()) {
+ if (item.isPlayed()) {
+ SynchronizationQueueSink.enqueueEpisodePlayedIfSynchronizationIsActive(
+ context, item.getMedia(), true);
+ }
+ }
+ }
+ adapter.close();
+ EventBus.getDefault().post(new FeedListUpdateEvent(feed));
+ });
+ }
+
/**
* Sort the FeedItems in the queue with the given the named sort order.
*
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedDatabaseWriter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedDatabaseWriter.java
index 7269fcd55..a62e18809 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedDatabaseWriter.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedDatabaseWriter.java
@@ -157,7 +157,8 @@ public abstract class FeedDatabaseWriter {
+ "\n\nNow the feed contains:\n" + duplicateEpisodeDetails(item)));
oldItem.setItemIdentifier(item.getItemIdentifier());
- if (oldItem.isPlayed() && oldItem.getMedia() != null) {
+ if (oldItem.isPlayed() && oldItem.getMedia() != null
+ && savedFeed.getState() == Feed.STATE_SUBSCRIBED) {
EpisodeAction action = new EpisodeAction.Builder(oldItem, EpisodeAction.PLAY)
.currentTimestamp()
.started(oldItem.getMedia().getDuration() / 1000)
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleaner.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleaner.java
new file mode 100644
index 000000000..47a5a5aee
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleaner.java
@@ -0,0 +1,46 @@
+package de.danoeh.antennapod.storage.database;
+
+import android.content.Context;
+import android.util.Log;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.model.feed.SortOrder;
+
+import java.util.List;
+
+public class NonSubscribedFeedsCleaner {
+ private static final String TAG = "NonSubscrFeedsCleaner";
+ private static final long TIME_TO_KEEP = 1000L * 3600 * 24 * 30; // 30 days
+
+ public static void deleteOldNonSubscribedFeeds(Context context) {
+ List<Feed> feeds = DBReader.getFeedList();
+ for (Feed feed : feeds) {
+ if (feed.getState() != Feed.STATE_NOT_SUBSCRIBED) {
+ continue;
+ }
+ DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
+ if (shouldDelete(feed)) {
+ Log.d(TAG, "Deleting unsubscribed feed " + feed.getTitle());
+ DBWriter.deleteFeed(context, feed.getId());
+ }
+ feed.setItems(null); // Let it be garbage collected
+ }
+ }
+
+ public static boolean shouldDelete(Feed feed) {
+ if (feed.getState() != Feed.STATE_NOT_SUBSCRIBED) {
+ return false;
+ } else if (feed.getItems() == null) {
+ return false;
+ }
+ for (FeedItem item : feed.getItems()) {
+ if (item.isTagged(FeedItem.TAG_FAVORITE)
+ || item.isTagged(FeedItem.TAG_QUEUE)
+ || item.isDownloaded()) {
+ return false;
+ }
+ }
+ return feed.getLastRefreshAttempt() < System.currentTimeMillis() - TIME_TO_KEEP;
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
index 2cbf27509..aec136457 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
@@ -52,7 +52,7 @@ public class PodDBAdapter {
private static final String TAG = "PodDBAdapter";
public static final String DATABASE_NAME = "Antennapod.db";
- public static final int VERSION = 3040000;
+ public static final int VERSION = 3050000;
/**
* Maximum number of arguments for IN-operator.
@@ -121,6 +121,7 @@ public class PodDBAdapter {
public static final String KEY_EPISODE_NOTIFICATION = "episode_notification";
public static final String KEY_NEW_EPISODES_ACTION = "new_episodes_action";
public static final String KEY_PODCASTINDEX_CHAPTER_URL = "podcastindex_chapter_url";
+ public static final String KEY_STATE = "state";
// Table names
public static final String TABLE_NAME_FEEDS = "Feeds";
@@ -171,6 +172,7 @@ public class PodDBAdapter {
+ KEY_FEED_SKIP_INTRO + " INTEGER DEFAULT 0,"
+ KEY_FEED_SKIP_ENDING + " INTEGER DEFAULT 0,"
+ KEY_EPISODE_NOTIFICATION + " INTEGER DEFAULT 0,"
+ + KEY_STATE + " INTEGER DEFAULT " + Feed.STATE_SUBSCRIBED + ","
+ KEY_NEW_EPISODES_ACTION + " INTEGER DEFAULT 0)";
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
@@ -323,6 +325,7 @@ public class PodDBAdapter {
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_INTRO + ", "
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING + ", "
+ TABLE_NAME_FEEDS + "." + KEY_EPISODE_NOTIFICATION + ", "
+ + TABLE_NAME_FEEDS + "." + KEY_STATE + ", "
+ TABLE_NAME_FEEDS + "." + KEY_NEW_EPISODES_ACTION;
private static final String JOIN_FEED_ITEM_AND_MEDIA = " LEFT JOIN " + TABLE_NAME_FEED_MEDIA
@@ -337,6 +340,9 @@ public class PodDBAdapter {
"SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
+ " FROM " + TABLE_NAME_FEED_ITEMS
+ JOIN_FEED_ITEM_AND_MEDIA;
+ public static final String SELECT_WHERE_FEED_IS_SUBSCRIBED = TABLE_NAME_FEED_ITEMS + "." + KEY_FEED
+ + " IN (SELECT " + KEY_ID + " FROM " + TABLE_NAME_FEEDS
+ + " WHERE " + KEY_STATE + "=" + Feed.STATE_SUBSCRIBED + ")";
private static Context context;
private static PodDBAdapter instance;
@@ -431,6 +437,7 @@ public class PodDBAdapter {
values.put(KEY_LASTUPDATE, feed.getLastModified());
values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
+ values.put(KEY_STATE, feed.getState());
values.put(KEY_IS_PAGED, feed.isPaged());
values.put(KEY_NEXT_PAGE_LINK, feed.getNextPageLink());
@@ -768,6 +775,12 @@ public class PodDBAdapter {
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
}
+ public void setFeedState(long feedId, int state) {
+ ContentValues values = new ContentValues();
+ values.put(KEY_STATE, state);
+ db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
+ }
+
/**
* Inserts or updates a download status.
*/
@@ -1101,6 +1114,7 @@ public class PodDBAdapter {
// Hide episodes that have been played but not completed
+ " AND (" + KEY_LAST_PLAYED_TIME + " == 0"
+ " OR " + KEY_LAST_PLAYED_TIME + " > " + (System.currentTimeMillis() - 1000L * 3600L) + ")"
+ + " AND " + SELECT_WHERE_FEED_IS_SUBSCRIBED
+ " ORDER BY " + randomEpisodeNumber(seed);
final String query = "SELECT * FROM (" + allItemsRandomOrder + ")"
+ " GROUP BY " + KEY_FEED
@@ -1221,6 +1235,7 @@ public class PodDBAdapter {
+ JOIN_FEED_ITEM_AND_MEDIA
+ " INNER JOIN " + TABLE_NAME_FEEDS
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
+ + " WHERE " + TABLE_NAME_FEEDS + "." + KEY_STATE + "=" + Feed.STATE_SUBSCRIBED
+ " GROUP BY " + TABLE_NAME_FEEDS + "." + KEY_ID;
return db.rawQuery(query, null);
}
@@ -1372,7 +1387,7 @@ public class PodDBAdapter {
}
String queryStart = SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION
- + " WHERE " + queryFeedId + " AND (";
+ + " WHERE " + queryFeedId + " AND " + SELECT_WHERE_FEED_IS_SUBSCRIBED + " AND (";
StringBuilder sb = new StringBuilder(queryStart);
for (int i = 0; i < queryWords.length; i++) {
@@ -1401,12 +1416,13 @@ public class PodDBAdapter {
public Cursor searchFeeds(String searchQuery) {
String[] queryWords = prepareSearchQuery(searchQuery);
- String queryStart = "SELECT " + KEYS_FEED + " FROM " + TABLE_NAME_FEEDS + " WHERE ";
+ String queryStart = "SELECT " + KEYS_FEED + " FROM " + TABLE_NAME_FEEDS
+ + " WHERE " + KEY_STATE + " = " + Feed.STATE_SUBSCRIBED;
StringBuilder sb = new StringBuilder(queryStart);
for (int i = 0; i < queryWords.length; i++) {
sb
- .append("(")
+ .append(" AND (")
.append(KEY_TITLE).append(" LIKE '%").append(queryWords[i])
.append("%' OR ")
.append(KEY_CUSTOM_TITLE).append(" LIKE '%").append(queryWords[i])
@@ -1415,13 +1431,9 @@ public class PodDBAdapter {
.append("%' OR ")
.append(KEY_DESCRIPTION).append(" LIKE '%").append(queryWords[i])
.append("%') ");
-
- if (i != queryWords.length - 1) {
- sb.append("AND ");
- }
}
- sb.append("ORDER BY " + KEY_TITLE + " ASC LIMIT 300");
+ sb.append(" ORDER BY " + KEY_TITLE + " ASC LIMIT 300");
return db.rawQuery(sb.toString(), null);
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java
index 2707275ca..3aba69106 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java
@@ -34,6 +34,7 @@ public class FeedCursor extends CursorWrapper {
private final int indexSortOrder;
private final int indexLastUpdateFailed;
private final int indexImageUrl;
+ private final int indexState;
public FeedCursor(Cursor cursor) {
super(new FeedPreferencesCursor(cursor));
@@ -58,6 +59,7 @@ public class FeedCursor extends CursorWrapper {
indexSortOrder = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SORT_ORDER);
indexLastUpdateFailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
+ indexState = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_STATE);
}
/**
@@ -85,7 +87,8 @@ public class FeedCursor extends CursorWrapper {
getString(indexNextPageLink),
getString(indexHide),
SortOrder.fromCodeString(getString(indexSortOrder)),
- getInt(indexLastUpdateFailed) > 0);
+ getInt(indexLastUpdateFailed) > 0,
+ getInt(indexState));
feed.setPreferences(preferencesCursor.getFeedPreferences());
return feed;
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java
index a4794d324..481107cfa 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemFilterQuery.java
@@ -66,6 +66,9 @@ public class FeedItemFilterQuery {
if (filter.showInHistory) {
statements.add(keyCompletionDate + " > 0 ");
}
+ if (!filter.includeNotSubscribed) {
+ statements.add(PodDBAdapter.SELECT_WHERE_FEED_IS_SUBSCRIBED);
+ }
if (statements.isEmpty()) {
return "";
diff --git a/storage/database/src/test/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleanerTest.java b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleanerTest.java
new file mode 100644
index 000000000..76bbfddc1
--- /dev/null
+++ b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/NonSubscribedFeedsCleanerTest.java
@@ -0,0 +1,104 @@
+package de.danoeh.antennapod.storage.database;
+
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedMedia;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(RobolectricTestRunner.class)
+public class NonSubscribedFeedsCleanerTest {
+
+ @Test
+ public void testSubscribed() {
+ Feed feed = createFeed();
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ assertTrue(NonSubscribedFeedsCleaner.shouldDelete(feed));
+ }
+
+ @Test
+ public void testOldDate() {
+ Feed feed = createFeed();
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ feed.setLastRefreshAttempt(System.currentTimeMillis());
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(10, TimeUnit.DAYS));
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ assertTrue(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ feed.setLastRefreshAttempt(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+ }
+
+ @Test
+ public void testQueuedItem() {
+ Feed feed = createFeed();
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ feed.getItems().add(createItem(feed));
+ assertTrue(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ FeedItem queuedItem = createItem(feed);
+ queuedItem.addTag(FeedItem.TAG_QUEUE);
+ feed.getItems().add(queuedItem);
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+ }
+
+ @Test
+ public void testFavoriteItem() {
+ Feed feed = createFeed();
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ feed.getItems().add(createItem(feed));
+ assertTrue(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ FeedItem queuedItem = createItem(feed);
+ queuedItem.addTag(FeedItem.TAG_FAVORITE);
+ feed.getItems().add(queuedItem);
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+ }
+
+ @Test
+ public void testDownloadedItem() {
+ Feed feed = createFeed();
+ feed.setState(Feed.STATE_NOT_SUBSCRIBED);
+ feed.setLastRefreshAttempt(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(200, TimeUnit.DAYS));
+ feed.getItems().add(createItem(feed));
+ assertTrue(NonSubscribedFeedsCleaner.shouldDelete(feed));
+
+ FeedItem queuedItem = createItem(feed);
+ queuedItem.getMedia().setDownloaded(true, System.currentTimeMillis());
+ feed.getItems().add(queuedItem);
+ assertFalse(NonSubscribedFeedsCleaner.shouldDelete(feed));
+ }
+
+ private Feed createFeed() {
+ Feed feed = new Feed(0, null, "title", "http://example.com", "This is the description",
+ "http://example.com/payment", "Daniel", "en", null, "http://example.com/feed",
+ "http://example.com/image", null, "http://example.com/feed", System.currentTimeMillis());
+ feed.setItems(new ArrayList<>());
+ return feed;
+ }
+
+ private FeedItem createItem(Feed feed) {
+ FeedItem item = new FeedItem(0, "Item", "ItemId", "url", new Date(), FeedItem.PLAYED, feed);
+ FeedMedia media = new FeedMedia(item, "http://download.url.net/", 1234567, "audio/mpeg");
+ media.setId(item.getId());
+ item.setMedia(media);
+ return item;
+ }
+}
diff --git a/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java
index 0b162fab0..d259db43b 100644
--- a/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/HtmlWriter.java
@@ -28,6 +28,9 @@ public class HtmlWriter {
writer.append(templateParts[0]);
for (Feed feed : feeds) {
+ if (feed.getState() != Feed.STATE_SUBSCRIBED) {
+ continue;
+ }
writer.append("<li><div><img src=\"");
writer.append(feed.getImageUrl());
writer.append("\" /><p>");
diff --git a/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java
index 9701476f9..d06932a5e 100644
--- a/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java
+++ b/storage/importexport/src/main/java/de/danoeh/antennapod/storage/importexport/OpmlWriter.java
@@ -48,6 +48,9 @@ public class OpmlWriter {
xs.startTag(null, OpmlSymbols.BODY);
for (Feed feed : feeds) {
+ if (feed.getState() != Feed.STATE_SUBSCRIBED) {
+ continue;
+ }
xs.startTag(null, OpmlSymbols.OUTLINE);
xs.attribute(null, OpmlSymbols.TEXT, feed.getTitle());
xs.attribute(null, OpmlSymbols.TITLE, feed.getTitle());
diff --git a/ui/common/src/main/res/drawable/bg_message_info.xml b/ui/common/src/main/res/drawable/bg_message_info.xml
new file mode 100644
index 000000000..6543066cf
--- /dev/null
+++ b/ui/common/src/main/res/drawable/bg_message_info.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <stroke
+ android:width="2dp"
+ android:color="?attr/colorPrimary" />
+
+ <corners android:radius="8dp" />
+
+ <solid>
+ <aapt:attr name="android:color" >
+ <selector>
+ <item android:alpha="0.1" android:color="?attr/colorPrimary" />
+ </selector>
+ </aapt:attr>
+ </solid>
+</shape> \ No newline at end of file
diff --git a/ui/common/src/main/res/drawable/bg_rounded_corners.xml b/ui/common/src/main/res/drawable/bg_rounded_corners.xml
deleted file mode 100644
index 11b7710c4..000000000
--- a/ui/common/src/main/res/drawable/bg_rounded_corners.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners android:radius="8dp" />
-</shape>
diff --git a/ui/common/src/main/res/drawable/ic_close.xml b/ui/common/src/main/res/drawable/ic_close.xml
new file mode 100644
index 000000000..ccba7f4a0
--- /dev/null
+++ b/ui/common/src/main/res/drawable/ic_close.xml
@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M17.656,6.343L12,12M12,12L6.343,17.656M12,12L17.656,17.656M12,12L6.343,6.343"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="?attr/action_icon_color"/>
+</vector>
diff --git a/ui/common/src/main/res/values/colors.xml b/ui/common/src/main/res/values/colors.xml
index ad835faf4..55ba650e7 100644
--- a/ui/common/src/main/res/values/colors.xml
+++ b/ui/common/src/main/res/values/colors.xml
@@ -8,7 +8,6 @@
<color name="medium_gray">#afafaf</color>
<color name="black">#000000</color>
<color name="image_readability_tint">#80000000</color>
- <color name="feed_image_bg">#50000000</color>
<color name="feed_text_bg">#55333333</color>
<!-- Theme colors -->
diff --git a/ui/common/src/main/res/values/dimens.xml b/ui/common/src/main/res/values/dimens.xml
index 5cfcd68b6..82c2b1451 100644
--- a/ui/common/src/main/res/values/dimens.xml
+++ b/ui/common/src/main/res/values/dimens.xml
@@ -7,8 +7,6 @@
<dimen name="text_size_large">22sp</dimen>
<dimen name="thumbnail_length_itemlist">56dp</dimen>
<dimen name="thumbnail_length_queue_item">56dp</dimen>
- <dimen name="thumbnail_length_onlinefeedview">92dp</dimen>
- <dimen name="feeditemlist_header_height">132dp</dimen>
<dimen name="thumbnail_length_navlist">40dp</dimen>
<dimen name="listitem_iconwithtext_height">48dp</dimen>
<dimen name="listitem_iconwithtext_textleftpadding">16dp</dimen>
diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml
index a840a1abf..f5ac3c306 100644
--- a/ui/i18n/src/main/res/values/strings.xml
+++ b/ui/i18n/src/main/res/values/strings.xml
@@ -681,9 +681,8 @@
<!-- Online feed view -->
<string name="subscribe_label">Subscribe</string>
- <string name="subscribing_label">Subscribing&#8230;</string>
- <string name="preview_episode">Preview</string>
- <string name="stop_preview">Stop preview</string>
+ <string name="preview_episodes">Episodes preview</string>
+ <string name="state_deleted_not_subscribed">Playback state and history of non-subscribed podcasts are deleted after a while. Subscribe to keep them.</string>
<!-- Content descriptions for image buttons -->
<string name="toolbar_back_button_content_description">Back</string>