From c3fad9dbe6d112bed6535d447341bef6ff12395a Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Sun, 30 Oct 2016 12:55:37 +0100 Subject: [PATCH] Integrate fyyd podcast search engine --- app/build.gradle | 2 + .../adapter/itunes/ItunesAdapter.java | 67 +++--- .../antennapod/fragment/AddFeedFragment.java | 5 +- .../fragment/FyydSearchFragment.java | 191 ++++++++++++++++++ app/src/main/res/layout/addfeed.xml | 56 +++-- core/src/main/res/values/strings.xml | 4 +- core/src/main/res/values/styles.xml | 10 + 7 files changed, 270 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java diff --git a/app/build.gradle b/app/build.gradle index f83b405f7..d15427aef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -160,6 +160,8 @@ dependencies { compile "com.github.shts:TriangleLabelView:$triangleLabelViewVersion" compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion" + + compile 'com.github.mfietz:fyydlin:v0.1' } play { 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 e9756b467..e381b4651 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 @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter.itunes; import android.content.Context; +import android.support.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -18,6 +19,7 @@ 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 { /** @@ -42,8 +44,9 @@ public class ItunesAdapter extends ArrayAdapter { this.context = context; } + @NonNull @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(int position, View convertView, @NonNull ViewGroup parent) { //Current podcast Podcast podcast = data.get(position); @@ -86,35 +89,6 @@ public class ItunesAdapter extends ArrayAdapter { return view; } - /** - * View holder object for the GridView - */ - class PodcastViewHolder { - - /** - * ImageView holding the Podcast image - */ - public final ImageView coverView; - - /** - * TextView holding the Podcast title - */ - public final TextView titleView; - - public final TextView urlView; - - - /** - * Constructor - * @param view GridView cell - */ - PodcastViewHolder(View view){ - coverView = (ImageView) view.findViewById(R.id.imgvCover); - titleView = (TextView) view.findViewById(R.id.txtvTitle); - urlView = (TextView) view.findViewById(R.id.txtvUrl); - } - } - /** * Represents an individual podcast on the iTunes Store. */ @@ -154,6 +128,10 @@ public class ItunesAdapter extends ArrayAdapter { return new Podcast(title, imageUrl, feedUrl); } + public static Podcast fromSearch(SearchHit searchHit) { + return new Podcast(searchHit.getTitle(), searchHit.getImageUrl(), searchHit.getXmlUrl()); + } + /** * Constructs a Podcast instance from iTunes toplist entry * @@ -177,4 +155,33 @@ public class ItunesAdapter extends ArrayAdapter { } } + + /** + * View holder object for the GridView + */ + class PodcastViewHolder { + + /** + * ImageView holding the Podcast image + */ + final ImageView coverView; + + /** + * TextView holding the Podcast title + */ + final TextView titleView; + + final TextView urlView; + + + /** + * Constructor + * @param view GridView cell + */ + PodcastViewHolder(View view){ + coverView = (ImageView) view.findViewById(R.id.imgvCover); + titleView = (TextView) view.findViewById(R.id.txtvTitle); + urlView = (TextView) view.findViewById(R.id.txtvUrl); + } + } } 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 45364ca07..f14ebbdaf 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -39,10 +39,11 @@ public class AddFeedFragment extends Fragment { etxtFeedurl.setText(args.getString(ARG_FEED_URL)); } + Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet); + Button butSearchFyyd = (Button) root.findViewById(R.id.butSearchFyyd); Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport); Button butConfirm = (Button) root.findViewById(R.id.butConfirm); - Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); final MainActivity activity = (MainActivity) getActivity(); activity.getSupportActionBar().setTitle(R.string.add_feed_label); @@ -51,6 +52,8 @@ public class AddFeedFragment extends Fragment { butBrowserGpoddernet.setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment())); + butSearchFyyd.setOnClickListener(v -> activity.loadChildFragment(new FyydSearchFragment())); + butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(), OpmlImportFromPathActivity.class))); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java new file mode 100644 index 000000000..7fcf9c93d --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java @@ -0,0 +1,191 @@ +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 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 de.mfietz.fyydlin.FyydClient; +import de.mfietz.fyydlin.FyydResponse; +import de.mfietz.fyydlin.SearchHit; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; + +import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast; +import static java.util.Collections.emptyList; + +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; + + private FyydClient client = new FyydClient(); + + /** + * List of podcasts retreived from the search + */ + private List searchResults; + private Subscription subscription; + + /** + * 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); + gridView = (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) -> { + Podcast 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 = (ProgressBar) root.findViewById(R.id.progressBar); + txtvError = (TextView) root.findViewById(R.id.txtvError); + butRetry = (Button) root.findViewById(R.id.butRetry); + txtvEmpty = (TextView) root.findViewById(android.R.id.empty); + + return root; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (subscription != null) { + subscription.unsubscribe(); + } + 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_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 (subscription != null) { + subscription.unsubscribe(); + } + showOnlyProgressBar(); + subscription = client.searchPodcasts(query) + .subscribeOn(Schedulers.newThread()) + .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); + }); + } + + private void showOnlyProgressBar() { + gridView.setVisibility(View.GONE); + txtvError.setVisibility(View.GONE); + butRetry.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + } + + void processSearchResult(FyydResponse response) { + adapter.clear(); + if (!response.getData().isEmpty()) { + adapter.clear(); + searchResults = new ArrayList<>(); + for (SearchHit searchHit : response.getData().values()) { + 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/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml index dff24c650..33951e060 100644 --- a/app/src/main/res/layout/addfeed.xml +++ b/app/src/main/res/layout/addfeed.xml @@ -7,18 +7,18 @@ + android:paddingTop="8dp"> + android:textSize="@dimen/text_size_medium"/>