mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-24 07:56:57 +00:00
searchfilters: replace old filter interaction and integrate new dialog into SearchFragment
There is also a configuration option to choose between different search UI's
This commit is contained in:
parent
94511671cf
commit
6bcca69563
@ -3,7 +3,6 @@ package org.schabi.newpipe.fragments.list.search;
|
|||||||
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
|
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -33,16 +32,18 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.TooltipCompat;
|
import androidx.appcompat.widget.TooltipCompat;
|
||||||
import androidx.collection.SparseArrayCompat;
|
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.FragmentSearchBinding;
|
import org.schabi.newpipe.databinding.FragmentSearchBinding;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
|
||||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
@ -53,10 +54,13 @@ import org.schabi.newpipe.extractor.Page;
|
|||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.search.SearchInfo;
|
import org.schabi.newpipe.extractor.search.SearchInfo;
|
||||||
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
|
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
|
|
||||||
import org.schabi.newpipe.fragments.BackPressable;
|
import org.schabi.newpipe.fragments.BackPressable;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||||
|
import org.schabi.newpipe.fragments.list.search.filter.SearchFilterChipDialogFragment;
|
||||||
|
import org.schabi.newpipe.fragments.list.search.filter.SearchFilterDialogFragment;
|
||||||
|
import org.schabi.newpipe.fragments.list.search.filter.SearchFilterLogic;
|
||||||
|
import org.schabi.newpipe.fragments.list.search.filter.SearchFilterOptionMenuAlikeDialogFragment;
|
||||||
import org.schabi.newpipe.ktx.AnimationType;
|
import org.schabi.newpipe.ktx.AnimationType;
|
||||||
import org.schabi.newpipe.ktx.ExceptionUtils;
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
@ -66,7 +70,6 @@ import org.schabi.newpipe.util.DeviceUtils;
|
|||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.KeyboardUtil;
|
import org.schabi.newpipe.util.KeyboardUtil;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -104,9 +107,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
||||||
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
||||||
|
|
||||||
@State
|
|
||||||
int filterItemCheckedId = -1;
|
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
|
|
||||||
@ -114,15 +114,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
@State
|
@State
|
||||||
String searchString;
|
String searchString;
|
||||||
|
|
||||||
/**
|
List<FilterItem> selectedContentFilter = new ArrayList<>();
|
||||||
* No content filter should add like contentFilter = all
|
|
||||||
* be aware of this when implementing an extractor.
|
|
||||||
*/
|
|
||||||
@State
|
|
||||||
String[] contentFilter = new String[0];
|
|
||||||
|
|
||||||
@State
|
List<FilterItem> selectedSortFilter = new ArrayList<>();
|
||||||
String sortFilter;
|
|
||||||
|
|
||||||
// these represents the last search
|
// these represents the last search
|
||||||
@State
|
@State
|
||||||
@ -140,8 +134,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
@State
|
@State
|
||||||
boolean wasSearchFocused = false;
|
boolean wasSearchFocused = false;
|
||||||
|
|
||||||
private final SparseArrayCompat<String> menuItemToFilterName = new SparseArrayCompat<>();
|
|
||||||
private StreamingService service;
|
|
||||||
private Page nextPage;
|
private Page nextPage;
|
||||||
private boolean showLocalSuggestions = true;
|
private boolean showLocalSuggestions = true;
|
||||||
private boolean showRemoteSuggestions = true;
|
private boolean showRemoteSuggestions = true;
|
||||||
@ -159,7 +151,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
private FragmentSearchBinding searchBinding;
|
private FragmentSearchBinding searchBinding;
|
||||||
|
|
||||||
private View searchToolbarContainer;
|
protected View searchToolbarContainer;
|
||||||
private EditText searchEditText;
|
private EditText searchEditText;
|
||||||
private View searchClear;
|
private View searchClear;
|
||||||
|
|
||||||
@ -173,9 +165,32 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
*/
|
*/
|
||||||
private TextWatcher textWatcher;
|
private TextWatcher textWatcher;
|
||||||
|
|
||||||
|
@State
|
||||||
|
ArrayList<Integer> userSelectedContentFilterList;
|
||||||
|
|
||||||
|
@State
|
||||||
|
ArrayList<Integer> userSelectedSortFilterList = null;
|
||||||
|
|
||||||
|
protected SearchViewModel searchViewModel;
|
||||||
|
protected SearchFilterLogic.Factory.Variant logicVariant =
|
||||||
|
SearchFilterLogic.Factory.Variant.SEARCH_FILTER_LOGIC_DEFAULT;
|
||||||
|
|
||||||
|
|
||||||
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
||||||
final SearchFragment searchFragment = new SearchFragment();
|
final SearchFragment searchFragment;
|
||||||
searchFragment.setQuery(serviceId, searchString, new String[0], "");
|
final App app = App.getApp();
|
||||||
|
|
||||||
|
|
||||||
|
final String searchUi = PreferenceManager.getDefaultSharedPreferences(app)
|
||||||
|
.getString(app.getString(R.string.search_filter_ui_key),
|
||||||
|
app.getString(R.string.search_filter_ui_value));
|
||||||
|
if (app.getString(R.string.search_filter_ui_option_menu_legacy_key).equals(searchUi)) {
|
||||||
|
searchFragment = new SearchFragmentLegacy();
|
||||||
|
} else {
|
||||||
|
searchFragment = new SearchFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFragment.setQuery(serviceId, searchString);
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(searchString)) {
|
if (!TextUtils.isEmpty(searchString)) {
|
||||||
searchFragment.setSearchOnResume();
|
searchFragment.setSearchOnResume();
|
||||||
@ -208,11 +223,53 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
|
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||||
|
@Nullable final ViewGroup container,
|
||||||
@Nullable final Bundle savedInstanceState) {
|
@Nullable final Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
if (userSelectedContentFilterList == null) {
|
||||||
|
userSelectedContentFilterList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSelectedSortFilterList == null) {
|
||||||
|
userSelectedSortFilterList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
initViewModel();
|
||||||
|
|
||||||
|
// observe the content/sort filter items lists
|
||||||
|
searchViewModel.getSelectedContentFilterItemListLiveData().observe(
|
||||||
|
getViewLifecycleOwner(), filterItems -> selectedContentFilter = filterItems);
|
||||||
|
searchViewModel.getSelectedSortFilterItemListLiveData().observe(
|
||||||
|
getViewLifecycleOwner(), filterItems -> selectedSortFilter = filterItems);
|
||||||
|
|
||||||
|
// the content/sort filters ids lists are only
|
||||||
|
// observed here to store them via Icepick
|
||||||
|
searchViewModel.getUserSelectedContentFilterListLiveData().observe(
|
||||||
|
getViewLifecycleOwner(), filterIds -> userSelectedContentFilterList = filterIds);
|
||||||
|
searchViewModel.getUserSelectedSortFilterListLiveData().observe(
|
||||||
|
getViewLifecycleOwner(), filterIds -> userSelectedSortFilterList = filterIds);
|
||||||
|
|
||||||
|
searchViewModel.getDoSearchLiveData().observe(
|
||||||
|
getViewLifecycleOwner(), doSearch -> {
|
||||||
|
if (doSearch) {
|
||||||
|
selectedFilters(selectedContentFilter, selectedSortFilter);
|
||||||
|
searchViewModel.weConsumedDoSearchLiveData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_search, container, false);
|
return inflater.inflate(R.layout.fragment_search, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void initViewModel() {
|
||||||
|
searchViewModel = new ViewModelProvider(this, SearchViewModel.Companion
|
||||||
|
.getFactory(serviceId,
|
||||||
|
logicVariant,
|
||||||
|
userSelectedContentFilterList,
|
||||||
|
userSelectedSortFilterList))
|
||||||
|
.get(SearchViewModel.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
||||||
searchBinding = FragmentSearchBinding.bind(rootView);
|
searchBinding = FragmentSearchBinding.bind(rootView);
|
||||||
@ -221,22 +278,12 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
initSearchListeners();
|
initSearchListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateService() {
|
|
||||||
try {
|
|
||||||
service = NewPipe.getService(serviceId);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
ErrorUtil.showUiErrorSnackbar(this, "Getting service for id " + serviceId, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onStart() called");
|
Log.d(TAG, "onStart() called");
|
||||||
}
|
}
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
updateService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -268,11 +315,11 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
if (!TextUtils.isEmpty(searchString)) {
|
if (!TextUtils.isEmpty(searchString)) {
|
||||||
if (wasLoading.getAndSet(false)) {
|
if (wasLoading.getAndSet(false)) {
|
||||||
search(searchString, contentFilter, sortFilter);
|
search(searchString);
|
||||||
return;
|
return;
|
||||||
} else if (infoListAdapter.getItemsList().isEmpty()) {
|
} else if (infoListAdapter.getItemsList().isEmpty()) {
|
||||||
if (savedState == null) {
|
if (savedState == null) {
|
||||||
search(searchString, contentFilter, sortFilter);
|
search(searchString);
|
||||||
return;
|
return;
|
||||||
} else if (!isLoading.get() && !wasSearchFocused && lastPanelError == null) {
|
} else if (!isLoading.get() && !wasSearchFocused && lastPanelError == null) {
|
||||||
infoListAdapter.clearStreamItemList();
|
infoListAdapter.clearStreamItemList();
|
||||||
@ -325,7 +372,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
|
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
|
||||||
if (resultCode == Activity.RESULT_OK
|
if (resultCode == Activity.RESULT_OK
|
||||||
&& !TextUtils.isEmpty(searchString)) {
|
&& !TextUtils.isEmpty(searchString)) {
|
||||||
search(searchString, contentFilter, sortFilter);
|
search(searchString);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "ReCaptcha failed");
|
Log.e(TAG, "ReCaptcha failed");
|
||||||
}
|
}
|
||||||
@ -391,6 +438,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
searchString = searchEditText != null
|
searchString = searchEditText != null
|
||||||
? searchEditText.getText().toString()
|
? searchEditText.getText().toString()
|
||||||
: searchString;
|
: searchString;
|
||||||
|
|
||||||
super.onSaveInstanceState(bundle);
|
super.onSaveInstanceState(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +452,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|| (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
|
|| (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
|
||||||
search(!TextUtils.isEmpty(searchString)
|
search(!TextUtils.isEmpty(searchString)
|
||||||
? searchString
|
? searchString
|
||||||
: searchEditText.getText().toString(), this.contentFilter, "");
|
: searchEditText.getText().toString());
|
||||||
} else {
|
} else {
|
||||||
if (searchEditText != null) {
|
if (searchEditText != null) {
|
||||||
searchEditText.setText("");
|
searchEditText.setText("");
|
||||||
@ -429,60 +477,22 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int itemId = 0;
|
createMenu(menu, inflater);
|
||||||
boolean isFirstItem = true;
|
}
|
||||||
final Context c = getContext();
|
|
||||||
|
|
||||||
if (service == null) {
|
protected void createMenu(@NonNull final Menu menu,
|
||||||
Log.w(TAG, "onCreateOptionsMenu() called with null service");
|
@NonNull final MenuInflater inflater) {
|
||||||
updateService();
|
inflater.inflate(R.menu.menu_search_fragment, menu);
|
||||||
}
|
|
||||||
|
|
||||||
for (final String filter : service.getSearchQHFactory().getAvailableContentFilter()) {
|
|
||||||
if (filter.equals(YoutubeSearchQueryHandlerFactory.MUSIC_SONGS)) {
|
|
||||||
final MenuItem musicItem = menu.add(2,
|
|
||||||
itemId++,
|
|
||||||
0,
|
|
||||||
"YouTube Music");
|
|
||||||
musicItem.setEnabled(false);
|
|
||||||
} else if (filter.equals(PeertubeSearchQueryHandlerFactory.SEPIA_VIDEOS)) {
|
|
||||||
final MenuItem sepiaItem = menu.add(2,
|
|
||||||
itemId++,
|
|
||||||
0,
|
|
||||||
"Sepia Search");
|
|
||||||
sepiaItem.setEnabled(false);
|
|
||||||
}
|
|
||||||
menuItemToFilterName.put(itemId, filter);
|
|
||||||
final MenuItem item = menu.add(1,
|
|
||||||
itemId++,
|
|
||||||
0,
|
|
||||||
ServiceHelper.getTranslatedFilterString(filter, c));
|
|
||||||
if (isFirstItem) {
|
|
||||||
item.setChecked(true);
|
|
||||||
isFirstItem = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu.setGroupCheckable(1, true, true);
|
|
||||||
|
|
||||||
restoreFilterChecked(menu, filterItemCheckedId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
|
||||||
final var filter = Collections.singletonList(menuItemToFilterName.get(item.getItemId()));
|
if (item.getItemId() == R.id.action_filter) {
|
||||||
changeContentFilter(item, filter);
|
hideKeyboardSearch();
|
||||||
return true;
|
showSelectFiltersDialog();
|
||||||
}
|
return false;
|
||||||
|
|
||||||
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
|
||||||
if (itemId != -1) {
|
|
||||||
final MenuItem item = menu.findItem(itemId);
|
|
||||||
if (item == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.setChecked(true);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
@ -562,7 +572,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
suggestionListAdapter.setListener(new SuggestionListAdapter.OnSuggestionItemSelected() {
|
suggestionListAdapter.setListener(new SuggestionListAdapter.OnSuggestionItemSelected() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuggestionItemSelected(final SuggestionItem item) {
|
public void onSuggestionItemSelected(final SuggestionItem item) {
|
||||||
search(item.query, new String[0], "");
|
search(item.query);
|
||||||
searchEditText.setText(item.query);
|
searchEditText.setText(item.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +629,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
} else if (event != null
|
} else if (event != null
|
||||||
&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|
&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|
||||||
|| event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
|
|| event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
|
||||||
search(searchEditText.getText().toString(), new String[0], "");
|
search(searchEditText.getText().toString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -671,7 +681,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
KeyboardUtil.showKeyboard(activity, searchEditText);
|
KeyboardUtil.showKeyboard(activity, searchEditText);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideKeyboardSearch() {
|
protected void hideKeyboardSearch() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "hideKeyboardSearch() called");
|
Log.d(TAG, "hideKeyboardSearch() called");
|
||||||
}
|
}
|
||||||
@ -805,9 +815,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
private void search(final String theSearchString,
|
private void search(final String theSearchString) {
|
||||||
final String[] theContentFilter,
|
|
||||||
final String theSortFilter) {
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "search() called with: query = [" + theSearchString + "]");
|
Log.d(TAG, "search() called with: query = [" + theSearchString + "]");
|
||||||
}
|
}
|
||||||
@ -862,13 +870,12 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
}
|
}
|
||||||
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
Arrays.asList(contentFilter),
|
selectedContentFilter,
|
||||||
sortFilter)
|
selectedSortFilter)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
||||||
.subscribe(this::handleResult, this::onItemError);
|
.subscribe(this::handleResult, this::onItemError);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -884,8 +891,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
||||||
serviceId,
|
serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
asList(contentFilter),
|
selectedContentFilter,
|
||||||
sortFilter,
|
selectedSortFilter,
|
||||||
nextPage)
|
nextPage)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -917,25 +924,21 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void changeContentFilter(final MenuItem item, final List<String> theContentFilter) {
|
public void selectedFilters(@NonNull final List<FilterItem> theSelectedContentFilter,
|
||||||
filterItemCheckedId = item.getItemId();
|
@NonNull final List<FilterItem> theSelectedSortFilter) {
|
||||||
item.setChecked(true);
|
|
||||||
|
|
||||||
contentFilter = theContentFilter.toArray(new String[0]);
|
selectedContentFilter = theSelectedContentFilter;
|
||||||
|
selectedSortFilter = theSelectedSortFilter;
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(searchString)) {
|
if (!TextUtils.isEmpty(searchString)) {
|
||||||
search(searchString, contentFilter, sortFilter);
|
search(searchString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setQuery(final int theServiceId,
|
private void setQuery(final int theServiceId,
|
||||||
final String theSearchString,
|
final String theSearchString) {
|
||||||
final String[] theContentFilter,
|
|
||||||
final String theSortFilter) {
|
|
||||||
serviceId = theServiceId;
|
serviceId = theServiceId;
|
||||||
searchString = theSearchString;
|
searchString = theSearchString;
|
||||||
contentFilter = theContentFilter;
|
|
||||||
sortFilter = theSortFilter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
@ -1020,7 +1023,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
searchBinding.correctSuggestion.setOnClickListener(v -> {
|
searchBinding.correctSuggestion.setOnClickListener(v -> {
|
||||||
searchBinding.correctSuggestion.setVisibility(View.GONE);
|
searchBinding.correctSuggestion.setVisibility(View.GONE);
|
||||||
search(searchSuggestion, contentFilter, sortFilter);
|
search(searchSuggestion);
|
||||||
searchEditText.setText(searchSuggestion);
|
searchEditText.setText(searchSuggestion);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1085,4 +1088,22 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
UserAction.DELETE_FROM_HISTORY, "Deleting item failed")));
|
UserAction.DELETE_FROM_HISTORY, "Deleting item failed")));
|
||||||
disposables.add(onDelete);
|
disposables.add(onDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showSelectFiltersDialog() {
|
||||||
|
final FragmentManager fragmentManager = getChildFragmentManager();
|
||||||
|
final DialogFragment searchFilterUiDialog;
|
||||||
|
|
||||||
|
final String searchUi = PreferenceManager.getDefaultSharedPreferences(App.getApp())
|
||||||
|
.getString(getString(R.string.search_filter_ui_key),
|
||||||
|
getString(R.string.search_filter_ui_value));
|
||||||
|
if (getString(R.string.search_filter_ui_option_menu_style_key).equals(searchUi)) {
|
||||||
|
searchFilterUiDialog = new SearchFilterOptionMenuAlikeDialogFragment();
|
||||||
|
} else if (getString(R.string.search_filter_ui_chip_dialog_key).equals(searchUi)) {
|
||||||
|
searchFilterUiDialog = new SearchFilterChipDialogFragment();
|
||||||
|
} else { // default dialog
|
||||||
|
searchFilterUiDialog = new SearchFilterDialogFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFilterUiDialog.show(fragmentManager, "fragment_search");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ import android.util.Log;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
@ -74,8 +76,8 @@ public final class ExtractorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Single<SearchInfo> searchFor(final int serviceId, final String searchString,
|
public static Single<SearchInfo> searchFor(final int serviceId, final String searchString,
|
||||||
final List<String> contentFilter,
|
final List<FilterItem> contentFilter,
|
||||||
final String sortFilter) {
|
final List<FilterItem> sortFilter) {
|
||||||
checkServiceId(serviceId);
|
checkServiceId(serviceId);
|
||||||
return Single.fromCallable(() ->
|
return Single.fromCallable(() ->
|
||||||
SearchInfo.getInfo(NewPipe.getService(serviceId),
|
SearchInfo.getInfo(NewPipe.getService(serviceId),
|
||||||
@ -87,8 +89,8 @@ public final class ExtractorHelper {
|
|||||||
public static Single<InfoItemsPage<InfoItem>> getMoreSearchItems(
|
public static Single<InfoItemsPage<InfoItem>> getMoreSearchItems(
|
||||||
final int serviceId,
|
final int serviceId,
|
||||||
final String searchString,
|
final String searchString,
|
||||||
final List<String> contentFilter,
|
final List<FilterItem> contentFilter,
|
||||||
final String sortFilter,
|
final List<FilterItem> sortFilter,
|
||||||
final Page page) {
|
final Page page) {
|
||||||
checkServiceId(serviceId);
|
checkServiceId(serviceId);
|
||||||
return Single.fromCallable(() ->
|
return Single.fromCallable(() ->
|
||||||
|
9
app/src/main/res/menu/menu_search_fragment.xml
Normal file
9
app/src/main/res/menu/menu_search_fragment.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_filter"
|
||||||
|
android:title="@string/filter"
|
||||||
|
android:icon="@drawable/ic_sort"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</menu>
|
@ -1383,6 +1383,28 @@
|
|||||||
<item>@string/card</item>
|
<item>@string/card</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string name="search_filter_ui_key">search_filter_ui</string>
|
||||||
|
<string name="search_filter_ui_value">@string/search_filter_ui_dialog_key</string>
|
||||||
|
|
||||||
|
<string name="search_filter_ui_dialog_key">dialog</string>
|
||||||
|
<string name="search_filter_ui_option_menu_style_key">style</string>
|
||||||
|
<string name="search_filter_ui_option_menu_legacy_key">legacy</string>
|
||||||
|
<string name="search_filter_ui_chip_dialog_key">chip</string>
|
||||||
|
|
||||||
|
<string-array name="search_filter_ui_values">
|
||||||
|
<item>@string/search_filter_ui_dialog_key</item>
|
||||||
|
<item>@string/search_filter_ui_option_menu_style_key</item>
|
||||||
|
<item>@string/search_filter_ui_option_menu_legacy_key</item>
|
||||||
|
<item>@string/search_filter_ui_chip_dialog_key</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="search_filter_ui_description">
|
||||||
|
<item>@string/search_filter_ui_dialog</item>
|
||||||
|
<item>@string/search_filter_ui_style</item>
|
||||||
|
<item>@string/search_filter_ui_legacy</item>
|
||||||
|
<item>@string/search_filter_ui_chip_dialog</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string name="tablet_mode_key">tablet_mode</string>
|
<string name="tablet_mode_key">tablet_mode</string>
|
||||||
|
|
||||||
<string name="tablet_mode_auto_key">auto</string>
|
<string name="tablet_mode_auto_key">auto</string>
|
||||||
|
@ -907,4 +907,16 @@
|
|||||||
<string name="search_filters_yes">Yes</string>
|
<string name="search_filters_yes">Yes</string>
|
||||||
<string name="search_filters_youtube_music">YouTube Music</string>
|
<string name="search_filters_youtube_music">YouTube Music</string>
|
||||||
<!-- end - strings for search filter feature (NewPipeExtractor Services) -->
|
<!-- end - strings for search filter feature (NewPipeExtractor Services) -->
|
||||||
|
|
||||||
|
<!-- begin - strings for search filter UI -->
|
||||||
|
<string name="filter">Filter</string>
|
||||||
|
<string name="filter_search_sort_filters">Sort filters</string>
|
||||||
|
<string name="filter_search_content_filters">Content filters</string>
|
||||||
|
<string name="search_filter_ui">Select Search Filter UI</string>
|
||||||
|
<string name="search_filter_ui_dialog">Simple Dialog (default)</string>
|
||||||
|
<string name="search_filter_ui_style">Action Menu styled Dialog</string>
|
||||||
|
<string name="search_filter_ui_legacy">Action Menu (legacy)</string>
|
||||||
|
<string name="search_filter_ui_chip_dialog">Chip Dialog</string>
|
||||||
|
<!-- end - strings for search filter UI -->
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -66,6 +66,16 @@
|
|||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/search_filter_ui_dialog_key"
|
||||||
|
android:entries="@array/search_filter_ui_description"
|
||||||
|
android:entryValues="@array/search_filter_ui_values"
|
||||||
|
android:key="@string/search_filter_ui_key"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/search_filter_ui"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="@string/main_tabs_position_key"
|
android:key="@string/main_tabs_position_key"
|
||||||
|
Loading…
Reference in New Issue
Block a user