summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java187
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java193
-rw-r--r--app/src/main/res/layout/addfeed.xml9
-rw-r--r--app/src/main/res/layout/fragment_itunes_search.xml26
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml38
6 files changed, 461 insertions, 2 deletions
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
new file mode 100644
index 000000000..4fc2838b7
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -0,0 +1,187 @@
+package de.danoeh.antennapod.adapter.itunes;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+
+public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
+ /**
+ * Related Context
+ */
+ private final Context context;
+
+ /**
+ * List holding the podcasts found in the search
+ */
+ private final List<Podcast> data;
+
+ /**
+ * Constructor.
+ *
+ * @param context Related context
+ * @param objects Search result
+ */
+ public ItunesAdapter(Context context, List<Podcast> objects) {
+ super(context, 0, objects);
+ this.data = objects;
+ this.context = context;
+ }
+
+ /**
+ * Updates the given ImageView with the image in the given Podcast's imageUrl
+ */
+ class FetchImageTask extends AsyncTask<Void,Void,Bitmap>{
+ /**
+ * Current podcast
+ */
+ private final Podcast podcast;
+
+ /**
+ * ImageView to be updated
+ */
+ private final ImageView imageView;
+
+ /**
+ * Constructor
+ *
+ * @param podcast Podcast that has the image
+ * @param imageView UI image to be updated
+ */
+ FetchImageTask(Podcast podcast, ImageView imageView){
+ this.podcast = podcast;
+ this.imageView = imageView;
+ }
+
+ //Get the image from the url
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ HttpClient client = new DefaultHttpClient();
+ HttpGet get = new HttpGet(podcast.imageUrl);
+ try {
+ HttpResponse response = client.execute(get);
+ return BitmapFactory.decodeStream(response.getEntity().getContent());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ //Set the background image for the podcast
+ @Override
+ protected void onPostExecute(Bitmap img) {
+ super.onPostExecute(img);
+ if(img!=null) {
+ imageView.setImageBitmap(img);
+ }
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ //Current podcast
+ Podcast podcast = data.get(position);
+
+ //ViewHolder
+ PodcastViewHolder viewHolder;
+
+ //Resulting view
+ View view;
+
+ //Handle view holder stuff
+ if(convertView == null) {
+ view = ((MainActivity) context).getLayoutInflater()
+ .inflate(R.layout.itunes_podcast_listitem, parent, false);
+ viewHolder = new PodcastViewHolder(view);
+ view.setTag(viewHolder);
+ } else {
+ view = convertView;
+ viewHolder = (PodcastViewHolder) view.getTag();
+ }
+
+ //Set the title
+ viewHolder.titleView.setText(podcast.title);
+
+ //Update the empty imageView with the image from the feed
+ new FetchImageTask(podcast,viewHolder.coverView).execute();
+
+ //Feed the grid view
+ 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;
+
+
+ /**
+ * Constructor
+ * @param view GridView cell
+ */
+ PodcastViewHolder(View view){
+ coverView = (ImageView) view.findViewById(R.id.imgvCover);
+ titleView = (TextView) view.findViewById(R.id.txtvTitle);
+ }
+ }
+
+ /**
+ * Represents an individual podcast on the iTunes Store.
+ */
+ public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model
+
+ /**
+ * The name of the podcast
+ */
+ public final String title;
+
+ /**
+ * URL of the podcast image
+ */
+ public final String imageUrl;
+ /**
+ * URL of the podcast feed
+ */
+ public final String feedUrl;
+
+ /**
+ * Constructor.
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public Podcast(JSONObject json) throws JSONException {
+ title = json.getString("collectionName");
+ imageUrl = json.getString("artworkUrl100");
+ feedUrl = json.getString("feedUrl");
+ }
+ }
+}
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 f5ae5a777..e4ae1683b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -8,6 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
import de.danoeh.antennapod.activity.MainActivity;
@@ -41,10 +42,18 @@ public class AddFeedFragment extends Fragment {
Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
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.getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+ butSearchITunes.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ activity.loadChildFragment(new ItunesSearchFragment());
+ }
+ });
+
butBrowserGpoddernet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -53,7 +62,6 @@ public class AddFeedFragment extends Fragment {
});
butOpmlImport.setOnClickListener(new View.OnClickListener() {
-
@Override
public void onClick(View v) {
startActivity(new Intent(getActivity(),
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
new file mode 100644
index 000000000..c14b0cc6e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -0,0 +1,193 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.SearchView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.GridView;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
+
+import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.*;
+
+//Searches iTunes store for given string and displays results in a list
+public class ItunesSearchFragment extends Fragment {
+ final String TAG = "ItunesSearchFragment";
+ /**
+ * Search input field
+ */
+ private SearchView searchView;
+
+ /**
+ * Adapter responsible with the search results
+ */
+ private ItunesAdapter adapter;
+
+ /**
+ * List of podcasts retreived from the search
+ */
+ private List<Podcast> searchResults;
+
+ /**
+ * Replace adapter data with provided search results from SearchTask.
+ * @param result List of Podcast objects containing search results
+ */
+ void updateData(List<Podcast> result) {
+ this.searchResults = result;
+ adapter.clear();
+
+ //ArrayAdapter.addAll() requires minsdk > 10
+ for(Podcast p: result) {
+ adapter.add(p);
+ }
+
+ adapter.notifyDataSetInvalidated();
+ }
+
+ /**
+ * Constructor
+ */
+ public ItunesSearchFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ adapter = new ItunesAdapter(getActivity(), new ArrayList<Podcast>());
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_itunes_search, container, false);
+ GridView gridView = (GridView) view.findViewById(R.id.gridView);
+ gridView.setAdapter(adapter);
+
+ //Show information about the podcast when the list item is clicked
+ gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Intent intent = new Intent(getActivity(),
+ DefaultOnlineFeedViewActivity.class);
+
+ //Tell the OnlineFeedViewActivity where to go
+ String url = searchResults.get(position).feedUrl;
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
+
+ intent.putExtra(DefaultOnlineFeedViewActivity.ARG_TITLE, "iTunes");
+ startActivity(intent);
+ }
+ });
+
+ //Configure search input view to be expanded by default with a visible submit button
+ searchView = (SearchView) view.findViewById(R.id.itunes_search_view);
+ searchView.setIconifiedByDefault(false);
+ searchView.setIconified(false);
+ searchView.setSubmitButtonEnabled(true);
+ searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ //This prevents onQueryTextSubmit() from being called twice when keyboard is used
+ //to submit the query.
+ searchView.clearFocus();
+ new SearchTask(s).execute();
+ return false;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+
+ return view;
+ }
+
+ /**
+ * Search the iTunes store for podcasts using the given query
+ */
+ class SearchTask extends AsyncTask<Void,Void,Void> {
+ /**
+ * Incomplete iTunes API search URL
+ */
+ final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s";
+
+ /**
+ * Search terms
+ */
+ final String query;
+
+ /**
+ * Search result
+ */
+ final List<Podcast> taskData = new ArrayList<>();
+
+ /**
+ * Constructor
+ *
+ * @param query Search string
+ */
+ public SearchTask(String query){
+ this.query = query;
+ }
+
+ //Get the podcast data
+ @Override
+ protected Void doInBackground(Void... params) {
+
+ //Spaces in the query need to be replaced with '+' character.
+ String formattedUrl = String.format(apiUrl, query).replace(' ', '+');
+
+ HttpClient client = new DefaultHttpClient();
+ HttpGet get = new HttpGet(formattedUrl);
+
+ try {
+ HttpResponse response = client.execute(get);
+ String resultString = EntityUtils.toString(response.getEntity());
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("results");
+
+ for (int i = 0; i < j.length(); i++){
+ JSONObject podcastJson = j.getJSONObject(i);
+ Podcast podcast = new Podcast(podcastJson);
+ taskData.add(podcast);
+ }
+
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ //Save the data and update the list
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ super.onPostExecute(aVoid);
+ updateData(taskData);
+ }
+ }
+}
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index 09502eb7b..a740d88cf 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -66,12 +66,19 @@
android:layout_margin="8dp"
android:text="@string/browse_gpoddernet_label"/>
+ <Button
+ android:id="@+id/butSearchItunes"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butBrowseGpoddernet"
+ android:layout_margin="8dp"
+ android:text="@string/search_itunes_label"/>
<TextView
android:id="@+id/txtvOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/butBrowseGpoddernet"
+ android:layout_below="@id/butSearchItunes"
android:layout_margin="8dp"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/opml_import_label"/>
diff --git a/app/src/main/res/layout/fragment_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml
new file mode 100644
index 000000000..17ffe349b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_itunes_search.xml
@@ -0,0 +1,26 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+xmlns:tools="http://schemas.android.com/tools"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+tools:context="de.danoeh.antennapod.activity.ITunesSearchActivity">
+<android.support.v7.widget.SearchView
+ android:id="@+id/itunes_search_view"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
+<GridView
+ android:id="@+id/gridView"
+ android:layout_below="@id/itunes_search_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:columnWidth="200dp"
+ android:gravity="center"
+ android:horizontalSpacing="8dp"
+ android:numColumns="auto_fit"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:stretchMode="columnWidth"
+ android:verticalSpacing="8dp"
+ tools:listitem="@layout/gpodnet_podcast_listitem" />
+</RelativeLayout>
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
new file mode 100644
index 000000000..41b1f495f
--- /dev/null
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+xmlns:tools="http://schemas.android.com/tools"
+android:layout_width="match_parent"
+android:layout_height="@dimen/listitem_threeline_height"
+tools:background="@android:color/darker_gray">
+
+<ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/cover_label"
+ android:cropToPadding="true"
+ android:scaleType="fitXY"
+ tools:src="@drawable/ic_stat_antenna_default"
+ tools:background="@android:color/holo_green_dark" />
+
+<TextView
+ android:id="@+id/txtvTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_toRightOf="@id/imgvCover"
+ android:maxLines="1"
+ tools:text="Podcast title"
+ tools:background="@android:color/holo_green_dark" />
+</RelativeLayout>