Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auto-complete to discovery country selection #6139

Merged
merged 14 commits into from Oct 15, 2022
171 changes: 104 additions & 67 deletions app/src/main/java/de/danoeh/antennapod/fragment/DiscoveryFragment.java
@@ -1,46 +1,53 @@
package de.danoeh.antennapod.fragment;

import static android.content.Context.MODE_PRIVATE;
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved

import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
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 com.google.android.material.appbar.MaterialToolbar;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;

import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
import org.greenrobot.eventbus.EventBus;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
import com.google.android.material.textfield.TextInputLayout;

import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
import io.reactivex.disposables.Disposable;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;

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 java.util.Map;

import static android.content.Context.MODE_PRIVATE;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
import io.reactivex.disposables.Disposable;

/**
* Searches iTunes store for top podcasts and displays results in a list.
*/
public class DiscoveryFragment extends Fragment {
public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemClickListener {

private static final String TAG = "ItunesSearchFragment";
private SharedPreferences prefs;
Expand All @@ -62,9 +69,12 @@ public class DiscoveryFragment extends Fragment {
private List<PodcastSearchResult> topList;
private Disposable disposable;
private String countryCode = "US";
private String previousCountryCode = countryCode;
private MaterialToolbar toolbar;

/**
* Replace adapter data with provided search results from SearchTask.
*
* @param result List of Podcast objects containing search results
*/
private void updateData(List<PodcastSearchResult> result) {
Expand Down Expand Up @@ -95,16 +105,17 @@ public void onCreate(Bundle savedInstanceState) {
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);

MaterialToolbar toolbar = root.findViewById(R.id.toolbar);
toolbar = root.findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
toolbar.inflateMenu(R.menu.countries_menu);
toolbar.setOnMenuItemClickListener(this);
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved

//Show information about the podcast when the list item is clicked
gridView.setOnItemClickListener((parent, view1, position, id) -> {
Expand All @@ -117,57 +128,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
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);
Expand Down Expand Up @@ -221,4 +181,81 @@ private void loadToplist(String country) {
});
}
}

@Override
public boolean onMenuItemClick(MenuItem item) {
if (super.onOptionsItemSelected(item)) {
return true;
}
final int itemId = item.getItemId();
if (itemId == R.id.discover_hide_item) {
item.setChecked(!item.isChecked());
if (item.isChecked()) {
previousCountryCode = countryCode;
countryCode = ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE;
} else {
countryCode = previousCountryCode;
}
prefs.edit().putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode).apply();

EventBus.getDefault().post(new DiscoveryDefaultUpdateEvent());
loadToplist(countryCode);
return true;
} else if (itemId == R.id.discover_countries_item) {

LayoutInflater inflater = getLayoutInflater();
View selectCountryDialogView = inflater.inflate(R.layout.select_country_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(selectCountryDialogView);

List<String> countryCodeArray = new ArrayList<>(Arrays.asList(Locale.getISOCountries()));
Map<String, String> countryCodeNames = new HashMap<>();
Map<String, String> countryNameCodes = new HashMap<>();
for (String code : countryCodeArray) {
Locale locale = new Locale("", code);
String countryName = locale.getDisplayCountry();
countryCodeNames.put(code, countryName);
countryNameCodes.put(countryName, code);
}

List<String> countryNamesSort = new ArrayList<>(countryCodeNames.values());
Collections.sort(countryNamesSort);

ArrayAdapter<String> dataAdapter =
new ArrayAdapter<>(this.getContext(), R.layout.list_item, countryNamesSort);
TextInputLayout textInput = selectCountryDialogView.findViewById(R.id.country_text_input);
MaterialAutoCompleteTextView editText = (MaterialAutoCompleteTextView) textInput.getEditText();
editText.setAdapter(dataAdapter);
if (countryCode.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
editText.setText(countryCodeNames.get(previousCountryCode));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you store the previous code? It's only in a variable anyway, so it doesn't really help?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use this variable in order to restore country user previously selected when they uncheck "Hide" checkbox, and to show previously selected country in drop-down list instead of empty string

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also made this variable stored in prefs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of storing (current, previous) country codes where the current one can be DISCOVER_HIDE_FAKE_COUNTRY_CODE, I think it would be a lot more clear to store (country, hidden). Then we need to store one string and one boolean and don't need to move strings back and forth between the two variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

} else {
editText.setText(countryCodeNames.get(countryCode));
}
editText.setOnClickListener(view -> {
if (StringUtils.isEmpty(editText.getText().toString())) {
return;
}
editText.getText().clear();
editText.postDelayed(editText::showDropDown, 100);
});
Button button = selectCountryDialogView.findViewById(R.id.select_country_button);
AlertDialog countryDialog = builder.show();
button.setOnClickListener(view -> {
String countryName = editText.getText().toString();
if (countryNameCodes.containsKey(countryName)) {
countryCode = countryNameCodes.get(countryName);
MenuItem discoverHideItem = toolbar.getMenu().findItem(R.id.discover_hide_item);
discoverHideItem.setChecked(false);
}

prefs.edit().putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode).apply();

EventBus.getDefault().post(new DiscoveryDefaultUpdateEvent());
loadToplist(countryCode);
countryDialog.dismiss();
});
return true;
}
return false;
}
}
Expand Up @@ -3,22 +3,26 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import android.widget.AbsListView;
import com.google.android.material.appbar.MaterialToolbar;
import androidx.fragment.app.Fragment;
import androidx.appcompat.widget.SearchView;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;

import com.google.android.material.appbar.MaterialToolbar;

import java.util.ArrayList;
import java.util.List;

import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
Expand All @@ -28,11 +32,6 @@
import de.danoeh.antennapod.net.discovery.PodcastSearcherRegistry;
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";
Expand Down Expand Up @@ -95,7 +94,6 @@ public void onCreate(Bundle savedInstanceState) {
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);
root.findViewById(R.id.spinner_country).setVisibility(INVISIBLE);
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
Expand Down
13 changes: 1 addition & 12 deletions app/src/main/res/layout/fragment_itunes_search.xml
Expand Up @@ -16,24 +16,13 @@

<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="wrap_content"
android:layout_width="match_parent"
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
app:title="@string/discover" />

<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
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/layout/list_item.xml
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="16dp"
android:textAppearance="?attr/textAppearanceSubtitle1" />
29 changes: 29 additions & 0 deletions app/src/main/res/layout/select_country_dialog.xml
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/country_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:hint="@string/country"
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu">

<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</com.google.android.material.textfield.TextInputLayout>

<Button
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved
android:id="@+id/select_country_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:text="@string/select" />

</LinearLayout>
16 changes: 16 additions & 0 deletions app/src/main/res/menu/countries_menu.xml
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">

<item
android:id="@+id/discover_hide_item"
android:checkable="true"
android:enabled="true"
android:title="@string/discover_hide"
android:visible="true" />
ByteHamster marked this conversation as resolved.
Show resolved Hide resolved
<item
android:id="@+id/discover_countries_item"
android:enabled="true"
android:title="@string/country"
android:visible="true" />
</menu>
2 changes: 2 additions & 0 deletions ui/i18n/src/main/res/values/strings.xml
Expand Up @@ -724,6 +724,8 @@
<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>
<string name="country">Country</string>
<string name="select">Select</string>

<!-- Local feeds -->
<string name="add_local_folder">Add local folder</string>
Expand Down