Merge pull request #2170 from mfietz/feature/fyyd
Integrate fyyd podcast search engine
This commit is contained in:
commit
a89dd28e23
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -86,35 +89,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||
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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue