content: package de.danoeh.antennapod.ui.discovery;
  
  import android.content.Context;
  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.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.net.discovery.PodcastSearchResult;
  import de.danoeh.antennapod.net.discovery.PodcastSearcher;
  import de.danoeh.antennapod.net.discovery.PodcastSearcherRegistry;
  import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
  import io.reactivex.rxjava3.disposables.Disposable;
  
  public class OnlineSearchFragment extends Fragment {
  
      private static final String TAG = "FyydSearchFragment";
      private static final String ARG_SEARCHER = "searcher";
      private static final String ARG_QUERY = "query";
  
      /**
       * Adapter responsible with the search results
       */
      private OnlineSearchAdapter adapter;
      private PodcastSearcher searchProvider;
      private GridView gridView;
      private ProgressBar progressBar;
      private TextView txtvError;
      private Button butRetry;
      private TextView txtvEmpty;
  
      /**
       * List of podcasts retreived from the search
       */
      private List<PodcastSearchResult> searchResults;
      private Disposable disposable;
  
      public static OnlineSearchFragment newInstance(Class<? extends PodcastSearcher> searchProvider) {
          return newInstance(searchProvider, null);
      }
  
      public static OnlineSearchFragment newInstance(Class<? extends PodcastSearcher> searchProvider, String query) {
          OnlineSearchFragment fragment = new OnlineSearchFragment();
          Bundle arguments = new Bundle();
          arguments.putString(ARG_SEARCHER, searchProvider.getName());
          arguments.putString(ARG_QUERY, query);
          fragment.setArguments(arguments);
          return fragment;
      }
  
      /**
       * Constructor
       */
      public OnlineSearchFragment() {
          // Required empty public constructor
      }
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          for (PodcastSearcherRegistry.SearcherInfo info : PodcastSearcherRegistry.getSearchProviders()) {
              if (info.searcher.getClass().getName().equals(getArguments().getString(ARG_SEARCHER))) {
                  searchProvider = info.searcher;
                  break;
              }
          }
          if (searchProvider == null) {
              throw new IllegalArgumentException("Podcast searcher not found");
          }
      }
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          // Inflate the layout for this fragment
          View root = inflater.inflate(R.layout.fragment_online_search, container, false);
          gridView = root.findViewById(R.id.gridView);
          adapter = new OnlineSearchAdapter(getActivity(), new ArrayList<>());
          gridView.setAdapter(adapter);
  
          //Show information about the podcast when the list item is clicked
          gridView.setOnItemClickListener((parent, view1, position, id) -> {
              PodcastSearchResult podcast = searchResults.get(position);
              startActivity(new OnlineFeedviewActivityStarter(getContext(), podcast.feedUrl).getIntent());
          });
          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);
          TextView txtvPoweredBy = root.findViewById(R.id.search_powered_by);
          txtvPoweredBy.setText(getString(R.string.search_powered_by, searchProvider.getName()));
          setupToolbar(root.findViewById(R.id.toolbar));
  
          gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
              @Override
              public void onScrollStateChanged(AbsListView view, int scrollState) {
                  if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
                      InputMethodManager imm = (InputMethodManager)
                              getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                      imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
                  }
              }
  
              @Override
              public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
              }
          });
          return root;
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          if (disposable != null) {
              disposable.dispose();
          }
          adapter = null;
      }
  
      private void setupToolbar(MaterialToolbar toolbar) {
          toolbar.inflateMenu(R.menu.online_search);
          toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
  
          MenuItem searchItem = toolbar.getMenu().findItem(R.id.action_search);
          final SearchView sv = (SearchView) searchItem.getActionView();
          sv.setQueryHint(getString(R.string.search_podcast_hint));
          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;
              }
          });
          sv.setOnQueryTextFocusChangeListener((view, hasFocus) -> {
              if (hasFocus) {
                  showInputMethod(view.findFocus());
              }
          });
          searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
              @Override
              public boolean onMenuItemActionExpand(MenuItem item) {
                  return true;
              }
  
              @Override
              public boolean onMenuItemActionCollapse(MenuItem item) {
                  getActivity().getSupportFragmentManager().popBackStack();
                  return true;
              }
          });
          searchItem.expandActionView();
  
          if (getArguments().getString(ARG_QUERY, null) != null) {
              sv.setQuery(getArguments().getString(ARG_QUERY, null), true);
          }
      }
  
      private void search(String query) {
          if (disposable != null) {
              disposable.dispose();
          }
          showOnlyProgressBar();
          disposable = searchProvider.search(query).subscribe(result -> {
              searchResults = result;
              progressBar.setVisibility(View.GONE);
              adapter.clear();
              adapter.addAll(searchResults);
              adapter.notifyDataSetInvalidated();
              gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE);
              txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE);
              txtvEmpty.setText(getString(R.string.no_results_for_query, query));
          }, 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);
      }
  
      private void showInputMethod(View view) {
          InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
          if (imm != null) {
              imm.showSoftInput(view, 0);
          }
      }
  }
  