Add episodes without subscribing (#7098)
This commit is contained in:
parent
53ce6cd71a
commit
084723ad76
@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
@ -48,6 +49,8 @@ public abstract class ItemActionButton {
|
|||||||
return new PlayActionButton(item);
|
return new PlayActionButton(item);
|
||||||
} else if (isDownloadingMedia) {
|
} else if (isDownloadingMedia) {
|
||||||
return new CancelDownloadActionButton(item);
|
return new CancelDownloadActionButton(item);
|
||||||
|
} else if (item.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
|
return new StreamActionButton(item);
|
||||||
} else if (UserPreferences.isStreamOverDownload()) {
|
} else if (UserPreferences.isStreamOverDownload()) {
|
||||||
return new StreamActionButton(item);
|
return new StreamActionButton(item);
|
||||||
} else {
|
} else {
|
||||||
|
@ -12,6 +12,7 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import de.danoeh.antennapod.ui.SelectableAdapter;
|
import de.danoeh.antennapod.ui.SelectableAdapter;
|
||||||
@ -32,13 +33,13 @@ import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
|
|||||||
public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHolder>
|
public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHolder>
|
||||||
implements View.OnCreateContextMenuListener {
|
implements View.OnCreateContextMenuListener {
|
||||||
|
|
||||||
private final WeakReference<MainActivity> mainActivityRef;
|
private final WeakReference<FragmentActivity> mainActivityRef;
|
||||||
private List<FeedItem> episodes = new ArrayList<>();
|
private List<FeedItem> episodes = new ArrayList<>();
|
||||||
private FeedItem longPressedItem;
|
private FeedItem longPressedItem;
|
||||||
int longPressedPosition = 0; // used to init actionMode
|
int longPressedPosition = 0; // used to init actionMode
|
||||||
private int dummyViews = 0;
|
private int dummyViews = 0;
|
||||||
|
|
||||||
public EpisodeItemListAdapter(MainActivity mainActivity) {
|
public EpisodeItemListAdapter(FragmentActivity mainActivity) {
|
||||||
super(mainActivity);
|
super(mainActivity);
|
||||||
this.mainActivityRef = new WeakReference<>(mainActivity);
|
this.mainActivityRef = new WeakReference<>(mainActivity);
|
||||||
setHasStableIds(true);
|
setHasStableIds(true);
|
||||||
@ -86,9 +87,18 @@ public class EpisodeItemListAdapter extends SelectableAdapter<EpisodeItemViewHol
|
|||||||
holder.bind(item);
|
holder.bind(item);
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
MainActivity activity = mainActivityRef.get();
|
if (!inActionMode()) {
|
||||||
if (activity != null && !inActionMode()) {
|
if (mainActivityRef.get() instanceof MainActivity) {
|
||||||
activity.loadChildFragment(ItemPagerFragment.newInstance(episodes, item));
|
((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 {
|
} else {
|
||||||
toggleSelection(holder.getBindingAdapterPosition());
|
toggleSelection(holder.getBindingAdapterPosition());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package de.danoeh.antennapod.ui.episodeslist;
|
package de.danoeh.antennapod.ui.episodeslist;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
@ -17,7 +18,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.google.android.material.elevation.SurfaceColors;
|
import com.google.android.material.elevation.SurfaceColors;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.activity.MainActivity;
|
|
||||||
import de.danoeh.antennapod.ui.CoverLoader;
|
import de.danoeh.antennapod.ui.CoverLoader;
|
||||||
import de.danoeh.antennapod.actionbutton.ItemActionButton;
|
import de.danoeh.antennapod.actionbutton.ItemActionButton;
|
||||||
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
||||||
@ -62,10 +62,10 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
private final View leftPadding;
|
private final View leftPadding;
|
||||||
public final CardView coverHolder;
|
public final CardView coverHolder;
|
||||||
|
|
||||||
private final MainActivity activity;
|
private final Activity activity;
|
||||||
private FeedItem item;
|
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));
|
super(LayoutInflater.from(activity).inflate(R.layout.feeditemlist_item, parent, false));
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
container = itemView.findViewById(R.id.container);
|
container = itemView.findViewById(R.id.container);
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
package de.danoeh.antennapod.ui.episodeslist;
|
package de.danoeh.antennapod.ui.episodeslist;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.PluralsRes;
|
import androidx.annotation.PluralsRes;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
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.net.download.serviceinterface.DownloadServiceInterface;
|
||||||
import de.danoeh.antennapod.storage.database.DBWriter;
|
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||||
import de.danoeh.antennapod.storage.database.LongList;
|
import de.danoeh.antennapod.storage.database.LongList;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.ui.view.LocalDeleteModal;
|
import de.danoeh.antennapod.ui.view.LocalDeleteModal;
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
|
||||||
public class EpisodeMultiSelectActionHandler {
|
public class EpisodeMultiSelectActionHandler {
|
||||||
private static final String TAG = "EpisodeSelectHandler";
|
private static final String TAG = "EpisodeSelectHandler";
|
||||||
private final MainActivity activity;
|
private final Activity activity;
|
||||||
private final int actionId;
|
private final int actionId;
|
||||||
private int totalNumItems = 0;
|
private int totalNumItems = 0;
|
||||||
private Snackbar snackbar = null;
|
|
||||||
|
|
||||||
public EpisodeMultiSelectActionHandler(MainActivity activity, int actionId) {
|
public EpisodeMultiSelectActionHandler(Activity activity, int actionId) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
this.actionId = actionId;
|
this.actionId = actionId;
|
||||||
}
|
}
|
||||||
@ -116,12 +115,7 @@ public class EpisodeMultiSelectActionHandler {
|
|||||||
totalNumItems += numItems;
|
totalNumItems += numItems;
|
||||||
activity.runOnUiThread(() -> {
|
activity.runOnUiThread(() -> {
|
||||||
String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems);
|
String text = activity.getResources().getQuantityString(msgId, totalNumItems, totalNumItems);
|
||||||
if (snackbar != null) {
|
EventBus.getDefault().post(new MessageEvent(text));
|
||||||
snackbar.setText(text);
|
|
||||||
snackbar.show(); // Resets the timeout
|
|
||||||
} else {
|
|
||||||
snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.activity.MainActivity;
|
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.net.sync.serviceinterface.SynchronizationQueueSink;
|
||||||
import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
|
import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
|
||||||
import de.danoeh.antennapod.playback.service.PlaybackServiceInterface;
|
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.add_to_favorites_item, !isFavorite);
|
||||||
setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite);
|
setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite);
|
||||||
setItemVisibility(menu, R.id.remove_item, fileDownloaded || isLocalFile);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +163,8 @@ public class FeedItemMenuHandler {
|
|||||||
} else if (menuItemId == R.id.mark_read_item) {
|
} else if (menuItemId == R.id.mark_read_item) {
|
||||||
selectedItem.setPlayed(true);
|
selectedItem.setPlayed(true);
|
||||||
DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, 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();
|
FeedMedia media = selectedItem.getMedia();
|
||||||
// not all items have media, Gpodder only cares about those that do
|
// not all items have media, Gpodder only cares about those that do
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
@ -174,7 +180,8 @@ public class FeedItemMenuHandler {
|
|||||||
} else if (menuItemId == R.id.mark_unread_item) {
|
} else if (menuItemId == R.id.mark_unread_item) {
|
||||||
selectedItem.setPlayed(false);
|
selectedItem.setPlayed(false);
|
||||||
DBWriter.markItemPlayed(selectedItem, FeedItem.UNPLAYED, 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)
|
EpisodeAction actionNew = new EpisodeAction.Builder(selectedItem, EpisodeAction.NEW)
|
||||||
.currentTimestamp()
|
.currentTimestamp()
|
||||||
.build();
|
.build();
|
||||||
|
@ -66,7 +66,12 @@ public class AllEpisodesFragment extends EpisodesListFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FeedItemFilter getFilter() {
|
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
|
@Override
|
||||||
@ -91,6 +96,7 @@ public class AllEpisodesFragment extends EpisodesListFragment {
|
|||||||
ArrayList<String> filter = new ArrayList<>(getFilter().getValuesList());
|
ArrayList<String> filter = new ArrayList<>(getFilter().getValuesList());
|
||||||
if (filter.contains(FeedItemFilter.IS_FAVORITE)) {
|
if (filter.contains(FeedItemFilter.IS_FAVORITE)) {
|
||||||
filter.remove(FeedItemFilter.IS_FAVORITE);
|
filter.remove(FeedItemFilter.IS_FAVORITE);
|
||||||
|
filter.remove(FeedItemFilter.INCLUDE_NOT_SUBSCRIBED);
|
||||||
} else {
|
} else {
|
||||||
filter.add(FeedItemFilter.IS_FAVORITE);
|
filter.add(FeedItemFilter.IS_FAVORITE);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public class PlaybackHistoryFragment extends EpisodesListFragment {
|
public class PlaybackHistoryFragment extends EpisodesListFragment {
|
||||||
public static final String TAG = "PlaybackHistoryFragment";
|
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
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
@ -285,7 +285,7 @@ public class CompletedDownloadsFragment extends Fragment
|
|||||||
disposable = Observable.fromCallable(() -> {
|
disposable = Observable.fromCallable(() -> {
|
||||||
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
|
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
|
||||||
List<FeedItem> downloadedItems = DBReader.getEpisodes(0, Integer.MAX_VALUE,
|
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<>();
|
List<String> mediaUrls = new ArrayList<>();
|
||||||
if (runningDownloads == null) {
|
if (runningDownloads == null) {
|
||||||
|
@ -38,6 +38,7 @@ import de.danoeh.antennapod.actionbutton.PlayLocalActionButton;
|
|||||||
import de.danoeh.antennapod.actionbutton.StreamActionButton;
|
import de.danoeh.antennapod.actionbutton.StreamActionButton;
|
||||||
import de.danoeh.antennapod.actionbutton.VisitWebsiteActionButton;
|
import de.danoeh.antennapod.actionbutton.VisitWebsiteActionButton;
|
||||||
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
|
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
import de.danoeh.antennapod.playback.service.PlaybackStatus;
|
||||||
import de.danoeh.antennapod.event.FeedItemEvent;
|
import de.danoeh.antennapod.event.FeedItemEvent;
|
||||||
import de.danoeh.antennapod.event.PlayerStatusEvent;
|
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.net.download.serviceinterface.DownloadServiceInterface;
|
||||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.storage.database.DBReader;
|
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.Converter;
|
||||||
import de.danoeh.antennapod.ui.common.DateFormatter;
|
import de.danoeh.antennapod.ui.common.DateFormatter;
|
||||||
import de.danoeh.antennapod.ui.common.CircularProgressBar;
|
import de.danoeh.antennapod.ui.common.CircularProgressBar;
|
||||||
@ -114,6 +116,7 @@ public class ItemFragment extends Fragment {
|
|||||||
private ItemActionButton actionButton1;
|
private ItemActionButton actionButton1;
|
||||||
private ItemActionButton actionButton2;
|
private ItemActionButton actionButton2;
|
||||||
private View noMediaLabel;
|
private View noMediaLabel;
|
||||||
|
private View nonSubscribedWarningLabel;
|
||||||
|
|
||||||
private Disposable disposable;
|
private Disposable disposable;
|
||||||
private PlaybackController controller;
|
private PlaybackController controller;
|
||||||
@ -164,6 +167,7 @@ public class ItemFragment extends Fragment {
|
|||||||
butAction1Text = layout.findViewById(R.id.butAction1Text);
|
butAction1Text = layout.findViewById(R.id.butAction1Text);
|
||||||
butAction2Text = layout.findViewById(R.id.butAction2Text);
|
butAction2Text = layout.findViewById(R.id.butAction2Text);
|
||||||
noMediaLabel = layout.findViewById(R.id.noMediaLabel);
|
noMediaLabel = layout.findViewById(R.id.noMediaLabel);
|
||||||
|
nonSubscribedWarningLabel = layout.findViewById(R.id.nonSubscribedWarningLabel);
|
||||||
|
|
||||||
butAction1.setOnClickListener(v -> {
|
butAction1.setOnClickListener(v -> {
|
||||||
if (actionButton1 instanceof StreamActionButton && !UserPreferences.isStreamOverDownload()
|
if (actionButton1 instanceof StreamActionButton && !UserPreferences.isStreamOverDownload()
|
||||||
@ -287,6 +291,11 @@ public class ItemFragment extends Fragment {
|
|||||||
txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate()));
|
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;
|
float radius = 8 * getResources().getDisplayMetrics().density;
|
||||||
RequestOptions options = new RequestOptions()
|
RequestOptions options = new RequestOptions()
|
||||||
.error(ImagePlaceholder.getDrawable(getContext(), radius))
|
.error(ImagePlaceholder.getDrawable(getContext(), radius))
|
||||||
@ -366,8 +375,13 @@ public class ItemFragment extends Fragment {
|
|||||||
if (item == null) {
|
if (item == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
|
if (item.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
((MainActivity) getActivity()).loadChildFragment(fragment);
|
Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
|
||||||
|
((MainActivity) getActivity()).loadChildFragment(fragment);
|
||||||
|
} else {
|
||||||
|
startActivity(new OnlineFeedviewActivityStarter(getContext(), item.getFeed().getDownloadUrl())
|
||||||
|
.getIntent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package de.danoeh.antennapod.ui.screen.episode;
|
package de.danoeh.antennapod.ui.screen.episode;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -13,7 +14,8 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
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.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
import org.greenrobot.eventbus.ThreadMode;
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
@ -173,8 +175,12 @@ public class ItemPagerFragment extends Fragment implements MaterialToolbar.OnMen
|
|||||||
if (item == null) {
|
if (item == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
|
if (item.getFeed().getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
((MainActivity) getActivity()).loadChildFragment(fragment);
|
Intent intent = MainActivity.getIntentToOpenFeed(getContext(), item.getFeedId());
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
startActivity(new OnlineFeedviewActivityStarter(getContext(), item.getFeed().getDownloadUrl()).getIntent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ItemPagerAdapter extends FragmentStateAdapter {
|
private class ItemPagerAdapter extends FragmentStateAdapter {
|
||||||
|
@ -122,7 +122,6 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
|
|||||||
viewBinding.header.butFilter.setVisibility(View.INVISIBLE);
|
viewBinding.header.butFilter.setVisibility(View.INVISIBLE);
|
||||||
// https://github.com/bumptech/glide/issues/529
|
// https://github.com/bumptech/glide/issues/529
|
||||||
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
|
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
|
||||||
|
|
||||||
viewBinding.urlLabel.setOnClickListener(copyUrlToClipboard);
|
viewBinding.urlLabel.setOnClickListener(copyUrlToClipboard);
|
||||||
|
|
||||||
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
||||||
@ -237,6 +236,25 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
|
|||||||
viewBinding.supportUrl.setText(str.toString());
|
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();
|
refreshToolbarState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,13 +267,14 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refreshToolbarState() {
|
private void refreshToolbarState() {
|
||||||
|
boolean isSubscribed = feed != null && feed.getState() == Feed.STATE_SUBSCRIBED;
|
||||||
viewBinding.toolbar.getMenu().findItem(R.id.reconnect_local_folder).setVisible(
|
viewBinding.toolbar.getMenu().findItem(R.id.reconnect_local_folder).setVisible(
|
||||||
feed != null && feed.isLocalFeed());
|
isSubscribed && feed.isLocalFeed());
|
||||||
viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(feed != null && !feed.isLocalFeed());
|
viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(isSubscribed && !feed.isLocalFeed());
|
||||||
viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(feed != null
|
viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(isSubscribed
|
||||||
&& feed.getLink() != null
|
&& feed.getLink() != null
|
||||||
&& IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
|
&& 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
|
@Override
|
||||||
|
@ -12,27 +12,63 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
import androidx.core.util.Pair;
|
import androidx.core.util.Pair;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.request.RequestOptions;
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
import com.google.android.material.appbar.MaterialToolbar;
|
import com.google.android.material.appbar.MaterialToolbar;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.ui.CoverLoader;
|
import de.danoeh.antennapod.activity.MainActivity;
|
||||||
import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
|
import de.danoeh.antennapod.databinding.FeedItemListFragmentBinding;
|
||||||
import de.danoeh.antennapod.ui.screen.SearchFragment;
|
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
|
||||||
import de.danoeh.antennapod.ui.TransitionEffect;
|
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;
|
||||||
|
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.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.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.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.download.DownloadLogFragment;
|
||||||
|
import de.danoeh.antennapod.ui.screen.episode.ItemPagerFragment;
|
||||||
import de.danoeh.antennapod.ui.screen.feed.preferences.FeedSettingsFragment;
|
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.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
@ -43,44 +79,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
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.FeedItemEvent;
|
|
||||||
import de.danoeh.antennapod.event.FeedListUpdateEvent;
|
|
||||||
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
|
|
||||||
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.storage.preferences.UserPreferences;
|
|
||||||
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
|
|
||||||
import de.danoeh.antennapod.ui.episodeslist.EpisodeItemViewHolder;
|
|
||||||
import io.reactivex.Maybe;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a list of FeedItems.
|
* Displays a list of FeedItems.
|
||||||
*/
|
*/
|
||||||
@ -100,7 +98,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
private boolean displayUpArrow;
|
private boolean displayUpArrow;
|
||||||
private long feedID;
|
private long feedID;
|
||||||
private Feed feed;
|
private Feed feed;
|
||||||
private boolean headerCreated = false;
|
|
||||||
private Disposable disposable;
|
private Disposable disposable;
|
||||||
private FeedItemListFragmentBinding viewBinding;
|
private FeedItemListFragmentBinding viewBinding;
|
||||||
|
|
||||||
@ -145,12 +142,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
|
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();
|
updateToolbar();
|
||||||
setupLoadMoreScrollListener();
|
setupLoadMoreScrollListener();
|
||||||
|
setupHeaderView();
|
||||||
|
|
||||||
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
|
adapter = new FeedItemListAdapter(getActivity());
|
||||||
adapter = new FeedItemListAdapter((MainActivity) getActivity());
|
|
||||||
adapter.setOnSelectModeListener(this);
|
adapter.setOnSelectModeListener(this);
|
||||||
viewBinding.recyclerView.setAdapter(adapter);
|
viewBinding.recyclerView.setAdapter(adapter);
|
||||||
swipeActions = new SwipeActions(this, TAG).attachTo(viewBinding.recyclerView);
|
swipeActions = new SwipeActions(this, TAG).attachTo(viewBinding.recyclerView);
|
||||||
@ -198,7 +201,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_SHORT);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
new EpisodeMultiSelectActionHandler(((MainActivity) getActivity()), menuItem.getItemId())
|
new EpisodeMultiSelectActionHandler(getActivity(), menuItem.getItemId())
|
||||||
.handleAction(adapter.getSelectedItems());
|
.handleAction(adapter.getSelectedItems());
|
||||||
adapter.endSelectMode();
|
adapter.endSelectMode();
|
||||||
return true;
|
return true;
|
||||||
@ -249,6 +252,13 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
if (feed.isLocalFeed()) {
|
if (feed.isLocalFeed()) {
|
||||||
viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(false);
|
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
|
@Override
|
||||||
@ -263,8 +273,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
if (feed == null) {
|
if (feed == null) {
|
||||||
((MainActivity) getActivity()).showSnackbarAbovePlayer(
|
EventBus.getDefault().post(getString(R.string.please_wait_for_data));
|
||||||
R.string.please_wait_for_data, Toast.LENGTH_LONG);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (item.getItemId() == R.id.visit_website_item) {
|
if (item.getItemId() == R.id.visit_website_item) {
|
||||||
@ -443,7 +452,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refreshHeaderView() {
|
private void refreshHeaderView() {
|
||||||
setupHeaderView();
|
|
||||||
if (viewBinding == null || feed == null) {
|
if (viewBinding == null || feed == null) {
|
||||||
Log.e(TAG, "Unable to refresh header view");
|
Log.e(TAG, "Unable to refresh header view");
|
||||||
return;
|
return;
|
||||||
@ -454,7 +462,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
} else {
|
} else {
|
||||||
viewBinding.header.txtvFailure.setVisibility(View.GONE);
|
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.setText(R.string.updates_disabled_label);
|
||||||
viewBinding.header.txtvUpdatesDisabled.setVisibility(View.VISIBLE);
|
viewBinding.header.txtvUpdatesDisabled.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
@ -462,7 +470,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
}
|
}
|
||||||
viewBinding.header.txtvTitle.setText(feed.getTitle());
|
viewBinding.header.txtvTitle.setText(feed.getTitle());
|
||||||
viewBinding.header.txtvAuthor.setText(feed.getAuthor());
|
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();
|
FeedItemFilter filter = feed.getItemFilter();
|
||||||
if (filter.getValues().length > 0) {
|
if (filter.getValues().length > 0) {
|
||||||
viewBinding.header.txtvInformation.setText(R.string.filtered_label);
|
viewBinding.header.txtvInformation.setText(R.string.filtered_label);
|
||||||
@ -475,17 +487,30 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
} else {
|
} else {
|
||||||
viewBinding.header.txtvInformation.setVisibility(View.GONE);
|
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);
|
||||||
|
|
||||||
|
if (!isSubscribed && feed.getLastRefreshAttempt() < System.currentTimeMillis() - 1000L * 3600 * 24) {
|
||||||
|
FeedUpdateManager.getInstance().runOnce(getContext(), feed, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupHeaderView() {
|
private void setupHeaderView() {
|
||||||
if (feed == null || headerCreated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/bumptech/glide/issues/529
|
// https://github.com/bumptech/glide/issues/529
|
||||||
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff666666, 0x000000));
|
viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff666666, 0x000000));
|
||||||
viewBinding.header.butShowInfo.setOnClickListener(v -> showFeedInfo());
|
viewBinding.header.butShowInfo.setOnClickListener(v -> showFeedInfo());
|
||||||
viewBinding.header.imgvCover.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 -> {
|
viewBinding.header.butShowSettings.setOnClickListener(v -> {
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed);
|
FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed);
|
||||||
@ -495,7 +520,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
viewBinding.header.butFilter.setOnClickListener(v ->
|
viewBinding.header.butFilter.setOnClickListener(v ->
|
||||||
FeedItemFilterDialog.newInstance(feed).show(getChildFragmentManager(), null));
|
FeedItemFilterDialog.newInstance(feed).show(getChildFragmentManager(), null));
|
||||||
viewBinding.header.txtvFailure.setOnClickListener(v -> showErrorDetails());
|
viewBinding.header.txtvFailure.setOnClickListener(v -> showErrorDetails());
|
||||||
headerCreated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorDetails() {
|
private void showErrorDetails() {
|
||||||
@ -516,9 +540,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showFeedInfo() {
|
private void showFeedInfo() {
|
||||||
if (feed != null) {
|
if (feed == null) {
|
||||||
FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
|
return;
|
||||||
|
}
|
||||||
|
FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed);
|
||||||
|
if (getActivity() instanceof MainActivity) {
|
||||||
((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
|
((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 {
|
private class FeedItemListAdapter extends EpisodeItemListAdapter {
|
||||||
public FeedItemListAdapter(MainActivity mainActivity) {
|
public FeedItemListAdapter(FragmentActivity mainActivity) {
|
||||||
super(mainActivity);
|
super(mainActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +681,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
if (!inActionMode()) {
|
if (!inActionMode() && feed.getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
menu.findItem(R.id.multi_select).setVisible(true);
|
menu.findItem(R.id.multi_select).setVisible(true);
|
||||||
}
|
}
|
||||||
MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected);
|
MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected);
|
||||||
|
@ -39,6 +39,8 @@ import java.util.List;
|
|||||||
public class DownloadsSection extends HomeSection {
|
public class DownloadsSection extends HomeSection {
|
||||||
public static final String TAG = "DownloadsSection";
|
public static final String TAG = "DownloadsSection";
|
||||||
private static final int NUM_EPISODES = 2;
|
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 EpisodeItemListAdapter adapter;
|
||||||
private List<FeedItem> items;
|
private List<FeedItem> items;
|
||||||
private Disposable disposable;
|
private Disposable disposable;
|
||||||
@ -52,7 +54,7 @@ public class DownloadsSection extends HomeSection {
|
|||||||
viewBinding.recyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
|
viewBinding.recyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
|
||||||
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
|
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
|
||||||
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) requireActivity()).getRecycledViewPool());
|
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) requireActivity()).getRecycledViewPool());
|
||||||
adapter = new EpisodeItemListAdapter((MainActivity) requireActivity()) {
|
adapter = new EpisodeItemListAdapter(requireActivity()) {
|
||||||
@Override
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
@ -124,8 +126,7 @@ public class DownloadsSection extends HomeSection {
|
|||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
}
|
}
|
||||||
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
|
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
|
||||||
disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, NUM_EPISODES,
|
disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, NUM_EPISODES, FILTER_DOWNLOADED, sortOrder))
|
||||||
new FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder))
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(downloads -> {
|
.subscribe(downloads -> {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,8 +4,6 @@ import android.app.Dialog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.graphics.LightingColorFilter;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
@ -13,68 +11,45 @@ import android.text.TextUtils;
|
|||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import com.bumptech.glide.Glide;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.bumptech.glide.request.RequestOptions;
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
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.EditTextDialogBinding;
|
||||||
import de.danoeh.antennapod.databinding.OnlinefeedviewHeaderBinding;
|
import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
|
||||||
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
|
import de.danoeh.antennapod.model.download.DownloadError;
|
||||||
import de.danoeh.antennapod.event.FeedListUpdateEvent;
|
|
||||||
import de.danoeh.antennapod.event.PlayerStatusEvent;
|
|
||||||
import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
|
|
||||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
|
||||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
|
||||||
import de.danoeh.antennapod.model.download.DownloadRequest;
|
import de.danoeh.antennapod.model.download.DownloadRequest;
|
||||||
import de.danoeh.antennapod.model.download.DownloadResult;
|
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||||
import de.danoeh.antennapod.storage.database.DBReader;
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.storage.database.DBWriter;
|
import de.danoeh.antennapod.net.common.UrlChecker;
|
||||||
import de.danoeh.antennapod.net.discovery.CombinedSearcher;
|
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.PodcastSearchResult;
|
||||||
import de.danoeh.antennapod.net.discovery.PodcastSearcherRegistry;
|
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.FeedHandler;
|
||||||
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
|
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.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.common.ThemeUtils;
|
||||||
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
|
|
||||||
import de.danoeh.antennapod.ui.preferences.screen.synchronization.AuthenticationDialog;
|
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.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.observers.DisposableMaybeObserver;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
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.File;
|
||||||
import java.io.IOException;
|
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.
|
* and the activity will finish as soon as the error dialog is closed.
|
||||||
*/
|
*/
|
||||||
public class OnlineFeedViewActivity extends AppCompatActivity {
|
public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private static final int RESULT_ERROR = 2;
|
|
||||||
private static final String TAG = "OnlineFeedViewActivity";
|
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 String selectedDownloadUrl;
|
||||||
private Downloader downloader;
|
private Downloader downloader;
|
||||||
private String username = null;
|
private String username = null;
|
||||||
private String password = null;
|
private String password = null;
|
||||||
|
|
||||||
private boolean isPaused;
|
private boolean isPaused;
|
||||||
private boolean didPressSubscribe = false;
|
|
||||||
private boolean isFeedFoundBySearch = false;
|
private boolean isFeedFoundBySearch = false;
|
||||||
|
|
||||||
private Dialog dialog;
|
private Dialog dialog;
|
||||||
|
|
||||||
private Disposable download;
|
private Disposable download;
|
||||||
private Disposable parser;
|
private Disposable parser;
|
||||||
private Disposable updater;
|
|
||||||
|
|
||||||
private OnlinefeedviewHeaderBinding headerBinding;
|
|
||||||
private OnlinefeedviewActivityBinding viewBinding;
|
private OnlinefeedviewActivityBinding viewBinding;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -128,12 +89,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
viewBinding = OnlinefeedviewActivityBinding.inflate(getLayoutInflater());
|
viewBinding = OnlinefeedviewActivityBinding.inflate(getLayoutInflater());
|
||||||
setContentView(viewBinding.getRoot());
|
setContentView(viewBinding.getRoot());
|
||||||
|
|
||||||
viewBinding.transparentBackground.setOnClickListener(v -> finish());
|
viewBinding.transparentBackground.setOnClickListener(v -> finish());
|
||||||
viewBinding.closeButton.setOnClickListener(view -> finish());
|
|
||||||
viewBinding.card.setOnClickListener(null);
|
viewBinding.card.setOnClickListener(null);
|
||||||
viewBinding.card.setCardBackgroundColor(ThemeUtils.getColorFromAttr(this, R.attr.colorSurface));
|
viewBinding.card.setCardBackgroundColor(ThemeUtils.getColorFromAttr(this, R.attr.colorSurface));
|
||||||
headerBinding = OnlinefeedviewHeaderBinding.inflate(getLayoutInflater());
|
|
||||||
|
|
||||||
String feedUrl = null;
|
String feedUrl = null;
|
||||||
if (getIntent().hasExtra(ARG_FEEDURL)) {
|
if (getIntent().hasExtra(ARG_FEEDURL)) {
|
||||||
@ -149,7 +107,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
showNoPodcastFoundError();
|
showNoPodcastFoundError();
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Activity was started with url " + feedUrl);
|
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
|
// Remove subscribeonandroid.com from feed URL in order to subscribe to the actual feed URL
|
||||||
if (feedUrl.contains("subscribeonandroid.com")) {
|
if (feedUrl.contains("subscribeonandroid.com")) {
|
||||||
feedUrl = feedUrl.replaceFirst("((www.)?(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())
|
.setNeutralButton(android.R.string.ok, (dialog, which) -> finish())
|
||||||
.setTitle(R.string.error_label)
|
.setTitle(R.string.error_label)
|
||||||
.setMessage(R.string.null_value_podcast_error)
|
.setMessage(R.string.null_value_podcast_error)
|
||||||
.setOnDismissListener(dialog1 -> {
|
.setOnDismissListener(dialog1 -> finish())
|
||||||
setResult(RESULT_ERROR);
|
|
||||||
finish();
|
|
||||||
})
|
|
||||||
.show());
|
.show());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a progress indicator.
|
|
||||||
*/
|
|
||||||
private void setLoadingLayout() {
|
|
||||||
viewBinding.progressBar.setVisibility(View.VISIBLE);
|
|
||||||
viewBinding.feedDisplayContainer.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
EventBus.getDefault().register(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
isPaused = true;
|
isPaused = true;
|
||||||
EventBus.getDefault().unregister(this);
|
|
||||||
if (downloader != null && !downloader.isFinished()) {
|
if (downloader != null && !downloader.isFinished()) {
|
||||||
downloader.cancel();
|
downloader.cancel();
|
||||||
}
|
}
|
||||||
@ -205,9 +149,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if(updater != null) {
|
|
||||||
updater.dispose();
|
|
||||||
}
|
|
||||||
if(download != null) {
|
if(download != null) {
|
||||||
download.dispose();
|
download.dispose();
|
||||||
}
|
}
|
||||||
@ -239,7 +180,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
download = PodcastSearcherRegistry.lookupUrl(url)
|
download = PodcastSearcherRegistry.lookupUrl(url)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.subscribe(this::startFeedDownload,
|
.subscribe(this::downloadIfNotAlreadySubscribed,
|
||||||
error -> {
|
error -> {
|
||||||
if (error instanceof FeedUrlNotFoundException) {
|
if (error instanceof FeedUrlNotFoundException) {
|
||||||
tryToRetrieveFeedUrlBySearch((FeedUrlNotFoundException) error);
|
tryToRetrieveFeedUrlBySearch((FeedUrlNotFoundException) error);
|
||||||
@ -256,7 +197,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
if (url != null) {
|
if (url != null) {
|
||||||
Log.d(TAG, "Successfully retrieve feed url");
|
Log.d(TAG, "Successfully retrieve feed url");
|
||||||
isFeedFoundBySearch = true;
|
isFeedFoundBySearch = true;
|
||||||
startFeedDownload(url);
|
downloadIfNotAlreadySubscribed(url);
|
||||||
} else {
|
} else {
|
||||||
showNoPodcastFoundError();
|
showNoPodcastFoundError();
|
||||||
Log.d(TAG, "Failed to retrieve feed url");
|
Log.d(TAG, "Failed to retrieve feed url");
|
||||||
@ -277,6 +218,28 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
return null;
|
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) {
|
private void startFeedDownload(String url) {
|
||||||
Log.d(TAG, "Starting feed download");
|
Log.d(TAG, "Starting feed download");
|
||||||
selectedDownloadUrl = UrlChecker.prepareUrl(url);
|
selectedDownloadUrl = UrlChecker.prepareUrl(url);
|
||||||
@ -286,7 +249,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
download = Observable.fromCallable(() -> {
|
download = Observable.fromCallable(() -> {
|
||||||
feeds = DBReader.getFeedList();
|
|
||||||
downloader = new HttpDownloader(request);
|
downloader = new HttpDownloader(request);
|
||||||
downloader.call();
|
downloader.call();
|
||||||
return downloader.getResult();
|
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) {
|
private void parseFeed(String destination) {
|
||||||
Log.d(TAG, "Parsing feed");
|
Log.d(TAG, "Parsing feed");
|
||||||
parser = Maybe.fromCallable(() -> doParseFeed(destination))
|
parser = Observable.fromCallable(() -> {
|
||||||
.subscribeOn(Schedulers.computation())
|
FeedHandlerResult handlerResult = doParseFeed(destination);
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
Feed feed = handlerResult.feed;
|
||||||
.subscribeWith(new DisposableMaybeObserver<FeedHandlerResult>() {
|
feed.setState(Feed.STATE_NOT_SUBSCRIBED);
|
||||||
@Override
|
feed.setLastRefreshAttempt(System.currentTimeMillis());
|
||||||
public void onSuccess(@NonNull FeedHandlerResult result) {
|
FeedDatabaseWriter.updateFeed(this, feed, false);
|
||||||
showFeedInformation(result.feed, result.alternateFeedUrls);
|
Feed feedFromDb = DBReader.getFeed(feed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
}
|
feedFromDb.getPreferences().setKeepUpdated(false);
|
||||||
|
DBWriter.setFeedPreferences(feedFromDb.getPreferences());
|
||||||
@Override
|
return feed.getId();
|
||||||
public void onComplete() {
|
})
|
||||||
// Ignore null result: We showed the discovery dialog.
|
.subscribeOn(Schedulers.computation())
|
||||||
}
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(this::showFeedFragment, error -> {
|
||||||
@Override
|
error.printStackTrace();
|
||||||
public void onError(@NonNull Throwable error) {
|
showErrorDialog(error.getMessage(), "");
|
||||||
showErrorDialog(error.getMessage(), "");
|
});
|
||||||
Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -392,123 +333,23 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void showFeedFragment(long id) {
|
||||||
* Called when feed parsed successfully.
|
|
||||||
* This method is executed on the GUI thread.
|
|
||||||
*/
|
|
||||||
private void showFeedInformation(final Feed feed, Map<String, String> alternateFeedUrls) {
|
|
||||||
viewBinding.progressBar.setVisibility(View.GONE);
|
|
||||||
viewBinding.feedDisplayContainer.setVisibility(View.VISIBLE);
|
|
||||||
if (isFeedFoundBySearch) {
|
if (isFeedFoundBySearch) {
|
||||||
int resId = R.string.no_feed_url_podcast_found_by_search;
|
Toast.makeText(this, R.string.no_feed_url_podcast_found_by_search, Toast.LENGTH_LONG).show();
|
||||||
Snackbar.make(findViewById(android.R.id.content), resId, Snackbar.LENGTH_LONG).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewBinding.backgroundImage.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
|
viewBinding.progressBar.setVisibility(View.GONE);
|
||||||
|
FeedItemlistFragment fragment = FeedItemlistFragment.newInstance(id);
|
||||||
viewBinding.listView.addHeaderView(headerBinding.getRoot());
|
getSupportFragmentManager()
|
||||||
viewBinding.listView.setSelector(android.R.color.transparent);
|
.beginTransaction()
|
||||||
viewBinding.listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems()));
|
.replace(R.id.fragmentContainer, fragment, FeedItemlistFragment.TAG)
|
||||||
|
.commitAllowingStateLoss();
|
||||||
if (StringUtils.isNotBlank(feed.getImageUrl())) {
|
|
||||||
Glide.with(this)
|
|
||||||
.load(feed.getImageUrl())
|
|
||||||
.apply(new RequestOptions()
|
|
||||||
.placeholder(R.color.light_gray)
|
|
||||||
.error(R.color.light_gray)
|
|
||||||
.fitCenter()
|
|
||||||
.dontAnimate())
|
|
||||||
.into(viewBinding.coverImage);
|
|
||||||
Glide.with(this)
|
|
||||||
.load(feed.getImageUrl())
|
|
||||||
.apply(new RequestOptions()
|
|
||||||
.placeholder(R.color.image_readability_tint)
|
|
||||||
.error(R.color.image_readability_tint)
|
|
||||||
.transform(new FastBlurTransformation())
|
|
||||||
.dontAnimate())
|
|
||||||
.into(viewBinding.backgroundImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
viewBinding.titleLabel.setText(feed.getTitle());
|
|
||||||
viewBinding.authorLabel.setText(feed.getAuthor());
|
|
||||||
headerBinding.txtvDescription.setText(HtmlToPlainText.getPlainText(feed.getDescription()));
|
|
||||||
|
|
||||||
viewBinding.subscribeButton.setOnClickListener(v -> {
|
|
||||||
if (feedInFeedlist()) {
|
|
||||||
openFeed();
|
|
||||||
} else {
|
|
||||||
FeedDatabaseWriter.updateFeed(this, feed, false);
|
|
||||||
didPressSubscribe = true;
|
|
||||||
handleUpdatedFeedStatus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
viewBinding.stopPreviewButton.setOnClickListener(v -> {
|
|
||||||
PlaybackPreferences.writeNoMediaPlaying();
|
|
||||||
IntentUtils.sendLocalBroadcast(this, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (UserPreferences.isEnableAutodownload()) {
|
|
||||||
SharedPreferences preferences = getSharedPreferences(PREFS, MODE_PRIVATE);
|
|
||||||
viewBinding.autoDownloadCheckBox.setChecked(preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
|
|
||||||
headerBinding.txtvDescription.setOnClickListener(v -> {
|
|
||||||
if (headerBinding.txtvDescription.getMaxLines() > DESCRIPTION_MAX_LINES_COLLAPSED) {
|
|
||||||
headerBinding.txtvDescription.setMaxLines(DESCRIPTION_MAX_LINES_COLLAPSED);
|
|
||||||
} else {
|
|
||||||
headerBinding.txtvDescription.setMaxLines(2000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (alternateFeedUrls.isEmpty()) {
|
|
||||||
viewBinding.alternateUrlsSpinner.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
viewBinding.alternateUrlsSpinner.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
final List<String> alternateUrlsList = new ArrayList<>();
|
|
||||||
final List<String> alternateUrlsTitleList = new ArrayList<>();
|
|
||||||
|
|
||||||
alternateUrlsList.add(feed.getDownloadUrl());
|
|
||||||
alternateUrlsTitleList.add(feed.getTitle());
|
|
||||||
|
|
||||||
|
|
||||||
alternateUrlsList.addAll(alternateFeedUrls.keySet());
|
|
||||||
for (String url : alternateFeedUrls.keySet()) {
|
|
||||||
alternateUrlsTitleList.add(alternateFeedUrls.get(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
|
|
||||||
R.layout.alternate_urls_item, alternateUrlsTitleList) {
|
|
||||||
@Override
|
|
||||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
// reusing the old view causes a visual bug on Android <= 10
|
|
||||||
return super.getDropDownView(position, null, parent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
adapter.setDropDownViewResource(R.layout.alternate_urls_dropdown_item);
|
|
||||||
viewBinding.alternateUrlsSpinner.setAdapter(adapter);
|
|
||||||
viewBinding.alternateUrlsSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
selectedDownloadUrl = alternateUrlsList.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
handleUpdatedFeedStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openFeed() {
|
private void openFeed(long feedId) {
|
||||||
// feed.getId() is always 0, we have to retrieve the id from the feed list from the database
|
// feed.getId() is always 0, we have to retrieve the id from the feed list from the database
|
||||||
MainActivityStarter mainActivityStarter = new MainActivityStarter(this);
|
MainActivityStarter mainActivityStarter = new MainActivityStarter(this);
|
||||||
mainActivityStarter.withOpenFeed(getFeedId());
|
mainActivityStarter.withOpenFeed(feedId);
|
||||||
if (getIntent().getBooleanExtra(ARG_STARTED_FROM_SEARCH, false)) {
|
if (getIntent().getBooleanExtra(ARG_STARTED_FROM_SEARCH, false)) {
|
||||||
mainActivityStarter.withAddToBackStack();
|
mainActivityStarter.withAddToBackStack();
|
||||||
}
|
}
|
||||||
@ -516,60 +357,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
startActivity(mainActivityStarter.getIntent());
|
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
|
@UiThread
|
||||||
private void showErrorDialog(String errorMsg, String details) {
|
private void showErrorDialog(String errorMsg, String details) {
|
||||||
if (!isFinishing() && !isPaused) {
|
if (!isFinishing() && !isPaused) {
|
||||||
@ -589,7 +376,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
builder.setNeutralButton(R.string.edit_url_menu, (dialog, which) -> editUrl());
|
builder.setNeutralButton(R.string.edit_url_menu, (dialog, which) -> editUrl());
|
||||||
}
|
}
|
||||||
builder.setOnCancelListener(dialog -> {
|
builder.setOnCancelListener(dialog -> {
|
||||||
setResult(RESULT_ERROR);
|
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
if (dialog != null && dialog.isShowing()) {
|
if (dialog != null && dialog.isShowing()) {
|
||||||
@ -608,24 +394,15 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
builder.setView(dialogBinding.getRoot());
|
builder.setView(dialogBinding.getRoot());
|
||||||
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
||||||
setLoadingLayout();
|
|
||||||
lookupUrlAndDownload(dialogBinding.urlEditText.getText().toString());
|
lookupUrlAndDownload(dialogBinding.urlEditText.getText().toString());
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel());
|
builder.setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel());
|
||||||
builder.setOnCancelListener(dialog1 -> {
|
builder.setOnCancelListener(dialog1 -> {
|
||||||
setResult(RESULT_ERROR);
|
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
builder.show();
|
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).
|
* @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) {
|
if (urls.size() == 1) {
|
||||||
// Skip dialog and display the item directly
|
// Skip dialog and display the item directly
|
||||||
resetIntent(urls.get(0));
|
resetIntent(urls.get(0));
|
||||||
startFeedDownload(urls.get(0));
|
downloadIfNotAlreadySubscribed(urls.get(0));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +444,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
String selectedUrl = urls.get(which);
|
String selectedUrl = urls.get(which);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
resetIntent(selectedUrl);
|
resetIntent(selectedUrl);
|
||||||
startFeedDownload(selectedUrl);
|
downloadIfNotAlreadySubscribed(selectedUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
MaterialAlertDialogBuilder ab = new MaterialAlertDialogBuilder(OnlineFeedViewActivity.this)
|
MaterialAlertDialogBuilder ab = new MaterialAlertDialogBuilder(OnlineFeedViewActivity.this)
|
||||||
@ -704,7 +481,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||||||
protected void onConfirmed(String username, String password) {
|
protected void onConfirmed(String username, String password) {
|
||||||
OnlineFeedViewActivity.this.username = username;
|
OnlineFeedViewActivity.this.username = username;
|
||||||
OnlineFeedViewActivity.this.password = password;
|
OnlineFeedViewActivity.this.password = password;
|
||||||
startFeedDownload(feedUrl);
|
downloadIfNotAlreadySubscribed(feedUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,10 @@ import com.google.android.material.appbar.MaterialToolbar;
|
|||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.elevation.SurfaceColors;
|
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.playback.service.PlaybackController;
|
||||||
import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
|
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.chapters.ChapterUtils;
|
||||||
import de.danoeh.antennapod.ui.episodes.PlaybackSpeedUtils;
|
import de.danoeh.antennapod.ui.episodes.PlaybackSpeedUtils;
|
||||||
import de.danoeh.antennapod.ui.episodes.TimeSpeedConverter;
|
import de.danoeh.antennapod.ui.episodes.TimeSpeedConverter;
|
||||||
@ -497,14 +499,25 @@ public class AudioPlayerFragment extends Fragment implements
|
|||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.open_feed_item) {
|
} else if (itemId == R.id.open_feed_item) {
|
||||||
if (feedItem != null) {
|
if (feedItem != null) {
|
||||||
Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feedItem.getFeedId());
|
openFeed(feedItem.getFeed());
|
||||||
startActivity(intent);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
public void fadePlayerToToolbar(float slideOffset) {
|
||||||
float playerFadeProgress = Math.max(0.0f, Math.min(0.2f, slideOffset - 0.2f)) / 0.2f;
|
float playerFadeProgress = Math.max(0.0f, Math.min(0.2f, slideOffset - 0.2f)) / 0.2f;
|
||||||
View player = getView().findViewById(R.id.playerFragment);
|
View player = getView().findViewById(R.id.playerFragment);
|
||||||
|
@ -32,6 +32,8 @@ import com.bumptech.glide.request.RequestOptions;
|
|||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.activity.MainActivity;
|
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.chapters.ChapterUtils;
|
||||||
import de.danoeh.antennapod.ui.screen.chapter.ChaptersFragment;
|
import de.danoeh.antennapod.ui.screen.chapter.ChaptersFragment;
|
||||||
import de.danoeh.antennapod.playback.service.PlaybackController;
|
import de.danoeh.antennapod.playback.service.PlaybackController;
|
||||||
@ -122,9 +124,7 @@ public class CoverFragment extends Fragment {
|
|||||||
+ "\u00A0"
|
+ "\u00A0"
|
||||||
+ StringUtils.replace(StringUtils.stripToEmpty(pubDateStr), " ", "\u00A0"));
|
+ StringUtils.replace(StringUtils.stripToEmpty(pubDateStr), " ", "\u00A0"));
|
||||||
if (media instanceof FeedMedia) {
|
if (media instanceof FeedMedia) {
|
||||||
Intent openFeed = MainActivity.getIntentToOpenFeed(requireContext(),
|
viewBinding.txtvPodcastTitle.setOnClickListener(v -> openFeed(((FeedMedia) media).getItem().getFeed()));
|
||||||
((FeedMedia) media).getItem().getFeedId());
|
|
||||||
viewBinding.txtvPodcastTitle.setOnClickListener(v -> startActivity(openFeed));
|
|
||||||
} else {
|
} else {
|
||||||
viewBinding.txtvPodcastTitle.setOnClickListener(null);
|
viewBinding.txtvPodcastTitle.setOnClickListener(null);
|
||||||
}
|
}
|
||||||
@ -164,6 +164,18 @@ public class CoverFragment extends Fragment {
|
|||||||
updateChapterControlVisibility();
|
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() {
|
private void updateChapterControlVisibility() {
|
||||||
boolean chapterControlVisible = false;
|
boolean chapterControlVisible = false;
|
||||||
if (media.getChapters() != null) {
|
if (media.getChapters() != 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" />
|
|
@ -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" />
|
|
@ -65,13 +65,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingHorizontal="@dimen/additional_horizontal_spacing">
|
android:paddingHorizontal="@dimen/additional_horizontal_spacing">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/statisticsHeadingLabel"
|
android:id="@+id/statisticsHeadingLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:text="@string/statistics_label"
|
android:text="@string/statistics_label"
|
||||||
@ -89,6 +89,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minWidth="0dp"
|
android:minWidth="0dp"
|
||||||
android:minHeight="0dp"
|
android:minHeight="0dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
android:text="@string/statistics_view_all"
|
android:text="@string/statistics_view_all"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton" />
|
style="@style/Widget.MaterialComponents.Button.TextButton" />
|
||||||
|
|
||||||
@ -96,7 +97,6 @@
|
|||||||
android:id="@+id/supportHeadingLabel"
|
android:id="@+id/supportHeadingLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:text="@string/support_funding_label"
|
android:text="@string/support_funding_label"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
@ -119,7 +119,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:text="@string/description_label"
|
android:text="@string/description_label"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
@ -129,7 +128,6 @@
|
|||||||
android:id="@+id/descriptionLabel"
|
android:id="@+id/descriptionLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/design_time_lorem_ipsum"
|
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
|
@ -174,6 +174,20 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</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
|
<TextView
|
||||||
android:id="@+id/noMediaLabel"
|
android:id="@+id/noMediaLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -28,6 +28,14 @@
|
|||||||
android:layout_width="148dp"
|
android:layout_width="148dp"
|
||||||
android:layout_height="match_parent" />
|
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
|
<ImageButton
|
||||||
android:id="@+id/butShowInfo"
|
android:id="@+id/butShowInfo"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
@ -187,4 +195,52 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</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>
|
</LinearLayout>
|
||||||
|
@ -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>
|
|
@ -2,7 +2,6 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/transparentBackground"
|
android:id="@+id/transparentBackground"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
@ -11,169 +10,22 @@
|
|||||||
android:id="@+id/card"
|
android:id="@+id/card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="24dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginVertical="56dp"
|
||||||
android:elevation="16dp"
|
android:elevation="16dp"
|
||||||
app:cardCornerRadius="8dp">
|
app:cardCornerRadius="8dp">
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/fragmentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
style="?android:attr/progressBarStyle" />
|
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>
|
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
@ -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>
|
|
@ -15,6 +15,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
public class Feed {
|
public class Feed {
|
||||||
|
|
||||||
public static final int FEEDFILETYPE_FEED = 0;
|
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_RSS2 = "rss";
|
||||||
public static final String TYPE_ATOM1 = "atom";
|
public static final String TYPE_ATOM1 = "atom";
|
||||||
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
|
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
|
||||||
@ -101,6 +103,7 @@ public class Feed {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private SortOrder sortOrder;
|
private SortOrder sortOrder;
|
||||||
|
private int state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor is used for restoring a feed from the database.
|
* 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 description, String paymentLinks, String author, String language,
|
||||||
String type, String feedIdentifier, String imageUrl, String fileUrl,
|
String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||||
String downloadUrl, long lastRefreshAttempt, boolean paged, String nextPageLink,
|
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.localFileUrl = fileUrl;
|
||||||
this.downloadUrl = downloadUrl;
|
this.downloadUrl = downloadUrl;
|
||||||
this.lastRefreshAttempt = lastRefreshAttempt;
|
this.lastRefreshAttempt = lastRefreshAttempt;
|
||||||
@ -135,6 +138,7 @@ public class Feed {
|
|||||||
}
|
}
|
||||||
setSortOrder(sortOrder);
|
setSortOrder(sortOrder);
|
||||||
this.lastUpdateFailed = lastUpdateFailed;
|
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 author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||||
String downloadUrl, long lastRefreshAttempt) {
|
String downloadUrl, long lastRefreshAttempt) {
|
||||||
this(id, lastModified, title, null, link, description, paymentLink, author, language, type, feedIdentifier,
|
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() {
|
public boolean isLocalFeed() {
|
||||||
return downloadUrl.startsWith(PREFIX_LOCAL_FOLDER);
|
return downloadUrl.startsWith(PREFIX_LOCAL_FOLDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(int state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ public class FeedItemFilter implements Serializable {
|
|||||||
public final boolean showIsFavorite;
|
public final boolean showIsFavorite;
|
||||||
public final boolean showNotFavorite;
|
public final boolean showNotFavorite;
|
||||||
public final boolean showInHistory;
|
public final boolean showInHistory;
|
||||||
|
public final boolean includeNotSubscribed;
|
||||||
|
|
||||||
public static final String PLAYED = "played";
|
public static final String PLAYED = "played";
|
||||||
public static final String UNPLAYED = "unplayed";
|
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 DOWNLOADED = "downloaded";
|
||||||
public static final String NOT_DOWNLOADED = "not_downloaded";
|
public static final String NOT_DOWNLOADED = "not_downloaded";
|
||||||
public static final String IS_IN_HISTORY = "is_in_history";
|
public static final String IS_IN_HISTORY = "is_in_history";
|
||||||
|
public static final String INCLUDE_NOT_SUBSCRIBED = "include_not_subscribed";
|
||||||
|
|
||||||
public static FeedItemFilter unfiltered() {
|
public static FeedItemFilter unfiltered() {
|
||||||
return new FeedItemFilter("");
|
return new FeedItemFilter("");
|
||||||
@ -48,6 +50,10 @@ public class FeedItemFilter implements Serializable {
|
|||||||
this(TextUtils.split(properties, ","));
|
this(TextUtils.split(properties, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FeedItemFilter(FeedItemFilter filter, String... additionalProperties) {
|
||||||
|
this(TextUtils.join(",", filter.getValues()) + "," + TextUtils.join(",", additionalProperties));
|
||||||
|
}
|
||||||
|
|
||||||
public FeedItemFilter(String... properties) {
|
public FeedItemFilter(String... properties) {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
|
||||||
@ -66,6 +72,7 @@ public class FeedItemFilter implements Serializable {
|
|||||||
showNotFavorite = hasProperty(NOT_FAVORITE);
|
showNotFavorite = hasProperty(NOT_FAVORITE);
|
||||||
showNew = hasProperty(NEW);
|
showNew = hasProperty(NEW);
|
||||||
showInHistory = hasProperty(IS_IN_HISTORY);
|
showInHistory = hasProperty(IS_IN_HISTORY);
|
||||||
|
includeNotSubscribed = hasProperty(INCLUDE_NOT_SUBSCRIBED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasProperty(String property) {
|
private boolean hasProperty(String property) {
|
||||||
@ -112,6 +119,9 @@ public class FeedItemFilter implements Serializable {
|
|||||||
} else if (showInHistory && item.getMedia() != null
|
} else if (showInHistory && item.getMedia() != null
|
||||||
&& item.getMedia().getPlaybackCompletionDate().getTime() == 0) {
|
&& item.getMedia().getPlaybackCompletionDate().getTime() == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
} else if (!includeNotSubscribed && item.getFeed() != null
|
||||||
|
&& item.getFeed().getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ public class SubscriptionsFilter {
|
|||||||
private final String[] properties;
|
private final String[] properties;
|
||||||
|
|
||||||
private boolean showIfCounterGreaterZero = false;
|
private boolean showIfCounterGreaterZero = false;
|
||||||
|
private boolean hideNonSubscribedFeeds = true;
|
||||||
|
|
||||||
private boolean showAutoDownloadEnabled = false;
|
private boolean showAutoDownloadEnabled = false;
|
||||||
private boolean showAutoDownloadDisabled = false;
|
private boolean showAutoDownloadDisabled = false;
|
||||||
@ -67,10 +68,6 @@ public class SubscriptionsFilter {
|
|||||||
* Run a list of feed items through the filter.
|
* Run a list of feed items through the filter.
|
||||||
*/
|
*/
|
||||||
public List<Feed> filter(List<Feed> items, Map<Long, Integer> feedCounters) {
|
public List<Feed> filter(List<Feed> items, Map<Long, Integer> feedCounters) {
|
||||||
if (properties.length == 0) {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Feed> result = new ArrayList<>();
|
List<Feed> result = new ArrayList<>();
|
||||||
|
|
||||||
for (Feed item : items) {
|
for (Feed item : items) {
|
||||||
@ -95,6 +92,10 @@ public class SubscriptionsFilter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hideNonSubscribedFeeds && item.getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If the item reaches here, it meets all criteria (except counter > 0)
|
// If the item reaches here, it meets all criteria (except counter > 0)
|
||||||
result.add(item);
|
result.add(item);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,8 @@ public class ItunesTopListLoader {
|
|||||||
List<PodcastSearchResult> suggestedPodcasts, List<Feed> subscribedFeeds, int limit) {
|
List<PodcastSearchResult> suggestedPodcasts, List<Feed> subscribedFeeds, int limit) {
|
||||||
Set<String> subscribedPodcastsSet = new HashSet<>();
|
Set<String> subscribedPodcastsSet = new HashSet<>();
|
||||||
for (Feed subscribedFeed : subscribedFeeds) {
|
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());
|
subscribedPodcastsSet.add(subscribedFeed.getTitle().trim() + " - " + subscribedFeed.getAuthor().trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import android.util.Log;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
|
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.net.sync.serviceinterface.SynchronizationQueueSink;
|
||||||
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
|
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
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());
|
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)
|
EpisodeAction action = new EpisodeAction.Builder(item, EpisodeAction.DOWNLOAD)
|
||||||
.currentTimestamp()
|
.currentTimestamp()
|
||||||
.build();
|
.build();
|
||||||
|
@ -35,6 +35,7 @@ import de.danoeh.antennapod.model.download.DownloadRequest;
|
|||||||
|
|
||||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestBuilder;
|
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequestBuilder;
|
||||||
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
|
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
|
||||||
|
import de.danoeh.antennapod.storage.database.NonSubscribedFeedsCleaner;
|
||||||
import de.danoeh.antennapod.ui.notifications.NotificationUtils;
|
import de.danoeh.antennapod.ui.notifications.NotificationUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -69,7 +70,7 @@ public class FeedUpdateWorker extends Worker {
|
|||||||
Iterator<Feed> itr = toUpdate.iterator();
|
Iterator<Feed> itr = toUpdate.iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
Feed feed = itr.next();
|
Feed feed = itr.next();
|
||||||
if (!feed.getPreferences().getKeepUpdated()) {
|
if (!feed.getPreferences().getKeepUpdated() || feed.getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -99,8 +100,9 @@ public class FeedUpdateWorker extends Worker {
|
|||||||
}
|
}
|
||||||
refreshFeeds(toUpdate, force);
|
refreshFeeds(toUpdate, force);
|
||||||
|
|
||||||
notificationManager.cancel(R.id.notification_updating_feeds);
|
NonSubscribedFeedsCleaner.deleteOldNonSubscribedFeeds(getApplicationContext());
|
||||||
AutoDownloadManager.getInstance().autodownloadUndownloadedItems(getApplicationContext());
|
AutoDownloadManager.getInstance().autodownloadUndownloadedItems(getApplicationContext());
|
||||||
|
notificationManager.cancel(R.id.notification_updating_feeds);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package de.danoeh.antennapod.net.sync.serviceinterface;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.storage.preferences.SynchronizationSettings;
|
import de.danoeh.antennapod.storage.preferences.SynchronizationSettings;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
|
|
||||||
@ -62,7 +63,8 @@ public class SynchronizationQueueSink {
|
|||||||
if (!SynchronizationSettings.isProviderConnected()) {
|
if (!SynchronizationSettings.isProviderConnected()) {
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (media.getStartPosition() < 0 || (!completed && media.getStartPosition() >= media.getPosition())) {
|
if (media.getStartPosition() < 0 || (!completed && media.getStartPosition() >= media.getPosition())) {
|
||||||
|
@ -436,7 +436,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||||||
DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.UNPLAYED))));
|
DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.UNPLAYED))));
|
||||||
List<Feed> feeds = DBReader.getFeedList();
|
List<Feed> feeds = DBReader.getFeedList();
|
||||||
for (Feed feed : feeds) {
|
for (Feed feed : feeds) {
|
||||||
mediaItems.add(createBrowsableMediaItemForFeed(feed));
|
if (feed.getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
|
mediaItems.add(createBrowsableMediaItemForFeed(feed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mediaItems;
|
return mediaItems;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,9 @@ public final class DBReader {
|
|||||||
try (FeedCursor cursor = new FeedCursor(adapter.getFeedCursor(feedId))) {
|
try (FeedCursor cursor = new FeedCursor(adapter.getFeedCursor(feedId))) {
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
feed = cursor.getFeed();
|
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);
|
List<FeedItem> items = getFeedItemList(feed, filter, feed.getSortOrder(), offset, limit);
|
||||||
for (FeedItem item : items) {
|
for (FeedItem item : items) {
|
||||||
item.setFeed(feed);
|
item.setFeed(feed);
|
||||||
@ -668,9 +670,10 @@ public final class DBReader {
|
|||||||
final Map<Long, Integer> feedCounters = adapter.getFeedCounters(feedCounter);
|
final Map<Long, Integer> feedCounters = adapter.getFeedCounters(feedCounter);
|
||||||
List<Feed> feeds = getFeedList();
|
List<Feed> feeds = getFeedList();
|
||||||
|
|
||||||
if (subscriptionsFilter != null) {
|
if (subscriptionsFilter == null) {
|
||||||
feeds = subscriptionsFilter.filter(feeds, feedCounters);
|
subscriptionsFilter = new SubscriptionsFilter("");
|
||||||
}
|
}
|
||||||
|
feeds = subscriptionsFilter.filter(feeds, feedCounters);
|
||||||
|
|
||||||
Comparator<Feed> comparator;
|
Comparator<Feed> comparator;
|
||||||
switch (feedOrder) {
|
switch (feedOrder) {
|
||||||
|
@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
|
|
||||||
import static de.danoeh.antennapod.model.feed.FeedPreferences.SPEED_USE_GLOBAL;
|
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
|
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_SKIP_SILENCE + " INTEGER");
|
+ " 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import androidx.documentfile.provider.DocumentFile;
|
|||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import de.danoeh.antennapod.event.DownloadLogEvent;
|
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.AutoDownloadManager;
|
||||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
||||||
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
|
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
|
// Do full update of this feed to get rid of the item
|
||||||
FeedUpdateManager.getInstance().runOnce(context, media.getItem().getFeed());
|
FeedUpdateManager.getInstance().runOnce(context, media.getItem().getFeed());
|
||||||
} else {
|
} else {
|
||||||
// Gpodder: queue delete action for synchronization
|
if (media.getItem().getFeed().getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
FeedItem item = media.getItem();
|
FeedItem item = media.getItem();
|
||||||
EpisodeAction action = new EpisodeAction.Builder(item, EpisodeAction.DELETE)
|
EpisodeAction action = new EpisodeAction.Builder(item, EpisodeAction.DELETE)
|
||||||
.currentTimestamp()
|
.currentTimestamp()
|
||||||
.build();
|
.build();
|
||||||
SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, action);
|
SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, action);
|
||||||
|
}
|
||||||
|
|
||||||
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
||||||
}
|
}
|
||||||
@ -174,7 +176,7 @@ public class DBWriter {
|
|||||||
adapter.removeFeed(feed);
|
adapter.removeFeed(feed);
|
||||||
adapter.close();
|
adapter.close();
|
||||||
|
|
||||||
if (!feed.isLocalFeed()) {
|
if (!feed.isLocalFeed() && feed.getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownloadUrl());
|
SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownloadUrl());
|
||||||
}
|
}
|
||||||
EventBus.getDefault().post(new FeedListUpdateEvent(feed));
|
EventBus.getDefault().post(new FeedListUpdateEvent(feed));
|
||||||
@ -786,7 +788,7 @@ public class DBWriter {
|
|||||||
adapter.close();
|
adapter.close();
|
||||||
|
|
||||||
for (Feed feed : feeds) {
|
for (Feed feed : feeds) {
|
||||||
if (!feed.isLocalFeed()) {
|
if (!feed.isLocalFeed() && feed.getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.getDownloadUrl());
|
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.
|
* Sort the FeedItems in the queue with the given the named sort order.
|
||||||
*
|
*
|
||||||
|
@ -157,7 +157,8 @@ public abstract class FeedDatabaseWriter {
|
|||||||
+ "\n\nNow the feed contains:\n" + duplicateEpisodeDetails(item)));
|
+ "\n\nNow the feed contains:\n" + duplicateEpisodeDetails(item)));
|
||||||
oldItem.setItemIdentifier(item.getItemIdentifier());
|
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)
|
EpisodeAction action = new EpisodeAction.Builder(oldItem, EpisodeAction.PLAY)
|
||||||
.currentTimestamp()
|
.currentTimestamp()
|
||||||
.started(oldItem.getMedia().getDuration() / 1000)
|
.started(oldItem.getMedia().getDuration() / 1000)
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -52,7 +52,7 @@ public class PodDBAdapter {
|
|||||||
|
|
||||||
private static final String TAG = "PodDBAdapter";
|
private static final String TAG = "PodDBAdapter";
|
||||||
public static final String DATABASE_NAME = "Antennapod.db";
|
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.
|
* 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_EPISODE_NOTIFICATION = "episode_notification";
|
||||||
public static final String KEY_NEW_EPISODES_ACTION = "new_episodes_action";
|
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_PODCASTINDEX_CHAPTER_URL = "podcastindex_chapter_url";
|
||||||
|
public static final String KEY_STATE = "state";
|
||||||
|
|
||||||
// Table names
|
// Table names
|
||||||
public static final String TABLE_NAME_FEEDS = "Feeds";
|
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_INTRO + " INTEGER DEFAULT 0,"
|
||||||
+ KEY_FEED_SKIP_ENDING + " INTEGER DEFAULT 0,"
|
+ KEY_FEED_SKIP_ENDING + " INTEGER DEFAULT 0,"
|
||||||
+ KEY_EPISODE_NOTIFICATION + " INTEGER DEFAULT 0,"
|
+ KEY_EPISODE_NOTIFICATION + " INTEGER DEFAULT 0,"
|
||||||
|
+ KEY_STATE + " INTEGER DEFAULT " + Feed.STATE_SUBSCRIBED + ","
|
||||||
+ KEY_NEW_EPISODES_ACTION + " INTEGER DEFAULT 0)";
|
+ KEY_NEW_EPISODES_ACTION + " INTEGER DEFAULT 0)";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
|
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_INTRO + ", "
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING + ", "
|
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING + ", "
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_EPISODE_NOTIFICATION + ", "
|
+ TABLE_NAME_FEEDS + "." + KEY_EPISODE_NOTIFICATION + ", "
|
||||||
|
+ TABLE_NAME_FEEDS + "." + KEY_STATE + ", "
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_NEW_EPISODES_ACTION;
|
+ TABLE_NAME_FEEDS + "." + KEY_NEW_EPISODES_ACTION;
|
||||||
|
|
||||||
private static final String JOIN_FEED_ITEM_AND_MEDIA = " LEFT JOIN " + TABLE_NAME_FEED_MEDIA
|
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
|
"SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA;
|
+ 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 Context context;
|
||||||
private static PodDBAdapter instance;
|
private static PodDBAdapter instance;
|
||||||
@ -431,6 +437,7 @@ public class PodDBAdapter {
|
|||||||
values.put(KEY_LASTUPDATE, feed.getLastModified());
|
values.put(KEY_LASTUPDATE, feed.getLastModified());
|
||||||
values.put(KEY_TYPE, feed.getType());
|
values.put(KEY_TYPE, feed.getType());
|
||||||
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
|
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
|
||||||
|
values.put(KEY_STATE, feed.getState());
|
||||||
|
|
||||||
values.put(KEY_IS_PAGED, feed.isPaged());
|
values.put(KEY_IS_PAGED, feed.isPaged());
|
||||||
values.put(KEY_NEXT_PAGE_LINK, feed.getNextPageLink());
|
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)});
|
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.
|
* Inserts or updates a download status.
|
||||||
*/
|
*/
|
||||||
@ -1101,6 +1114,7 @@ public class PodDBAdapter {
|
|||||||
// Hide episodes that have been played but not completed
|
// Hide episodes that have been played but not completed
|
||||||
+ " AND (" + KEY_LAST_PLAYED_TIME + " == 0"
|
+ " AND (" + KEY_LAST_PLAYED_TIME + " == 0"
|
||||||
+ " OR " + KEY_LAST_PLAYED_TIME + " > " + (System.currentTimeMillis() - 1000L * 3600L) + ")"
|
+ " OR " + KEY_LAST_PLAYED_TIME + " > " + (System.currentTimeMillis() - 1000L * 3600L) + ")"
|
||||||
|
+ " AND " + SELECT_WHERE_FEED_IS_SUBSCRIBED
|
||||||
+ " ORDER BY " + randomEpisodeNumber(seed);
|
+ " ORDER BY " + randomEpisodeNumber(seed);
|
||||||
final String query = "SELECT * FROM (" + allItemsRandomOrder + ")"
|
final String query = "SELECT * FROM (" + allItemsRandomOrder + ")"
|
||||||
+ " GROUP BY " + KEY_FEED
|
+ " GROUP BY " + KEY_FEED
|
||||||
@ -1221,6 +1235,7 @@ public class PodDBAdapter {
|
|||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
+ JOIN_FEED_ITEM_AND_MEDIA
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
|
+ " 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;
|
+ " GROUP BY " + TABLE_NAME_FEEDS + "." + KEY_ID;
|
||||||
return db.rawQuery(query, null);
|
return db.rawQuery(query, null);
|
||||||
}
|
}
|
||||||
@ -1372,7 +1387,7 @@ public class PodDBAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String queryStart = SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION
|
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);
|
StringBuilder sb = new StringBuilder(queryStart);
|
||||||
|
|
||||||
for (int i = 0; i < queryWords.length; i++) {
|
for (int i = 0; i < queryWords.length; i++) {
|
||||||
@ -1401,12 +1416,13 @@ public class PodDBAdapter {
|
|||||||
public Cursor searchFeeds(String searchQuery) {
|
public Cursor searchFeeds(String searchQuery) {
|
||||||
String[] queryWords = prepareSearchQuery(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);
|
StringBuilder sb = new StringBuilder(queryStart);
|
||||||
|
|
||||||
for (int i = 0; i < queryWords.length; i++) {
|
for (int i = 0; i < queryWords.length; i++) {
|
||||||
sb
|
sb
|
||||||
.append("(")
|
.append(" AND (")
|
||||||
.append(KEY_TITLE).append(" LIKE '%").append(queryWords[i])
|
.append(KEY_TITLE).append(" LIKE '%").append(queryWords[i])
|
||||||
.append("%' OR ")
|
.append("%' OR ")
|
||||||
.append(KEY_CUSTOM_TITLE).append(" LIKE '%").append(queryWords[i])
|
.append(KEY_CUSTOM_TITLE).append(" LIKE '%").append(queryWords[i])
|
||||||
@ -1415,13 +1431,9 @@ public class PodDBAdapter {
|
|||||||
.append("%' OR ")
|
.append("%' OR ")
|
||||||
.append(KEY_DESCRIPTION).append(" LIKE '%").append(queryWords[i])
|
.append(KEY_DESCRIPTION).append(" LIKE '%").append(queryWords[i])
|
||||||
.append("%') ");
|
.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);
|
return db.rawQuery(sb.toString(), null);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ public class FeedCursor extends CursorWrapper {
|
|||||||
private final int indexSortOrder;
|
private final int indexSortOrder;
|
||||||
private final int indexLastUpdateFailed;
|
private final int indexLastUpdateFailed;
|
||||||
private final int indexImageUrl;
|
private final int indexImageUrl;
|
||||||
|
private final int indexState;
|
||||||
|
|
||||||
public FeedCursor(Cursor cursor) {
|
public FeedCursor(Cursor cursor) {
|
||||||
super(new FeedPreferencesCursor(cursor));
|
super(new FeedPreferencesCursor(cursor));
|
||||||
@ -58,6 +59,7 @@ public class FeedCursor extends CursorWrapper {
|
|||||||
indexSortOrder = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SORT_ORDER);
|
indexSortOrder = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SORT_ORDER);
|
||||||
indexLastUpdateFailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
|
indexLastUpdateFailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
|
||||||
indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
|
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(indexNextPageLink),
|
||||||
getString(indexHide),
|
getString(indexHide),
|
||||||
SortOrder.fromCodeString(getString(indexSortOrder)),
|
SortOrder.fromCodeString(getString(indexSortOrder)),
|
||||||
getInt(indexLastUpdateFailed) > 0);
|
getInt(indexLastUpdateFailed) > 0,
|
||||||
|
getInt(indexState));
|
||||||
feed.setPreferences(preferencesCursor.getFeedPreferences());
|
feed.setPreferences(preferencesCursor.getFeedPreferences());
|
||||||
return feed;
|
return feed;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,9 @@ public class FeedItemFilterQuery {
|
|||||||
if (filter.showInHistory) {
|
if (filter.showInHistory) {
|
||||||
statements.add(keyCompletionDate + " > 0 ");
|
statements.add(keyCompletionDate + " > 0 ");
|
||||||
}
|
}
|
||||||
|
if (!filter.includeNotSubscribed) {
|
||||||
|
statements.add(PodDBAdapter.SELECT_WHERE_FEED_IS_SUBSCRIBED);
|
||||||
|
}
|
||||||
|
|
||||||
if (statements.isEmpty()) {
|
if (statements.isEmpty()) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,9 @@ public class HtmlWriter {
|
|||||||
|
|
||||||
writer.append(templateParts[0]);
|
writer.append(templateParts[0]);
|
||||||
for (Feed feed : feeds) {
|
for (Feed feed : feeds) {
|
||||||
|
if (feed.getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
writer.append("<li><div><img src=\"");
|
writer.append("<li><div><img src=\"");
|
||||||
writer.append(feed.getImageUrl());
|
writer.append(feed.getImageUrl());
|
||||||
writer.append("\" /><p>");
|
writer.append("\" /><p>");
|
||||||
|
@ -48,6 +48,9 @@ public class OpmlWriter {
|
|||||||
|
|
||||||
xs.startTag(null, OpmlSymbols.BODY);
|
xs.startTag(null, OpmlSymbols.BODY);
|
||||||
for (Feed feed : feeds) {
|
for (Feed feed : feeds) {
|
||||||
|
if (feed.getState() != Feed.STATE_SUBSCRIBED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
xs.startTag(null, OpmlSymbols.OUTLINE);
|
xs.startTag(null, OpmlSymbols.OUTLINE);
|
||||||
xs.attribute(null, OpmlSymbols.TEXT, feed.getTitle());
|
xs.attribute(null, OpmlSymbols.TEXT, feed.getTitle());
|
||||||
xs.attribute(null, OpmlSymbols.TITLE, feed.getTitle());
|
xs.attribute(null, OpmlSymbols.TITLE, feed.getTitle());
|
||||||
|
17
ui/common/src/main/res/drawable/bg_message_info.xml
Normal file
17
ui/common/src/main/res/drawable/bg_message_info.xml
Normal file
@ -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>
|
@ -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>
|
|
11
ui/common/src/main/res/drawable/ic_close.xml
Normal file
11
ui/common/src/main/res/drawable/ic_close.xml
Normal file
@ -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>
|
@ -8,7 +8,6 @@
|
|||||||
<color name="medium_gray">#afafaf</color>
|
<color name="medium_gray">#afafaf</color>
|
||||||
<color name="black">#000000</color>
|
<color name="black">#000000</color>
|
||||||
<color name="image_readability_tint">#80000000</color>
|
<color name="image_readability_tint">#80000000</color>
|
||||||
<color name="feed_image_bg">#50000000</color>
|
|
||||||
<color name="feed_text_bg">#55333333</color>
|
<color name="feed_text_bg">#55333333</color>
|
||||||
|
|
||||||
<!-- Theme colors -->
|
<!-- Theme colors -->
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
<dimen name="text_size_large">22sp</dimen>
|
<dimen name="text_size_large">22sp</dimen>
|
||||||
<dimen name="thumbnail_length_itemlist">56dp</dimen>
|
<dimen name="thumbnail_length_itemlist">56dp</dimen>
|
||||||
<dimen name="thumbnail_length_queue_item">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="thumbnail_length_navlist">40dp</dimen>
|
||||||
<dimen name="listitem_iconwithtext_height">48dp</dimen>
|
<dimen name="listitem_iconwithtext_height">48dp</dimen>
|
||||||
<dimen name="listitem_iconwithtext_textleftpadding">16dp</dimen>
|
<dimen name="listitem_iconwithtext_textleftpadding">16dp</dimen>
|
||||||
|
@ -681,9 +681,8 @@
|
|||||||
|
|
||||||
<!-- Online feed view -->
|
<!-- Online feed view -->
|
||||||
<string name="subscribe_label">Subscribe</string>
|
<string name="subscribe_label">Subscribe</string>
|
||||||
<string name="subscribing_label">Subscribing…</string>
|
<string name="preview_episodes">Episodes preview</string>
|
||||||
<string name="preview_episode">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>
|
||||||
<string name="stop_preview">Stop preview</string>
|
|
||||||
|
|
||||||
<!-- Content descriptions for image buttons -->
|
<!-- Content descriptions for image buttons -->
|
||||||
<string name="toolbar_back_button_content_description">Back</string>
|
<string name="toolbar_back_button_content_description">Back</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user