2017-09-03 08:04:18 +02:00
|
|
|
package org.schabi.newpipe.fragments.list.search;
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.text.Editable;
|
2020-07-07 20:23:37 +02:00
|
|
|
import android.text.Html;
|
2017-09-03 08:04:18 +02:00
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.text.TextWatcher;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.KeyEvent;
|
|
|
|
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.view.animation.DecelerateInterpolator;
|
|
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import android.view.inputmethod.InputMethodManager;
|
2017-09-28 15:06:48 +02:00
|
|
|
import android.widget.EditText;
|
2017-09-03 08:04:18 +02:00
|
|
|
import android.widget.TextView;
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import androidx.appcompat.app.ActionBar;
|
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.appcompat.widget.TooltipCompat;
|
2020-09-13 13:50:29 +02:00
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
import androidx.core.text.HtmlCompat;
|
|
|
|
import androidx.preference.PreferenceManager;
|
2020-03-31 19:20:15 +02:00
|
|
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.R;
|
2017-09-28 15:06:48 +02:00
|
|
|
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
2020-11-03 08:58:21 +01:00
|
|
|
import org.schabi.newpipe.databinding.FragmentSearchBinding;
|
2020-12-09 12:42:01 +01:00
|
|
|
import org.schabi.newpipe.error.ErrorActivity;
|
|
|
|
import org.schabi.newpipe.error.ErrorInfo;
|
|
|
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
|
|
|
import org.schabi.newpipe.error.UserAction;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.InfoItem;
|
|
|
|
import org.schabi.newpipe.extractor.ListExtractor;
|
2020-12-15 17:41:21 +01:00
|
|
|
import org.schabi.newpipe.extractor.MetaInfo;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
2020-04-15 15:31:53 +02:00
|
|
|
import org.schabi.newpipe.extractor.Page;
|
2017-09-15 19:27:39 +02:00
|
|
|
import org.schabi.newpipe.extractor.StreamingService;
|
2018-07-08 17:46:21 +02:00
|
|
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
2018-07-08 14:27:12 +02:00
|
|
|
import org.schabi.newpipe.extractor.search.SearchInfo;
|
2020-12-23 15:14:26 +01:00
|
|
|
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
|
|
|
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
|
2017-09-28 15:06:48 +02:00
|
|
|
import org.schabi.newpipe.fragments.BackPressable;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
2021-01-16 04:32:01 +01:00
|
|
|
import org.schabi.newpipe.ktx.AnimationType;
|
2020-11-21 10:45:42 +01:00
|
|
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
2018-04-12 23:46:03 +02:00
|
|
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
2018-12-29 19:47:13 +01:00
|
|
|
import org.schabi.newpipe.util.Constants;
|
2020-09-13 13:50:29 +02:00
|
|
|
import org.schabi.newpipe.util.DeviceUtils;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.util.ExtractorHelper;
|
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
2018-07-19 16:18:57 +02:00
|
|
|
import org.schabi.newpipe.util.ServiceHelper;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2018-07-10 16:26:42 +02:00
|
|
|
import java.util.Arrays;
|
2018-07-22 13:55:17 +02:00
|
|
|
import java.util.HashMap;
|
2017-09-03 08:04:18 +02:00
|
|
|
import java.util.List;
|
2018-07-22 13:55:17 +02:00
|
|
|
import java.util.Map;
|
2017-09-03 08:04:18 +02:00
|
|
|
import java.util.Queue;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
import icepick.State;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
|
|
import io.reactivex.rxjava3.core.Flowable;
|
|
|
|
import io.reactivex.rxjava3.core.Observable;
|
|
|
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
|
|
import io.reactivex.rxjava3.disposables.Disposable;
|
|
|
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
|
|
import io.reactivex.rxjava3.subjects.PublishSubject;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2019-10-04 14:59:08 +02:00
|
|
|
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
|
2018-07-10 16:26:42 +02:00
|
|
|
import static java.util.Arrays.asList;
|
2021-01-16 04:32:01 +01:00
|
|
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
2020-12-20 15:05:37 +01:00
|
|
|
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
2018-03-18 16:37:49 +01:00
|
|
|
implements BackPressable {
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Search
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
/**
|
2017-09-28 15:06:48 +02:00
|
|
|
* The suggestions will only be fetched from network if the query meet this threshold (>=).
|
|
|
|
* (local ones will be fetched regardless of the length)
|
2017-09-03 08:04:18 +02:00
|
|
|
*/
|
2017-09-28 15:06:48 +02:00
|
|
|
private static final int THRESHOLD_NETWORK_SUGGESTION = 1;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
/**
|
2020-03-31 19:20:15 +02:00
|
|
|
* How much time have to pass without emitting a item (i.e. the user stop typing)
|
|
|
|
* to fetch/show the suggestions, in milliseconds.
|
2017-09-03 08:04:18 +02:00
|
|
|
*/
|
2017-09-28 15:06:48 +02:00
|
|
|
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
2020-03-31 19:20:15 +02:00
|
|
|
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
int filterItemCheckedId = -1;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
@State
|
2017-10-08 21:04:37 +02:00
|
|
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
2020-04-02 13:51:10 +02:00
|
|
|
|
|
|
|
// these three represents the current search query
|
2018-07-10 16:26:42 +02:00
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
String searchString;
|
2019-01-29 17:20:30 +01:00
|
|
|
|
|
|
|
/**
|
2020-04-02 13:51:10 +02:00
|
|
|
* No content filter should add like contentFilter = all
|
2019-01-29 17:20:30 +01:00
|
|
|
* be aware of this when implementing an extractor.
|
|
|
|
*/
|
2017-09-03 08:04:18 +02:00
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
String[] contentFilter = new String[0];
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
String sortFilter;
|
|
|
|
|
|
|
|
// these represents the last search
|
2018-07-10 16:26:42 +02:00
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
String lastSearchedString;
|
|
|
|
|
2020-06-06 22:44:04 +02:00
|
|
|
@State
|
2020-06-28 15:15:51 +02:00
|
|
|
String searchSuggestion;
|
2020-06-06 22:44:04 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@State
|
2020-06-06 22:44:04 +02:00
|
|
|
boolean isCorrectedSearch;
|
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
@State
|
|
|
|
MetaInfo[] metaInfo;
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@State
|
2020-04-02 13:51:10 +02:00
|
|
|
boolean wasSearchFocused = false;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2018-07-22 13:55:17 +02:00
|
|
|
private Map<Integer, String> menuItemToFilterName;
|
2018-07-08 14:27:12 +02:00
|
|
|
private StreamingService service;
|
2020-04-15 15:31:53 +02:00
|
|
|
private Page nextPage;
|
2017-09-28 15:06:48 +02:00
|
|
|
private boolean isSuggestionsEnabled = true;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
private Disposable searchDisposable;
|
2017-09-28 15:06:48 +02:00
|
|
|
private Disposable suggestionDisposable;
|
2018-08-28 20:02:25 +02:00
|
|
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
private SuggestionListAdapter suggestionListAdapter;
|
2018-01-27 06:34:17 +01:00
|
|
|
private HistoryRecordManager historyRecordManager;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Views
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-11-03 08:58:21 +01:00
|
|
|
private FragmentSearchBinding searchBinding;
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
private View searchToolbarContainer;
|
2017-09-28 15:06:48 +02:00
|
|
|
private EditText searchEditText;
|
2017-09-03 08:04:18 +02:00
|
|
|
private View searchClear;
|
|
|
|
|
2020-07-31 11:28:22 +02:00
|
|
|
private boolean suggestionsPanelVisible = false;
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private TextWatcher textWatcher;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final SearchFragment searchFragment = new SearchFragment();
|
2018-07-10 16:26:42 +02:00
|
|
|
searchFragment.setQuery(serviceId, searchString, new String[0], "");
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
if (!TextUtils.isEmpty(searchString)) {
|
2017-09-28 15:06:48 +02:00
|
|
|
searchFragment.setSearchOnResume();
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
return searchFragment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set wasLoading to true so when the fragment onResume is called, the initial search is done.
|
|
|
|
*/
|
2017-09-28 15:06:48 +02:00
|
|
|
private void setSearchOnResume() {
|
|
|
|
wasLoading.set(true);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Fragment's LifeCycle
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-11-01 13:55:20 +01:00
|
|
|
public void onAttach(@NonNull final Context context) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onAttach(context);
|
2017-10-30 22:04:58 +01:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
suggestionListAdapter = new SuggestionListAdapter(activity);
|
2020-08-16 10:24:58 +02:00
|
|
|
final SharedPreferences preferences
|
|
|
|
= PreferenceManager.getDefaultSharedPreferences(activity);
|
|
|
|
final boolean isSearchHistoryEnabled = preferences
|
2020-03-31 19:20:15 +02:00
|
|
|
.getBoolean(getString(R.string.enable_search_history_key), true);
|
2017-11-14 19:51:44 +01:00
|
|
|
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
2018-01-27 06:34:17 +01:00
|
|
|
|
|
|
|
historyRecordManager = new HistoryRecordManager(context);
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onCreate(final Bundle savedInstanceState) {
|
2017-09-28 15:06:48 +02:00
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
2020-08-16 10:24:58 +02:00
|
|
|
final SharedPreferences preferences
|
|
|
|
= PreferenceManager.getDefaultSharedPreferences(activity);
|
2020-03-31 19:20:15 +02:00
|
|
|
isSuggestionsEnabled = preferences
|
|
|
|
.getBoolean(getString(R.string.show_search_suggestions_key), true);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
|
|
|
|
@Nullable final Bundle savedInstanceState) {
|
2017-09-03 08:04:18 +02:00
|
|
|
return inflater.inflate(R.layout.fragment_search, container, false);
|
|
|
|
}
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
@Override
|
2020-11-01 13:55:20 +01:00
|
|
|
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
2017-09-28 15:06:48 +02:00
|
|
|
super.onViewCreated(rootView, savedInstanceState);
|
|
|
|
showSearchOnStart();
|
|
|
|
initSearchListeners();
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
wasSearchFocused = searchEditText.hasFocus();
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (searchDisposable != null) {
|
|
|
|
searchDisposable.dispose();
|
|
|
|
}
|
|
|
|
if (suggestionDisposable != null) {
|
|
|
|
suggestionDisposable.dispose();
|
|
|
|
}
|
2020-07-31 11:40:29 +02:00
|
|
|
disposables.clear();
|
2017-09-28 15:06:48 +02:00
|
|
|
hideKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResume() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onResume() called");
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onResume();
|
|
|
|
|
2018-07-08 14:27:12 +02:00
|
|
|
try {
|
|
|
|
service = NewPipe.getService(serviceId);
|
2020-08-16 10:24:58 +02:00
|
|
|
} catch (final Exception e) {
|
2021-01-09 16:33:59 +01:00
|
|
|
ErrorActivity.reportUiErrorInSnackbar(this,
|
2020-12-11 14:55:47 +01:00
|
|
|
"Getting service for id " + serviceId, e);
|
2018-07-08 14:27:12 +02:00
|
|
|
}
|
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
if (!TextUtils.isEmpty(searchString)) {
|
2017-09-03 08:04:18 +02:00
|
|
|
if (wasLoading.getAndSet(false)) {
|
2018-07-10 16:26:42 +02:00
|
|
|
search(searchString, contentFilter, sortFilter);
|
2020-11-18 23:54:16 +01:00
|
|
|
} else if (infoListAdapter.getItemsList().isEmpty()) {
|
2017-09-03 08:04:18 +02:00
|
|
|
if (savedState == null) {
|
2018-07-10 16:26:42 +02:00
|
|
|
search(searchString, contentFilter, sortFilter);
|
2017-09-03 08:04:18 +02:00
|
|
|
} else if (!isLoading.get() && !wasSearchFocused) {
|
|
|
|
infoListAdapter.clearStreamItemList();
|
|
|
|
showEmptyState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-28 15:15:51 +02:00
|
|
|
handleSearchSuggestion();
|
2020-06-06 22:44:04 +02:00
|
|
|
|
2021-01-15 20:57:19 +01:00
|
|
|
disposables.add(showMetaInfoInTextView(metaInfo == null ? null : Arrays.asList(metaInfo),
|
2021-01-15 14:55:05 +01:00
|
|
|
searchBinding.searchMetaInfoTextView, searchBinding.searchMetaInfoSeparator));
|
2020-12-15 17:41:21 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) {
|
|
|
|
initSuggestionObserver();
|
|
|
|
}
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
if (TextUtils.isEmpty(searchString) || wasSearchFocused) {
|
2017-09-28 15:06:48 +02:00
|
|
|
showKeyboardSearch();
|
|
|
|
showSuggestionsPanel();
|
|
|
|
} else {
|
|
|
|
hideKeyboardSearch();
|
|
|
|
hideSuggestionsPanel();
|
|
|
|
}
|
|
|
|
wasSearchFocused = false;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyView() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onDestroyView() called");
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
unsetSearchListeners();
|
2020-11-03 08:58:21 +01:00
|
|
|
|
|
|
|
searchBinding = null;
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onDestroyView();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (searchDisposable != null) {
|
|
|
|
searchDisposable.dispose();
|
|
|
|
}
|
|
|
|
if (suggestionDisposable != null) {
|
|
|
|
suggestionDisposable.dispose();
|
|
|
|
}
|
2020-07-31 11:40:29 +02:00
|
|
|
disposables.clear();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
2020-07-31 11:40:29 +02:00
|
|
|
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
|
|
|
|
if (resultCode == Activity.RESULT_OK
|
|
|
|
&& !TextUtils.isEmpty(searchString)) {
|
|
|
|
search(searchString, contentFilter, sortFilter);
|
|
|
|
} else {
|
|
|
|
Log.e(TAG, "ReCaptcha failed");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Init
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
2017-09-28 15:06:48 +02:00
|
|
|
super.initViews(rootView, savedInstanceState);
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding = FragmentSearchBinding.bind(rootView);
|
|
|
|
|
|
|
|
searchBinding.suggestionsList.setAdapter(suggestionListAdapter);
|
2018-12-29 19:47:13 +01:00
|
|
|
new ItemTouchHelper(new ItemTouchHelper.Callback() {
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public int getMovementFlags(@NonNull final RecyclerView recyclerView,
|
|
|
|
@NonNull final RecyclerView.ViewHolder viewHolder) {
|
2020-07-31 11:40:29 +02:00
|
|
|
return getSuggestionMovementFlags(viewHolder);
|
2018-12-29 19:47:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public boolean onMove(@NonNull final RecyclerView recyclerView,
|
|
|
|
@NonNull final RecyclerView.ViewHolder viewHolder,
|
|
|
|
@NonNull final RecyclerView.ViewHolder viewHolder1) {
|
2018-12-29 19:47:13 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, final int i) {
|
2020-07-31 11:40:29 +02:00
|
|
|
onSuggestionItemSwiped(viewHolder);
|
2018-12-29 19:47:13 +01:00
|
|
|
}
|
2020-11-03 08:58:21 +01:00
|
|
|
}).attachToRecyclerView(searchBinding.suggestionsList);
|
2017-09-28 15:06:48 +02:00
|
|
|
|
|
|
|
searchToolbarContainer = activity.findViewById(R.id.toolbar_search_container);
|
|
|
|
searchEditText = searchToolbarContainer.findViewById(R.id.toolbar_search_edit_text);
|
|
|
|
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// State Saving
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void writeTo(final Queue<Object> objectsToSave) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.writeTo(objectsToSave);
|
2020-04-15 15:31:53 +02:00
|
|
|
objectsToSave.add(nextPage);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void readFrom(@NonNull final Queue<Object> savedObjects) throws Exception {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.readFrom(savedObjects);
|
2020-04-15 15:31:53 +02:00
|
|
|
nextPage = (Page) savedObjects.poll();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-01 13:55:20 +01:00
|
|
|
public void onSaveInstanceState(@NonNull final Bundle bundle) {
|
2018-07-10 16:26:42 +02:00
|
|
|
searchString = searchEditText != null
|
|
|
|
? searchEditText.getText().toString()
|
|
|
|
: searchString;
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onSaveInstanceState(bundle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Init's
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void reloadContent() {
|
2018-07-10 16:26:42 +02:00
|
|
|
if (!TextUtils.isEmpty(searchString)
|
2018-07-08 14:27:12 +02:00
|
|
|
|| (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
|
2018-07-10 16:26:42 +02:00
|
|
|
search(!TextUtils.isEmpty(searchString)
|
|
|
|
? searchString
|
2019-01-29 17:20:30 +01:00
|
|
|
: searchEditText.getText().toString(), this.contentFilter, "");
|
2017-09-03 08:04:18 +02:00
|
|
|
} else {
|
|
|
|
if (searchEditText != null) {
|
|
|
|
searchEditText.setText("");
|
2017-09-28 15:06:48 +02:00
|
|
|
showKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2020-12-11 14:55:47 +01:00
|
|
|
hideErrorPanel();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Menu
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onCreateOptionsMenu(menu, inflater);
|
|
|
|
|
2020-08-16 10:24:58 +02:00
|
|
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
2017-09-03 08:04:18 +02:00
|
|
|
if (supportActionBar != null) {
|
|
|
|
supportActionBar.setDisplayShowTitleEnabled(false);
|
|
|
|
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
|
|
|
}
|
|
|
|
|
2018-07-22 13:55:17 +02:00
|
|
|
menuItemToFilterName = new HashMap<>();
|
|
|
|
|
2018-07-18 15:05:49 +02:00
|
|
|
int itemId = 0;
|
|
|
|
boolean isFirstItem = true;
|
2018-07-19 16:18:57 +02:00
|
|
|
final Context c = getContext();
|
2020-08-16 10:24:58 +02:00
|
|
|
for (final String filter : service.getSearchQHFactory().getAvailableContentFilter()) {
|
2020-12-23 15:14:26 +01:00
|
|
|
if (filter.equals(YoutubeSearchQueryHandlerFactory.MUSIC_SONGS)) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final MenuItem musicItem = menu.add(2,
|
2020-03-21 20:53:30 +01:00
|
|
|
itemId++,
|
|
|
|
0,
|
|
|
|
"YouTube Music");
|
|
|
|
musicItem.setEnabled(false);
|
2020-12-23 15:14:26 +01:00
|
|
|
} else if (filter.equals(PeertubeSearchQueryHandlerFactory.SEPIA_VIDEOS)) {
|
|
|
|
final MenuItem sepiaItem = menu.add(2,
|
|
|
|
itemId++,
|
|
|
|
0,
|
|
|
|
"Sepia Search");
|
|
|
|
sepiaItem.setEnabled(false);
|
2020-03-21 20:53:30 +01:00
|
|
|
}
|
2018-07-22 13:55:17 +02:00
|
|
|
menuItemToFilterName.put(itemId, filter);
|
2020-08-16 10:24:58 +02:00
|
|
|
final MenuItem item = menu.add(1,
|
2018-07-19 16:18:57 +02:00
|
|
|
itemId++,
|
|
|
|
0,
|
|
|
|
ServiceHelper.getTranslatedFilterString(filter, c));
|
2020-03-31 19:20:15 +02:00
|
|
|
if (isFirstItem) {
|
2018-07-18 15:05:49 +02:00
|
|
|
item.setChecked(true);
|
|
|
|
isFirstItem = false;
|
|
|
|
}
|
2018-07-08 14:27:12 +02:00
|
|
|
}
|
2018-07-18 15:05:49 +02:00
|
|
|
menu.setGroupCheckable(1, true, true);
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
restoreFilterChecked(menu, filterItemCheckedId);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final List<String> cf = new ArrayList<>(1);
|
2020-03-31 19:20:15 +02:00
|
|
|
cf.add(menuItemToFilterName.get(item.getItemId()));
|
|
|
|
changeContentFilter(item, cf);
|
2018-07-08 14:27:12 +02:00
|
|
|
|
|
|
|
return true;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
2017-09-03 08:04:18 +02:00
|
|
|
if (itemId != -1) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final MenuItem item = menu.findItem(itemId);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (item == null) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
item.setChecked(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Search
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
private void showSearchOnStart() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "showSearchOnStart() called, searchQuery → "
|
|
|
|
+ searchString
|
|
|
|
+ ", lastSearchedQuery → "
|
|
|
|
+ lastSearchedString);
|
|
|
|
}
|
2018-07-10 16:26:42 +02:00
|
|
|
searchEditText.setText(searchString);
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
if (TextUtils.isEmpty(searchString) || TextUtils.isEmpty(searchEditText.getText())) {
|
2017-09-03 08:04:18 +02:00
|
|
|
searchToolbarContainer.setTranslationX(100);
|
2020-06-27 05:25:50 +02:00
|
|
|
searchToolbarContainer.setAlpha(0.0f);
|
2017-09-03 08:04:18 +02:00
|
|
|
searchToolbarContainer.setVisibility(View.VISIBLE);
|
2018-07-10 16:26:42 +02:00
|
|
|
searchToolbarContainer.animate()
|
|
|
|
.translationX(0)
|
2020-06-27 05:25:50 +02:00
|
|
|
.alpha(1.0f)
|
2018-07-10 16:26:42 +02:00
|
|
|
.setDuration(200)
|
|
|
|
.setInterpolator(new DecelerateInterpolator()).start();
|
2017-09-03 08:04:18 +02:00
|
|
|
} else {
|
|
|
|
searchToolbarContainer.setTranslationX(0);
|
2020-06-27 05:25:50 +02:00
|
|
|
searchToolbarContainer.setAlpha(1.0f);
|
2017-09-03 08:04:18 +02:00
|
|
|
searchToolbarContainer.setVisibility(View.VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initSearchListeners() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "initSearchListeners() called");
|
|
|
|
}
|
2018-07-08 14:27:12 +02:00
|
|
|
searchClear.setOnClickListener(v -> {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
|
|
|
}
|
2018-07-08 14:27:12 +02:00
|
|
|
if (TextUtils.isEmpty(searchEditText.getText())) {
|
2020-08-03 14:47:02 +02:00
|
|
|
NavigationHelper.gotoMainFragment(getFM());
|
2018-07-08 14:27:12 +02:00
|
|
|
return;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2018-07-08 14:27:12 +02:00
|
|
|
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setVisibility(View.GONE);
|
2020-04-21 01:06:10 +02:00
|
|
|
|
2018-07-08 14:27:12 +02:00
|
|
|
searchEditText.setText("");
|
|
|
|
suggestionListAdapter.setItems(new ArrayList<>());
|
|
|
|
showKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
TooltipCompat.setTooltipText(searchClear, getString(R.string.clear));
|
|
|
|
|
2018-07-08 14:27:12 +02:00
|
|
|
searchEditText.setOnClickListener(v -> {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
|
|
|
}
|
2020-12-11 14:55:47 +01:00
|
|
|
if (isSuggestionsEnabled && !isErrorPanelVisible()) {
|
2018-07-08 14:27:12 +02:00
|
|
|
showSuggestionsPanel();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2020-07-21 00:43:49 +02:00
|
|
|
if (DeviceUtils.isTv(getContext())) {
|
2019-02-01 14:02:28 +01:00
|
|
|
showKeyboardSearch();
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
});
|
|
|
|
|
2018-07-08 14:27:12 +02:00
|
|
|
searchEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onFocusChange() called with: "
|
|
|
|
+ "v = [" + v + "], hasFocus = [" + hasFocus + "]");
|
|
|
|
}
|
2020-12-11 14:55:47 +01:00
|
|
|
if (isSuggestionsEnabled && hasFocus && !isErrorPanelVisible()) {
|
2018-07-08 14:27:12 +02:00
|
|
|
showSuggestionsPanel();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
suggestionListAdapter.setListener(new SuggestionListAdapter.OnSuggestionItemSelected() {
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSuggestionItemSelected(final SuggestionItem item) {
|
2018-07-10 16:26:42 +02:00
|
|
|
search(item.query, new String[0], "");
|
2017-09-28 15:06:48 +02:00
|
|
|
searchEditText.setText(item.query);
|
|
|
|
}
|
|
|
|
|
2017-11-14 19:51:44 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSuggestionItemInserted(final SuggestionItem item) {
|
2017-11-14 19:51:44 +01:00
|
|
|
searchEditText.setText(item.query);
|
2017-11-15 00:58:13 +01:00
|
|
|
searchEditText.setSelection(searchEditText.getText().length());
|
2017-11-14 19:51:44 +01:00
|
|
|
}
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSuggestionItemLongClick(final SuggestionItem item) {
|
|
|
|
if (item.fromHistory) {
|
|
|
|
showDeleteSuggestionDialog(item);
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (textWatcher != null) {
|
|
|
|
searchEditText.removeTextChangedListener(textWatcher);
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
textWatcher = new TextWatcher() {
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void beforeTextChanged(final CharSequence s, final int start,
|
2020-04-21 01:06:10 +02:00
|
|
|
final int count, final int after) {
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onTextChanged(final CharSequence s, final int start,
|
2020-04-21 01:06:10 +02:00
|
|
|
final int before, final int count) {
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void afterTextChanged(final Editable s) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final String newText = searchEditText.getText().toString();
|
2017-09-28 15:06:48 +02:00
|
|
|
suggestionPublisher.onNext(newText);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
searchEditText.addTextChangedListener(textWatcher);
|
2018-07-08 14:27:12 +02:00
|
|
|
searchEditText.setOnEditorActionListener(
|
|
|
|
(TextView v, int actionId, KeyEvent event) -> {
|
|
|
|
if (DEBUG) {
|
2020-03-31 19:20:15 +02:00
|
|
|
Log.d(TAG, "onEditorAction() called with: v = [" + v + "], "
|
|
|
|
+ "actionId = [" + actionId + "], event = [" + event + "]");
|
2018-07-08 14:27:12 +02:00
|
|
|
}
|
2020-03-31 19:20:15 +02:00
|
|
|
if (actionId == EditorInfo.IME_ACTION_PREVIOUS) {
|
2019-02-01 14:02:28 +01:00
|
|
|
hideKeyboardSearch();
|
|
|
|
} else if (event != null
|
2018-07-08 14:27:12 +02:00
|
|
|
&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|
2020-03-31 19:20:15 +02:00
|
|
|
|| event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
|
2018-07-10 16:26:42 +02:00
|
|
|
search(searchEditText.getText().toString(), new String[0], "");
|
2018-07-08 14:27:12 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) {
|
2018-07-08 14:27:12 +02:00
|
|
|
initSuggestionObserver();
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void unsetSearchListeners() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "unsetSearchListeners() called");
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
searchClear.setOnClickListener(null);
|
|
|
|
searchClear.setOnLongClickListener(null);
|
|
|
|
searchEditText.setOnClickListener(null);
|
|
|
|
searchEditText.setOnFocusChangeListener(null);
|
|
|
|
searchEditText.setOnEditorActionListener(null);
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (textWatcher != null) {
|
|
|
|
searchEditText.removeTextChangedListener(textWatcher);
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
textWatcher = null;
|
|
|
|
}
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
private void showSuggestionsPanel() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "showSuggestionsPanel() called");
|
|
|
|
}
|
2020-07-31 11:28:22 +02:00
|
|
|
suggestionsPanelVisible = true;
|
2021-01-16 04:32:01 +01:00
|
|
|
animate(searchBinding.suggestionsPanel, true, 200,
|
|
|
|
AnimationType.LIGHT_SLIDE_AND_ALPHA);
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
private void hideSuggestionsPanel() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "hideSuggestionsPanel() called");
|
|
|
|
}
|
2020-07-31 11:28:22 +02:00
|
|
|
suggestionsPanelVisible = false;
|
2021-01-16 04:32:01 +01:00
|
|
|
animate(searchBinding.suggestionsPanel, false, 200,
|
|
|
|
AnimationType.LIGHT_SLIDE_AND_ALPHA);
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void showKeyboardSearch() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "showKeyboardSearch() called");
|
|
|
|
}
|
|
|
|
if (searchEditText == null) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-28 15:06:48 +02:00
|
|
|
|
|
|
|
if (searchEditText.requestFocus()) {
|
2020-09-13 13:50:29 +02:00
|
|
|
final InputMethodManager imm = ContextCompat.getSystemService(activity,
|
|
|
|
InputMethodManager.class);
|
2019-02-01 14:02:28 +01:00
|
|
|
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
private void hideKeyboardSearch() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "hideKeyboardSearch() called");
|
|
|
|
}
|
|
|
|
if (searchEditText == null) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-09-13 13:50:29 +02:00
|
|
|
final InputMethodManager imm = ContextCompat.getSystemService(activity,
|
|
|
|
InputMethodManager.class);
|
2020-03-31 19:20:15 +02:00
|
|
|
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(),
|
|
|
|
InputMethodManager.RESULT_UNCHANGED_SHOWN);
|
2017-09-28 15:06:48 +02:00
|
|
|
|
|
|
|
searchEditText.clearFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void showDeleteSuggestionDialog(final SuggestionItem item) {
|
2020-07-31 11:40:29 +02:00
|
|
|
if (activity == null || historyRecordManager == null || searchEditText == null) {
|
2020-03-31 19:20:15 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-02-22 22:30:48 +01:00
|
|
|
final String query = item.query;
|
2017-09-28 15:06:48 +02:00
|
|
|
new AlertDialog.Builder(activity)
|
2018-02-22 22:30:48 +01:00
|
|
|
.setTitle(query)
|
2017-09-28 15:06:48 +02:00
|
|
|
.setMessage(R.string.delete_item_search_history)
|
|
|
|
.setCancelable(true)
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
2018-02-22 22:30:48 +01:00
|
|
|
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
|
|
|
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(
|
|
|
|
howManyDeleted -> suggestionPublisher
|
|
|
|
.onNext(searchEditText.getText().toString()),
|
2020-12-11 14:55:47 +01:00
|
|
|
throwable -> showSnackBarError(new ErrorInfo(throwable,
|
|
|
|
UserAction.DELETE_FROM_HISTORY,
|
|
|
|
"Deleting item failed")));
|
2018-02-22 22:30:48 +01:00
|
|
|
disposables.add(onDelete);
|
|
|
|
})
|
2018-01-27 06:34:17 +01:00
|
|
|
.show();
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
@Override
|
|
|
|
public boolean onBackPressed() {
|
2020-07-31 11:28:22 +02:00
|
|
|
if (suggestionsPanelVisible
|
2018-07-10 16:26:42 +02:00
|
|
|
&& infoListAdapter.getItemsList().size() > 0
|
|
|
|
&& !isLoading.get()) {
|
2017-09-28 15:06:48 +02:00
|
|
|
hideSuggestionsPanel();
|
|
|
|
hideKeyboardSearch();
|
2018-07-10 16:26:42 +02:00
|
|
|
searchEditText.setText(lastSearchedString);
|
2017-09-28 15:06:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void initSuggestionObserver() {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "initSuggestionObserver() called");
|
|
|
|
}
|
|
|
|
if (suggestionDisposable != null) {
|
|
|
|
suggestionDisposable.dispose();
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
final Observable<String> observable = suggestionPublisher
|
2017-09-03 08:04:18 +02:00
|
|
|
.debounce(SUGGESTIONS_DEBOUNCE, TimeUnit.MILLISECONDS)
|
2020-10-31 21:55:45 +01:00
|
|
|
.startWithItem(searchString != null
|
2018-07-10 16:26:42 +02:00
|
|
|
? searchString
|
2018-07-08 14:27:12 +02:00
|
|
|
: "")
|
2020-03-31 19:20:15 +02:00
|
|
|
.filter(ss -> isSuggestionsEnabled);
|
2017-09-28 15:06:48 +02:00
|
|
|
|
|
|
|
suggestionDisposable = observable
|
2018-01-27 06:34:17 +01:00
|
|
|
.switchMap(query -> {
|
|
|
|
final Flowable<List<SearchHistoryEntry>> flowable = historyRecordManager
|
|
|
|
.getRelatedSearches(query, 3, 25);
|
|
|
|
final Observable<List<SuggestionItem>> local = flowable.toObservable()
|
|
|
|
.map(searchHistoryEntries -> {
|
2020-08-16 10:24:58 +02:00
|
|
|
final List<SuggestionItem> result = new ArrayList<>();
|
|
|
|
for (final SearchHistoryEntry entry : searchHistoryEntries) {
|
2018-01-27 06:34:17 +01:00
|
|
|
result.add(new SuggestionItem(true, entry.getSearch()));
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2018-01-27 06:34:17 +01:00
|
|
|
return result;
|
|
|
|
});
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2018-01-27 06:34:17 +01:00
|
|
|
if (query.length() < THRESHOLD_NETWORK_SUGGESTION) {
|
2020-03-31 19:20:15 +02:00
|
|
|
// Only pass through if the query length
|
|
|
|
// is equal or greater than THRESHOLD_NETWORK_SUGGESTION
|
2018-01-27 06:34:17 +01:00
|
|
|
return local.materialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
final Observable<List<SuggestionItem>> network = ExtractorHelper
|
2018-10-05 16:19:21 +02:00
|
|
|
.suggestionsFor(serviceId, query)
|
2020-07-31 11:28:22 +02:00
|
|
|
.onErrorReturn(throwable -> {
|
|
|
|
if (!ExceptionUtils.isNetworkRelated(throwable)) {
|
2020-12-11 14:55:47 +01:00
|
|
|
showSnackBarError(new ErrorInfo(throwable,
|
|
|
|
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
2020-07-31 11:28:22 +02:00
|
|
|
}
|
|
|
|
return new ArrayList<>();
|
|
|
|
})
|
2018-01-27 06:34:17 +01:00
|
|
|
.toObservable()
|
|
|
|
.map(strings -> {
|
2020-08-16 10:24:58 +02:00
|
|
|
final List<SuggestionItem> result = new ArrayList<>();
|
|
|
|
for (final String entry : strings) {
|
2018-01-27 06:34:17 +01:00
|
|
|
result.add(new SuggestionItem(false, entry));
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
|
|
|
return result;
|
2018-01-27 06:34:17 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return Observable.zip(local, network, (localResult, networkResult) -> {
|
2020-08-16 10:24:58 +02:00
|
|
|
final List<SuggestionItem> result = new ArrayList<>();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (localResult.size() > 0) {
|
|
|
|
result.addAll(localResult);
|
|
|
|
}
|
2018-01-27 06:34:17 +01:00
|
|
|
|
|
|
|
// Remove duplicates
|
2020-06-25 14:04:08 +02:00
|
|
|
networkResult.removeIf(networkItem ->
|
|
|
|
localResult.stream().anyMatch(localItem ->
|
|
|
|
localItem.query.equals(networkItem.query)));
|
2018-01-27 06:34:17 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (networkResult.size() > 0) {
|
|
|
|
result.addAll(networkResult);
|
|
|
|
}
|
2018-01-27 06:34:17 +01:00
|
|
|
return result;
|
|
|
|
}).materialize();
|
2017-09-03 08:04:18 +02:00
|
|
|
})
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-01-27 06:34:17 +01:00
|
|
|
.subscribe(listNotification -> {
|
|
|
|
if (listNotification.isOnNext()) {
|
|
|
|
handleSuggestions(listNotification.getValue());
|
|
|
|
} else if (listNotification.isOnError()) {
|
2020-12-11 14:55:47 +01:00
|
|
|
showError(new ErrorInfo(listNotification.getError(),
|
|
|
|
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void doInitialLoadLogic() {
|
|
|
|
// no-op
|
|
|
|
}
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
private void search(final String theSearchString,
|
|
|
|
final String[] theContentFilter,
|
|
|
|
final String theSortFilter) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
2020-07-31 11:40:29 +02:00
|
|
|
Log.d(TAG, "search() called with: query = [" + theSearchString + "]");
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2020-07-31 11:40:29 +02:00
|
|
|
if (theSearchString.isEmpty()) {
|
2020-03-31 19:20:15 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2017-09-15 19:27:39 +02:00
|
|
|
try {
|
2020-07-31 11:40:29 +02:00
|
|
|
final StreamingService streamingService = NewPipe.getServiceByUrl(theSearchString);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (streamingService != null) {
|
2017-09-15 19:27:39 +02:00
|
|
|
showLoading();
|
|
|
|
disposables.add(Observable
|
2020-07-31 11:40:29 +02:00
|
|
|
.fromCallable(() -> NavigationHelper.getIntentByLink(activity,
|
|
|
|
streamingService, theSearchString))
|
2017-09-15 19:27:39 +02:00
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-07-08 14:27:12 +02:00
|
|
|
.subscribe(intent -> {
|
2020-08-03 14:47:02 +02:00
|
|
|
getFM().popBackStackImmediate();
|
2018-07-08 14:27:12 +02:00
|
|
|
activity.startActivity(intent);
|
2020-12-11 14:55:47 +01:00
|
|
|
}, throwable -> showTextError(getString(R.string.unsupported_url))));
|
2017-09-15 19:27:39 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-08-16 10:24:58 +02:00
|
|
|
} catch (final Exception ignored) {
|
2017-09-15 19:27:39 +02:00
|
|
|
// Exception occurred, it's not a url
|
|
|
|
}
|
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
lastSearchedString = this.searchString;
|
2020-07-31 11:40:29 +02:00
|
|
|
this.searchString = theSearchString;
|
2017-09-03 08:04:18 +02:00
|
|
|
infoListAdapter.clearStreamItemList();
|
2017-09-28 15:06:48 +02:00
|
|
|
hideSuggestionsPanel();
|
2021-01-15 14:55:05 +01:00
|
|
|
showMetaInfoInTextView(null, searchBinding.searchMetaInfoTextView,
|
|
|
|
searchBinding.searchMetaInfoSeparator);
|
2017-09-28 15:06:48 +02:00
|
|
|
hideKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
disposables.add(historyRecordManager.onSearched(serviceId, theSearchString)
|
2018-01-27 06:34:17 +01:00
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(
|
2020-12-11 15:07:18 +01:00
|
|
|
ignored -> { },
|
2020-12-11 14:55:47 +01:00
|
|
|
throwable -> showSnackBarError(new ErrorInfo(throwable, UserAction.SEARCHED,
|
|
|
|
theSearchString, serviceId))
|
2020-07-31 11:40:29 +02:00
|
|
|
));
|
|
|
|
suggestionPublisher.onNext(theSearchString);
|
2017-09-03 08:04:18 +02:00
|
|
|
startLoading(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void startLoading(final boolean forceLoad) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.startLoading(forceLoad);
|
2020-07-31 11:40:29 +02:00
|
|
|
disposables.clear();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (searchDisposable != null) {
|
|
|
|
searchDisposable.dispose();
|
|
|
|
}
|
2018-07-10 16:26:42 +02:00
|
|
|
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
2020-03-31 19:20:15 +02:00
|
|
|
searchString,
|
|
|
|
Arrays.asList(contentFilter),
|
|
|
|
sortFilter)
|
2017-09-03 08:04:18 +02:00
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-02-22 22:30:48 +01:00
|
|
|
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
2020-12-11 14:55:47 +01:00
|
|
|
.subscribe(this::handleResult, this::onItemError);
|
2018-07-10 16:26:42 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void loadMoreItems() {
|
2020-04-15 15:31:53 +02:00
|
|
|
if (!Page.isValid(nextPage)) {
|
2020-03-31 19:20:15 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
isLoading.set(true);
|
|
|
|
showListFooter(true);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (searchDisposable != null) {
|
|
|
|
searchDisposable.dispose();
|
|
|
|
}
|
2018-07-10 16:26:42 +02:00
|
|
|
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
2020-03-31 19:20:15 +02:00
|
|
|
serviceId,
|
|
|
|
searchString,
|
|
|
|
asList(contentFilter),
|
|
|
|
sortFilter,
|
2020-04-15 15:31:53 +02:00
|
|
|
nextPage)
|
2017-09-03 08:04:18 +02:00
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-02-22 22:30:48 +01:00
|
|
|
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
2020-12-11 14:55:47 +01:00
|
|
|
.subscribe(this::handleNextItems, this::onItemError);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean hasMoreItems() {
|
2020-07-31 11:40:29 +02:00
|
|
|
return Page.isValid(nextPage);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void onItemSelected(final InfoItem selectedItem) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onItemSelected(selectedItem);
|
2017-09-28 15:06:48 +02:00
|
|
|
hideKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
private void onItemError(final Throwable exception) {
|
|
|
|
if (exception instanceof SearchExtractor.NothingFoundException) {
|
|
|
|
infoListAdapter.clearStreamItemList();
|
|
|
|
showEmptyState();
|
|
|
|
} else {
|
|
|
|
showError(new ErrorInfo(exception, UserAction.SEARCHED, searchString, serviceId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
private void changeContentFilter(final MenuItem item, final List<String> theContentFilter) {
|
|
|
|
filterItemCheckedId = item.getItemId();
|
2017-09-03 08:04:18 +02:00
|
|
|
item.setChecked(true);
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
contentFilter = new String[]{theContentFilter.get(0)};
|
2018-07-08 14:27:12 +02:00
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
if (!TextUtils.isEmpty(searchString)) {
|
2020-07-31 11:40:29 +02:00
|
|
|
search(searchString, contentFilter, sortFilter);
|
2017-09-28 15:06:48 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
private void setQuery(final int theServiceId,
|
|
|
|
final String theSearchString,
|
|
|
|
final String[] theContentFilter,
|
|
|
|
final String theSortFilter) {
|
|
|
|
serviceId = theServiceId;
|
|
|
|
searchString = theSearchString;
|
|
|
|
contentFilter = theContentFilter;
|
|
|
|
sortFilter = theSortFilter;
|
2018-07-08 14:27:12 +02:00
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Suggestion Results
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-28 15:06:48 +02:00
|
|
|
public void handleSuggestions(@NonNull final List<SuggestionItem> suggestions) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "handleSuggestions() called with: suggestions = [" + suggestions + "]");
|
|
|
|
}
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.suggestionsList.smoothScrollToPosition(0);
|
|
|
|
searchBinding.suggestionsList.post(() -> suggestionListAdapter.setItems(suggestions));
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
if (suggestionsPanelVisible && isErrorPanelVisible()) {
|
2017-09-28 15:06:48 +02:00
|
|
|
hideLoading();
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Contract
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void hideLoading() {
|
|
|
|
super.hideLoading();
|
|
|
|
showListFooter(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Search Results
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void handleResult(@NonNull final SearchInfo result) {
|
2018-08-18 14:20:36 +02:00
|
|
|
final List<Throwable> exceptions = result.getErrors();
|
|
|
|
if (!exceptions.isEmpty()
|
2020-03-31 19:20:15 +02:00
|
|
|
&& !(exceptions.size() == 1
|
|
|
|
&& exceptions.get(0) instanceof SearchExtractor.NothingFoundException)) {
|
2020-12-11 14:55:47 +01:00
|
|
|
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
|
|
|
|
searchString, serviceId));
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2020-06-28 15:15:51 +02:00
|
|
|
searchSuggestion = result.getSearchSuggestion();
|
2020-06-06 22:44:04 +02:00
|
|
|
isCorrectedSearch = result.isCorrectedSearch();
|
2020-06-28 15:15:51 +02:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
// List<MetaInfo> cannot be bundled without creating some containers
|
|
|
|
metaInfo = new MetaInfo[result.getMetaInfo().size()];
|
|
|
|
metaInfo = result.getMetaInfo().toArray(metaInfo);
|
2021-01-15 14:55:05 +01:00
|
|
|
disposables.add(showMetaInfoInTextView(result.getMetaInfo(),
|
|
|
|
searchBinding.searchMetaInfoTextView, searchBinding.searchMetaInfoSeparator));
|
2020-12-15 17:41:21 +01:00
|
|
|
|
2020-06-28 15:15:51 +02:00
|
|
|
handleSearchSuggestion();
|
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
lastSearchedString = searchString;
|
2020-04-15 15:31:53 +02:00
|
|
|
nextPage = result.getNextPage();
|
2017-09-28 15:06:48 +02:00
|
|
|
|
2020-11-18 23:54:16 +01:00
|
|
|
if (infoListAdapter.getItemsList().isEmpty()) {
|
2018-07-08 17:46:21 +02:00
|
|
|
if (!result.getRelatedItems().isEmpty()) {
|
|
|
|
infoListAdapter.addInfoItemList(result.getRelatedItems());
|
2017-09-03 08:04:18 +02:00
|
|
|
} else {
|
|
|
|
infoListAdapter.clearStreamItemList();
|
|
|
|
showEmptyState();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
super.handleResult(result);
|
|
|
|
}
|
|
|
|
|
2020-06-28 15:15:51 +02:00
|
|
|
private void handleSearchSuggestion() {
|
2020-07-05 00:44:40 +02:00
|
|
|
if (TextUtils.isEmpty(searchSuggestion)) {
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setVisibility(View.GONE);
|
2020-07-05 00:44:40 +02:00
|
|
|
} else {
|
2020-06-28 15:15:51 +02:00
|
|
|
final String helperText = getString(isCorrectedSearch
|
2020-04-21 01:06:10 +02:00
|
|
|
? R.string.search_showing_result_for
|
|
|
|
: R.string.did_you_mean);
|
|
|
|
|
2020-07-07 20:23:37 +02:00
|
|
|
final String highlightedSearchSuggestion =
|
2020-08-27 22:59:09 +02:00
|
|
|
"<b><i>" + Html.escapeHtml(searchSuggestion) + "</i></b>";
|
|
|
|
final String text = String.format(helperText, highlightedSearchSuggestion);
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setText(HtmlCompat.fromHtml(text,
|
|
|
|
HtmlCompat.FROM_HTML_MODE_LEGACY));
|
2020-04-21 01:06:10 +02:00
|
|
|
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setOnClickListener(v -> {
|
|
|
|
searchBinding.correctSuggestion.setVisibility(View.GONE);
|
2020-06-06 22:44:04 +02:00
|
|
|
search(searchSuggestion, contentFilter, sortFilter);
|
|
|
|
searchEditText.setText(searchSuggestion);
|
2020-04-21 01:06:10 +02:00
|
|
|
});
|
|
|
|
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setOnLongClickListener(v -> {
|
2020-07-05 00:44:40 +02:00
|
|
|
searchEditText.setText(searchSuggestion);
|
|
|
|
searchEditText.setSelection(searchSuggestion.length());
|
|
|
|
showKeyboardSearch();
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2020-11-03 08:58:21 +01:00
|
|
|
searchBinding.correctSuggestion.setVisibility(View.VISIBLE);
|
2020-04-21 01:06:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2020-07-31 11:40:29 +02:00
|
|
|
public void handleNextItems(final ListExtractor.InfoItemsPage<?> result) {
|
2017-09-03 08:04:18 +02:00
|
|
|
showListFooter(false);
|
2018-03-18 16:37:49 +01:00
|
|
|
infoListAdapter.addInfoItemList(result.getItems());
|
2020-04-15 15:31:53 +02:00
|
|
|
nextPage = result.getNextPage();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
if (!result.getErrors().isEmpty()) {
|
2020-12-11 14:55:47 +01:00
|
|
|
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
|
2020-04-15 15:31:53 +02:00
|
|
|
"\"" + searchString + "\" → pageUrl: " + nextPage.getUrl() + ", "
|
|
|
|
+ "pageIds: " + nextPage.getIds() + ", "
|
2020-12-11 14:55:47 +01:00
|
|
|
+ "pageCookies: " + nextPage.getCookies(),
|
|
|
|
serviceId));
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
super.handleNextItems(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-11 14:55:47 +01:00
|
|
|
public void handleError() {
|
|
|
|
super.handleError();
|
|
|
|
hideSuggestionsPanel();
|
|
|
|
hideKeyboardSearch();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2018-12-29 19:47:13 +01:00
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Suggestion item touch helper
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
public int getSuggestionMovementFlags(@NonNull final RecyclerView.ViewHolder viewHolder) {
|
2018-12-29 19:47:13 +01:00
|
|
|
final int position = viewHolder.getAdapterPosition();
|
2020-06-07 21:28:54 +02:00
|
|
|
if (position == RecyclerView.NO_POSITION) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-29 19:47:13 +01:00
|
|
|
final SuggestionItem item = suggestionListAdapter.getItem(position);
|
2020-03-31 19:20:15 +02:00
|
|
|
return item.fromHistory ? makeMovementFlags(0,
|
|
|
|
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) : 0;
|
2018-12-29 19:47:13 +01:00
|
|
|
}
|
|
|
|
|
2020-07-31 11:40:29 +02:00
|
|
|
public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHolder) {
|
2018-12-29 19:47:13 +01:00
|
|
|
final int position = viewHolder.getAdapterPosition();
|
|
|
|
final String query = suggestionListAdapter.getItem(position).query;
|
|
|
|
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(
|
|
|
|
howManyDeleted -> suggestionPublisher
|
|
|
|
.onNext(searchEditText.getText().toString()),
|
2020-12-11 14:55:47 +01:00
|
|
|
throwable -> showSnackBarError(new ErrorInfo(throwable,
|
|
|
|
UserAction.DELETE_FROM_HISTORY, "Deleting item failed")));
|
2018-12-29 19:47:13 +01:00
|
|
|
disposables.add(onDelete);
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|