Skip to content

Commit

Permalink
Rewrite SearchProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsvanvelzen committed Jun 5, 2022
1 parent 3f63473 commit 8f1cee7
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void onCreate(Bundle savedInstanceState) {
backgroundService.getValue().attach(requireActivity());

// Create provider
SearchProvider searchProvider = new SearchProvider(getContext());
SearchProvider searchProvider = new SearchProvider(getContext(), getLifecycle());
setSearchResultProvider(searchProvider);

// Create click listener
Expand Down
120 changes: 50 additions & 70 deletions app/src/main/java/org/jellyfin/androidtv/ui/search/SearchProvider.kt
Original file line number Diff line number Diff line change
@@ -1,71 +1,51 @@
package org.jellyfin.androidtv.ui.search;

import android.content.Context;
import android.os.Handler;

import androidx.leanback.app.SearchSupportFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
import androidx.leanback.widget.ObjectAdapter;

import org.jellyfin.androidtv.ui.presentation.CustomListRowPresenter;
import org.jellyfin.androidtv.util.Utils;

public class SearchProvider implements SearchSupportFragment.SearchResultProvider {
private static final int SEARCH_DELAY_MS = 600;
private final Handler mHandler = new Handler();
private ArrayObjectAdapter mRowsAdapter;
private SearchRunnable mDelayedLoad;
private String lastQuery;

SearchProvider(Context context) {
mRowsAdapter = new ArrayObjectAdapter(new CustomListRowPresenter());
mDelayedLoad = new SearchRunnable(context, mRowsAdapter);
}

@Override
public ObjectAdapter getResultsAdapter() {
return mRowsAdapter;
}

@Override
public boolean onQueryTextChange(String query) {
search(query, true);

return true;
}

@Override
public boolean onQueryTextSubmit(String query) {
search(query, false);

return true;
}

/**
* Update search results
*
* @param query String to search for
* @param delayed When true the search is delayed by [SEARCH_DELAY_MS] milliseconds
*/
private void search(String query, boolean delayed) {
// Clear results when query is empty
if (Utils.isEmpty(query)) {
mRowsAdapter.clear();
return;
}

// Don't search the same thing twice
if (query.equals(lastQuery)) return;
lastQuery = query;

// Remove current delayed search (if any)
mHandler.removeCallbacks(mDelayedLoad);

// Update search string
mDelayedLoad.setQueryString(query);

// Schedule search depending on [delayed]
if (delayed) mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
else mHandler.post(mDelayedLoad);
}
package org.jellyfin.androidtv.ui.search

import android.content.Context
import androidx.leanback.app.SearchSupportFragment
import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.ObjectAdapter
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.jellyfin.androidtv.ui.presentation.CustomListRowPresenter
import kotlin.time.Duration.Companion.milliseconds

class SearchProvider(
context: Context,
private val lifecycle: Lifecycle,
) : SearchSupportFragment.SearchResultProvider {
companion object {
private val SEARCH_DELAY = 600.milliseconds
}

private val rowsAdapter = ArrayObjectAdapter(CustomListRowPresenter())
private var previousQuery: String? = null
private val searchRunnable = SearchRunnable(context, rowsAdapter)
private var searchJob: Job? = null

override fun getResultsAdapter(): ObjectAdapter = rowsAdapter

override fun onQueryTextChange(query: String): Boolean = search(query, true)
override fun onQueryTextSubmit(query: String): Boolean = search(query, false)

private fun search(query: String, delayed: Boolean): Boolean {
if (query.isBlank()) {
rowsAdapter.clear()
return true
}

// Don't search the same thing twice
if (query == previousQuery) return false
previousQuery = query

searchJob?.cancel()
searchJob = lifecycle.coroutineScope.launch {
if (delayed) delay(SEARCH_DELAY)
searchRunnable.run(query)
}

return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,85 +16,79 @@

import timber.log.Timber;

public class SearchRunnable implements Runnable {
private String searchString;
public class SearchRunnable {
private Context context;
private ArrayObjectAdapter mRowsAdapter;
private int searchesReceived;
private ArrayList<ItemRowAdapter> searchItemRows;

public void setQueryString(String value) {
searchString = value;
}
private int searchesReceived;

public SearchRunnable(Context context, ArrayObjectAdapter adapter) {
this.context = context;
this.mRowsAdapter = adapter;
this.searchItemRows = new ArrayList<>();
}

@Override
public void run() {
public void run(String searchString) {
mRowsAdapter.clear();
searchItemRows.clear();
searchesReceived = 0;

//Get search results by type
SearchQuery movies = getSearchQuery(new String[]{"Movie", "BoxSet"});
SearchQuery movies = getSearchQuery(new String[]{"Movie", "BoxSet"}, searchString);
ItemRowAdapter movieAdapter = new ItemRowAdapter(context, movies, new CardPresenter(), mRowsAdapter);
ListRow movieRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_movies)), movieAdapter);
movieAdapter.setRow(movieRow);
retrieveSearchResult(movieAdapter);

SearchQuery tvSeries = getSearchQuery(new String[]{"Series"});
SearchQuery tvSeries = getSearchQuery(new String[]{"Series"}, searchString);
ItemRowAdapter tvSeriesAdapter = new ItemRowAdapter(context, tvSeries, new CardPresenter(), mRowsAdapter);
ListRow tvSeriesRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_series)), tvSeriesAdapter);
tvSeriesAdapter.setRow(tvSeriesRow);
retrieveSearchResult(tvSeriesAdapter);

SearchQuery tv = getSearchQuery(new String[]{"Episode"});
SearchQuery tv = getSearchQuery(new String[]{"Episode"}, searchString);
ItemRowAdapter tvAdapter = new ItemRowAdapter(context, tv, new CardPresenter(), mRowsAdapter);
ListRow tvRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_episodes)), tvAdapter);
tvAdapter.setRow(tvRow);
retrieveSearchResult(tvAdapter);

SearchQuery people = getSearchQuery(new String[]{"Person", "People"});
SearchQuery people = getSearchQuery(new String[]{"Person", "People"}, searchString);
ItemRowAdapter peopleAdapter = new ItemRowAdapter(context, people, new CardPresenter(), mRowsAdapter);
ListRow peopleRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_people)), peopleAdapter);
peopleAdapter.setRow(peopleRow);
retrieveSearchResult(peopleAdapter);

SearchQuery videos = getSearchQuery(new String[]{"Video"});
SearchQuery videos = getSearchQuery(new String[]{"Video"}, searchString);
ItemRowAdapter videoAdapter = new ItemRowAdapter(context, videos, new CardPresenter(), mRowsAdapter);
ListRow videoRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_videos)), videoAdapter);
videoAdapter.setRow(videoRow);
retrieveSearchResult(videoAdapter);

SearchQuery recordings = getSearchQuery(new String[]{"Recording"});
SearchQuery recordings = getSearchQuery(new String[]{"Recording"}, searchString);
ItemRowAdapter recordingAdapter = new ItemRowAdapter(context, recordings, new CardPresenter(), mRowsAdapter);
ListRow recordingRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_recordings)), recordingAdapter);
recordingAdapter.setRow(recordingRow);
retrieveSearchResult(recordingAdapter);

SearchQuery programs = getSearchQuery(new String[]{"Program"});
SearchQuery programs = getSearchQuery(new String[]{"Program"}, searchString);
ItemRowAdapter programAdapter = new ItemRowAdapter(context, programs, new CardPresenter(), mRowsAdapter);
ListRow programRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_programs)), programAdapter);
programAdapter.setRow(programRow);
retrieveSearchResult(programAdapter);

SearchQuery artists = getSearchQuery(new String[]{"MusicArtist"});
SearchQuery artists = getSearchQuery(new String[]{"MusicArtist"}, searchString);
ItemRowAdapter artistAdapter = new ItemRowAdapter(context, artists, new CardPresenter(), mRowsAdapter);
ListRow artistRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_artists)), artistAdapter);
artistAdapter.setRow(artistRow);
retrieveSearchResult(artistAdapter);

SearchQuery albums = getSearchQuery(new String[]{"MusicAlbum"});
SearchQuery albums = getSearchQuery(new String[]{"MusicAlbum"}, searchString);
ItemRowAdapter albumAdapter = new ItemRowAdapter(context, albums, new CardPresenter(), mRowsAdapter);
ListRow albumRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_albums)), albumAdapter);
albumAdapter.setRow(albumRow);
retrieveSearchResult(albumAdapter);

SearchQuery songs = getSearchQuery(new String[]{"Audio"});
SearchQuery songs = getSearchQuery(new String[]{"Audio"}, searchString);
ItemRowAdapter songAdapter = new ItemRowAdapter(context, songs, new CardPresenter(), mRowsAdapter);
ListRow songRow = new ListRow(new HeaderItem(context.getString(R.string.lbl_songs)), songAdapter);
songAdapter.setRow(songRow);
Expand Down Expand Up @@ -127,7 +121,7 @@ public void onError(Exception ex) {
itemRow.Retrieve();
}

private SearchQuery getSearchQuery(String[] itemTypes) {
private static SearchQuery getSearchQuery(String[] itemTypes, String searchString) {
SearchQuery query = new SearchQuery();
query.setLimit(50);
query.setSearchTerm(searchString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class TextSearchFragment extends Fragment implements TextWatcher, TextVie
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

searchProvider = new SearchProvider(getContext());
searchProvider = new SearchProvider(getContext(), getLifecycle());
}

@Override
Expand Down

0 comments on commit 8f1cee7

Please sign in to comment.