diff options
author | Martin Fietz <Martin.Fietz@gmail.com> | 2016-11-01 10:41:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-01 10:41:51 +0100 |
commit | a89dd28e23eb7f2846aaed868b9c1f4755ccdf51 (patch) | |
tree | 3640a3dfdd0056917d3e75826286cf668abc4eb6 | |
parent | ad986e9f07b0bf54a651170fe44fb9805ab8be0a (diff) | |
parent | c3fad9dbe6d112bed6535d447341bef6ff12395a (diff) | |
download | AntennaPod-a89dd28e23eb7f2846aaed868b9c1f4755ccdf51.zip |
Merge pull request #2170 from mfietz/feature/fyyd
Integrate fyyd podcast search engine
-rw-r--r-- | app/build.gradle | 2 | ||||
-rw-r--r-- | app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java | 67 | ||||
-rw-r--r-- | app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java | 5 | ||||
-rw-r--r-- | app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java | 191 | ||||
-rw-r--r-- | app/src/main/res/layout/addfeed.xml | 56 | ||||
-rw-r--r-- | core/src/main/res/values/strings.xml | 4 | ||||
-rw-r--r-- | core/src/main/res/values/styles.xml | 10 |
7 files changed, 270 insertions, 65 deletions
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<ItunesAdapter.Podcast> { /** @@ -42,8 +44,9 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { 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); @@ -87,35 +90,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { } /** - * 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. */ public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model @@ -154,6 +128,10 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { 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<ItunesAdapter.Podcast> { } } + + /** + * 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<Podcast> 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 @@ <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingTop="8dp" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingBottom="8dp" android:paddingLeft="16dp" android:paddingRight="16dp" - android:paddingBottom="8dp" - android:orientation="vertical"> + android:paddingTop="8dp"> <TextView android:id="@+id/txtvPodcastDirectories" + style="@style/AntennaPod.TextView.Heading" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/AntennaPod.TextView.Heading" android:text="@string/podcastdirectories_label"/> <TextView @@ -26,83 +26,73 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/podcastdirectories_descr" - android:textSize="@dimen/text_size_medium" - android:layout_marginTop="4dp"/> + android:textSize="@dimen/text_size_medium"/> <Button android:id="@+id/butSearchItunes" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" + android:layout_marginTop="4dp" android:text="@string/search_itunes_label"/> <Button + android:id="@+id/butSearchFyyd" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/search_fyyd_label"/> + + <Button android:id="@+id/butBrowseGpoddernet" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:text="@string/browse_gpoddernet_label"/> - <View - android:id="@+id/divider1" - android:layout_width="match_parent" - android:layout_height="1dp" - android:layout_margin="16dp" - android:background="?android:attr/listDivider"/> + <View style="@style/Divider"/> <TextView android:id="@+id/txtvFeedurl" + style="@style/AntennaPod.TextView.Heading" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_below="@id/divider1" - style="@style/AntennaPod.TextView.Heading" android:text="@string/txtvfeedurl_label"/> <EditText android:id="@+id/etxtFeedurl" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:hint="@string/etxtFeedurlHint" - android:inputType="textUri" + android:cursorVisible="true" android:focusable="true" android:focusableInTouchMode="true" - android:cursorVisible="true"/> + android:hint="@string/etxtFeedurlHint" + android:inputType="textUri"/> <Button android:id="@+id/butConfirm" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:text="@string/confirm_label"/> - <View - android:id="@+id/divider2" - android:layout_width="match_parent" - android:layout_height="1dp" - android:layout_margin="16dp" - android:background="?android:attr/listDivider"/> + <View style="@style/Divider"/> <TextView android:id="@+id/txtvOpmlImport" + style="@style/AntennaPod.TextView.Heading" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/AntennaPod.TextView.Heading" android:text="@string/opml_import_label"/> <TextView android:id="@+id/txtvOpmlImportExpl" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:textSize="@dimen/text_size_medium" - android:text="@string/opml_import_txtv_button_lable"/> + android:text="@string/opml_import_txtv_button_lable" + android:textSize="@dimen/text_size_medium"/> <Button android:id="@+id/butOpmlImport" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" + android:layout_marginTop="4dp" android:text="@string/opml_import_label"/> </LinearLayout> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 621fc547b..48bd15b13 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -103,7 +103,7 @@ <string name="etxtFeedurlHint">www.example.com/feed</string> <string name="txtvfeedurl_label">Add Podcast by URL</string> <string name="podcastdirectories_label">Find Podcast in Directory</string> - <string name="podcastdirectories_descr">You can search for new podcasts by name, category or popularity in the gpodder.net directory, or search the iTunes store.</string> + <string name="podcastdirectories_descr">For new podcasts, you can search iTunes or fyyd, or browse gpodder.net by name, category or popularity.</string> <string name="browse_gpoddernet_label">Browse gpodder.net</string> <!-- Actions on feeds --> @@ -580,6 +580,8 @@ <string name="search_itunes_label">Search iTunes</string> <string name="filter">Filter</string> + + <string name="search_fyyd_label">Search fyyd</string> <!-- Episodes apply actions --> <string name="all_label">All</string> diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index 6a4dc4781..9b20fdd02 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -285,6 +285,16 @@ <item name="textAllCaps">false</item> </style> + <style name="Divider"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">1dp</item> + <item name="android:layout_marginTop">8dp</item> + <item name="android:layout_marginLeft">16dp</item> + <item name="android:layout_marginRight">16dp</item> + <item name="android:layout_marginBottom">8dp</item> + <item name="android:background">?android:attr/listDivider</item> + </style> + <style name="AntennaPod.Dialog.Light" parent="Theme.AppCompat.Light.Dialog"> <item name="colorAccent">@color/holo_blue_light</item> </style> |