iTunes Search: SearchView in Action Bar, error/result message, retry, feed url
This commit is contained in:
parent
e65d6bddf3
commit
5a077774fc
|
@ -10,6 +10,7 @@ import android.widget.TextView;
|
|||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -65,6 +66,12 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||
|
||||
//Set the title
|
||||
viewHolder.titleView.setText(podcast.title);
|
||||
if(!podcast.feedUrl.contains("itunes.apple.com")) {
|
||||
viewHolder.urlView.setText(podcast.feedUrl);
|
||||
viewHolder.urlView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
viewHolder.urlView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
//Update the empty imageView with the image from the feed
|
||||
Glide.with(context)
|
||||
|
@ -94,6 +101,8 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||
*/
|
||||
public final TextView titleView;
|
||||
|
||||
public final TextView urlView;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -102,6 +111,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||
PodcastViewHolder(View view){
|
||||
coverView = (ImageView) view.findViewById(R.id.imgvCover);
|
||||
titleView = (TextView) view.findViewById(R.id.txtvTitle);
|
||||
urlView = (TextView) view.findViewById(R.id.txtvUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,16 +134,47 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||
*/
|
||||
public final String feedUrl;
|
||||
|
||||
|
||||
private Podcast(String title, String imageUrl, String feedUrl) {
|
||||
this.title = title;
|
||||
this.imageUrl = imageUrl;
|
||||
this.feedUrl = feedUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructs a Podcast instance from a iTunes search result
|
||||
*
|
||||
* @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");
|
||||
public static Podcast fromSearch(JSONObject json) throws JSONException {
|
||||
String title = json.getString("collectionName");
|
||||
String imageUrl = json.getString("artworkUrl100");
|
||||
String feedUrl = json.getString("feedUrl");
|
||||
return new Podcast(title, imageUrl, feedUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Podcast instance from iTunes toplist entry
|
||||
*
|
||||
* @param json object holding the podcast information
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static Podcast fromToplist(JSONObject json) throws JSONException {
|
||||
String title = json.getJSONObject("title").getString("label");
|
||||
String imageUrl = null;
|
||||
JSONArray images = json.getJSONArray("im:image");
|
||||
for(int i=0; imageUrl == null && i < images.length(); i++) {
|
||||
JSONObject image = images.getJSONObject(i);
|
||||
String height = image.getJSONObject("attributes").getString("height");
|
||||
if(Integer.valueOf(height) >= 100) {
|
||||
imageUrl = image.getString("label");
|
||||
}
|
||||
}
|
||||
String feedUrl = "https://itunes.apple.com/lookup?id=" +
|
||||
json.getJSONObject("id").getJSONObject("attributes").getString("im:id");
|
||||
return new Podcast(title, imageUrl, feedUrl);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
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.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
@ -25,13 +31,14 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
|
@ -46,21 +53,22 @@ public class ItunesSearchFragment extends Fragment {
|
|||
|
||||
private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
|
||||
|
||||
/**
|
||||
* Search input field
|
||||
*/
|
||||
private SearchView searchView;
|
||||
|
||||
/**
|
||||
* 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<Podcast> searchResults;
|
||||
|
||||
private List<Podcast> topList;
|
||||
private Subscription subscription;
|
||||
|
||||
/**
|
||||
|
@ -70,13 +78,17 @@ public class ItunesSearchFragment extends Fragment {
|
|||
void updateData(List<Podcast> result) {
|
||||
this.searchResults = result;
|
||||
adapter.clear();
|
||||
|
||||
//ArrayAdapter.addAll() requires minsdk > 10
|
||||
for(Podcast p: result) {
|
||||
adapter.add(p);
|
||||
if (result != null && result.size() > 0) {
|
||||
gridView.setVisibility(View.VISIBLE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
for (Podcast p : result) {
|
||||
adapter.add(p);
|
||||
}
|
||||
adapter.notifyDataSetInvalidated();
|
||||
} else {
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
adapter.notifyDataSetInvalidated();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,47 +101,105 @@ public class ItunesSearchFragment extends Fragment {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
adapter = new ItunesAdapter(getActivity(), new ArrayList<Podcast>());
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@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);
|
||||
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(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Intent intent = new Intent(getActivity(),
|
||||
OnlineFeedViewActivity.class);
|
||||
|
||||
//Tell the OnlineFeedViewActivity where to go
|
||||
String url = searchResults.get(position).feedUrl;
|
||||
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
|
||||
|
||||
gridView.setOnItemClickListener((parent, view1, position, id) -> {
|
||||
Podcast podcast = searchResults.get(position);
|
||||
if (!podcast.feedUrl.contains("itunes.apple.com")) {
|
||||
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);
|
||||
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
|
||||
intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, "iTunes");
|
||||
startActivity(intent);
|
||||
} else {
|
||||
gridView.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
rx.Observable.create((Observable.OnSubscribe<String>) subscriber -> {
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
.url(podcast.feedUrl)
|
||||
.header("User-Agent", ClientConfig.USER_AGENT);
|
||||
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");
|
||||
subscriber.onNext(feedUrl);
|
||||
} else {
|
||||
String prefix = getString(R.string.error_msg_prefix);
|
||||
subscriber.onError(new IOException(prefix + response));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.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 MaterialDialog.Builder(getActivity())
|
||||
.content(prefix + " " + error.getMessage())
|
||||
.neutralText(android.R.string.ok)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
});
|
||||
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);
|
||||
|
||||
//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() {
|
||||
loadToplist();
|
||||
|
||||
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_itunes_label));
|
||||
sv.setOnQueryTextListener(new android.support.v7.widget.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();
|
||||
sv.clearFocus();
|
||||
search(s);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,21 +207,97 @@ public class ItunesSearchFragment extends Fragment {
|
|||
return false;
|
||||
}
|
||||
});
|
||||
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SearchView.SearchAutoComplete textField = (SearchView.SearchAutoComplete) searchView.findViewById(de.danoeh.antennapod.R.id.search_src_text);
|
||||
if(UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark) {
|
||||
textField.setTextColor(Resources.getSystem().getColor(android.R.color.white));
|
||||
} else {
|
||||
textField.setTextColor(Resources.getSystem().getColor(android.R.color.black));
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
if(searchResults != null) {
|
||||
searchResults = null;
|
||||
updateData(topList);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadToplist() {
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.GONE);
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
|
||||
String lang = Locale.getDefault().getLanguage();
|
||||
String url = "https://itunes.apple.com/" + lang + "/rss/toppodcasts/limit=25/explicit=true/json";
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
.url(url)
|
||||
.header("User-Agent", ClientConfig.USER_AGENT);
|
||||
List<Podcast> results = new ArrayList<>();
|
||||
try {
|
||||
Response response = client.newCall(httpReq.build()).execute();
|
||||
if(!response.isSuccessful()) {
|
||||
// toplist for language does not exist, fall back to united states
|
||||
url = "https://itunes.apple.com/us/rss/toppodcasts/limit=25/explicit=true/json";
|
||||
httpReq = new Request.Builder()
|
||||
.url(url)
|
||||
.header("User-Agent", ClientConfig.USER_AGENT);
|
||||
response = client.newCall(httpReq.build()).execute();
|
||||
}
|
||||
if(response.isSuccessful()) {
|
||||
String resultString = response.body().string();
|
||||
JSONObject result = new JSONObject(resultString);
|
||||
JSONObject feed = result.getJSONObject("feed");
|
||||
JSONArray entries = feed.getJSONArray("entry");
|
||||
|
||||
return view;
|
||||
for(int i=0; i < entries.length(); i++) {
|
||||
JSONObject json = entries.getJSONObject(i);
|
||||
Podcast podcast = Podcast.fromToplist(json);
|
||||
results.add(podcast);
|
||||
}
|
||||
}
|
||||
else {
|
||||
String prefix = getString(R.string.error_msg_prefix);
|
||||
subscriber.onError(new IOException(prefix + response));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
subscriber.onNext(results);
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.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 (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.GONE);
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
|
||||
String encodedQuery = null;
|
||||
try {
|
||||
|
@ -181,15 +327,16 @@ public class ItunesSearchFragment extends Fragment {
|
|||
|
||||
for (int i = 0; i < j.length(); i++) {
|
||||
JSONObject podcastJson = j.getJSONObject(i);
|
||||
Podcast podcast = new Podcast(podcastJson);
|
||||
Podcast podcast = Podcast.fromSearch(podcastJson);
|
||||
podcasts.add(podcast);
|
||||
}
|
||||
}
|
||||
else {
|
||||
subscriber.onError(new IOException("Unexpected error: " + response));
|
||||
String prefix = getString(R.string.error_msg_prefix);
|
||||
subscriber.onError(new IOException(prefix + response));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
subscriber.onError(e);
|
||||
}
|
||||
subscriber.onNext(podcasts);
|
||||
subscriber.onCompleted();
|
||||
|
@ -197,9 +344,15 @@ public class ItunesSearchFragment extends Fragment {
|
|||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,64 @@
|
|||
<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"
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
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="400dp"
|
||||
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" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<GridView
|
||||
android:id="@+id/gridView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:columnWidth="400dp"
|
||||
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" />
|
||||
|
||||
<TextView
|
||||
android:id="@id/android:empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:text="@string/search_status_no_results" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvError"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_margin="16dp"
|
||||
android:textAlignment="center"
|
||||
android:textSize="@dimen/text_size_small"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:text="Error message"
|
||||
tools:background="@android:color/holo_red_light" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/butRetry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/txtvError"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/retry_label"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:background="@android:color/holo_red_light" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,38 +1,58 @@
|
|||
<?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"
|
||||
<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="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" />
|
||||
android:paddingTop="8dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
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_alignParentTop="true"
|
||||
android:layout_marginRight="8dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/cover_label"
|
||||
android:cropToPadding="true"
|
||||
android:scaleType="fitXY"
|
||||
tools:background="@android:color/holo_green_dark"
|
||||
tools:src="@drawable/ic_stat_antenna_default" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/imgvCover"
|
||||
android:layout_centerVertical="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvTitle"
|
||||
style="@style/AntennaPod.TextView.ListItemPrimaryTitle2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
tools:background="@android:color/holo_green_dark"
|
||||
tools:text="Podcast title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvUrl"
|
||||
style="android:style/TextAppearance.Small"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:ellipsize="middle"
|
||||
android:maxLines="2"
|
||||
tools:text="http://www.example.com/feed"
|
||||
tools:background="@android:color/holo_green_dark"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:icon="?attr/action_search"
|
||||
custom:showAsAction="collapseActionView|ifRoom"
|
||||
custom:actionViewClass="android.support.v7.widget.SearchView"
|
||||
android:title="@string/search_label"/>
|
||||
|
||||
</menu>
|
|
@ -249,6 +249,12 @@
|
|||
<item name="android:ellipsize">end</item>
|
||||
</style>
|
||||
|
||||
<style name="AntennaPod.TextView.ListItemPrimaryTitle2" parent="@android:style/TextAppearance.Small">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
</style>
|
||||
|
||||
<style name="AntennaPod.TextView.ListItemSecondaryTitle" parent="@android:style/TextAppearance.Small">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
|
|
Loading…
Reference in New Issue