summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java120
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java84
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java96
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java38
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java74
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java110
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java81
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java99
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java281
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java173
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java137
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java39
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java77
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java80
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java210
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java32
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java89
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java119
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java99
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java143
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/FlattrPreferencesFragment.java61
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java35
48 files changed, 1476 insertions, 1340 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
index bfa694e5c..26e360bd3 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -199,8 +199,6 @@ public class FeedInfoActivity extends AppCompatActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.support_item).setVisible(
- feed != null && feed.getPaymentLink() != null);
menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
deleted file mode 100644
index 2b4384a02..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/FlattrAuthActivity.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import org.shredzone.flattr4j.exception.FlattrException;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-
-/** Guides the user through the authentication process */
-
-public class FlattrAuthActivity extends AppCompatActivity {
- private static final String TAG = "FlattrAuthActivity";
-
- private TextView txtvExplanation;
- private Button butAuthenticate;
- private Button butReturn;
-
- private boolean authSuccessful;
-
- private static FlattrAuthActivity singleton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- singleton = this;
- authSuccessful = false;
- if (BuildConfig.DEBUG) Log.d(TAG, "Activity created");
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.flattr_auth);
- txtvExplanation = findViewById(R.id.txtvExplanation);
- butAuthenticate = findViewById(R.id.but_authenticate);
- butReturn = findViewById(R.id.but_return_home);
-
- butReturn.setOnClickListener(v -> {
- Intent intent = new Intent(FlattrAuthActivity.this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- });
-
- butAuthenticate.setOnClickListener(v -> {
- try {
- FlattrUtils.startAuthProcess(FlattrAuthActivity.this);
- } catch (FlattrException e) {
- e.printStackTrace();
- }
- });
- }
-
- public static FlattrAuthActivity getInstance() {
- return singleton;
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (BuildConfig.DEBUG) Log.d(TAG, "Activity resumed");
- Uri uri = getIntent().getData();
- if (uri != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Received uri");
- FlattrUtils.handleCallback(this, uri);
- }
- }
-
- public void handleAuthenticationSuccess() {
- authSuccessful = true;
- txtvExplanation.setText(R.string.flattr_auth_success);
- butAuthenticate.setEnabled(false);
- butReturn.setVisibility(View.VISIBLE);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
-
-
- @Override
- protected void onPause() {
- super.onPause();
- if (authSuccessful) {
- finish();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- if (authSuccessful) {
- Intent intent = new Intent(this, PreferenceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- } else {
- finish();
- }
- break;
- default:
- return false;
- }
- return true;
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 91e89d7c5..728019196 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -208,7 +208,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
checkFirstLaunch();
PreferenceUpgrader.checkUpgrades(this);
- NotificationUtils.createChannels(this);
}
private void saveLastNavFragment(String tag) {
@@ -579,17 +578,17 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(this,
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
+ case R.id.remove_all_new_flags_item:
+ ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(this,
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg) {
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
- DBWriter.markFeedSeen(feed.getId());
+ DBWriter.removeFeedNewFlag(feed.getId());
}
};
- markAllSeenConfirmationDialog.createNewDialog().show();
+ removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
case R.id.mark_all_read_item:
ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(this,
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 3d5c59a4a..3946400a4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -330,11 +330,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Playable media = controller.getMedia();
boolean isFeedMedia = media != null && (media instanceof FeedMedia);
- menu.findItem(R.id.support_item).setVisible(isFeedMedia && media.getPaymentLink() != null &&
- ((FeedMedia) media).getItem() != null &&
- ((FeedMedia) media).getItem().getFlattrStatus().flattrable()
- );
-
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
@@ -603,11 +598,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
- case R.id.support_item:
- if (media instanceof FeedMedia) {
- DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
- }
- break;
case R.id.share_link_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
index 191481dd8..4fec1cfc5 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java
@@ -46,7 +46,6 @@ import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
@@ -170,6 +169,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
pager.setCurrentItem(lastPosition);
}
+ @Override
protected void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
@@ -339,8 +339,8 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- DBWriter.markFeedSeen(feed.getId());
+ case R.id.remove_all_new_flags_item:
+ DBWriter.removeFeedNewFlag(feed.getId());
return true;
case R.id.mark_all_read_item:
DBWriter.markFeedRead(feed.getId());
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index c13f713e0..7e0ae173f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -15,7 +15,6 @@ import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.preferences.AutoDownloadPreferencesFragment;
-import de.danoeh.antennapod.fragment.preferences.FlattrPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.GpodderPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.IntegrationsPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment;
@@ -64,8 +63,6 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
prefFragment = new AutoDownloadPreferencesFragment();
} else if (screen == R.xml.preferences_gpodder) {
prefFragment = new GpodderPreferencesFragment();
- } else if (screen == R.xml.preferences_flattr) {
- prefFragment = new FlattrPreferencesFragment();
} else if (screen == R.xml.preferences_playback) {
prefFragment = new PlaybackPreferencesFragment();
}
@@ -86,8 +83,6 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
return R.string.user_interface_label;
case R.xml.preferences_integrations:
return R.string.integrations_label;
- case R.xml.preferences_flattr:
- return R.string.flattr_label;
case R.xml.preferences_gpodder:
return R.string.gpodnet_main_label;
default:
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
index df21f713d..2d7898d5b 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
@@ -104,10 +104,6 @@ public class GpodnetAuthenticationActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- }
-
private void setupLoginView(View view) {
final EditText username = view.findViewById(R.id.etxtUsername);
final EditText password = view.findViewById(R.id.etxtPassword);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index 8866d987e..7aa9f8f21 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.adapter;
-import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
@@ -280,7 +279,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
};
FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
- contextMenuInterface.setItemVisibility(R.id.mark_as_seen_item, item.isNew());
+ contextMenuInterface.setItemVisibility(R.id.remove_new_flag_item, item.isNew());
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
index 636a23088..909fd6459 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java
@@ -49,9 +49,10 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
StoragePath storagePath = entries.get(position);
String freeSpace = Converter.byteToString(storagePath.getAvailableSpace());
+ String totalSpace = Converter.byteToString(storagePath.getTotalSpace());
holder.path.setText(storagePath.getShortPath());
- holder.size.setText(String.format(freeSpaceString, freeSpace));
+ holder.size.setText(String.format(freeSpaceString, freeSpace, totalSpace));
holder.progressBar.setProgress(storagePath.getUsagePercentage());
holder.root.setOnClickListener((View v) -> selectAndDismiss(storagePath));
holder.radioButton.setOnClickListener((View v) -> selectAndDismiss(storagePath));
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
new file mode 100644
index 000000000..df7ec46e0
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedDiscoverAdapter.java
@@ -0,0 +1,76 @@
+package de.danoeh.antennapod.adapter;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FeedDiscoverAdapter extends BaseAdapter {
+
+ private final WeakReference<MainActivity> mainActivityRef;
+ private final List<PodcastSearchResult> data = new ArrayList<>();
+
+ public FeedDiscoverAdapter(MainActivity mainActivity) {
+ this.mainActivityRef = new WeakReference<>(mainActivity);
+ }
+
+ public void updateData(List<PodcastSearchResult> newData) {
+ data.clear();
+ data.addAll(newData);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return data.size();
+ }
+
+ @Override
+ public PodcastSearchResult getItem(int position) {
+ return data.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+
+ if (convertView == null) {
+ convertView = View.inflate(mainActivityRef.get(), R.layout.quick_feed_discovery_item, null);
+ holder = new Holder();
+ holder.imageView = convertView.findViewById(R.id.discovery_cover);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+
+ final PodcastSearchResult podcast = getItem(position);
+ Glide.with(mainActivityRef.get())
+ .load(podcast.imageUrl)
+ .apply(new RequestOptions()
+ .placeholder(R.color.light_gray)
+ .fitCenter()
+ .dontAnimate())
+ .into(holder.imageView);
+
+ return convertView;
+ }
+
+ static class Holder {
+ ImageView imageView;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
index 2cf17c85f..f5213e4ab 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.adapter.itunes;
import android.content.Context;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
@@ -13,18 +12,14 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.mfietz.fyydlin.SearchHit;
-public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
+public class ItunesAdapter extends ArrayAdapter<PodcastSearchResult> {
/**
* Related Context
*/
@@ -33,7 +28,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
/**
* List holding the podcasts found in the search
*/
- private final List<Podcast> data;
+ private final List<PodcastSearchResult> data;
/**
* Constructor.
@@ -41,7 +36,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
* @param context Related context
* @param objects Search result
*/
- public ItunesAdapter(Context context, List<Podcast> objects) {
+ public ItunesAdapter(Context context, List<PodcastSearchResult> objects) {
super(context, 0, objects);
this.data = objects;
this.context = context;
@@ -51,7 +46,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
//Current podcast
- Podcast podcast = data.get(position);
+ PodcastSearchResult podcast = data.get(position);
//ViewHolder
PodcastViewHolder viewHolder;
@@ -94,75 +89,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
}
/**
- * Represents an individual podcast on the iTunes Store.
- */
- public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model
-
- /**
- * The name of the podcast
- */
- public final String title;
-
- /**
- * URL of the podcast image
- */
- @Nullable
- public final String imageUrl;
- /**
- * URL of the podcast feed
- */
- @Nullable
- public final String feedUrl;
-
-
- private Podcast(String title, @Nullable String imageUrl, @Nullable String feedUrl) {
- this.title = title;
- this.imageUrl = imageUrl;
- this.feedUrl = feedUrl;
- }
-
- /**
- * Constructs a Podcast instance from a iTunes search result
- *
- * @param json object holding the podcast information
- * @throws JSONException
- */
- public static Podcast fromSearch(JSONObject json) {
- String title = json.optString("collectionName", "");
- String imageUrl = json.optString("artworkUrl100", null);
- String feedUrl = json.optString("feedUrl", null);
- return new Podcast(title, imageUrl, feedUrl);
- }
-
- public static Podcast fromSearch(SearchHit searchHit) {
- return new Podcast(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
- }
-
- /**
- * Constructs a Podcast instance from iTunes toplist entry
- *
- * @param json object holding the podcast information
- * @throws JSONException
- */
- public static Podcast fromToplist(JSONObject json) throws JSONException {
- String title = json.getJSONObject("title").getString("label");
- String imageUrl = null;
- JSONArray images = json.getJSONArray("im:image");
- for(int i=0; imageUrl == null && i < images.length(); i++) {
- JSONObject image = images.getJSONObject(i);
- String height = image.getJSONObject("attributes").getString("height");
- if(Integer.parseInt(height) >= 100) {
- imageUrl = image.getString("label");
- }
- }
- String feedUrl = "https://itunes.apple.com/lookup?id=" +
- json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
- return new Podcast(title, imageUrl, feedUrl);
- }
-
- }
-
- /**
* View holder object for the GridView
*/
static class PodcastViewHolder {
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
index 4138738f6..3dd7c350d 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -16,7 +16,6 @@ class ClientConfigurator {
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl();
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
- ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl();
ClientConfig.castCallbacks = new CastCallbackImpl();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
deleted file mode 100644
index 3817db6de..000000000
--- a/app/src/main/java/de/danoeh/antennapod/config/FlattrCallbacksImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package de.danoeh.antennapod.config;
-
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import org.shredzone.flattr4j.oauth.AccessToken;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.activity.FlattrAuthActivity;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.FlattrCallbacks;
-
-public class FlattrCallbacksImpl implements FlattrCallbacks {
- private static final String TAG = "FlattrCallbacksImpl";
-
- @Override
- public boolean flattrEnabled() {
- return true;
- }
-
- @Override
- public Intent getFlattrAuthenticationActivityIntent(Context context) {
- return new Intent(context, FlattrAuthActivity.class);
- }
-
- @Override
- public PendingIntent getFlattrFailedNotificationContentIntent(Context context) {
- return PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
- }
-
- @Override
- public String getFlattrAppKey() {
- return BuildConfig.FLATTR_APP_KEY;
- }
-
- @Override
- public String getFlattrAppSecret() {
- return BuildConfig.FLATTR_APP_SECRET;
- }
-
- @Override
- public void handleFlattrAuthenticationSuccess(AccessToken token) {
- FlattrAuthActivity instance = FlattrAuthActivity.getInstance();
- if (instance != null) {
- instance.handleAuthenticationSuccess();
- } else {
- Log.e(TAG, "FlattrAuthActivity instance was null");
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
deleted file mode 100644
index c28342374..000000000
--- a/app/src/main/java/de/danoeh/antennapod/dialog/AutoFlattrPreferenceDialog.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.danoeh.antennapod.dialog;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Context;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-/**
- * Creates a new AlertDialog that displays preferences for auto-flattring to the user.
- */
-public class AutoFlattrPreferenceDialog {
-
- private AutoFlattrPreferenceDialog() {
- }
-
- public static void newAutoFlattrPreferenceDialog(final Activity activity, final AutoFlattrPreferenceDialogInterface callback) {
- Validate.notNull(activity);
- Validate.notNull(callback);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-
- @SuppressLint("InflateParams") View view = activity.getLayoutInflater().inflate(R.layout.autoflattr_preference_dialog, null);
- final CheckBox chkAutoFlattr = view.findViewById(R.id.chkAutoFlattr);
- final SeekBar skbPercent = view.findViewById(R.id.skbPercent);
- final TextView txtvStatus = view.findViewById(R.id.txtvStatus);
-
- chkAutoFlattr.setChecked(UserPreferences.isAutoFlattr());
- skbPercent.setEnabled(chkAutoFlattr.isChecked());
- txtvStatus.setEnabled(chkAutoFlattr.isChecked());
-
- final int initialValue = (int) (UserPreferences.getAutoFlattrPlayedDurationThreshold() * 100.0f);
- setStatusMsgText(activity, txtvStatus, initialValue);
- skbPercent.setProgress(initialValue);
-
- chkAutoFlattr.setOnClickListener(v -> {
- skbPercent.setEnabled(chkAutoFlattr.isChecked());
- txtvStatus.setEnabled(chkAutoFlattr.isChecked());
- });
-
- skbPercent.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- setStatusMsgText(activity, txtvStatus, progress);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
- });
-
- builder.setTitle(R.string.pref_auto_flattr_title)
- .setView(view)
- .setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- float progDouble = ((float) skbPercent.getProgress()) / 100.0f;
- callback.onConfirmed(chkAutoFlattr.isChecked(), progDouble);
- dialog.dismiss();
- })
- .setNegativeButton(R.string.cancel_label, (dialog, which) -> {
- callback.onCancelled();
- dialog.dismiss();
- })
- .setCancelable(false).show();
- }
-
- private static void setStatusMsgText(Context context, TextView txtvStatus, int progress) {
- if (progress == 0) {
- txtvStatus.setText(R.string.auto_flattr_ater_beginning);
- } else if (progress == 100) {
- txtvStatus.setText(R.string.auto_flattr_ater_end);
- } else {
- txtvStatus.setText(context.getString(R.string.auto_flattr_after_percent, progress));
- }
- }
-
- public interface AutoFlattrPreferenceDialogInterface {
- void onCancelled();
-
- void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue);
- }
-
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index ab9b7fcf5..7697aaa69 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.dialog;
import android.app.AlertDialog;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
@@ -12,6 +13,7 @@ import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.util.ArrayMap;
+import android.support.v4.view.ViewCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
@@ -45,7 +47,7 @@ public class EpisodesApplyActionFragment extends Fragment {
public static final String TAG = "EpisodeActionFragment";
public static final int ACTION_ADD_TO_QUEUE = 1;
- private static final int ACTION_REMOVE_FROM_QUEUE = 2;
+ public static final int ACTION_REMOVE_FROM_QUEUE = 2;
private static final int ACTION_MARK_PLAYED = 4;
private static final int ACTION_MARK_UNPLAYED = 8;
private static final int ACTION_DOWNLOAD = 16;
@@ -203,6 +205,10 @@ public class EpisodesApplyActionFragment extends Fragment {
return true;
});
+ if (Build.VERSION.SDK_INT == 23 || Build.VERSION.SDK_INT == 24) {
+ ViewCompat.setElevation(view.findViewById(R.id.fabSDScrollCtr), 8);
+ }
+
showSpeedDialIfAnyChecked();
return view;
@@ -218,10 +224,6 @@ public class EpisodesApplyActionFragment extends Fragment {
mSpeedDialView.setVisibility(checkedIds.size() > 0 ? View.VISIBLE : View.GONE);
}
- private void hideSpeedDial() {
- mSpeedDialView.setVisibility(View.GONE);
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java
new file mode 100644
index 000000000..18d65a03c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java
@@ -0,0 +1,96 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+public class CombinedSearcher implements PodcastSearcher {
+ private static final String TAG = "CombinedSearcher";
+
+ private final List<Pair<PodcastSearcher, Float>> searchProviders = new ArrayList<>();
+
+ public CombinedSearcher(Context context) {
+ addProvider(new FyydPodcastSearcher(), 1.f);
+ addProvider(new ItunesPodcastSearcher(context), 1.f);
+ addProvider(new GpodnetPodcastSearcher(), 0.6f);
+ }
+
+ private void addProvider(PodcastSearcher provider, float priority) {
+ searchProviders.add(new Pair<>(provider, priority));
+ }
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ ArrayList<Disposable> disposables = new ArrayList<>();
+ List<List<PodcastSearchResult>> singleResults = new ArrayList<>(Collections.nCopies(searchProviders.size(), null));
+ CountDownLatch latch = new CountDownLatch(searchProviders.size());
+ for (int i = 0; i < searchProviders.size(); i++) {
+ Pair<PodcastSearcher, Float> searchProviderInfo = searchProviders.get(i);
+ PodcastSearcher searcher = searchProviderInfo.first;
+ final int index = i;
+ disposables.add(searcher.search(query).subscribe(e -> {
+ singleResults.set(index, e);
+ latch.countDown();
+ }, throwable -> {
+ Log.d(TAG, Log.getStackTraceString(throwable));
+ latch.countDown();
+ }
+ ));
+ }
+
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ latch.await();
+ List<PodcastSearchResult> results = weightSearchResults(singleResults);
+ subscriber.onSuccess(results);
+ })
+ .doOnDispose(() -> {
+ for (Disposable disposable : disposables) {
+ disposable.dispose();
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ private List<PodcastSearchResult> weightSearchResults(List<List<PodcastSearchResult>> singleResults) {
+ HashMap<String, Float> resultRanking = new HashMap<>();
+ HashMap<String, PodcastSearchResult> urlToResult = new HashMap<>();
+ for (int i = 0; i < singleResults.size(); i++) {
+ float providerPriority = searchProviders.get(i).second;
+ List<PodcastSearchResult> providerResults = singleResults.get(i);
+ if (providerResults == null) {
+ continue;
+ }
+ for (int position = 0; position < providerResults.size(); position++) {
+ PodcastSearchResult result = providerResults.get(position);
+ urlToResult.put(result.feedUrl, result);
+
+ float ranking = 0;
+ if (resultRanking.containsKey(result.feedUrl)) {
+ ranking = resultRanking.get(result.feedUrl);
+ }
+ ranking += 1.f / (position + 1.f);
+ resultRanking.put(result.feedUrl, ranking * providerPriority);
+ }
+ }
+ List<Map.Entry<String, Float>> sortedResults = new ArrayList<>(resultRanking.entrySet());
+ Collections.sort(sortedResults, (o1, o2) -> Double.compare(o2.getValue(), o1.getValue()));
+
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (Map.Entry<String, Float> res : sortedResults) {
+ results.add(urlToResult.get(res.getKey()));
+ }
+ return results;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java
new file mode 100644
index 000000000..529a9e3d5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.discovery;
+
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.mfietz.fyydlin.FyydClient;
+import de.mfietz.fyydlin.FyydResponse;
+import de.mfietz.fyydlin.SearchHit;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FyydPodcastSearcher implements PodcastSearcher {
+ private final FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ FyydResponse response = client.searchPodcasts(query, 10)
+ .subscribeOn(Schedulers.io())
+ .blockingGet();
+
+ ArrayList<PodcastSearchResult> searchResults = new ArrayList<>();
+
+ if (!response.getData().isEmpty()) {
+ for (SearchHit searchHit : response.getData()) {
+ PodcastSearchResult podcast = PodcastSearchResult.fromFyyd(searchHit);
+ searchResults.add(podcast);
+ }
+ }
+
+ subscriber.onSuccess(searchResults);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
new file mode 100644
index 000000000..6e5debb38
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.discovery;
+
+import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
+import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
+import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GpodnetPodcastSearcher implements PodcastSearcher {
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ GpodnetService service = null;
+ try {
+ service = new GpodnetService();
+ List<GpodnetPodcast> gpodnetPodcasts = service.searchPodcasts(query, 0);
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (GpodnetPodcast podcast : gpodnetPodcasts) {
+ results.add(PodcastSearchResult.fromGpodder(podcast));
+ }
+ subscriber.onSuccess(results);
+ } catch (GpodnetServiceException e) {
+ e.printStackTrace();
+ subscriber.onError(e);
+ } finally {
+ if (service != null) {
+ service.shutdown();
+ }
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
new file mode 100644
index 000000000..a91aae1a8
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java
@@ -0,0 +1,74 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ItunesPodcastSearcher implements PodcastSearcher {
+ private static final String ITUNES_API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
+ private final Context context;
+
+ public ItunesPodcastSearcher(Context context) {
+ this.context = context;
+ }
+
+ public Single<List<PodcastSearchResult>> search(String query) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
+ String encodedQuery;
+ try {
+ encodedQuery = URLEncoder.encode(query, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // this won't ever be thrown
+ encodedQuery = query;
+ }
+
+ String formattedUrl = String.format(ITUNES_API_URL, encodedQuery);
+
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(formattedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ List<PodcastSearchResult> podcasts = new ArrayList<>();
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("results");
+
+ for (int i = 0; i < j.length(); i++) {
+ JSONObject podcastJson = j.getJSONObject(i);
+ PodcastSearchResult podcast = PodcastSearchResult.fromItunes(podcastJson);
+ podcasts.add(podcast);
+ }
+ } else {
+ String prefix = context.getString(R.string.error_msg_prefix);
+ subscriber.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onSuccess(podcasts);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
new file mode 100644
index 000000000..bc9133258
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java
@@ -0,0 +1,110 @@
+package de.danoeh.antennapod.discovery;
+
+import android.content.Context;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import io.reactivex.Single;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class ItunesTopListLoader {
+ private final Context context;
+
+ public ItunesTopListLoader(Context context) {
+ this.context = context;
+ }
+
+ public Single<List<PodcastSearchResult>> loadToplist(int limit) {
+ return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
+ String lang = Locale.getDefault().getLanguage();
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ String feedString;
+ try {
+ try {
+ feedString = getTopListFeed(client, lang, limit);
+ } catch (IOException e) {
+ feedString = getTopListFeed(client, "us", limit);
+ }
+ List<PodcastSearchResult> podcasts = parseFeed(feedString);
+ emitter.onSuccess(podcasts);
+ } catch (IOException | JSONException e) {
+ emitter.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ public Single<String> getFeedUrl(PodcastSearchResult podcast) {
+ if (!podcast.feedUrl.contains("itunes.apple.com")) {
+ return Single.just(podcast.feedUrl)
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+ return Single.create((SingleOnSubscribe<String>) emitter -> {
+ OkHttpClient client = AntennapodHttpClient.getHttpClient();
+ Request.Builder httpReq = new Request.Builder()
+ .url(podcast.feedUrl)
+ .header("User-Agent", ClientConfig.USER_AGENT);
+ try {
+ Response response = client.newCall(httpReq.build()).execute();
+ if (response.isSuccessful()) {
+ String resultString = response.body().string();
+ JSONObject result = new JSONObject(resultString);
+ JSONObject results = result.getJSONArray("results").getJSONObject(0);
+ String feedUrl = results.getString("feedUrl");
+ emitter.onSuccess(feedUrl);
+ } else {
+ String prefix = context.getString(R.string.error_msg_prefix);
+ emitter.onError(new IOException(prefix + response));
+ }
+ } catch (IOException | JSONException e) {
+ emitter.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ private String getTopListFeed(OkHttpClient client, String language, int limit) throws IOException {
+ String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit="+limit+"/explicit=true/json";
+ Request.Builder httpReq = new Request.Builder()
+ .header("User-Agent", ClientConfig.USER_AGENT)
+ .url(String.format(url, language));
+
+ try (Response response = client.newCall(httpReq.build()).execute()) {
+ if (response.isSuccessful()) {
+ return response.body().string();
+ }
+ String prefix = context.getString(R.string.error_msg_prefix);
+ throw new IOException(prefix + response);
+ }
+ }
+
+ private List<PodcastSearchResult> parseFeed(String jsonString) throws JSONException {
+ JSONObject result = new JSONObject(jsonString);
+ JSONObject feed = result.getJSONObject("feed");
+ JSONArray entries = feed.getJSONArray("entry");
+
+ List<PodcastSearchResult> results = new ArrayList<>();
+ for (int i=0; i < entries.length(); i++) {
+ JSONObject json = entries.getJSONObject(i);
+ results.add(PodcastSearchResult.fromItunesToplist(json));
+ }
+
+ return results;
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
new file mode 100644
index 000000000..ca9ed83d7
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -0,0 +1,81 @@
+package de.danoeh.antennapod.discovery;
+
+import android.support.annotation.Nullable;
+import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
+import de.mfietz.fyydlin.SearchHit;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class PodcastSearchResult {
+
+ /**
+ * The name of the podcast
+ */
+ public final String title;
+
+ /**
+ * URL of the podcast image
+ */
+ @Nullable
+ public final String imageUrl;
+ /**
+ * URL of the podcast feed
+ */
+ @Nullable
+ public final String feedUrl;
+
+
+ private PodcastSearchResult(String title, @Nullable String imageUrl, @Nullable String feedUrl) {
+ this.title = title;
+ this.imageUrl = imageUrl;
+ this.feedUrl = feedUrl;
+ }
+
+ public static PodcastSearchResult dummy() {
+ return new PodcastSearchResult("", "", "");
+ }
+
+ /**
+ * Constructs a Podcast instance from a iTunes search result
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public static PodcastSearchResult fromItunes(JSONObject json) {
+ String title = json.optString("collectionName", "");
+ String imageUrl = json.optString("artworkUrl100", null);
+ String feedUrl = json.optString("feedUrl", null);
+ return new PodcastSearchResult(title, imageUrl, feedUrl);
+ }
+
+ /**
+ * Constructs a Podcast instance from iTunes toplist entry
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public static PodcastSearchResult fromItunesToplist(JSONObject json) throws JSONException {
+ String title = json.getJSONObject("title").getString("label");
+ String imageUrl = null;
+ JSONArray images = json.getJSONArray("im:image");
+ for(int i=0; imageUrl == null && i < images.length(); i++) {
+ JSONObject image = images.getJSONObject(i);
+ String height = image.getJSONObject("attributes").getString("height");
+ if(Integer.parseInt(height) >= 100) {
+ imageUrl = image.getString("label");
+ }
+ }
+ String feedUrl = "https://itunes.apple.com/lookup?id=" +
+ json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
+ return new PodcastSearchResult(title, imageUrl, feedUrl);
+ }
+
+ public static PodcastSearchResult fromFyyd(SearchHit searchHit) {
+ return new PodcastSearchResult(searchHit.getTitle(), searchHit.getThumbImageURL(), searchHit.getXmlUrl());
+ }
+
+ public static PodcastSearchResult fromGpodder(GpodnetPodcast searchHit) {
+ return new PodcastSearchResult(searchHit.getTitle(), searchHit.getLogoUrl(), searchHit.getUrl());
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java
new file mode 100644
index 000000000..b19d7d695
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java
@@ -0,0 +1,10 @@
+package de.danoeh.antennapod.discovery;
+
+import io.reactivex.Single;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+import java.util.List;
+
+public interface PodcastSearcher {
+ Single<List<PodcastSearchResult>> search(String query);
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index ee2373da8..35bcaa76e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -2,13 +2,20 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.MediaStore;
import android.support.v4.app.Fragment;
+import android.view.ContextMenu;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
@@ -27,11 +34,28 @@ public class AddFeedFragment extends Fragment {
*/
private static final String ARG_FEED_URL = "feedurl";
+ private EditText combinedFeedSearchBox;
+ private MainActivity activity;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.addfeed, container, false);
+ activity = (MainActivity) getActivity();
+ activity.getSupportActionBar().setTitle(R.string.add_feed_label);
+
+ setupAdvancedSearchButtons(root);
+ setupSeachBox(root);
+
+ View butOpmlImport = root.findViewById(R.id.btn_opml_import);
+ butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
+ OpmlImportFromPathActivity.class)));
+
+ return root;
+ }
+
+ private void setupSeachBox(View root) {
final EditText etxtFeedurl = root.findViewById(R.id.etxtFeedurl);
Bundle args = getArguments();
@@ -39,32 +63,69 @@ public class AddFeedFragment extends Fragment {
etxtFeedurl.setText(args.getString(ARG_FEED_URL));
}
- Button butSearchITunes = root.findViewById(R.id.butSearchItunes);
- Button butBrowserGpoddernet = root.findViewById(R.id.butBrowseGpoddernet);
- Button butSearchFyyd = root.findViewById(R.id.butSearchFyyd);
- Button butOpmlImport = root.findViewById(R.id.butOpmlImport);
- Button butConfirm = root.findViewById(R.id.butConfirm);
+ Button butConfirmAddUrl = root.findViewById(R.id.butConfirm);
+ butConfirmAddUrl.setOnClickListener(v -> {
+ addUrl(etxtFeedurl.getText().toString());
+ });
- final MainActivity activity = (MainActivity) getActivity();
- activity.getSupportActionBar().setTitle(R.string.add_feed_label);
+ combinedFeedSearchBox = root.findViewById(R.id.combinedFeedSearchBox);
+ combinedFeedSearchBox.setOnEditorActionListener((v, actionId, event) -> {
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ performSearch();
+ return true;
+ }
+ return false;
+ });
+ }
- butSearchITunes.setOnClickListener(v -> activity.loadChildFragment(new ItunesSearchFragment()));
+ private void setupAdvancedSearchButtons(View root) {
+ View butAdvancedSearch = root.findViewById(R.id.advanced_search);
+ registerForContextMenu(butAdvancedSearch);
+ butAdvancedSearch.setOnClickListener(v -> butAdvancedSearch.showContextMenu());
+ }
- butBrowserGpoddernet.setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment()));
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ getActivity().getMenuInflater().inflate(R.menu.advanced_search, menu);
+ }
- butSearchFyyd.setOnClickListener(v -> activity.loadChildFragment(new FyydSearchFragment()));
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.search_fyyd:
+ activity.loadChildFragment(new FyydSearchFragment());
+ return true;
+ case R.id.search_gpodder:
+ activity.loadChildFragment(new GpodnetMainFragment());
+ return true;
+ case R.id.search_itunes:
+ activity.loadChildFragment(new ItunesSearchFragment());
+ return true;
+ }
+ return false;
+ }
- butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
- OpmlImportFromPathActivity.class)));
- butConfirm.setOnClickListener(v -> {
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString());
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
- startActivity(intent);
- });
+ private void addUrl(String url) {
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
+ startActivity(intent);
+ }
- return root;
+ private void performSearch() {
+ String query = combinedFeedSearchBox.getText().toString();
+
+ if (query.startsWith("http")) {
+ addUrl(query);
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putString(CombinedSearchFragment.ARGUMENT_QUERY, query);
+ CombinedSearchFragment fragment = new CombinedSearchFragment();
+ fragment.setArguments(bundle);
+ activity.loadChildFragment(fragment);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index 8f4e9f656..62d798cf6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -21,11 +21,15 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
-import android.widget.TextView;
import android.widget.Toast;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -40,6 +44,7 @@ import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -50,15 +55,11 @@ import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
/**
* Shows unread or recently published episodes
@@ -81,11 +82,10 @@ public class AllEpisodesFragment extends Fragment {
private ProgressBar progLoading;
EmptyViewHandler emptyView;
- List<FeedItem> episodes;
- private List<Downloader> downloaderList;
-
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
+ @NonNull
+ List<FeedItem> episodes = new ArrayList<>();
+ @NonNull
+ private List<Downloader> downloaderList = new ArrayList<>();
private boolean isUpdatingFeeds;
boolean isMenuInvalidationAllowed = false;
@@ -93,29 +93,26 @@ public class AllEpisodesFragment extends Fragment {
Disposable disposable;
private LinearLayoutManager layoutManager;
- boolean showOnlyNewEpisodes() { return false; }
- String getPrefName() { return DEFAULT_PREF_NAME; }
+ boolean showOnlyNewEpisodes() {
+ return false;
+ }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
+ String getPrefName() {
+ return DEFAULT_PREF_NAME;
}
@Override
public void onStart() {
super.onStart();
+ setHasOptionsMenu(true);
EventDistributor.getInstance().register(contentUpdate);
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
EventBus.getDefault().register(this);
+ loadItems();
}
@Override
public void onResume() {
super.onResume();
- loadItems();
registerForContextMenu(recyclerView);
}
@@ -136,17 +133,11 @@ public class AllEpisodesFragment extends Fragment {
}
}
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- resetViewState();
- }
-
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
float topOffset;
- if(firstItemView == null) {
+ if (firstItemView == null) {
topOffset = 0;
} else {
topOffset = firstItemView.getTop();
@@ -173,43 +164,35 @@ public class AllEpisodesFragment extends Fragment {
}
}
- void resetViewState() {
- viewsCreated = false;
- listAdapter = null;
- }
-
-
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
() -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds();
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- inflater.inflate(R.menu.episodes, menu);
-
- MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- sv.clearFocus();
- ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
- return true;
- }
+ inflater.inflate(R.menu.episodes, menu);
+
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) requireActivity()).loadChildFragment(SearchFragment.newInstance(s));
+ return true;
+ }
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
- }
- });
- isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
- }
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
@@ -217,11 +200,11 @@ public class AllEpisodesFragment extends Fragment {
super.onPrepareOptionsMenu(menu);
MenuItem markAllRead = menu.findItem(R.id.mark_all_read_item);
if (markAllRead != null) {
- markAllRead.setVisible(!showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty());
+ markAllRead.setVisible(!showOnlyNewEpisodes() && !episodes.isEmpty());
}
- MenuItem markAllSeen = menu.findItem(R.id.mark_all_seen_item);
- if(markAllSeen != null) {
- markAllSeen.setVisible(showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty());
+ MenuItem removeAllNewFlags = menu.findItem(R.id.remove_all_new_flags_item);
+ if (removeAllNewFlags != null) {
+ removeAllNewFlags.setVisible(showOnlyNewEpisodes() && !episodes.isEmpty());
}
}
@@ -249,19 +232,19 @@ public class AllEpisodesFragment extends Fragment {
};
markAllReadConfirmationDialog.createNewDialog().show();
return true;
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(),
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
+ case R.id.remove_all_new_flags_item:
+ ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getActivity(),
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg) {
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
- DBWriter.markNewItemsSeen();
- Toast.makeText(getActivity(), R.string.mark_all_seen_msg, Toast.LENGTH_SHORT).show();
+ DBWriter.removeAllNewFlags();
+ Toast.makeText(getActivity(), R.string.removed_all_new_flags_msg, Toast.LENGTH_SHORT).show();
}
};
- markAllSeenConfirmationDialog.createNewDialog().show();
+ removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
default:
return false;
@@ -275,111 +258,102 @@ public class AllEpisodesFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]");
- if(!isVisible()) {
+ if (!getUserVisibleHint()) {
return false;
}
- if(item.getItemId() == R.id.share_item) {
+ if (!isVisible()) {
+ return false;
+ }
+ if (item.getItemId() == R.id.share_item) {
return true; // avoids that the position is reset when we need it in the submenu
}
- if (listAdapter == null || listAdapter.getSelectedItem() == null) {
+ if (listAdapter.getSelectedItem() == null) {
Log.i(TAG, "Selected item or listAdapter was null, ignoring selection");
return super.onContextItemSelected(item);
}
FeedItem selectedItem = listAdapter.getSelectedItem();
- // Mark as seen contains UI logic specific to All/New/FavoriteSegments,
+ // Remove new flag contains UI logic specific to All/New/FavoriteSegments,
// e.g., Undo with Snackbar,
// and is handled by this class rather than the generic FeedItemMenuHandler
- // Undo is useful for Mark as seen, given there is no UI to undo it otherwise,
+ // Undo is useful for Remove new flag, given there is no UI to undo it otherwise,
// i.e., there is context menu item for Mark as new
- if (R.id.mark_as_seen_item == item.getItemId()) {
- markItemAsSeenWithUndo(selectedItem);
+ if (R.id.remove_new_flag_item == item.getItemId()) {
+ removeNewFlagWithUndo(selectedItem);
return true;
}
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
}
+ @NonNull
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- return onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
- }
-
- View onCreateViewHelper(LayoutInflater inflater,
- ViewGroup container,
- Bundle savedInstanceState,
- int fragmentResource) {
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.all_episodes_fragment, container, false);
- View root = inflater.inflate(fragmentResource, container, false);
-
- recyclerView = root.findViewById(android.R.id.list);
- RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
- if (animator instanceof SimpleItemAnimator) {
- ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
- }
layoutManager = new LinearLayoutManager(getActivity());
+ recyclerView = root.findViewById(android.R.id.list);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
+ recyclerView.setVisibility(View.GONE);
- progLoading = root.findViewById(R.id.progLoading);
-
- if (!itemsLoaded) {
- progLoading.setVisibility(View.VISIBLE);
+ RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
+ if (animator instanceof SimpleItemAnimator) {
+ ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
- viewsCreated = true;
-
- if (itemsLoaded) {
- onFragmentLoaded();
- }
+ progLoading = root.findViewById(R.id.progLoading);
+ progLoading.setVisibility(View.VISIBLE);
emptyView = new EmptyViewHandler(getContext());
emptyView.attachToRecyclerView(recyclerView);
+ emptyView.setIcon(R.attr.feed);
emptyView.setTitle(R.string.no_all_episodes_head_label);
emptyView.setMessage(R.string.no_all_episodes_label);
+ createRecycleAdapter(recyclerView, emptyView);
+ emptyView.hide();
+
return root;
}
- private void onFragmentLoaded() {
- if (episodes != null && episodes.size() > 0) {
- if (listAdapter == null) {
- MainActivity mainActivity = (MainActivity) getActivity();
- listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess, showOnlyNewEpisodes());
- listAdapter.setHasStableIds(true);
- recyclerView.setAdapter(listAdapter);
- emptyView.updateAdapter(listAdapter);
- }
- recyclerView.setVisibility(View.VISIBLE);
- listAdapter.notifyDataSetChanged();
- } else {
- listAdapter = null;
- recyclerView.setVisibility(View.GONE);
- emptyView.updateAdapter(listAdapter);
+ private void onFragmentLoaded(List<FeedItem> episodes) {
+ this.episodes = episodes;
+ listAdapter.notifyDataSetChanged();
+
+ if (episodes.size() == 0) {
+ createRecycleAdapter(recyclerView, emptyView);
}
restoreScrollPosition();
- getActivity().supportInvalidateOptionsMenu();
- updateShowOnlyEpisodesListViewState();
+ requireActivity().invalidateOptionsMenu();
+ }
+
+ /**
+ * Currently, we need to recreate the list adapter in order to be able to undo last item via the
+ * snackbar. See #3084 for details.
+ */
+ private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) {
+ MainActivity mainActivity = (MainActivity) getActivity();
+ listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess, showOnlyNewEpisodes());
+ listAdapter.setHasStableIds(true);
+ recyclerView.setAdapter(listAdapter);
+ emptyViewHandler.updateAdapter(listAdapter);
}
private final AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
@Override
public int getCount() {
- if (episodes != null) {
- return episodes.size();
- }
- return 0;
+ return episodes.size();
}
@Override
public FeedItem getItem(int position) {
- if (episodes != null && 0 <= position && position < episodes.size()) {
+ if (0 <= position && position < episodes.size()) {
return episodes.get(position);
}
return null;
@@ -387,11 +361,8 @@ public class AllEpisodesFragment extends Fragment {
@Override
public LongList getItemsIds() {
- if(episodes == null) {
- return new LongList(0);
- }
LongList ids = new LongList(episodes.size());
- for(FeedItem episode : episodes) {
+ for (FeedItem episode : episodes) {
ids.add(episode.getId());
}
return ids;
@@ -399,12 +370,11 @@ public class AllEpisodesFragment extends Fragment {
@Override
public int getItemDownloadProgressPercent(FeedItem item) {
- if (downloaderList != null) {
- for (Downloader downloader : downloaderList) {
- if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
- && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
- return downloader.getDownloadRequest().getProgressPercent();
- }
+ for (Downloader downloader : downloaderList) {
+ DownloadRequest downloadRequest = downloader.getDownloadRequest();
+ if (downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloadRequest.getFeedfileId() == item.getMedia().getId()) {
+ return downloadRequest.getProgressPercent();
}
}
return 0;
@@ -418,11 +388,8 @@ public class AllEpisodesFragment extends Fragment {
@Override
public LongList getQueueIds() {
LongList queueIds = new LongList();
- if(episodes == null) {
- return queueIds;
- }
- for(FeedItem item : episodes) {
- if(item.isTagged(FeedItem.TAG_QUEUE)) {
+ for (FeedItem item : episodes) {
+ if (item.isTagged(FeedItem.TAG_QUEUE)) {
queueIds.add(item.getId());
}
}
@@ -434,12 +401,6 @@ public class AllEpisodesFragment extends Fragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
- if (episodes == null) {
- return;
- } else if (listAdapter == null) {
- loadItems();
- return;
- }
for (FeedItem item : event.items) {
int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
if (pos >= 0) {
@@ -464,16 +425,12 @@ public class AllEpisodesFragment extends Fragment {
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) {
- getActivity().supportInvalidateOptionsMenu();
- }
- if (listAdapter == null) {
- loadItems();
- return;
+ requireActivity().invalidateOptionsMenu();
}
if (update.mediaIds.length > 0) {
- for(long mediaId : update.mediaIds) {
+ for (long mediaId : update.mediaIds) {
int pos = FeedItemUtil.indexOfItemWithMediaId(episodes, mediaId);
- if(pos >= 0) {
+ if (pos >= 0) {
listAdapter.notifyItemChanged(pos);
}
}
@@ -486,35 +443,22 @@ public class AllEpisodesFragment extends Fragment {
if ((arg & EVENTS) != 0) {
loadItems();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
- getActivity().supportInvalidateOptionsMenu();
+ requireActivity().invalidateOptionsMenu();
}
}
}
};
- private void updateShowOnlyEpisodesListViewState() {
- }
-
void loadItems() {
if (disposable != null) {
disposable.dispose();
}
- if (viewsCreated && !itemsLoaded) {
- recyclerView.setVisibility(View.GONE);
- emptyView.hide();
- progLoading.setVisibility(View.VISIBLE);
- }
disposable = Observable.fromCallable(this::loadData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
- recyclerView.setVisibility(View.VISIBLE);
progLoading.setVisibility(View.GONE);
- episodes = data;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded(data);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@@ -523,12 +467,12 @@ public class AllEpisodesFragment extends Fragment {
return DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT);
}
- void markItemAsSeenWithUndo(FeedItem item) {
+ void removeNewFlagWithUndo(FeedItem item) {
if (item == null) {
return;
}
- Log.d(TAG, "markItemAsSeenWithUndo(" + item.getId() + ")");
+ Log.d(TAG, "removeNewFlagWithUndo(" + item.getId() + ")");
if (disposable != null) {
disposable.dispose();
}
@@ -537,14 +481,14 @@ public class AllEpisodesFragment extends Fragment {
DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
final Handler h = new Handler(getActivity().getMainLooper());
- final Runnable r = () -> {
+ final Runnable r = () -> {
FeedMedia media = item.getMedia();
if (media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
}
};
- Snackbar snackbar = Snackbar.make(getView(), getString(R.string.marked_as_seen_label),
+ Snackbar snackbar = Snackbar.make(getView(), getString(R.string.removed_new_flag_label),
Snackbar.LENGTH_LONG);
snackbar.setAction(getString(R.string.undo), v -> {
DBWriter.markItemPlayed(FeedItem.NEW, item.getId());
@@ -552,7 +496,6 @@ public class AllEpisodesFragment extends Fragment {
h.removeCallbacks(r);
});
snackbar.show();
- h.postDelayed(r, (int)Math.ceil(snackbar.getDuration() * 1.05f));
+ h.postDelayed(r, (int) Math.ceil(snackbar.getDuration() * 1.05f));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index 0ffd1a8da..4bebfe4c9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -15,6 +15,7 @@ import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -25,6 +26,7 @@ public class ChaptersFragment extends ListFragment {
private ChaptersListAdapter adapter;
private PlaybackController controller;
private Disposable disposable;
+ private EmptyViewHandler emptyView;
@Override
@@ -36,6 +38,12 @@ public class ChaptersFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
+ emptyView = new EmptyViewHandler(getContext());
+ emptyView.attachToListView(lv);
+ emptyView.setIcon(R.attr.ic_bookmark);
+ emptyView.setTitle(R.string.no_chapters_head_label);
+ emptyView.setMessage(R.string.no_chapters_label);
+
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
controller.seekToChapter(chapter);
@@ -118,10 +126,7 @@ public class ChaptersFragment extends ListFragment {
if (adapter != null) {
adapter.setMedia(media);
adapter.notifyDataSetChanged();
- if (media == null || media.getChapters() == null || media.getChapters().size() == 0) {
- setEmptyText(getString(R.string.no_chapters_label));
- } else {
- setEmptyText(null);
+ if (media != null && media.getChapters() != null && media.getChapters().size() != 0) {
scrollTo(getCurrentChapter(media));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
new file mode 100644
index 000000000..1d9020f0d
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java
@@ -0,0 +1,173 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.SearchView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.GridView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
+import de.danoeh.antennapod.discovery.CombinedSearcher;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import io.reactivex.disposables.Disposable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CombinedSearchFragment extends Fragment {
+
+ private static final String TAG = "CombinedSearchFragment";
+ public static final String ARGUMENT_QUERY = "query";
+
+ /**
+ * Adapter responsible with the search results
+ */
+ private ItunesAdapter adapter;
+ private GridView gridView;
+ private ProgressBar progressBar;
+ private TextView txtvError;
+ private Button butRetry;
+ private TextView txtvEmpty;
+
+ /**
+ * List of podcasts retreived from the search
+ */
+ private List<PodcastSearchResult> searchResults = new ArrayList<>();
+ private Disposable disposable;
+
+ /**
+ * Constructor
+ */
+ public CombinedSearchFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
+ gridView = root.findViewById(R.id.gridView);
+ adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
+ gridView.setAdapter(adapter);
+
+ //Show information about the podcast when the list item is clicked
+ gridView.setOnItemClickListener((parent, view1, position, id) -> {
+ PodcastSearchResult podcast = searchResults.get(position);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
+ startActivity(intent);
+ });
+ progressBar = root.findViewById(R.id.progressBar);
+ txtvError = root.findViewById(R.id.txtvError);
+ butRetry = root.findViewById(R.id.butRetry);
+ txtvEmpty = root.findViewById(android.R.id.empty);
+
+ return root;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ adapter = null;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.itunes_search, menu);
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_label));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ search(s);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ getActivity().getSupportFragmentManager().popBackStack();
+ return true;
+ }
+ });
+ MenuItemCompat.expandActionView(searchItem);
+
+ if (getArguments() != null && getArguments().getString(ARGUMENT_QUERY, null) != null) {
+ sv.setQuery(getArguments().getString(ARGUMENT_QUERY, null), true);
+ }
+ }
+
+ private void search(String query) {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ showOnlyProgressBar();
+
+ CombinedSearcher searcher = new CombinedSearcher(getContext());
+ disposable = searcher.search(query).subscribe(result -> {
+ searchResults = result;
+ progressBar.setVisibility(View.GONE);
+
+ adapter.clear();
+ adapter.addAll(searchResults);
+ adapter.notifyDataSetInvalidated();
+ gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+ txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
+ }
+
+ private void showOnlyProgressBar() {
+ gridView.setVisibility(View.GONE);
+ txtvError.setVisibility(View.GONE);
+ butRetry.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
+ progressBar.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index b52fd444f..705151062 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.fragment;
-import android.content.Context;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.Menu;
@@ -10,6 +10,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -27,6 +28,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_ADD_TO_QUEUE;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
+
/**
* Displays all running downloads and provides a button to delete them
*/
@@ -38,24 +42,27 @@ public class CompletedDownloadsFragment extends ListFragment {
EventDistributor.DOWNLOADLOG_UPDATE |
EventDistributor.UNREAD_ITEMS_UPDATE;
- private List<FeedItem> items;
+ private List<FeedItem> items = new ArrayList<>();
private DownloadedEpisodesListAdapter listAdapter;
-
- private boolean viewCreated = false;
-
private Disposable disposable;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
- loadItems();
+ addVerticalPadding();
+ addEmptyView();
+
+ listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
+ setListAdapter(listAdapter);
+ setListShown(false);
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ loadItems();
}
@Override
@@ -68,104 +75,54 @@ public class CompletedDownloadsFragment extends ListFragment {
}
@Override
- public void onDetach() {
- super.onDetach();
- if (disposable != null) {
- disposable.dispose();
- }
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+ position -= l.getHeaderViewsCount();
+ long[] ids = FeedItemUtil.getIds(items);
+ ((MainActivity) requireActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
- listAdapter = null;
- viewCreated = false;
- if (disposable != null) {
- disposable.dispose();
- }
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.downloads_completed, menu);
+ menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
}
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (viewCreated && items != null) {
- onFragmentLoaded();
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.episode_actions) {
+ ((MainActivity) requireActivity())
+ .loadChildFragment(EpisodesApplyActionFragment.newInstance(items, ACTION_DELETE | ACTION_ADD_TO_QUEUE));
+ return true;
}
+ return false;
}
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // add padding
- final ListView lv = getListView();
- lv.setClipToPadding(false);
- final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
- lv.setPadding(0, vertPadding, 0, vertPadding);
-
- viewCreated = true;
- if (items != null && getActivity() != null) {
- onFragmentLoaded();
- }
-
+ private void addEmptyView() {
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
emptyView.setTitle(R.string.no_comp_downloads_head_label);
emptyView.setMessage(R.string.no_comp_downloads_label);
emptyView.attachToListView(getListView());
}
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- super.onListItemClick(l, v, position, id);
- position -= l.getHeaderViewsCount();
- long[] ids = FeedItemUtil.getIds(items);
- ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(ids, position));
- }
-
- private void onFragmentLoaded() {
- if (listAdapter == null) {
- listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
- setListAdapter(listAdapter);
- }
- setListShown(true);
- listAdapter.notifyDataSetChanged();
- getActivity().supportInvalidateOptionsMenu();
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
- return;
- }
- super.onCreateOptionsMenu(menu, inflater);
- if(items != null) {
- inflater.inflate(R.menu.downloads_completed, menu);
- menu.findItem(R.id.episode_actions).setVisible(items.size() > 0);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.episode_actions:
- EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment
- .newInstance(items, EpisodesApplyActionFragment.ACTION_DELETE | EpisodesApplyActionFragment.ACTION_ADD_TO_QUEUE);
- ((MainActivity) getActivity()).loadChildFragment(fragment);
- return true;
- default:
- return false;
- }
+ private void addVerticalPadding() {
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
}
private final DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
@Override
public int getCount() {
- return (items != null) ? items.size() : 0;
+ return items.size();
}
@Override
public FeedItem getItem(int position) {
- if (items != null && 0 <= position && position < items.size()) {
+ if (0 <= position && position < items.size()) {
return items.get(position);
} else {
return null;
@@ -174,7 +131,7 @@ public class CompletedDownloadsFragment extends ListFragment {
@Override
public void onFeedItemSecondaryAction(FeedItem item) {
- DBWriter.deleteFeedMediaOfItem(getActivity(), item.getMedia().getId());
+ DBWriter.deleteFeedMediaOfItem(requireActivity(), item.getMedia().getId());
}
};
@@ -191,18 +148,18 @@ public class CompletedDownloadsFragment extends ListFragment {
if (disposable != null) {
disposable.dispose();
}
- if (items == null && viewCreated) {
- setListShown(false);
- }
disposable = Observable.fromCallable(DBReader::getDownloadedItems)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
items = result;
- if (viewCreated && getActivity() != null) {
- onFragmentLoaded();
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ onItemsLoaded();
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
+ private void onItemsLoaded() {
+ setListShown(true);
+ listAdapter.notifyDataSetChanged();
+ requireActivity().invalidateOptionsMenu();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index 973772049..26b115b4b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -14,6 +14,7 @@ import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -37,18 +38,13 @@ public class DownloadLogFragment extends ListFragment {
private static final String TAG = "DownloadLogFragment";
- private List<DownloadStatus> downloadLog;
+ private List<DownloadStatus> downloadLog = new ArrayList<>();
private DownloadLogAdapter adapter;
-
- private boolean viewsCreated = false;
- private boolean itemsLoaded = false;
-
private Disposable disposable;
@Override
public void onStart() {
super.onStart();
- setHasOptionsMenu(true);
EventDistributor.getInstance().register(contentUpdate);
loadItems();
}
@@ -57,7 +53,7 @@ public class DownloadLogFragment extends ListFragment {
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
}
@@ -65,6 +61,7 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ setHasOptionsMenu(true);
// add padding
final ListView lv = getListView();
@@ -72,23 +69,17 @@ public class DownloadLogFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
-
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
emptyView.setTitle(R.string.no_log_downloads_head_label);
emptyView.setMessage(R.string.no_log_downloads_label);
emptyView.attachToListView(getListView());
+ adapter = new DownloadLogAdapter(getActivity(), itemAccess);
+ setListAdapter(adapter);
}
private void onFragmentLoaded() {
- if (adapter == null) {
- adapter = new DownloadLogAdapter(getActivity(), itemAccess);
- setListAdapter(adapter);
- }
setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
@@ -129,12 +120,12 @@ public class DownloadLogFragment extends ListFragment {
@Override
public int getCount() {
- return (downloadLog != null) ? downloadLog.size() : 0;
+ return downloadLog.size();
}
@Override
public DownloadStatus getItem(int position) {
- if (downloadLog != null && 0 <= position && position < downloadLog.size()) {
+ if (0 <= position && position < downloadLog.size()) {
return downloadLog.get(position);
} else {
return null;
@@ -154,27 +145,23 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
- clearHistory.setIcon(drawables.getDrawable(0));
- drawables.recycle();
- }
+ MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
+ MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
+ clearHistory.setIcon(drawables.getDrawable(0));
+ drawables.recycle();
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- if (itemsLoaded) {
- MenuItem menuItem = menu.findItem(R.id.clear_history_item);
- if(menuItem != null) {
- menuItem.setVisible(downloadLog != null && !downloadLog.isEmpty());
- }
+ MenuItem menuItem = menu.findItem(R.id.clear_history_item);
+ if (menuItem != null) {
+ menuItem.setVisible(!downloadLog.isEmpty());
}
}
@@ -194,7 +181,7 @@ public class DownloadLogFragment extends ListFragment {
}
private void loadItems() {
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(DBReader::getDownloadLog)
@@ -203,12 +190,8 @@ public class DownloadLogFragment extends ListFragment {
.subscribe(result -> {
if (result != null) {
downloadLog = result;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
index d362d5c0b..bb029b731 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
@@ -8,7 +9,8 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
+
+import org.greenrobot.eventbus.Subscribe;
import java.util.List;
@@ -18,42 +20,37 @@ import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
/**
* Like 'EpisodesFragment' except that it only shows favorite episodes and
* supports swiping to remove from favorites.
*/
-
public class FavoriteEpisodesFragment extends AllEpisodesFragment {
private static final String TAG = "FavoriteEpisodesFrag";
-
private static final String PREF_NAME = "PrefFavoriteEpisodesFragment";
@Override
- protected boolean showOnlyNewEpisodes() { return true; }
+ protected boolean showOnlyNewEpisodes() {
+ return true;
+ }
@Override
- protected String getPrefName() { return PREF_NAME; }
+ protected String getPrefName() {
+ return PREF_NAME;
+ }
@Subscribe
public void onEvent(FavoritesEvent event) {
- Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
+ Log.d(TAG, String.format("onEvent() called with: event = [%s]", event));
loadItems();
}
+ @NonNull
@Override
- protected void resetViewState() {
- super.resetViewState();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View root = super.onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = super.onCreateView(inflater, container, savedInstanceState);
+ emptyView.setIcon(R.attr.ic_unfav);
emptyView.setTitle(R.string.no_fav_episodes_head_label);
emptyView.setMessage(R.string.no_fav_episodes_label);
@@ -65,8 +62,8 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
- AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
- Log.d(TAG, "remove(" + holder.getItemId() + ")");
+ AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
+ Log.d(TAG, String.format("remove(%s)", holder.getItemId()));
if (disposable != null) {
disposable.dispose();
@@ -75,8 +72,7 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
if (item != null) {
DBWriter.removeFavoriteItem(item);
- Snackbar snackbar = Snackbar.make(root, getString(R.string.removed_item),
- Snackbar.LENGTH_LONG);
+ Snackbar snackbar = Snackbar.make(root, getString(R.string.removed_item), Snackbar.LENGTH_LONG);
snackbar.setAction(getString(R.string.undo), v -> DBWriter.addFavoriteItem(item));
snackbar.show();
}
@@ -88,6 +84,7 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
return root;
}
+ @NonNull
@Override
protected List<FeedItem> loadData() {
return DBReader.getFavoriteItemsList();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
index dadc596e2..9c16cfe56 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java
@@ -16,24 +16,16 @@ import android.widget.Button;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
-import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.discovery.FyydPodcastSearcher;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
-import de.mfietz.fyydlin.FyydClient;
-import de.mfietz.fyydlin.FyydResponse;
-import de.mfietz.fyydlin.SearchHit;
-import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
-import static java.util.Collections.emptyList;
+import java.util.ArrayList;
+import java.util.List;
public class FyydSearchFragment extends Fragment {
@@ -49,12 +41,10 @@ public class FyydSearchFragment extends Fragment {
private Button butRetry;
private TextView txtvEmpty;
- private final FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient());
-
/**
* List of podcasts retreived from the search
*/
- private List<Podcast> searchResults;
+ private List<PodcastSearchResult> searchResults;
private Disposable disposable;
/**
@@ -81,7 +71,7 @@ public class FyydSearchFragment extends Fragment {
//Show information about the podcast when the list item is clicked
gridView.setOnItemClickListener((parent, view1, position, id) -> {
- Podcast podcast = searchResults.get(position);
+ PodcastSearchResult podcast = searchResults.get(position);
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title);
@@ -145,20 +135,26 @@ public class FyydSearchFragment extends Fragment {
disposable.dispose();
}
showOnlyProgressBar();
- disposable = client.searchPodcasts(query, 10)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- progressBar.setVisibility(View.GONE);
- processSearchResult(result);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- txtvError.setText(error.toString());
- txtvError.setVisibility(View.VISIBLE);
- butRetry.setOnClickListener(v -> search(query));
- butRetry.setVisibility(View.VISIBLE);
- });
+
+ FyydPodcastSearcher searcher = new FyydPodcastSearcher();
+ disposable = searcher.search(query).subscribe(result -> {
+ searchResults = result;
+ progressBar.setVisibility(View.GONE);
+
+ adapter.clear();
+ adapter.addAll(searchResults);
+ adapter.notifyDataSetInvalidated();
+ gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+ txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
+
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
}
private void showOnlyProgressBar() {
@@ -168,25 +164,4 @@ public class FyydSearchFragment extends Fragment {
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
-
- private void processSearchResult(FyydResponse response) {
- adapter.clear();
- if (!response.getData().isEmpty()) {
- adapter.clear();
- searchResults = new ArrayList<>();
- for (SearchHit searchHit : response.getData()) {
- Podcast podcast = Podcast.fromSearch(searchHit);
- searchResults.add(podcast);
- }
- } else {
- searchResults = emptyList();
- }
- for(Podcast podcast : searchResults) {
- adapter.add(podcast);
- }
- adapter.notifyDataSetInvalidated();
- gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
- txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
- }
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index a2472b071..432ada44e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -36,6 +36,9 @@ import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
import org.apache.commons.lang3.ArrayUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
@@ -71,9 +74,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
/**
* Displays information about a FeedItem and actions.
@@ -266,7 +266,6 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- load();
}
@Override
@@ -274,6 +273,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
+ load();
}
@Override
@@ -306,19 +306,20 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Override
public boolean onSwipeLeftToRight() {
- Log.d(TAG, "onSwipeLeftToRight()");
- feedItemPos = feedItemPos - 1;
- if(feedItemPos < 0) {
- feedItemPos = feedItems.length - 1;
- }
- load();
- return true;
+ return swipeFeedItem(-1);
}
@Override
public boolean onSwipeRightToLeft() {
- Log.d(TAG, "onSwipeRightToLeft()");
- feedItemPos = (feedItemPos + 1) % feedItems.length;
+ return swipeFeedItem(+1);
+ }
+
+ private boolean swipeFeedItem(int position) {
+ Log.d(TAG, String.format("onSwipe() shift: %s", position));
+ feedItemPos = (feedItemPos + position) % feedItems.length;
+ if (feedItemPos < 0) {
+ feedItemPos = feedItems.length - 1;
+ }
load();
return true;
}
@@ -602,8 +603,9 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
@Nullable
private FeedItem loadInBackground() {
FeedItem feedItem = DBReader.getFeedItem(feedItems[feedItemPos]);
- if (feedItem != null) {
- Timeline t = new Timeline(getContext(), feedItem);
+ Context context = getContext();
+ if (feedItem != null && context != null) {
+ Timeline t = new Timeline(context, feedItem);
webviewData = t.processShownotes(false);
}
return feedItem;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index 6a04758b9..0c75af986 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -30,6 +30,9 @@ import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
@@ -71,9 +74,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
/**
* Displays a list of FeedItems.
@@ -96,8 +96,6 @@ public class ItemlistFragment extends ListFragment {
private long feedID;
private Feed feed;
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
private boolean headerCreated = false;
private List<Downloader> downloaderList;
@@ -105,7 +103,7 @@ public class ItemlistFragment extends ListFragment {
private MoreContentListFooterUtil listFooter;
private boolean isUpdatingFeed;
-
+
private TextView txtvTitle;
private IconTextView txtvFailure;
private ImageView imgvBackground;
@@ -146,9 +144,7 @@ public class ItemlistFragment extends ListFragment {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
+ loadItems();
}
@Override
@@ -156,7 +152,6 @@ public class ItemlistFragment extends ListFragment {
super.onResume();
((MainActivity)getActivity()).getSupportActionBar().setTitle("");
updateProgressBarVisibility();
- loadItems();
}
@Override
@@ -177,7 +172,6 @@ public class ItemlistFragment extends ListFragment {
private void resetViewState() {
adapter = null;
- viewsCreated = false;
listFooter = null;
}
@@ -190,45 +184,43 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
-
- MenuItem searchItem = menu.findItem(R.id.action_search);
- final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
- MenuItemUtils.adjustTextColor(getActivity(), sv);
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- sv.clearFocus();
- if (itemsLoaded) {
- ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
- }
- return true;
- }
+ FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuItemUtils.adjustTextColor(getActivity(), sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ if (feed != null) {
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
}
- });
- if(feed == null || feed.getLink() == null) {
- menu.findItem(R.id.share_link_item).setVisible(false);
- menu.findItem(R.id.visit_website_item).setVisible(false);
+ return true;
}
- isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ if (feed == null || feed.getLink() == null) {
+ menu.findItem(R.id.share_link_item).setVisible(false);
+ menu.findItem(R.id.visit_website_item).setVisible(false);
}
+
+ isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
- if (itemsLoaded) {
+ if (feed != null) {
FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
}
}
@@ -341,11 +333,6 @@ public class ItemlistFragment extends ListFragment {
super.onViewCreated(view, savedInstanceState);
registerForContextMenu(getListView());
-
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
}
@Override
@@ -503,7 +490,7 @@ public class ItemlistFragment extends ListFragment {
butShowInfo.setOnClickListener(v -> showFeedInfo());
imgvCover.setOnClickListener(v -> showFeedInfo());
butShowSettings.setOnClickListener(v -> {
- if (viewsCreated && itemsLoaded) {
+ if (feed != null) {
Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class);
startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID,
feed.getId());
@@ -514,7 +501,7 @@ public class ItemlistFragment extends ListFragment {
}
private void showFeedInfo() {
- if (viewsCreated && itemsLoaded) {
+ if (feed != null) {
Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
feed.getId());
@@ -624,10 +611,7 @@ public class ItemlistFragment extends ListFragment {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result.orElse(null);
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index a9f56d317..80767bef2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -20,13 +20,14 @@ import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
+import de.danoeh.antennapod.discovery.ItunesTopListLoader;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -46,15 +47,11 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
-import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
-
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
private static final String TAG = "ItunesSearchFragment";
- private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
-
/**
* Adapter responsible with the search results
@@ -69,21 +66,21 @@ public class ItunesSearchFragment extends Fragment {
/**
* List of podcasts retreived from the search
*/
- private List<Podcast> searchResults;
- private List<Podcast> topList;
+ private List<PodcastSearchResult> searchResults;
+ private List<PodcastSearchResult> topList;
private Disposable disposable;
/**
* Replace adapter data with provided search results from SearchTask.
* @param result List of Podcast objects containing search results
*/
- private void updateData(List<Podcast> result) {
+ private void updateData(List<PodcastSearchResult> result) {
this.searchResults = result;
adapter.clear();
if (result != null && result.size() > 0) {
gridView.setVisibility(View.VISIBLE);
txtvEmpty.setVisibility(View.GONE);
- for (Podcast p : result) {
+ for (PodcastSearchResult p : result) {
adapter.add(p);
}
adapter.notifyDataSetInvalidated();
@@ -117,61 +114,31 @@ public class ItunesSearchFragment extends Fragment {
//Show information about the podcast when the list item is clicked
gridView.setOnItemClickListener((parent, view1, position, id) -> {
- Podcast podcast = searchResults.get(position);
- if(podcast.feedUrl == null) {
+ PodcastSearchResult podcast = searchResults.get(position);
+ if (podcast.feedUrl == null) {
return;
}
- if (!podcast.feedUrl.contains("itunes.apple.com")) {
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
- startActivity(intent);
- } else {
- gridView.setVisibility(View.GONE);
- progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<String>) emitter -> {
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder()
- .url(podcast.feedUrl)
- .header("User-Agent", ClientConfig.USER_AGENT);
- try {
- Response response = client.newCall(httpReq.build()).execute();
- if (response.isSuccessful()) {
- String resultString = response.body().string();
- JSONObject result = new JSONObject(resultString);
- JSONObject results = result.getJSONArray("results").getJSONObject(0);
- String feedUrl = results.getString("feedUrl");
- emitter.onSuccess(feedUrl);
- } else {
- String prefix = getString(R.string.error_msg_prefix);
- emitter.onError(new IOException(prefix + response));
- }
- } catch (IOException | JSONException e) {
- if (!disposable.isDisposed()) {
- emitter.onError(e);
- }
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(feedUrl -> {
- progressBar.setVisibility(View.GONE);
- gridView.setVisibility(View.VISIBLE);
- Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
- startActivity(intent);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- gridView.setVisibility(View.VISIBLE);
- String prefix = getString(R.string.error_msg_prefix);
- new MaterialDialog.Builder(getActivity())
- .content(prefix + " " + error.getMessage())
- .neutralText(android.R.string.ok)
- .show();
- });
- }
+ gridView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.VISIBLE);
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.getFeedUrl(podcast)
+ .subscribe(feedUrl -> {
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
+ startActivity(intent);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ gridView.setVisibility(View.VISIBLE);
+ String prefix = getString(R.string.error_msg_prefix);
+ new MaterialDialog.Builder(getActivity())
+ .content(prefix + " " + error.getMessage())
+ .neutralText(android.R.string.ok)
+ .show();
+ });
});
progressBar = root.findViewById(R.id.progressBar);
txtvError = root.findViewById(R.id.txtvError);
@@ -239,26 +206,9 @@ public class ItunesSearchFragment extends Fragment {
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<List<Podcast>>) emitter -> {
- String lang = Locale.getDefault().getLanguage();
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- String feedString;
- try {
- try {
- feedString = getTopListFeed(client, lang);
- } catch (IOException e) {
- feedString = getTopListFeed(client, "us");
- }
- List<Podcast> podcasts = parseFeed(feedString);
- emitter.onSuccess(podcasts);
- } catch (IOException | JSONException e) {
- if (!disposable.isDisposed()) {
- emitter.onError(e);
- }
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
+
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.loadToplist(25)
.subscribe(podcasts -> {
progressBar.setVisibility(View.GONE);
topList = podcasts;
@@ -273,35 +223,6 @@ public class ItunesSearchFragment extends Fragment {
});
}
- private String getTopListFeed(OkHttpClient client, String language) throws IOException {
- String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=25/explicit=true/json";
- Request.Builder httpReq = new Request.Builder()
- .header("User-Agent", ClientConfig.USER_AGENT)
- .url(String.format(url, language));
-
- try (Response response = client.newCall(httpReq.build()).execute()) {
- if (response.isSuccessful()) {
- return response.body().string();
- }
- String prefix = getString(R.string.error_msg_prefix);
- throw new IOException(prefix + response);
- }
- }
-
- private List<Podcast> parseFeed(String jsonString) throws JSONException {
- JSONObject result = new JSONObject(jsonString);
- JSONObject feed = result.getJSONObject("feed");
- JSONArray entries = feed.getJSONArray("entry");
-
- List<Podcast> results = new ArrayList<>();
- for (int i=0; i < entries.length(); i++) {
- JSONObject json = entries.getJSONObject(i);
- results.add(Podcast.fromToplist(json));
- }
-
- return results;
- }
-
private void search(String query) {
if (disposable != null) {
disposable.dispose();
@@ -311,60 +232,19 @@ public class ItunesSearchFragment extends Fragment {
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- disposable = Single.create((SingleOnSubscribe<List<Podcast>>) subscriber -> {
- String encodedQuery = null;
- try {
- encodedQuery = URLEncoder.encode(query, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- // this won't ever be thrown
- }
- if (encodedQuery == null) {
- encodedQuery = query; // failsafe
- }
-
- String formattedUrl = String.format(API_URL, encodedQuery);
-
- OkHttpClient client = AntennapodHttpClient.getHttpClient();
- Request.Builder httpReq = new Request.Builder()
- .url(formattedUrl)
- .header("User-Agent", ClientConfig.USER_AGENT);
- List<Podcast> podcasts = new ArrayList<>();
- try {
- Response response = client.newCall(httpReq.build()).execute();
-
- if(response.isSuccessful()) {
- String resultString = response.body().string();
- JSONObject result = new JSONObject(resultString);
- JSONArray j = result.getJSONArray("results");
- for (int i = 0; i < j.length(); i++) {
- JSONObject podcastJson = j.getJSONObject(i);
- Podcast podcast = Podcast.fromSearch(podcastJson);
- podcasts.add(podcast);
- }
- }
- else {
- String prefix = getString(R.string.error_msg_prefix);
- subscriber.onError(new IOException(prefix + response));
- }
- } catch (IOException | JSONException e) {
- subscriber.onError(e);
- }
- subscriber.onSuccess(podcasts);
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(podcasts -> {
- progressBar.setVisibility(View.GONE);
- updateData(podcasts);
- }, error -> {
- Log.e(TAG, Log.getStackTraceString(error));
- progressBar.setVisibility(View.GONE);
- txtvError.setText(error.toString());
- txtvError.setVisibility(View.VISIBLE);
- butRetry.setOnClickListener(v -> search(query));
- butRetry.setVisibility(View.VISIBLE);
- });
+ ItunesPodcastSearcher searcher = new ItunesPodcastSearcher(getContext());
+ disposable = searcher.search(query).subscribe(podcasts -> {
+ progressBar.setVisibility(View.GONE);
+ updateData(podcasts);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.toString());
+ txtvError.setVisibility(View.VISIBLE);
+ butRetry.setOnClickListener(v -> search(query));
+ butRetry.setVisibility(View.VISIBLE);
+ });
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index 5751855c7..1bf907aee 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -1,40 +1,37 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
+
import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
-import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.FeedItemUtil;
-
/**
* Like 'EpisodesFragment' except that it only shows new episodes and
* supports swiping to mark as read.
*/
-
public class NewEpisodesFragment extends AllEpisodesFragment {
public static final String TAG = "NewEpisodesFragment";
private static final String PREF_NAME = "PrefNewEpisodesFragment";
- @Override
- protected boolean showOnlyNewEpisodes() { return true; }
@Override
- protected String getPrefName() { return PREF_NAME; }
+ protected boolean showOnlyNewEpisodes() {
+ return true;
+ }
@Override
- protected void resetViewState() {
- super.resetViewState();
+ protected String getPrefName() {
+ return PREF_NAME;
}
@Override
@@ -42,10 +39,10 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
return item.isNew();
}
+ @NonNull
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View root = super.onCreateViewHelper(inflater, container, savedInstanceState,
- R.layout.all_episodes_fragment);
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = super.onCreateView(inflater, container, savedInstanceState);
emptyView.setTitle(R.string.no_new_episodes_head_label);
emptyView.setMessage(R.string.no_new_episodes_label);
@@ -57,8 +54,8 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
- AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder)viewHolder;
- markItemAsSeenWithUndo(holder.getFeedItem());
+ AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder;
+ removeNewFlagWithUndo(holder.getFeedItem());
}
@Override
@@ -75,6 +72,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
super.onSelectedChanged(viewHolder, actionState);
}
+
@Override
public void clearView(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
@@ -94,9 +92,9 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
return root;
}
+ @NonNull
@Override
protected List<FeedItem> loadData() {
return DBReader.getNewItemsList();
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index da11383a5..e2060481f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.fragment;
-import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -13,6 +12,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
import java.util.List;
import de.danoeh.antennapod.R;
@@ -34,9 +37,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
public class PlaybackHistoryFragment extends ListFragment {
@@ -47,23 +47,10 @@ public class PlaybackHistoryFragment extends ListFragment {
private List<FeedItem> playbackHistory;
private FeedItemlistAdapter adapter;
-
- private boolean itemsLoaded = false;
- private boolean viewsCreated = false;
-
private List<Downloader> downloaderList;
-
private Disposable disposable;
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
- }
-
- @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
@@ -80,16 +67,17 @@ public class PlaybackHistoryFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
-
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.ic_history);
emptyView.setTitle(R.string.no_history_head_label);
emptyView.setMessage(R.string.no_history_label);
emptyView.attachToListView(getListView());
+ // played items shoudln't be transparent for this fragment since, *all* items
+ // in this fragment will, by definition, be played. So it serves no purpose and can make
+ // it harder to read.
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess, true, false);
+ setListAdapter(adapter);
}
@Override
@@ -105,34 +93,17 @@ public class PlaybackHistoryFragment extends ListFragment {
super.onStop();
EventBus.getDefault().unregister(this);
EventDistributor.getInstance().unregister(contentUpdate);
- if(disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
}
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- adapter = null;
- viewsCreated = false;
- }
-
@Subscribe(sticky = true)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
}
@Override
@@ -145,27 +116,23 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if(!isAdded()) {
+ if (!isAdded()) {
return;
}
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
- MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
- clearHistory.setIcon(drawables.getDrawable(0));
- drawables.recycle();
- }
+ MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
+ MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard});
+ clearHistory.setIcon(drawables.getDrawable(0));
+ drawables.recycle();
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- if (itemsLoaded) {
- MenuItem menuItem = menu.findItem(R.id.clear_history_item);
- if (menuItem != null) {
- menuItem.setVisible(playbackHistory != null && !playbackHistory.isEmpty());
- }
+ MenuItem menuItem = menu.findItem(R.id.clear_history_item);
+ if (menuItem != null) {
+ menuItem.setVisible(playbackHistory != null && !playbackHistory.isEmpty());
}
}
@@ -211,14 +178,6 @@ public class PlaybackHistoryFragment extends ListFragment {
};
private void onFragmentLoaded() {
- if (adapter == null) {
- // played items shoudln't be transparent for this fragment since, *all* items
- // in this fragment will, by definition, be played. So it serves no purpose and can make
- // it harder to read.
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess, true, false);
- setListAdapter(adapter);
- }
- setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
}
@@ -277,10 +236,7 @@ public class PlaybackHistoryFragment extends ListFragment {
.subscribe(result -> {
if (result != null) {
playbackHistory = result;
- itemsLoaded = true;
- if (viewsCreated) {
- onFragmentLoaded();
- }
+ onFragmentLoaded();
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@@ -291,5 +247,4 @@ public class PlaybackHistoryFragment extends ListFragment {
DBReader.loadAdditionalFeedItemListData(history);
return history;
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index f3421c8fd..4947d5a87 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -49,6 +49,7 @@ import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.QueueSorter;
+import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
@@ -61,6 +62,9 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
+import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
+
/**
* Shows all items in the queue
*/
@@ -323,6 +327,10 @@ public class QueueFragment extends Fragment {
};
conDialog.createNewDialog().show();
return true;
+ case R.id.episode_actions:
+ ((MainActivity) requireActivity()) .loadChildFragment(
+ EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE));
+ return true;
case R.id.queue_sort_episode_title_asc:
QueueSorter.sort(QueueSorter.Rule.EPISODE_TITLE_ASC, true);
return true;
@@ -518,6 +526,7 @@ public class QueueFragment extends Fragment {
emptyView = new EmptyViewHandler(getContext());
emptyView.attachToRecyclerView(recyclerView);
+ emptyView.setIcon(R.attr.stat_playlist);
emptyView.setTitle(R.string.no_items_header_label);
emptyView.setMessage(R.string.no_items_label);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
new file mode 100644
index 000000000..e4213cc6b
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -0,0 +1,119 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.GridView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
+import de.danoeh.antennapod.discovery.ItunesTopListLoader;
+import de.danoeh.antennapod.discovery.PodcastSearchResult;
+import io.reactivex.disposables.Disposable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = "FeedDiscoveryFragment";
+
+ private ProgressBar progressBar;
+ private Disposable disposable;
+ private FeedDiscoverAdapter adapter;
+ private GridView subscriptionGridLayout;
+ private TextView errorTextView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.quick_feed_discovery, container, false);
+ View discoverMore = root.findViewById(R.id.discover_more);
+ discoverMore.setOnClickListener(v ->
+ ((MainActivity) getActivity()).loadChildFragment(new ItunesSearchFragment()));
+
+ subscriptionGridLayout = root.findViewById(R.id.discover_grid);
+ progressBar = root.findViewById(R.id.discover_progress_bar);
+ errorTextView = root.findViewById(R.id.discover_error);
+
+ adapter = new FeedDiscoverAdapter((MainActivity) getActivity());
+ subscriptionGridLayout.setAdapter(adapter);
+ subscriptionGridLayout.setOnItemClickListener(this);
+
+ // Fill with dummy elements to have a fixed height and
+ // prevent the UI elements below from jumping on slow connections
+ List<PodcastSearchResult> dummies = new ArrayList<>();
+ for (int i = 0; i < 8; i++) {
+ dummies.add(PodcastSearchResult.dummy());
+ }
+ adapter.updateData(dummies);
+
+ loadToplist();
+
+ return root;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ private void loadToplist() {
+ progressBar.setVisibility(View.VISIBLE);
+ subscriptionGridLayout.setVisibility(View.INVISIBLE);
+ errorTextView.setVisibility(View.GONE);
+
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.loadToplist(8)
+ .subscribe(podcasts -> {
+ errorTextView.setVisibility(View.GONE);
+ progressBar.setVisibility(View.GONE);
+ subscriptionGridLayout.setVisibility(View.VISIBLE);
+ adapter.updateData(podcasts);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ errorTextView.setText(error.getLocalizedMessage());
+ errorTextView.setVisibility(View.VISIBLE);
+ progressBar.setVisibility(View.GONE);
+ subscriptionGridLayout.setVisibility(View.INVISIBLE);
+ });
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+ PodcastSearchResult podcast = adapter.getItem(position);
+ if (podcast.feedUrl == null) {
+ return;
+ }
+ view.setAlpha(0.5f);
+ ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
+ disposable = loader.getFeedUrl(podcast)
+ .subscribe(feedUrl -> {
+ view.setAlpha(1f);
+ Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, feedUrl);
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
+ startActivity(intent);
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ view.setAlpha(1f);
+ String prefix = getString(R.string.error_msg_prefix);
+ new MaterialDialog.Builder(getActivity())
+ .content(prefix + " " + error.getMessage())
+ .neutralText(android.R.string.ok)
+ .show();
+ });
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index 718502ea2..2a7f7d12b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -7,6 +7,10 @@ import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -21,8 +25,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.view.EmptyViewHandler;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
/**
* Displays all running downloads and provides actions to cancel them
@@ -32,7 +34,7 @@ public class RunningDownloadsFragment extends ListFragment {
private static final String TAG = "RunningDownloadsFrag";
private DownloadlistAdapter adapter;
- private List<Downloader> downloaderList;
+ private List<Downloader> downloaderList = new ArrayList<>();
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -48,6 +50,7 @@ public class RunningDownloadsFragment extends ListFragment {
setListAdapter(adapter);
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
+ emptyView.setIcon(R.attr.av_download);
emptyView.setTitle(R.string.no_run_downloads_head_label);
emptyView.setMessage(R.string.no_run_downloads_label);
emptyView.attachToListView(getListView());
@@ -70,7 +73,6 @@ public class RunningDownloadsFragment extends ListFragment {
public void onDestroy() {
super.onDestroy();
setListAdapter(null);
- adapter = null;
}
@Subscribe(sticky = true)
@@ -78,21 +80,18 @@ public class RunningDownloadsFragment extends ListFragment {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
+ adapter.notifyDataSetChanged();
}
-
private final DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
@Override
public int getCount() {
- return (downloaderList != null) ? downloaderList.size() : 0;
+ return downloaderList.size();
}
@Override
public Downloader getItem(int position) {
- if (downloaderList != null && 0 <= position && position < downloaderList.size()) {
+ if (0 <= position && position < downloaderList.size()) {
return downloaderList.get(position);
} else {
return null;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 1d7ac8824..0892bce0a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -14,6 +14,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -40,11 +41,7 @@ public class SearchFragment extends ListFragment {
private static final String ARG_FEED = "feed";
private SearchlistAdapter searchAdapter;
- private List<SearchResult> searchResults;
-
- private boolean viewCreated = false;
- private boolean itemsLoaded = false;
-
+ private List<SearchResult> searchResults = new ArrayList<>();
private Disposable disposable;
/**
@@ -74,13 +71,13 @@ public class SearchFragment extends ListFragment {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
- search();
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ search();
}
@Override
@@ -93,21 +90,6 @@ public class SearchFragment extends ListFragment {
}
@Override
- public void onDetach() {
- super.onDetach();
- if(disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- searchAdapter = null;
- viewCreated = false;
- }
-
- @Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -118,10 +100,9 @@ public class SearchFragment extends ListFragment {
lv.setPadding(0, vertPadding, 0, vertPadding);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
- viewCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
- }
+
+ searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
+ setListAdapter(searchAdapter);
}
@Override
@@ -142,28 +123,26 @@ public class SearchFragment extends ListFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
- if (itemsLoaded) {
- MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
- MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
- final SearchView sv = new SearchView(getActivity());
- sv.setQueryHint(getString(R.string.search_hint));
- sv.setQuery(getArguments().getString(ARG_QUERY), false);
- sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String s) {
- getArguments().putString(ARG_QUERY, s);
- itemsLoaded = false;
- search();
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String s) {
- return false;
- }
- });
- MenuItemCompat.setActionView(item, sv);
- }
+ MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
+ MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ final SearchView sv = new SearchView(getActivity());
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setQuery(getArguments().getString(ARG_QUERY), false);
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ getArguments().putString(ARG_QUERY, s);
+ search();
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ MenuItemCompat.setActionView(item, sv);
}
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@@ -176,14 +155,9 @@ public class SearchFragment extends ListFragment {
}
};
- private void onFragmentLoaded() {
- if (searchAdapter == null) {
- searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
- setListAdapter(searchAdapter);
- }
+ private void onSearchResults(List<SearchResult> results) {
+ searchResults = results;
searchAdapter.notifyDataSetChanged();
- setListShown(true);
-
String query = getArguments().getString(ARG_QUERY);
setEmptyText(getString(R.string.no_results_for_query, query));
}
@@ -191,12 +165,12 @@ public class SearchFragment extends ListFragment {
private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() {
@Override
public int getCount() {
- return (searchResults != null) ? searchResults.size() : 0;
+ return searchResults.size();
}
@Override
public SearchResult getItem(int position) {
- if (searchResults != null && 0 <= position && position < searchResults.size()) {
+ if (0 <= position && position < searchResults.size()) {
return searchResults.get(position);
} else {
return null;
@@ -204,24 +178,14 @@ public class SearchFragment extends ListFragment {
}
};
-
private void search() {
if(disposable != null) {
disposable.dispose();
}
- if (viewCreated && !itemsLoaded) {
- setListShown(false);
- }
disposable = Observable.fromCallable(this::performSearch)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- itemsLoaded = true;
- searchResults = result;
- if (viewCreated) {
- onFragmentLoaded();
- }
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ .subscribe(this::onSearchResults, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@NonNull
@@ -232,5 +196,4 @@ public class SearchFragment extends ListFragment {
Context context = getActivity();
return FeedSearcher.performSearch(context, query, feed);
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index 75da522d1..15c6052a9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -1,9 +1,11 @@
package de.danoeh.antennapod.fragment;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
@@ -16,6 +18,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
+import java.util.concurrent.Callable;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsAdapter;
@@ -56,16 +60,13 @@ public class SubscriptionFragment extends Fragment {
private Disposable disposable;
private SharedPreferences prefs;
- public SubscriptionFragment() {
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
- prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
+ prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
@Override
@@ -123,23 +124,25 @@ public class SubscriptionFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
subscriptionAdapter = new SubscriptionsAdapter((MainActivity)getActivity(), itemAccess);
-
subscriptionGridLayout.setAdapter(subscriptionAdapter);
-
- loadSubscriptions();
-
subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter);
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.subscriptions_label);
}
+ }
+ @Override
+ public void onStart() {
+ super.onStart();
EventDistributor.getInstance().register(contentUpdate);
+ loadSubscriptions();
}
@Override
- public void onDestroy() {
- super.onDestroy();
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
if(disposable != null) {
disposable.dispose();
}
@@ -172,7 +175,7 @@ public class SubscriptionFragment extends Fragment {
Feed feed = (Feed)selectedObject;
- MenuInflater inflater = getActivity().getMenuInflater();
+ MenuInflater inflater = requireActivity().getMenuInflater();
inflater.inflate(R.menu.nav_feed_context, menu);
menu.setHeaderTitle(feed.getTitle());
@@ -182,7 +185,6 @@ public class SubscriptionFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
-
final int position = mPosition;
mPosition = -1; // reset
if(position < 0) {
@@ -197,84 +199,73 @@ public class SubscriptionFragment extends Fragment {
Feed feed = (Feed)selectedObject;
switch(item.getItemId()) {
- case R.id.mark_all_seen_item:
- ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(),
- R.string.mark_all_seen_label,
- R.string.mark_all_seen_confirmation_msg) {
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- dialog.dismiss();
-
- Observable.fromCallable(() -> DBWriter.markFeedSeen(feed.getId()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
- };
- markAllSeenConfirmationDialog.createNewDialog().show();
+ case R.id.remove_all_new_flags_item:
+ displayConfirmationDialog(
+ R.string.remove_all_new_flags_label,
+ R.string.remove_all_new_flags_confirmation_msg,
+ () -> DBWriter.removeFeedNewFlag(feed.getId()));
return true;
case R.id.mark_all_read_item:
- ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(),
+ displayConfirmationDialog(
R.string.mark_all_read_label,
- R.string.mark_all_read_confirmation_msg) {
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- dialog.dismiss();
- Observable.fromCallable(() -> DBWriter.markFeedRead(feed.getId()))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadSubscriptions(),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
- };
- markAllReadConfirmationDialog.createNewDialog().show();
+ R.string.mark_all_read_confirmation_msg,
+ () -> DBWriter.markFeedRead(feed.getId()));
return true;
case R.id.rename_item:
new RenameFeedDialog(getActivity(), feed).show();
return true;
case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(getContext(), feed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- loadSubscriptions();
- }
- };
- ConfirmationDialog conDialog = new ConfirmationDialog(getContext(),
- R.string.remove_feed_label,
- getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) {
- @Override
- public void onConfirmButtonPressed(
- DialogInterface dialog) {
- dialog.dismiss();
- long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
- if (mediaId > 0 &&
- FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) {
- Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
- remover.skipOnCompletion = true;
- int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
- if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
- IntentUtils.sendLocalBroadcast(getContext(), PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
-
- }
- }
- remover.executeAsync();
- }
- };
- conDialog.createNewDialog().show();
+ displayRemoveFeedDialog(feed);
return true;
default:
return super.onContextItemSelected(item);
}
}
- @Override
- public void onResume() {
- super.onResume();
- loadSubscriptions();
+ private void displayRemoveFeedDialog(Feed feed) {
+ final FeedRemover remover = new FeedRemover(getContext(), feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ loadSubscriptions();
+ }
+ };
+
+ String message = getString(R.string.feed_delete_confirmation_msg, feed.getTitle());
+ ConfirmationDialog dialog = new ConfirmationDialog(getContext(), R.string.remove_feed_label, message) {
+ @Override
+ public void onConfirmButtonPressed(DialogInterface clickedDialog) {
+ clickedDialog.dismiss();
+ long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
+ if (mediaId > 0 && FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) {
+ Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
+ remover.skipOnCompletion = true;
+ int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
+ if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
+ IntentUtils.sendLocalBroadcast(getContext(), PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
+
+ }
+ }
+ remover.executeAsync();
+ }
+ };
+ dialog.createNewDialog().show();
+ }
+
+ private <T> void displayConfirmationDialog(@StringRes int title, @StringRes int message, Callable<? extends T> task) {
+ ConfirmationDialog dialog = new ConfirmationDialog(getActivity(), title, message) {
+ @Override
+ @SuppressLint("CheckResult")
+ public void onConfirmButtonPressed(DialogInterface clickedDialog) {
+ clickedDialog.dismiss();
+ Observable.fromCallable(task)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> loadSubscriptions(),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+ };
+ dialog.createNewDialog().show();
}
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/FlattrPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/FlattrPreferencesFragment.java
deleted file mode 100644
index 152c3da87..000000000
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/FlattrPreferencesFragment.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package de.danoeh.antennapod.fragment.preferences;
-
-import android.os.Bundle;
-import android.support.v7.preference.PreferenceFragmentCompat;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
-
-public class FlattrPreferencesFragment extends PreferenceFragmentCompat {
- private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
- private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
- private static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs";
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- addPreferencesFromResource(R.xml.preferences_flattr);
- setupFlattrScreen();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- checkFlattrItemVisibility();
- }
-
- private void setupFlattrScreen() {
- findPreference(PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
- preference -> {
- FlattrUtils.revokeAccessToken(getActivity());
- checkFlattrItemVisibility();
- return true;
- }
- );
-
- findPreference(PREF_AUTO_FLATTR_PREFS)
- .setOnPreferenceClickListener(preference -> {
- AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(getActivity(),
- new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
- @Override
- public void onCancelled() {
-
- }
-
- @Override
- public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
- UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
- checkFlattrItemVisibility();
- }
- });
- return true;
- });
- }
-
- private void checkFlattrItemVisibility() {
- boolean hasFlattrToken = FlattrUtils.hasToken();
- findPreference(PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
- findPreference(PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
- findPreference(PREF_AUTO_FLATTR_PREFS).setEnabled(hasFlattrToken);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
index 805d84215..229274b76 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java
@@ -4,10 +4,8 @@ import android.os.Bundle;
import android.support.v7.preference.PreferenceFragmentCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat {
- private static final String PREF_SCREEN_FLATTR = "prefFlattrSettings";
private static final String PREF_SCREEN_GPODDER = "prefGpodderSettings";
@Override
@@ -17,19 +15,9 @@ public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat {
}
private void setupIntegrationsScreen() {
- findPreference(PREF_SCREEN_FLATTR).setOnPreferenceClickListener(preference -> {
- ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_flattr);
- return true;
- });
findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder);
return true;
});
}
-
- @Override
- public void onResume() {
- super.onResume();
- findPreference(PREF_SCREEN_FLATTR).setEnabled(FlattrUtils.hasAPICredentials());
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
index 5a4866206..701d21ce0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -143,8 +143,5 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
config.index(R.xml.preferences_gpodder)
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_integrations))
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_gpodder));
- config.index(R.xml.preferences_flattr)
- .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_integrations))
- .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_flattr));
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index 2886a7e33..0c7622a47 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -124,10 +124,6 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.deactivate_auto_download, false);
}
- if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
- mi.setItemVisibility(R.id.support_item, false);
- }
-
boolean isFavorite = selectedItem.isTagged(FeedItem.TAG_FAVORITE);
mi.setItemVisibility(R.id.add_to_favorites_item, !isFavorite);
mi.setItemVisibility(R.id.remove_from_favorites_item, isFavorite);
@@ -230,9 +226,6 @@ public class FeedItemMenuHandler {
Toast.LENGTH_SHORT).show();
}
break;
- case R.id.support_item:
- DBTasks.flattrItemIfLoggedIn(context, selectedItem);
- break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index bd4fe9bcf..0928cfd62 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -46,11 +46,6 @@ public class FeedMenuHandler {
}
Log.d(TAG, "Preparing options menu");
- if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable()) {
- menu.findItem(R.id.support_item).setVisible(true);
- } else {
- menu.findItem(R.id.support_item).setVisible(false);
- }
menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged());
@@ -98,9 +93,6 @@ public class FeedMenuHandler {
Toast.LENGTH_SHORT).show();
}
break;
- case R.id.support_item:
- DBTasks.flattrFeedIfLoggedIn(context, selectedFeed);
- break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 93b326698..5866f8715 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -2,28 +2,51 @@ package de.danoeh.antennapod.preferences;
import android.content.Context;
import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.gui.NotificationUtils;
public class PreferenceUpgrader {
private static final String PREF_CONFIGURED_VERSION = "configuredVersion";
private static final String PREF_NAME = "PreferenceUpgrader";
+ private static SharedPreferences prefs;
public static void checkUpgrades(Context context) {
- SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- int oldVersion = prefs.getInt(PREF_CONFIGURED_VERSION, 1070200);
+ prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences upgraderPrefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ int oldVersion = upgraderPrefs.getInt(PREF_CONFIGURED_VERSION, 1070200);
int newVersion = BuildConfig.VERSION_CODE;
if (oldVersion != newVersion) {
- prefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply();
+ NotificationUtils.createChannels(context);
+
+ upgraderPrefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply();
upgrade(oldVersion);
}
}
private static void upgrade(int oldVersion) {
+ if (oldVersion < 1070196) {
+ // migrate episode cleanup value (unit changed from days to hours)
+ int oldValueInDays = UserPreferences.getEpisodeCleanupValue();
+ if (oldValueInDays > 0) {
+ UserPreferences.setEpisodeCleanupValue(oldValueInDays * 24);
+ } // else 0 or special negative values, no change needed
+ }
+ if (oldVersion < 1070197) {
+ if (prefs.getBoolean("prefMobileUpdate", false)) {
+ prefs.edit().putString(UserPreferences.PREF_MOBILE_UPDATE, "everything").apply();
+ }
+ }
if (oldVersion < 1070300) {
UserPreferences.restartUpdateAlarm();
+
+ if (UserPreferences.getMediaPlayer().equals("builtin")) {
+ prefs.edit().putString(UserPreferences.PREF_MEDIA_PLAYER,
+ UserPreferences.PREF_MEDIA_PLAYER_EXOPLAYER).apply();
+ }
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
index 42c11bc8e..8b886e699 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java
@@ -1,9 +1,14 @@
package de.danoeh.antennapod.view;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.AttrRes;
+import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -15,14 +20,18 @@ public class EmptyViewHandler {
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
+ private final Context context;
private final View emptyView;
private final TextView tvTitle;
private final TextView tvMessage;
+ private final ImageView ivIcon;
public EmptyViewHandler(Context context) {
emptyView = View.inflate(context, R.layout.empty_view_layout, null);
+ this.context = context;
tvTitle = emptyView.findViewById(R.id.emptyViewTitle);
tvMessage = emptyView.findViewById(R.id.emptyViewMessage);
+ ivIcon = emptyView.findViewById(R.id.emptyViewIcon);
}
public void setTitle(int title) {
@@ -33,6 +42,14 @@ public class EmptyViewHandler {
tvMessage.setText(message);
}
+ public void setIcon(@AttrRes int iconAttr) {
+ TypedValue typedValue = new TypedValue();
+ context.getTheme().resolveAttribute(iconAttr, typedValue, true);
+ Drawable d = ContextCompat.getDrawable(context, typedValue.resourceId);
+ ivIcon.setImageDrawable(d);
+ ivIcon.setVisibility(View.VISIBLE);
+ }
+
public void hide() {
emptyView.setVisibility(View.GONE);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java b/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java
new file mode 100644
index 000000000..37792b4d1
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/WrappingGridView.java
@@ -0,0 +1,35 @@
+package de.danoeh.antennapod.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.GridView;
+
+/**
+ * Source: https://stackoverflow.com/a/46350213/
+ */
+public class WrappingGridView extends GridView {
+
+ public WrappingGridView(Context context) {
+ super(context);
+ }
+
+ public WrappingGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WrappingGridView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int heightSpec = heightMeasureSpec;
+ if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
+ // The great Android "hackatlon", the love, the magic.
+ // The two leftmost bits in the height measure spec have
+ // a special meaning, hence we can't use them to describe height.
+ heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ }
+ super.onMeasure(widthMeasureSpec, heightSpec);
+ }
+}