mirror of
https://github.com/MaintainTeam/LastPipeBender.git
synced 2025-03-01 22:08:22 +03:00
searchfilters: common base classes for DialogFragment based UI's
This commit is contained in:
parent
5b95094a77
commit
55240193c0
5 changed files with 481 additions and 0 deletions
|
@ -0,0 +1,108 @@
|
|||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common base for the {@link SearchFilterDialogGenerator} and
|
||||
* {@link SearchFilterOptionMenuAlikeDialogGenerator}'s
|
||||
* {@link SearchFilterLogic.ICreateUiForFiltersWorker} implementation.
|
||||
*/
|
||||
public abstract class BaseCreateSearchFilterUI
|
||||
implements SearchFilterLogic.ICreateUiForFiltersWorker {
|
||||
|
||||
protected final BaseSearchFilterUiDialogGenerator dialogGenBase;
|
||||
protected final Context context;
|
||||
protected final List<View> titleViewElements = new ArrayList<>();
|
||||
protected int titleResId;
|
||||
|
||||
protected BaseCreateSearchFilterUI(final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
final Context context,
|
||||
final int titleResId) {
|
||||
this.dialogGenBase = dialogGenBase;
|
||||
this.context = context;
|
||||
this.titleResId = titleResId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterItem(final FilterItem filterItem, final FilterGroup filterGroup) {
|
||||
// no implementation here all creation stuff is done in createFilterGroupBeforeItems
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupAfterItems(final FilterGroup filterGroup) {
|
||||
// no implementation here all creation stuff is done in createFilterGroupBeforeItems
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
// no implementation here all creation stuff is done in createFilterGroupBeforeItems
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to control the visibility of the title 'sort filter' if the
|
||||
* chosen content filter has no sort filters.
|
||||
*
|
||||
* @param areFiltersVisible true if filter visible
|
||||
*/
|
||||
@Override
|
||||
public void filtersVisible(final boolean areFiltersVisible) {
|
||||
final int visibility = areFiltersVisible ? View.VISIBLE : View.GONE;
|
||||
for (final View view : titleViewElements) {
|
||||
if (view != null) {
|
||||
view.setVisibility(visibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateContentFilterUI extends CreateSortFilterUI {
|
||||
|
||||
public CreateContentFilterUI(final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
final Context context) {
|
||||
super(dialogGenBase, context);
|
||||
this.titleResId = R.string.filter_search_content_filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupBeforeItems(
|
||||
final FilterGroup filterGroup) {
|
||||
dialogGenBase.createFilterGroup(filterGroup,
|
||||
dialogGenBase::addContentFilterUiWrapperToItemMap,
|
||||
dialogGenBase::selectContentFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filtersVisible(final boolean areFiltersVisible) {
|
||||
// no implementation here. As content filters have to be always visible
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateSortFilterUI extends BaseCreateSearchFilterUI {
|
||||
|
||||
public CreateSortFilterUI(final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
final Context context) {
|
||||
super(dialogGenBase, context, R.string.filter_search_sort_filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
dialogGenBase.createTitle(context.getString(titleResId), titleViewElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupBeforeItems(final FilterGroup filterGroup) {
|
||||
dialogGenBase.createFilterGroup(filterGroup,
|
||||
dialogGenBase::addSortFilterUiWrapperToItemMap,
|
||||
dialogGenBase::selectSortFilter);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import icepick.Icepick;
|
||||
import icepick.State;
|
||||
|
||||
/**
|
||||
* Base dialog class for {@link DialogFragment} based search filter dialogs.
|
||||
*/
|
||||
public abstract class BaseSearchFilterDialogFragment extends DialogFragment {
|
||||
|
||||
private static final String CONTENT_FILTERS = "CONTENT_FILTERS";
|
||||
private static final String SORT_FILTERS = "SORT_FILTERS";
|
||||
private static final String SERVICE_ID = "SERVICE_ID";
|
||||
|
||||
@State
|
||||
public ArrayList<Integer> userSelectedContentFilterList;
|
||||
protected List<FilterItem> selectedContentFilters;
|
||||
protected List<FilterItem> selectedSortFilters;
|
||||
protected BaseSearchFilterUiGenerator dialogGenerator;
|
||||
@State
|
||||
ArrayList<Integer> userSelectedSortFilterList = null;
|
||||
|
||||
protected static DialogFragment initDialogArguments(
|
||||
final DialogFragment dialogFragment,
|
||||
final int serviceId,
|
||||
final ArrayList<Integer> userSelectedContentFilter,
|
||||
final ArrayList<Integer> userSelectedSortFilter) {
|
||||
final Bundle bundle = new Bundle(1);
|
||||
bundle.putInt(SERVICE_ID, serviceId);
|
||||
bundle.putIntegerArrayList(CONTENT_FILTERS, userSelectedContentFilter);
|
||||
bundle.putIntegerArrayList(SORT_FILTERS, userSelectedSortFilter);
|
||||
dialogFragment.setArguments(bundle);
|
||||
|
||||
return dialogFragment;
|
||||
}
|
||||
|
||||
private void initializeFilterData() {
|
||||
|
||||
assert getArguments() != null;
|
||||
final int serviceId = getArguments().getInt(SERVICE_ID);
|
||||
final ArrayList<Integer> contentFilters =
|
||||
getArguments().getIntegerArrayList(CONTENT_FILTERS);
|
||||
final ArrayList<Integer> sortFilters =
|
||||
getArguments().getIntegerArrayList(SORT_FILTERS);
|
||||
|
||||
final StreamingService service;
|
||||
try {
|
||||
service = NewPipe.getService(serviceId);
|
||||
} catch (final ExtractionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
dialogGenerator = createSearchFilterDialogGenerator(service,
|
||||
(userSelectedContentFilter, userSelectedSortFilter) -> {
|
||||
selectedContentFilters = userSelectedContentFilter;
|
||||
selectedSortFilters = userSelectedSortFilter;
|
||||
sendDataToParentFragment();
|
||||
});
|
||||
|
||||
userSelectedContentFilterList = contentFilters;
|
||||
userSelectedSortFilterList = sortFilters;
|
||||
|
||||
dialogGenerator.restorePreviouslySelectedFilters(
|
||||
userSelectedContentFilterList,
|
||||
userSelectedSortFilterList);
|
||||
|
||||
dialogGenerator.createSearchUI();
|
||||
}
|
||||
|
||||
protected abstract BaseSearchFilterUiGenerator createSearchFilterDialogGenerator(
|
||||
StreamingService service,
|
||||
SearchFilterLogic.Callback callback);
|
||||
|
||||
/**
|
||||
* As we have different bindings we need to get this sorted in a method.
|
||||
*
|
||||
* @return the {@link Toolbar}
|
||||
*/
|
||||
protected abstract Toolbar getToolbar();
|
||||
|
||||
protected abstract View getRootView(LayoutInflater inflater,
|
||||
ViewGroup container);
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
final ViewGroup container,
|
||||
final Bundle savedInstanceState) {
|
||||
final View rootView = getRootView(inflater, container);
|
||||
initializeFilterData();
|
||||
return rootView;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
dialogGenerator.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
dialogGenerator.onPause();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View view, final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
Icepick.restoreInstanceState(this, savedInstanceState);
|
||||
|
||||
initToolbar(getToolbar());
|
||||
}
|
||||
|
||||
protected void initToolbar(final Toolbar toolbar) {
|
||||
toolbar.setTitle(R.string.filter);
|
||||
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
|
||||
toolbar.inflateMenu(R.menu.menu_search_filter_dialog_fragment);
|
||||
toolbar.setNavigationOnClickListener(v -> dismiss());
|
||||
toolbar.setNavigationContentDescription(R.string.cancel);
|
||||
|
||||
final View okButton = toolbar.findViewById(R.id.search);
|
||||
okButton.setEnabled(true);
|
||||
|
||||
final View resetButton = toolbar.findViewById(R.id.reset);
|
||||
resetButton.setEnabled(true);
|
||||
|
||||
toolbar.setOnMenuItemClickListener(item -> {
|
||||
if (item.getItemId() == R.id.search) {
|
||||
dialogGenerator.prepareForSearch();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.reset) {
|
||||
dialogGenerator.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
// get data to save its state via Icepick
|
||||
userSelectedContentFilterList = dialogGenerator.getSelectedContentFilters();
|
||||
userSelectedSortFilterList = dialogGenerator.getSelectedSortFilters();
|
||||
|
||||
Icepick.saveInstanceState(this, outState);
|
||||
}
|
||||
|
||||
private void sendDataToParentFragment() {
|
||||
final Listener listener = (Listener) getTargetFragment();
|
||||
if (listener != null) {
|
||||
listener.onFinishSearchFilterDialog(
|
||||
userSelectedContentFilterList, userSelectedSortFilterList,
|
||||
selectedContentFilters, selectedSortFilters);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to be implemented by the parent Fragment so it can receive data.
|
||||
*/
|
||||
public interface Listener {
|
||||
|
||||
void onFinishSearchFilterDialog(ArrayList<Integer> userSelectedContentFilterList,
|
||||
ArrayList<Integer> userSelectedSortFilterList,
|
||||
List<FilterItem> selectedContentFilters,
|
||||
List<FilterItem> selectedSortFilters);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||
|
||||
public abstract class BaseSearchFilterUiDialogGenerator extends BaseSearchFilterUiGenerator {
|
||||
private static final float FONT_SIZE_TITLE_ITEMS_IN_DIP = 20f;
|
||||
|
||||
protected final Map<View, View.OnClickListener> viewListeners = new HashMap<>();
|
||||
|
||||
protected BaseSearchFilterUiDialogGenerator(
|
||||
final SearchQueryHandlerFactory linkHandlerFactory,
|
||||
final Callback callback,
|
||||
final Context context) {
|
||||
super(linkHandlerFactory, callback, context);
|
||||
}
|
||||
|
||||
protected abstract void createTitle(String name, List<View> titleViewElements);
|
||||
|
||||
protected abstract void createFilterGroup(FilterGroup filterGroup,
|
||||
UiWrapperMapDelegate wrapperDelegate,
|
||||
UiSelectorDelegate selectorDelegate);
|
||||
|
||||
@Override
|
||||
protected ICreateUiForFiltersWorker createContentFilterWorker() {
|
||||
return new BaseCreateSearchFilterUI.CreateContentFilterUI(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ICreateUiForFiltersWorker createSortFilterWorker() {
|
||||
return new BaseCreateSearchFilterUI.CreateSortFilterUI(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
for (final Map.Entry<View, View.OnClickListener> view : viewListeners.entrySet()) {
|
||||
view.getKey().setOnClickListener(view.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
for (final Map.Entry<View, View.OnClickListener> view : viewListeners.entrySet()) {
|
||||
view.getKey().setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected View createSeparatorLine(final ViewGroup.LayoutParams layoutParams) {
|
||||
final View separatorLine = new View(context);
|
||||
separatorLine.setBackgroundColor(getSeparatorLineColorFromTheme());
|
||||
layoutParams.height = 1; // always set the separator to 1
|
||||
separatorLine.setLayoutParams(layoutParams);
|
||||
return separatorLine;
|
||||
}
|
||||
|
||||
protected TextView createTitleText(final String name,
|
||||
final ViewGroup.LayoutParams layoutParams) {
|
||||
final TextView title = new TextView(context);
|
||||
title.setText(name);
|
||||
title.setTextSize(COMPLEX_UNIT_DIP, FONT_SIZE_TITLE_ITEMS_IN_DIP);
|
||||
title.setLayoutParams(layoutParams);
|
||||
return title;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
|
||||
public abstract class BaseUiItemWrapper implements SearchFilterLogic.IUiItemWrapper {
|
||||
protected final FilterItem item;
|
||||
protected final int groupId;
|
||||
protected View view;
|
||||
|
||||
protected BaseUiItemWrapper(final FilterItem item,
|
||||
final int groupId,
|
||||
final View view) {
|
||||
this.item = item;
|
||||
this.groupId = groupId;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(final boolean visible) {
|
||||
if (visible) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return item.getIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper for views that are either just labels or eg. a RadioGroup container
|
||||
* etc. that represent a {@link org.schabi.newpipe.extractor.search.filter.FilterGroup}.
|
||||
*/
|
||||
final class UiItemWrapperViews implements SearchFilterLogic.IUiItemWrapper {
|
||||
|
||||
private final int itemId;
|
||||
private final int groupId;
|
||||
private final List<View> views = new ArrayList<>();
|
||||
|
||||
UiItemWrapperViews(final int itemId, final int groupId) {
|
||||
this.itemId = itemId;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public void add(final View view) {
|
||||
this.views.add(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(final boolean visible) {
|
||||
for (final View view : views) {
|
||||
if (visible) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return this.itemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
boolean isChecked = false;
|
||||
for (final View view : views) {
|
||||
if (view.isSelected()) {
|
||||
isChecked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(final boolean checked) {
|
||||
// not relevant as here views are wrapped that are either just labels or eg. a
|
||||
// RadioGroup container etc. that represent a FilterGroup.
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue