diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 4bae6f1ca..09c852763 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -3,7 +3,6 @@ package org.schabi.newpipe.fragments.list.search; import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; -import static java.util.Arrays.asList; import android.app.Activity; import android.content.Context; @@ -33,16 +32,18 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.TooltipCompat; -import androidx.collection.SparseArrayCompat; 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.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.FragmentSearchBinding; import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; 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.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchInfo; -import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; -import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory; +import org.schabi.newpipe.extractor.search.filter.FilterItem; import org.schabi.newpipe.fragments.BackPressable; 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.ExceptionUtils; 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.KeyboardUtil; import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.util.ServiceHelper; import java.util.ArrayList; import java.util.Arrays; @@ -104,9 +107,6 @@ public class SearchFragment extends BaseListFragment suggestionPublisher = PublishSubject.create(); - @State - int filterItemCheckedId = -1; - @State protected int serviceId = Constants.NO_SERVICE_ID; @@ -114,15 +114,9 @@ public class SearchFragment extends BaseListFragment selectedContentFilter = new ArrayList<>(); - @State - String sortFilter; + List selectedSortFilter = new ArrayList<>(); // these represents the last search @State @@ -140,8 +134,6 @@ public class SearchFragment extends BaseListFragment menuItemToFilterName = new SparseArrayCompat<>(); - private StreamingService service; private Page nextPage; private boolean showLocalSuggestions = true; private boolean showRemoteSuggestions = true; @@ -159,7 +151,7 @@ public class SearchFragment extends BaseListFragment userSelectedContentFilterList; + + @State + ArrayList 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) { - final SearchFragment searchFragment = new SearchFragment(); - searchFragment.setQuery(serviceId, searchString, new String[0], ""); + final SearchFragment searchFragment; + 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)) { searchFragment.setSearchOnResume(); @@ -208,11 +223,53 @@ public class SearchFragment extends BaseListFragment(); + } + + 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); } + protected void initViewModel() { + searchViewModel = new ViewModelProvider(this, SearchViewModel.Companion + .getFactory(serviceId, + logicVariant, + userSelectedContentFilterList, + userSelectedSortFilterList)) + .get(SearchViewModel.class); + } + @Override public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { searchBinding = FragmentSearchBinding.bind(rootView); @@ -221,22 +278,12 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) .subscribe(this::handleResult, this::onItemError); - } @Override @@ -884,8 +891,8 @@ public class SearchFragment extends BaseListFragment theContentFilter) { - filterItemCheckedId = item.getItemId(); - item.setChecked(true); + public void selectedFilters(@NonNull final List theSelectedContentFilter, + @NonNull final List theSelectedSortFilter) { - contentFilter = theContentFilter.toArray(new String[0]); + selectedContentFilter = theSelectedContentFilter; + selectedSortFilter = theSelectedSortFilter; if (!TextUtils.isEmpty(searchString)) { - search(searchString, contentFilter, sortFilter); + search(searchString); } } private void setQuery(final int theServiceId, - final String theSearchString, - final String[] theContentFilter, - final String theSortFilter) { + final String theSearchString) { serviceId = theServiceId; searchString = theSearchString; - contentFilter = theContentFilter; - sortFilter = theSortFilter; } /*////////////////////////////////////////////////////////////////////////// @@ -1020,7 +1023,7 @@ public class SearchFragment extends BaseListFragment { searchBinding.correctSuggestion.setVisibility(View.GONE); - search(searchSuggestion, contentFilter, sortFilter); + search(searchSuggestion); searchEditText.setText(searchSuggestion); }); @@ -1085,4 +1088,22 @@ public class SearchFragment extends BaseListFragment searchFor(final int serviceId, final String searchString, - final List contentFilter, - final String sortFilter) { + final List contentFilter, + final List sortFilter) { checkServiceId(serviceId); return Single.fromCallable(() -> SearchInfo.getInfo(NewPipe.getService(serviceId), @@ -87,8 +89,8 @@ public final class ExtractorHelper { public static Single> getMoreSearchItems( final int serviceId, final String searchString, - final List contentFilter, - final String sortFilter, + final List contentFilter, + final List sortFilter, final Page page) { checkServiceId(serviceId); return Single.fromCallable(() -> diff --git a/app/src/main/res/menu/menu_search_fragment.xml b/app/src/main/res/menu/menu_search_fragment.xml new file mode 100644 index 000000000..1461245a5 --- /dev/null +++ b/app/src/main/res/menu/menu_search_fragment.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 880fa92da..61fd11f19 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -1383,6 +1383,28 @@ @string/card + search_filter_ui + @string/search_filter_ui_dialog_key + + dialog + style + legacy + chip + + + @string/search_filter_ui_dialog_key + @string/search_filter_ui_option_menu_style_key + @string/search_filter_ui_option_menu_legacy_key + @string/search_filter_ui_chip_dialog_key + + + + @string/search_filter_ui_dialog + @string/search_filter_ui_style + @string/search_filter_ui_legacy + @string/search_filter_ui_chip_dialog + + tablet_mode auto diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e1fd0ea56..6dbe06562 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -907,4 +907,16 @@ Yes YouTube Music + + + Filter + Sort filters + Content filters + Select Search Filter UI + Simple Dialog (default) + Action Menu styled Dialog + Action Menu (legacy) + Chip Dialog + + diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml index beb46cdf5..7365995b6 100644 --- a/app/src/main/res/xml/appearance_settings.xml +++ b/app/src/main/res/xml/appearance_settings.xml @@ -66,6 +66,16 @@ app:singleLineTitle="false" app:iconSpaceReserved="false" /> + +