From b146a1163cda8855052613c2c6c378e9773b3212 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 9 Apr 2020 11:57:16 +0200 Subject: Abstract from iTunes search provider lookup --- .../activity/OnlineFeedViewActivity.java | 43 +++++++++++++----- .../antennapod/discovery/CombinedSearcher.java | 41 ++++++++++------- .../antennapod/discovery/FyydPodcastSearcher.java | 10 +++++ .../discovery/GpodnetPodcastSearcher.java | 10 +++++ .../discovery/ItunesPodcastSearcher.java | 40 ++++++++++++++--- .../antennapod/discovery/ItunesTopListLoader.java | 30 ------------- .../antennapod/discovery/PodcastSearcher.java | 4 ++ .../discovery/PodcastSearcherRegistry.java | 52 ++++++++++++++++++++++ .../antennapod/fragment/AddFeedFragment.java | 1 - .../fragment/CombinedSearchFragment.java | 1 - .../antennapod/fragment/FyydSearchFragment.java | 1 - .../antennapod/fragment/ItunesSearchFragment.java | 26 ++--------- .../fragment/QuickFeedDiscoveryFragment.java | 21 ++------- .../fragment/gpodnet/PodcastListFragment.java | 1 - 14 files changed, 172 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java (limited to 'app/src/main') diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 821defd86..15816199d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -57,6 +57,7 @@ import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer; import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; import de.danoeh.antennapod.dialog.AuthenticationDialog; +import de.danoeh.antennapod.discovery.PodcastSearcherRegistry; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; @@ -84,7 +85,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity { public static final String ARG_FEEDURL = "arg.feedurl"; // Optional argument: specify a title for the actionbar. - public static final String ARG_TITLE = "title"; private static final int RESULT_ERROR = 2; private static final String TAG = "OnlineFeedViewActivity"; private volatile List feeds; @@ -127,11 +127,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { if (feedUrl == null) { Log.e(TAG, "feedUrl is null."); - new AlertDialog.Builder(OnlineFeedViewActivity.this) - .setNeutralButton(android.R.string.ok, (dialog, which) -> finish()) - .setTitle(R.string.error_label) - .setMessage(R.string.null_value_podcast_error) - .show(); + showNoPodcastFoundError(); } else { Log.d(TAG, "Activity was started with url " + feedUrl); setLoadingLayout(); @@ -140,13 +136,26 @@ public class OnlineFeedViewActivity extends AppCompatActivity { feedUrl = feedUrl.replaceFirst("((www.)?(subscribeonandroid.com/))", ""); } if (savedInstanceState == null) { - startFeedDownload(feedUrl, null, null); + lookupUrlAndDownload(feedUrl, null, null); } else { - startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password")); + lookupUrlAndDownload(feedUrl, savedInstanceState.getString("username"), + savedInstanceState.getString("password")); } } } + private void showNoPodcastFoundError() { + new AlertDialog.Builder(OnlineFeedViewActivity.this) + .setNeutralButton(android.R.string.ok, (dialog, which) -> finish()) + .setTitle(R.string.error_label) + .setMessage(R.string.null_value_podcast_error) + .setOnDismissListener(dialog1 -> { + setResult(RESULT_ERROR); + finish(); + }) + .show(); + } + /** * Displays a progress indicator. */ @@ -198,10 +207,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } } - private void resetIntent(String url, String title) { + private void resetIntent(String url) { Intent intent = new Intent(); intent.putExtra(ARG_FEEDURL, url); - intent.putExtra(ARG_TITLE, title); setIntent(intent); } @@ -226,6 +234,17 @@ public class OnlineFeedViewActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } + private void lookupUrlAndDownload(String url, String username, String password) { + download = PodcastSearcherRegistry.lookupUrl(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe(lookedUpUrl -> startFeedDownload(lookedUpUrl, username, password), + error -> { + showNoPodcastFoundError(); + Log.e(TAG, Log.getStackTraceString(error)); + }); + } + private void startFeedDownload(String url, String username, String password) { Log.d(TAG, "Starting feed download"); url = URLChecker.prepareURL(url); @@ -580,7 +599,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { if (urls.size() == 1) { // Skip dialog and display the item directly - resetIntent(urls.get(0), titles.get(0)); + resetIntent(urls.get(0)); startFeedDownload(urls.get(0), null, null); return true; } @@ -589,7 +608,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { DialogInterface.OnClickListener onClickListener = (dialog, which) -> { String selectedUrl = urls.get(which); dialog.dismiss(); - resetIntent(selectedUrl, titles.get(which)); + resetIntent(selectedUrl); FeedPreferences prefs = feed.getPreferences(); if(prefs != null) { startFeedDownload(selectedUrl, prefs.getUsername(), prefs.getPassword()); diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java index e34d8539c..287e20964 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java @@ -19,25 +19,22 @@ import java.util.concurrent.CountDownLatch; public class CombinedSearcher implements PodcastSearcher { private static final String TAG = "CombinedSearcher"; - private final List> 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> search(String query) { ArrayList disposables = new ArrayList<>(); - List> singleResults = new ArrayList<>(Collections.nCopies(searchProviders.size(), null)); - CountDownLatch latch = new CountDownLatch(searchProviders.size()); - for (int i = 0; i < searchProviders.size(); i++) { - Pair searchProviderInfo = searchProviders.get(i); - PodcastSearcher searcher = searchProviderInfo.first; + List> singleResults = new ArrayList<>( + Collections.nCopies(PodcastSearcherRegistry.getSearchProviders().size(), null)); + CountDownLatch latch = new CountDownLatch(PodcastSearcherRegistry.getSearchProviders().size()); + for (int i = 0; i < PodcastSearcherRegistry.getSearchProviders().size(); i++) { + PodcastSearcherRegistry.SearcherInfo searchProviderInfo + = PodcastSearcherRegistry.getSearchProviders().get(i); + PodcastSearcher searcher = searchProviderInfo.searcher; + if (searchProviderInfo.weight <= 0.00001f) { + latch.countDown(); + continue; + } final int index = i; disposables.add(searcher.search(query).subscribe(e -> { singleResults.set(index, e); @@ -56,7 +53,9 @@ public class CombinedSearcher implements PodcastSearcher { }) .doOnDispose(() -> { for (Disposable disposable : disposables) { - disposable.dispose(); + if (disposable != null) { + disposable.dispose(); + } } }) .subscribeOn(Schedulers.io()) @@ -67,7 +66,7 @@ public class CombinedSearcher implements PodcastSearcher { HashMap resultRanking = new HashMap<>(); HashMap urlToResult = new HashMap<>(); for (int i = 0; i < singleResults.size(); i++) { - float providerPriority = searchProviders.get(i).second; + float providerPriority = PodcastSearcherRegistry.getSearchProviders().get(i).weight; List providerResults = singleResults.get(i); if (providerResults == null) { continue; @@ -93,4 +92,14 @@ public class CombinedSearcher implements PodcastSearcher { } return results; } + + @Override + public Single lookupUrl(String url) { + return PodcastSearcherRegistry.lookupUrl(url); + } + + @Override + public boolean urlNeedsLookup(String url) { + return PodcastSearcherRegistry.urlNeedsLookup(url); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java index 529a9e3d5..856ca8569 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java @@ -35,4 +35,14 @@ public class FyydPodcastSearcher implements PodcastSearcher { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } + + @Override + public Single lookupUrl(String url) { + return Single.just(url); + } + + @Override + public boolean urlNeedsLookup(String url) { + return false; + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java index 4fbac19ff..46b3e5775 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java @@ -33,4 +33,14 @@ public class GpodnetPodcastSearcher implements PodcastSearcher { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } + + @Override + public Single lookupUrl(String url) { + return Single.just(url); + } + + @Override + public boolean urlNeedsLookup(String url) { + return false; + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java index 620b30177..ed1efaf73 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java @@ -2,7 +2,6 @@ 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; @@ -23,12 +22,11 @@ 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 ItunesPodcastSearcher() { } + @Override public Single> search(String query) { return Single.create((SingleOnSubscribe>) subscriber -> { String encodedQuery; @@ -56,11 +54,12 @@ public class ItunesPodcastSearcher implements PodcastSearcher { for (int i = 0; i < j.length(); i++) { JSONObject podcastJson = j.getJSONObject(i); PodcastSearchResult podcast = PodcastSearchResult.fromItunes(podcastJson); - podcasts.add(podcast); + if (podcast.feedUrl != null) { + podcasts.add(podcast); + } } } else { - String prefix = context.getString(R.string.error_msg_prefix); - subscriber.onError(new IOException(prefix + response)); + subscriber.onError(new IOException(response.toString())); } } catch (IOException | JSONException e) { subscriber.onError(e); @@ -70,4 +69,31 @@ public class ItunesPodcastSearcher implements PodcastSearcher { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } + + @Override + public Single lookupUrl(String url) { + return Single.create(emitter -> { + OkHttpClient client = AntennapodHttpClient.getHttpClient(); + Request.Builder httpReq = new Request.Builder().url(url); + 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 { + emitter.onError(new IOException(response.toString())); + } + } catch (IOException | JSONException e) { + emitter.onError(e); + } + }); + } + + @Override + public boolean urlNeedsLookup(String url) { + return url.contains("itunes.apple.com"); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java index 226b18204..e93a89ef0 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesTopListLoader.java @@ -4,7 +4,6 @@ import android.content.Context; import android.util.Log; 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; @@ -49,35 +48,6 @@ public class ItunesTopListLoader { .observeOn(AndroidSchedulers.mainThread()); } - public Single getFeedUrl(PodcastSearchResult podcast) { - if (!podcast.feedUrl.contains("itunes.apple.com")) { - return Single.just(podcast.feedUrl) - .observeOn(AndroidSchedulers.mainThread()); - } - return Single.create((SingleOnSubscribe) emitter -> { - OkHttpClient client = AntennapodHttpClient.getHttpClient(); - Request.Builder httpReq = new Request.Builder() - .url(podcast.feedUrl); - 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 country, int limit) throws IOException { String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=" + limit + "/explicit=true/json"; Log.d(TAG, "Feed URL " + String.format(url, country)); diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java index b19d7d695..3312e0d57 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java @@ -7,4 +7,8 @@ import java.util.List; public interface PodcastSearcher { Single> search(String query); + + Single lookupUrl(String resultUrl); + + boolean urlNeedsLookup(String resultUrl); } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java new file mode 100644 index 000000000..32fa96d5d --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java @@ -0,0 +1,52 @@ +package de.danoeh.antennapod.discovery; + + +import io.reactivex.Single; + +import java.util.ArrayList; +import java.util.List; + +public class PodcastSearcherRegistry { + private static List searchProviders; + + private PodcastSearcherRegistry() { + } + + public static List getSearchProviders() { + if (searchProviders == null) { + searchProviders = new ArrayList<>(); + searchProviders.add(new SearcherInfo(new FyydPodcastSearcher(), 1.f)); + searchProviders.add(new SearcherInfo(new ItunesPodcastSearcher(), 1.f)); + searchProviders.add(new SearcherInfo(new GpodnetPodcastSearcher(), 0.0f)); + } + return searchProviders; + } + + public static Single lookupUrl(String url) { + for (PodcastSearcherRegistry.SearcherInfo searchProviderInfo : getSearchProviders()) { + if (searchProviderInfo.searcher.urlNeedsLookup(url)) { + return searchProviderInfo.searcher.lookupUrl(url); + } + } + return Single.just(url); + } + + public static boolean urlNeedsLookup(String url) { + for (PodcastSearcherRegistry.SearcherInfo searchProviderInfo : getSearchProviders()) { + if (searchProviderInfo.searcher.urlNeedsLookup(url)) { + return true; + } + } + return false; + } + + public static class SearcherInfo { + final PodcastSearcher searcher; + final float weight; + + public SearcherInfo(PodcastSearcher searcher, float weight) { + this.searcher = searcher; + this.weight = weight; + } + } +} 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 2d2244a85..49b2ae7ac 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -89,7 +89,6 @@ public class AddFeedFragment extends Fragment { 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); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java index 256438c2b..b71a7e0cc 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java @@ -77,7 +77,6 @@ public class CombinedSearchFragment extends Fragment { 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); 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 547bd6b24..6bd191af4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java @@ -76,7 +76,6 @@ public class FyydSearchFragment extends Fragment { 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); 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 0e3caf2fe..78096b39a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java @@ -105,27 +105,9 @@ public class ItunesSearchFragment extends Fragment { if (podcast.feedUrl == null) { return; } - 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 AlertDialog.Builder(getActivity()) - .setMessage(prefix + " " + error.getMessage()) - .setPositiveButton(android.R.string.ok, null) - .show(); - }); + Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl); + startActivity(intent); }); progressBar = root.findViewById(R.id.progressBar); txtvError = root.findViewById(R.id.txtvError); @@ -219,7 +201,7 @@ public class ItunesSearchFragment extends Fragment { txtvEmpty.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); - ItunesPodcastSearcher searcher = new ItunesPodcastSearcher(getContext()); + ItunesPodcastSearcher searcher = new ItunesPodcastSearcher(); disposable = searcher.search(query).subscribe(podcasts -> { progressBar.setVisibility(View.GONE); updateData(podcasts); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java index d8d0f41c5..c3f2dae3b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java @@ -106,23 +106,8 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView. 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 AlertDialog.Builder(getActivity()) - .setMessage(prefix + " " + error.getMessage()) - .setPositiveButton(android.R.string.ok, null) - .show(); - }); + Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl); + startActivity(intent); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java index 87378ae6c..e1c85a2d3 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java @@ -104,7 +104,6 @@ public abstract class PodcastListFragment extends Fragment { Log.d(TAG, "Selected podcast: " + selection.toString()); Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, selection.getUrl()); - intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.gpodnet_main_label)); startActivity(intent); } -- cgit v1.2.3 From ac13b7aa7b14e5e46971748ba2751c8bfa2bcf15 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 9 Apr 2020 12:33:31 +0200 Subject: Use a single search fragment for all searchers --- .../antennapod/discovery/CombinedSearcher.java | 21 +- .../antennapod/discovery/FyydPodcastSearcher.java | 5 + .../discovery/GpodnetPodcastSearcher.java | 5 + .../discovery/ItunesPodcastSearcher.java | 5 + .../antennapod/discovery/PodcastSearcher.java | 2 + .../discovery/PodcastSearcherRegistry.java | 13 +- .../antennapod/fragment/AddFeedFragment.java | 14 +- .../fragment/CombinedSearchFragment.java | 173 ---------------- .../antennapod/fragment/DiscoveryFragment.java | 143 ++++++++++++++ .../antennapod/fragment/FyydSearchFragment.java | 167 ---------------- .../antennapod/fragment/ItunesSearchFragment.java | 218 --------------------- .../antennapod/fragment/OnlineSearchFragment.java | 195 ++++++++++++++++++ .../fragment/QuickFeedDiscoveryFragment.java | 3 +- app/src/main/res/layout/fragment_itunes_search.xml | 1 - app/src/main/res/menu/itunes_search.xml | 13 -- app/src/main/res/menu/online_search.xml | 13 ++ 16 files changed, 400 insertions(+), 591 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java delete mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java delete mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java delete mode 100644 app/src/main/res/menu/itunes_search.xml create mode 100644 app/src/main/res/menu/online_search.xml (limited to 'app/src/main') diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java index 287e20964..6c2a87c12 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/CombinedSearcher.java @@ -1,8 +1,7 @@ package de.danoeh.antennapod.discovery; -import android.content.Context; +import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import io.reactivex.Single; import io.reactivex.SingleOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -19,7 +18,7 @@ import java.util.concurrent.CountDownLatch; public class CombinedSearcher implements PodcastSearcher { private static final String TAG = "CombinedSearcher"; - public CombinedSearcher(Context context) { + public CombinedSearcher() { } public Single> search(String query) { @@ -31,7 +30,7 @@ public class CombinedSearcher implements PodcastSearcher { PodcastSearcherRegistry.SearcherInfo searchProviderInfo = PodcastSearcherRegistry.getSearchProviders().get(i); PodcastSearcher searcher = searchProviderInfo.searcher; - if (searchProviderInfo.weight <= 0.00001f) { + if (searchProviderInfo.weight <= 0.00001f || searcher.getClass() == CombinedSearcher.class) { latch.countDown(); continue; } @@ -102,4 +101,18 @@ public class CombinedSearcher implements PodcastSearcher { public boolean urlNeedsLookup(String url) { return PodcastSearcherRegistry.urlNeedsLookup(url); } + + @Override + public String getName() { + ArrayList names = new ArrayList<>(); + for (int i = 0; i < PodcastSearcherRegistry.getSearchProviders().size(); i++) { + PodcastSearcherRegistry.SearcherInfo searchProviderInfo + = PodcastSearcherRegistry.getSearchProviders().get(i); + PodcastSearcher searcher = searchProviderInfo.searcher; + if (searchProviderInfo.weight > 0.00001f && searcher.getClass() != CombinedSearcher.class) { + names.add(searcher.getName()); + } + } + return TextUtils.join(", ", names); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java index 856ca8569..5a93e6530 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/FyydPodcastSearcher.java @@ -45,4 +45,9 @@ public class FyydPodcastSearcher implements PodcastSearcher { public boolean urlNeedsLookup(String url) { return false; } + + @Override + public String getName() { + return "Fyyd"; + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java index 46b3e5775..53237579f 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/GpodnetPodcastSearcher.java @@ -43,4 +43,9 @@ public class GpodnetPodcastSearcher implements PodcastSearcher { public boolean urlNeedsLookup(String url) { return false; } + + @Override + public String getName() { + return "Gpodder.net"; + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java index ed1efaf73..796ec556f 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/ItunesPodcastSearcher.java @@ -96,4 +96,9 @@ public class ItunesPodcastSearcher implements PodcastSearcher { public boolean urlNeedsLookup(String url) { return url.contains("itunes.apple.com"); } + + @Override + public String getName() { + return "iTunes"; + } } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java index 3312e0d57..eeebd2ebf 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcher.java @@ -11,4 +11,6 @@ public interface PodcastSearcher { Single lookupUrl(String resultUrl); boolean urlNeedsLookup(String resultUrl); + + String getName(); } diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java index 32fa96d5d..3f738424b 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearcherRegistry.java @@ -15,8 +15,9 @@ public class PodcastSearcherRegistry { public static List getSearchProviders() { if (searchProviders == null) { searchProviders = new ArrayList<>(); - searchProviders.add(new SearcherInfo(new FyydPodcastSearcher(), 1.f)); + searchProviders.add(new SearcherInfo(new CombinedSearcher(), 1.f)); searchProviders.add(new SearcherInfo(new ItunesPodcastSearcher(), 1.f)); + searchProviders.add(new SearcherInfo(new FyydPodcastSearcher(), 1.f)); searchProviders.add(new SearcherInfo(new GpodnetPodcastSearcher(), 0.0f)); } return searchProviders; @@ -24,7 +25,8 @@ public class PodcastSearcherRegistry { public static Single lookupUrl(String url) { for (PodcastSearcherRegistry.SearcherInfo searchProviderInfo : getSearchProviders()) { - if (searchProviderInfo.searcher.urlNeedsLookup(url)) { + if (searchProviderInfo.searcher.getClass() != CombinedSearcher.class + && searchProviderInfo.searcher.urlNeedsLookup(url)) { return searchProviderInfo.searcher.lookupUrl(url); } } @@ -33,7 +35,8 @@ public class PodcastSearcherRegistry { public static boolean urlNeedsLookup(String url) { for (PodcastSearcherRegistry.SearcherInfo searchProviderInfo : getSearchProviders()) { - if (searchProviderInfo.searcher.urlNeedsLookup(url)) { + if (searchProviderInfo.searcher.getClass() != CombinedSearcher.class + && searchProviderInfo.searcher.urlNeedsLookup(url)) { return true; } } @@ -41,8 +44,8 @@ public class PodcastSearcherRegistry { } public static class SearcherInfo { - final PodcastSearcher searcher; - final float weight; + public final PodcastSearcher searcher; + public final float weight; public SearcherInfo(PodcastSearcher searcher, float weight) { this.searcher = searcher; 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 49b2ae7ac..046a39355 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -19,6 +19,9 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.activity.OpmlImportActivity; +import de.danoeh.antennapod.discovery.CombinedSearcher; +import de.danoeh.antennapod.discovery.FyydPodcastSearcher; +import de.danoeh.antennapod.discovery.ItunesPodcastSearcher; import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment; /** @@ -40,9 +43,9 @@ public class AddFeedFragment extends Fragment { ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); root.findViewById(R.id.btn_search_itunes).setOnClickListener(v - -> activity.loadChildFragment(new ItunesSearchFragment())); + -> activity.loadChildFragment(OnlineSearchFragment.newInstance(ItunesPodcastSearcher.class))); root.findViewById(R.id.btn_search_fyyd).setOnClickListener(v - -> activity.loadChildFragment(new FyydSearchFragment())); + -> activity.loadChildFragment(OnlineSearchFragment.newInstance(FyydPodcastSearcher.class))); root.findViewById(R.id.btn_search_gpodder).setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment())); @@ -99,12 +102,7 @@ public class AddFeedFragment extends Fragment { addUrl(query); return; } - - Bundle bundle = new Bundle(); - bundle.putString(CombinedSearchFragment.ARGUMENT_QUERY, query); - CombinedSearchFragment fragment = new CombinedSearchFragment(); - fragment.setArguments(bundle); - activity.loadChildFragment(fragment); + activity.loadChildFragment(OnlineSearchFragment.newInstance(CombinedSearcher.class, query)); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java deleted file mode 100644 index b71a7e0cc..000000000 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java +++ /dev/null @@ -1,173 +0,0 @@ -package de.danoeh.antennapod.fragment; - -import android.content.Intent; -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.Fragment; -import androidx.core.view.MenuItemCompat; -import androidx.appcompat.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 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); - ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); - 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); - 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); - 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/DiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java new file mode 100644 index 000000000..89d3c7af9 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java @@ -0,0 +1,143 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +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 androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.OnlineFeedViewActivity; +import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; +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; + +/** + * Searches iTunes store for top podcasts and displays results in a list. + */ +public class DiscoveryFragment extends Fragment { + + private static final String TAG = "ItunesSearchFragment"; + + /** + * 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 searchResults; + private List 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 result) { + this.searchResults = result; + adapter.clear(); + if (result != null && result.size() > 0) { + gridView.setVisibility(View.VISIBLE); + txtvEmpty.setVisibility(View.GONE); + for (PodcastSearchResult p : result) { + adapter.add(p); + } + adapter.notifyDataSetInvalidated(); + } else { + gridView.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.VISIBLE); + } + } + + public DiscoveryFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_itunes_search, container, false); + ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); + 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); + if (podcast.feedUrl == null) { + return; + } + Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl); + 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); + + loadToplist(); + + return root; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposable != null) { + disposable.dispose(); + } + adapter = null; + } + + private void loadToplist() { + if (disposable != null) { + disposable.dispose(); + } + gridView.setVisibility(View.GONE); + txtvError.setVisibility(View.GONE); + butRetry.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + + ItunesTopListLoader loader = new ItunesTopListLoader(getContext()); + disposable = loader.loadToplist(25).subscribe(podcasts -> { + progressBar.setVisibility(View.GONE); + topList = podcasts; + updateData(topList); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + progressBar.setVisibility(View.GONE); + txtvError.setText(error.toString()); + txtvError.setVisibility(View.VISIBLE); + butRetry.setOnClickListener(v -> loadToplist()); + butRetry.setVisibility(View.VISIBLE); + }); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java deleted file mode 100644 index 6bd191af4..000000000 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java +++ /dev/null @@ -1,167 +0,0 @@ -package de.danoeh.antennapod.fragment; - -import android.content.Intent; -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.Fragment; -import androidx.core.view.MenuItemCompat; -import androidx.appcompat.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.FyydPodcastSearcher; -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 FyydSearchFragment extends Fragment { - - private static final String TAG = "FyydSearchFragment"; - - /** - * 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 searchResults; - private Disposable disposable; - - /** - * Constructor - */ - public FyydSearchFragment() { - // 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); - ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); - 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); - 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); - sv.setQueryHint(getString(R.string.search_fyyd_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); - } - - private void search(String query) { - if (disposable != null) { - disposable.dispose(); - } - showOnlyProgressBar(); - - 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() { - 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/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java deleted file mode 100644 index 78096b39a..000000000 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java +++ /dev/null @@ -1,218 +0,0 @@ -package de.danoeh.antennapod.fragment; - -import android.content.Intent; -import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.Fragment; -import androidx.core.view.MenuItemCompat; -import androidx.appcompat.widget.SearchView; -import androidx.annotation.NonNull; -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.discovery.ItunesPodcastSearcher; -import de.danoeh.antennapod.discovery.ItunesTopListLoader; -import de.danoeh.antennapod.discovery.PodcastSearchResult; - -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.menuhandler.MenuItemUtils; -import io.reactivex.disposables.Disposable; - -//Searches iTunes store for given string and displays results in a list -public class ItunesSearchFragment extends Fragment { - - private static final String TAG = "ItunesSearchFragment"; - - - /** - * 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 searchResults; - private List 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 result) { - this.searchResults = result; - adapter.clear(); - if (result != null && result.size() > 0) { - gridView.setVisibility(View.VISIBLE); - txtvEmpty.setVisibility(View.GONE); - for (PodcastSearchResult p : result) { - adapter.add(p); - } - adapter.notifyDataSetInvalidated(); - } else { - gridView.setVisibility(View.GONE); - txtvEmpty.setVisibility(View.VISIBLE); - } - } - - /** - * Constructor - */ - public ItunesSearchFragment() { - // Required empty public constructor - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - // Inflate the layout for this fragment - View root = inflater.inflate(R.layout.fragment_itunes_search, container, false); - ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); - 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); - if (podcast.feedUrl == null) { - return; - } - Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); - intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl); - 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); - - loadToplist(); - - 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); - sv.setQueryHint(getString(R.string.search_itunes_label)); - sv.setOnQueryTextListener(new androidx.appcompat.widget.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) { - if (searchResults != null) { - searchResults = null; - updateData(topList); - } - return true; - } - }); - } - - private void loadToplist() { - if (disposable != null) { - disposable.dispose(); - } - gridView.setVisibility(View.GONE); - txtvError.setVisibility(View.GONE); - butRetry.setVisibility(View.GONE); - txtvEmpty.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - - ItunesTopListLoader loader = new ItunesTopListLoader(getContext()); - disposable = loader.loadToplist(25) - .subscribe(podcasts -> { - progressBar.setVisibility(View.GONE); - topList = podcasts; - updateData(topList); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - progressBar.setVisibility(View.GONE); - txtvError.setText(error.toString()); - txtvError.setVisibility(View.VISIBLE); - butRetry.setOnClickListener(v -> loadToplist()); - butRetry.setVisibility(View.VISIBLE); - }); - } - - private void search(String query) { - if (disposable != null) { - disposable.dispose(); - } - gridView.setVisibility(View.GONE); - txtvError.setVisibility(View.GONE); - butRetry.setVisibility(View.GONE); - txtvEmpty.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - - ItunesPodcastSearcher searcher = new ItunesPodcastSearcher(); - 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/OnlineSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java new file mode 100644 index 000000000..d9c31f993 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/OnlineSearchFragment.java @@ -0,0 +1,195 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Intent; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.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.PodcastSearchResult; +import de.danoeh.antennapod.discovery.PodcastSearcher; +import de.danoeh.antennapod.discovery.PodcastSearcherRegistry; +import io.reactivex.disposables.Disposable; + +import java.util.ArrayList; +import java.util.List; + +public class OnlineSearchFragment extends Fragment { + + private static final String TAG = "FyydSearchFragment"; + private static final String ARG_SEARCHER = "searcher"; + private static final String ARG_QUERY = "query"; + + /** + * Adapter responsible with the search results + */ + private ItunesAdapter adapter; + private PodcastSearcher searchProvider; + private GridView gridView; + private ProgressBar progressBar; + private TextView txtvError; + private Button butRetry; + private TextView txtvEmpty; + + /** + * List of podcasts retreived from the search + */ + private List searchResults; + private Disposable disposable; + + public static OnlineSearchFragment newInstance(Class searchProvider) { + return newInstance(searchProvider, null); + } + + public static OnlineSearchFragment newInstance(Class searchProvider, String query) { + OnlineSearchFragment fragment = new OnlineSearchFragment(); + Bundle arguments = new Bundle(); + arguments.putString(ARG_SEARCHER, searchProvider.getName()); + arguments.putString(ARG_QUERY, query); + fragment.setArguments(arguments); + return fragment; + } + + /** + * Constructor + */ + public OnlineSearchFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + + for (PodcastSearcherRegistry.SearcherInfo info : PodcastSearcherRegistry.getSearchProviders()) { + if (info.searcher.getClass().getName().equals(getArguments().getString(ARG_SEARCHER))) { + searchProvider = info.searcher; + break; + } + } + if (searchProvider == null) { + throw new IllegalArgumentException("Podcast searcher not found"); + } + } + + @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); + ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar)); + 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); + 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); + + txtvEmpty.setText(getString(R.string.search_powered_by, searchProvider.getName())); + 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.online_search, menu); + MenuItem searchItem = menu.findItem(R.id.action_search); + final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem); + sv.setQueryHint(getString(R.string.search_podcast_hint)); + 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; + } + }); + searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + getActivity().getSupportFragmentManager().popBackStack(); + return true; + } + }); + searchItem.expandActionView(); + + if (getArguments().getString(ARG_QUERY, null) != null) { + sv.setQuery(getArguments().getString(ARG_QUERY, null), true); + } + + } + + private void search(String query) { + if (disposable != null) { + disposable.dispose(); + } + showOnlyProgressBar(); + disposable = searchProvider.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); + txtvEmpty.setText(getString(R.string.no_results_for_query, query)); + }, 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/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java index c3f2dae3b..d6bcdd79c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java @@ -3,7 +3,6 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; import android.util.DisplayMetrics; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import android.util.Log; import android.view.LayoutInflater; @@ -41,7 +40,7 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView. 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())); + ((MainActivity) getActivity()).loadChildFragment(new DiscoveryFragment())); discoverGridLayout = root.findViewById(R.id.discover_grid); progressBar = root.findViewById(R.id.discover_progress_bar); diff --git a/app/src/main/res/layout/fragment_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml index 0de57f62b..228bfb803 100644 --- a/app/src/main/res/layout/fragment_itunes_search.xml +++ b/app/src/main/res/layout/fragment_itunes_search.xml @@ -36,7 +36,6 @@ android:layout_height="match_parent" android:layout_centerInParent="true" android:gravity="center" - android:visibility="gone" android:text="@string/search_status_no_results" /> - - - - - - diff --git a/app/src/main/res/menu/online_search.xml b/app/src/main/res/menu/online_search.xml new file mode 100644 index 000000000..93d93157a --- /dev/null +++ b/app/src/main/res/menu/online_search.xml @@ -0,0 +1,13 @@ + + + + + + + -- cgit v1.2.3