mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-02-02 11:46:55 +01:00
Discovery filter by country & hide discovery on first subscribe screen (#4515)
This commit is contained in:
parent
4df751a018
commit
2ef464ad93
@ -1,6 +1,7 @@
|
||||
package de.danoeh.antennapod.discovery;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
@ -23,24 +24,46 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
public class ItunesTopListLoader {
|
||||
private static final String TAG = "ITunesTopListLoader";
|
||||
private final Context context;
|
||||
public static final String PREF_KEY_COUNTRY_CODE = "country_code";
|
||||
public static final String PREFS = "CountryRegionPrefs";
|
||||
public static final String DISCOVER_HIDE_FAKE_COUNTRY_CODE = "00";
|
||||
public static final String COUNTRY_CODE_UNSET = "99";
|
||||
|
||||
public ItunesTopListLoader(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Single<List<PodcastSearchResult>> loadToplist(int limit) {
|
||||
public Single<List<PodcastSearchResult>> loadToplist() {
|
||||
String defaultCountry = Locale.getDefault().getCountry();
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
String countryCode = prefs.getString(PREF_KEY_COUNTRY_CODE, COUNTRY_CODE_UNSET);
|
||||
return this.loadToplist(countryCode, 25);
|
||||
}
|
||||
|
||||
public Single<List<PodcastSearchResult>> loadToplist(String country, int limit) {
|
||||
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
|
||||
String country = Locale.getDefault().getCountry();
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
String feedString;
|
||||
try {
|
||||
feedString = getTopListFeed(client, country, limit);
|
||||
} catch (IOException e) {
|
||||
feedString = getTopListFeed(client, "us", limit);
|
||||
String loadCountry = country;
|
||||
if (COUNTRY_CODE_UNSET.equals(country)) {
|
||||
loadCountry = Locale.getDefault().getCountry();
|
||||
}
|
||||
try {
|
||||
feedString = getTopListFeed(client, loadCountry, limit);
|
||||
} catch (IOException e) {
|
||||
if (COUNTRY_CODE_UNSET.equals(country)) {
|
||||
feedString = getTopListFeed(client, "US", limit);
|
||||
} else {
|
||||
emitter.onError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<PodcastSearchResult> podcasts = parseFeed(feedString);
|
||||
emitter.onSuccess(podcasts);
|
||||
})
|
||||
@ -59,6 +82,9 @@ public class ItunesTopListLoader {
|
||||
if (response.isSuccessful()) {
|
||||
return response.body().string();
|
||||
}
|
||||
if (response.code() == 400) {
|
||||
throw new IOException("iTunes does not have data for the selected country.");
|
||||
}
|
||||
String prefix = context.getString(R.string.error_msg_prefix);
|
||||
throw new IOException(prefix + response);
|
||||
}
|
||||
@ -66,8 +92,14 @@ public class ItunesTopListLoader {
|
||||
|
||||
private List<PodcastSearchResult> parseFeed(String jsonString) throws JSONException {
|
||||
JSONObject result = new JSONObject(jsonString);
|
||||
JSONObject feed = result.getJSONObject("feed");
|
||||
JSONArray entries = feed.getJSONArray("entry");
|
||||
JSONObject feed;
|
||||
JSONArray entries;
|
||||
try {
|
||||
feed = result.getJSONObject("feed");
|
||||
entries = feed.getJSONArray("entry");
|
||||
} catch (JSONException e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<PodcastSearchResult> results = new ArrayList<>();
|
||||
for (int i = 0; i < entries.length(); i++) {
|
||||
|
@ -1,27 +1,41 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
|
||||
import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
|
||||
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.discovery.PodcastSearchResult;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
/**
|
||||
* Searches iTunes store for top podcasts and displays results in a list.
|
||||
@ -29,6 +43,7 @@ import java.util.List;
|
||||
public class DiscoveryFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "ItunesSearchFragment";
|
||||
private SharedPreferences prefs;
|
||||
|
||||
/**
|
||||
* Adapter responsible with the search results.
|
||||
@ -46,6 +61,7 @@ public class DiscoveryFragment extends Fragment {
|
||||
private List<PodcastSearchResult> searchResults;
|
||||
private List<PodcastSearchResult> topList;
|
||||
private Disposable disposable;
|
||||
private String countryCode = "US";
|
||||
|
||||
/**
|
||||
* Replace adapter data with provided search results from SearchTask.
|
||||
@ -75,6 +91,8 @@ public class DiscoveryFragment extends Fragment {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
prefs = getActivity().getSharedPreferences(ItunesTopListLoader.PREFS, MODE_PRIVATE);
|
||||
countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().getCountry());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,13 +115,64 @@ public class DiscoveryFragment extends Fragment {
|
||||
intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
List<String> countryCodeArray = new ArrayList<String>(Arrays.asList(Locale.getISOCountries()));
|
||||
HashMap<String, String> countryCodeNames = new HashMap<String, String>();
|
||||
for (String code: countryCodeArray) {
|
||||
Locale locale = new Locale("", code);
|
||||
String countryName = locale.getDisplayCountry();
|
||||
if (countryName != null) {
|
||||
countryCodeNames.put(code, countryName);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> countryNamesSort = new ArrayList<String>(countryCodeNames.values());
|
||||
Collections.sort(countryNamesSort);
|
||||
countryNamesSort.add(0, getResources().getString(R.string.discover_hide));
|
||||
|
||||
Spinner countrySpinner = root.findViewById(R.id.spinner_country);
|
||||
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this.getContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
countryNamesSort);
|
||||
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
countrySpinner.setAdapter(dataAdapter);
|
||||
int pos = countryNamesSort.indexOf(countryCodeNames.get(countryCode));
|
||||
countrySpinner.setSelection(pos);
|
||||
|
||||
countrySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> countrySpinner, View view, int position, long id) {
|
||||
String countryName = (String) countrySpinner.getItemAtPosition(position);
|
||||
|
||||
if (countryName.equals(getResources().getString(R.string.discover_hide))) {
|
||||
countryCode = ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE;
|
||||
} else {
|
||||
for (Object o : countryCodeNames.keySet()) {
|
||||
if (countryCodeNames.get(o).equals(countryName)) {
|
||||
countryCode = o.toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prefs.edit()
|
||||
.putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode)
|
||||
.apply();
|
||||
|
||||
EventBus.getDefault().post(new DiscoveryDefaultUpdateEvent());
|
||||
loadToplist(countryCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
progressBar = root.findViewById(R.id.progressBar);
|
||||
txtvError = root.findViewById(R.id.txtvError);
|
||||
butRetry = root.findViewById(R.id.butRetry);
|
||||
txtvEmpty = root.findViewById(android.R.id.empty);
|
||||
|
||||
loadToplist();
|
||||
|
||||
loadToplist(countryCode);
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -116,28 +185,39 @@ public class DiscoveryFragment extends Fragment {
|
||||
adapter = null;
|
||||
}
|
||||
|
||||
private void loadToplist() {
|
||||
private void loadToplist(String country) {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.GONE);
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
if (country.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
|
||||
gridView.setVisibility(View.GONE);
|
||||
txtvError.setVisibility(View.VISIBLE);
|
||||
txtvError.setText(getResources().getString(R.string.discover_is_hidden));
|
||||
butRetry.setVisibility(View.GONE);
|
||||
txtvEmpty.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
} else {
|
||||
ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
|
||||
disposable = loader.loadToplist(25).subscribe(podcasts -> {
|
||||
disposable = loader.loadToplist(country, 25).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.setText(error.getMessage());
|
||||
txtvError.setVisibility(View.VISIBLE);
|
||||
butRetry.setOnClickListener(v -> loadToplist());
|
||||
butRetry.setOnClickListener(v -> loadToplist(country));
|
||||
butRetry.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ import io.reactivex.disposables.Disposable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.view.View.INVISIBLE;
|
||||
|
||||
public class OnlineSearchFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "FyydSearchFragment";
|
||||
@ -93,6 +95,7 @@ public class OnlineSearchFragment extends Fragment {
|
||||
// Inflate the layout for this fragment
|
||||
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
|
||||
root.findViewById(R.id.spinner_country).setVisibility(INVISIBLE);
|
||||
gridView = root.findViewById(R.id.gridView);
|
||||
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
|
||||
gridView.setAdapter(adapter);
|
||||
|
@ -1,9 +1,11 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -14,16 +16,25 @@ import android.widget.GridView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
|
||||
import de.danoeh.antennapod.core.event.DiscoveryDefaultUpdateEvent;
|
||||
import de.danoeh.antennapod.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.discovery.PodcastSearchResult;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
|
||||
public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.OnItemClickListener {
|
||||
@ -36,6 +47,7 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
|
||||
private GridView discoverGridLayout;
|
||||
private TextView errorTextView;
|
||||
private LinearLayout errorView;
|
||||
private Button errorRetry;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
@ -49,7 +61,7 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
|
||||
progressBar = root.findViewById(R.id.discover_progress_bar);
|
||||
errorView = root.findViewById(R.id.discover_error);
|
||||
errorTextView = root.findViewById(R.id.discover_error_txtV);
|
||||
Button errorRetry = root.findViewById(R.id.discover_error_retry_btn);
|
||||
errorRetry = root.findViewById(R.id.discover_error_retry_btn);
|
||||
errorRetry.setOnClickListener((listener) -> loadToplist());
|
||||
|
||||
adapter = new FeedDiscoverAdapter((MainActivity) getActivity());
|
||||
@ -73,35 +85,66 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
|
||||
|
||||
adapter.updateData(dummies);
|
||||
loadToplist();
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventBus.getDefault().unregister(this);
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@SuppressWarnings("unused")
|
||||
public void onDiscoveryDefaultUpdateEvent(DiscoveryDefaultUpdateEvent event) {
|
||||
loadToplist();
|
||||
}
|
||||
|
||||
private void loadToplist() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
errorView.setVisibility(View.GONE);
|
||||
errorRetry.setVisibility(View.INVISIBLE);
|
||||
|
||||
ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
|
||||
disposable = loader.loadToplist(NUM_SUGGESTIONS)
|
||||
.subscribe(podcasts -> {
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(ItunesTopListLoader.PREFS, MODE_PRIVATE);
|
||||
String countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE,
|
||||
Locale.getDefault().getCountry());
|
||||
if (countryCode.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
|
||||
errorTextView.setText(String.format(getResources().getString(R.string.discover_is_hidden),
|
||||
getResources().getString(R.string.discover_hide)));
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
errorRetry.setVisibility(View.INVISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
disposable = loader.loadToplist(countryCode, NUM_SUGGESTIONS)
|
||||
.subscribe(
|
||||
podcasts -> {
|
||||
errorView.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
discoverGridLayout.setVisibility(View.VISIBLE);
|
||||
if (podcasts.size() == 0) {
|
||||
errorTextView.setText(getResources().getText(R.string.search_status_no_results));
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
adapter.updateData(podcasts);
|
||||
}
|
||||
}, error -> {
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
errorTextView.setText(error.getLocalizedMessage());
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
errorRetry.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,18 +4,35 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/browsing"
|
||||
android:layout_alignParentTop="true">
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
app:title="@string/discover"
|
||||
android:id="@+id/toolbar"/>
|
||||
|
||||
<android.widget.Spinner
|
||||
android:id="@+id/spinner_country"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right|end"
|
||||
android:gravity="right|end"
|
||||
android:isScrollContainer="true"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:spinnerMode="dropdown"
|
||||
android:textAlignment="textEnd" />
|
||||
</LinearLayout>
|
||||
|
||||
<GridView
|
||||
android:layout_below="@id/toolbar"
|
||||
android:layout_below="@id/browsing"
|
||||
android:id="@+id/gridView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -0,0 +1,6 @@
|
||||
package de.danoeh.antennapod.core.event;
|
||||
|
||||
public class DiscoveryDefaultUpdateEvent {
|
||||
public DiscoveryDefaultUpdateEvent() {
|
||||
}
|
||||
}
|
@ -729,6 +729,8 @@
|
||||
<string name="add_podcast_by_url_hint" translatable="false">www.example.com/feed</string>
|
||||
<string name="browse_gpoddernet_label">Browse gpodder.net</string>
|
||||
<string name="discover">Discover</string>
|
||||
<string name="discover_hide">Hide</string>
|
||||
<string name="discover_is_hidden">You selected to hide suggestions.</string>
|
||||
<string name="discover_more">more »</string>
|
||||
<string name="discover_powered_by_itunes">Suggestions by iTunes</string>
|
||||
<string name="search_powered_by">Results by %1$s</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user