mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-10 09:20:31 +00:00
searchfilters: common base classes for DialogFragment based UI's
This commit is contained in:
parent
651a333393
commit
3c038aaf7c
@ -0,0 +1,123 @@
|
||||
// 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;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import static org.schabi.newpipe.fragments.list.search.filter.SearchFilterLogic.ICreateUiForFiltersWorker;
|
||||
|
||||
/**
|
||||
* Common base for the {@link SearchFilterDialogGenerator} and
|
||||
* {@link SearchFilterOptionMenuAlikeDialogGenerator}'s
|
||||
* {@link ICreateUiForFiltersWorker} implementation.
|
||||
*/
|
||||
public abstract class BaseCreateSearchFilterUI
|
||||
implements ICreateUiForFiltersWorker {
|
||||
|
||||
@NonNull
|
||||
protected final BaseSearchFilterUiDialogGenerator dialogGenBase;
|
||||
@NonNull
|
||||
protected final Context context;
|
||||
protected final List<View> titleViewElements = new ArrayList<>();
|
||||
protected final SearchFilterLogic logic;
|
||||
protected int titleResId;
|
||||
|
||||
protected BaseCreateSearchFilterUI(
|
||||
@NonNull final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
@NonNull final SearchFilterLogic logic,
|
||||
@NonNull final Context context,
|
||||
final int titleResId) {
|
||||
this.dialogGenBase = dialogGenBase;
|
||||
this.logic = logic;
|
||||
this.context = context;
|
||||
this.titleResId = titleResId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterItem(@NonNull final FilterItem filterItem,
|
||||
@NonNull final FilterGroup filterGroup) {
|
||||
// no implementation here all creation stuff is done in createFilterGroupBeforeItems
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupAfterItems(@NonNull 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(
|
||||
@NonNull final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
@NonNull final Context context,
|
||||
@NonNull final SearchFilterLogic logic) {
|
||||
super(dialogGenBase, context, logic);
|
||||
this.titleResId = R.string.filter_search_content_filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupBeforeItems(
|
||||
@NonNull final FilterGroup filterGroup) {
|
||||
dialogGenBase.createFilterGroup(filterGroup,
|
||||
logic::addContentFilterUiWrapperToItemMap,
|
||||
logic::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(
|
||||
@NonNull final BaseSearchFilterUiDialogGenerator dialogGenBase,
|
||||
@NonNull final Context context,
|
||||
@NonNull final SearchFilterLogic logic) {
|
||||
super(dialogGenBase, logic, context, R.string.filter_search_sort_filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
dialogGenBase.createTitle(context.getString(titleResId), titleViewElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createFilterGroupBeforeItems(@NonNull final FilterGroup filterGroup) {
|
||||
dialogGenBase.createFilterGroup(filterGroup,
|
||||
logic::addSortFilterUiWrapperToItemMap,
|
||||
logic::selectSortFilter);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public abstract class BaseItemWrapper implements SearchFilterLogic.IUiItemWrapper {
|
||||
@NonNull
|
||||
protected final FilterItem item;
|
||||
|
||||
protected BaseItemWrapper(@NonNull final FilterItem item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return item.getIdentifier();
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
// 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.fragments.list.search.SearchViewModel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
/**
|
||||
* Base dialog class for {@link DialogFragment} based search filter dialogs.
|
||||
*/
|
||||
public abstract class BaseSearchFilterDialogFragment extends DialogFragment {
|
||||
|
||||
protected BaseSearchFilterUiGenerator dialogGenerator;
|
||||
protected SearchViewModel searchViewModel;
|
||||
|
||||
private void createSearchFilterUi() {
|
||||
dialogGenerator = createSearchFilterDialogGenerator();
|
||||
dialogGenerator.createSearchUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(@NonNull final FragmentManager manager, @Nullable final String tag) {
|
||||
// Avoid multiple instances of the dialog that could be triggered by multiple taps
|
||||
if (manager.findFragmentByTag(tag) == null) {
|
||||
super.show(manager, tag);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract BaseSearchFilterUiGenerator createSearchFilterDialogGenerator();
|
||||
|
||||
/**
|
||||
* As we have different bindings we need to get this sorted in a method.
|
||||
*
|
||||
* @return the {@link Toolbar} null if there is no toolbar available.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract Toolbar getToolbar();
|
||||
|
||||
protected abstract View getRootView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container);
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Make sure that the first parameter is pointing to instance of SearchFragment otherwise
|
||||
// another SearchViewModel object will be created instead of the existing one used.
|
||||
// -> the SearchViewModel is first instantiated in SearchFragment. Here we just use it.
|
||||
searchViewModel =
|
||||
new ViewModelProvider(requireParentFragment()).get(SearchViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
@Nullable final ViewGroup container,
|
||||
final Bundle savedInstanceState) {
|
||||
final View rootView = getRootView(inflater, container);
|
||||
createSearchFilterUi();
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View view, final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final Toolbar toolbar = getToolbar();
|
||||
if (toolbar != null) {
|
||||
initToolbar(toolbar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the toolbar.
|
||||
* <p>
|
||||
* This method is only called if {@link #getToolbar()} is implemented to return a toolbar.
|
||||
*
|
||||
* @param toolbar the actual toolbar for this dialog fragment
|
||||
*/
|
||||
protected void initToolbar(@NonNull 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) {
|
||||
searchViewModel.getSearchFilterLogic().prepareForSearch();
|
||||
dismiss();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.reset) {
|
||||
searchViewModel.getSearchFilterLogic().reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
// 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.search.filter.FilterGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||
import static org.schabi.newpipe.fragments.list.search.filter.SearchFilterLogic.ICreateUiForFiltersWorker;
|
||||
|
||||
public abstract class BaseSearchFilterUiDialogGenerator extends BaseSearchFilterUiGenerator {
|
||||
private static final float FONT_SIZE_TITLE_ITEMS_IN_DIP = 20f;
|
||||
|
||||
protected BaseSearchFilterUiDialogGenerator(
|
||||
@NonNull final SearchFilterLogic logic,
|
||||
@NonNull final Context context) {
|
||||
super(logic, context);
|
||||
}
|
||||
|
||||
protected abstract void createTitle(@NonNull String name,
|
||||
@NonNull List<View> titleViewElements);
|
||||
|
||||
protected abstract void createFilterGroup(@NonNull FilterGroup filterGroup,
|
||||
@NonNull UiWrapperMapDelegate wrapperDelegate,
|
||||
@NonNull UiSelectorDelegate selectorDelegate);
|
||||
|
||||
@Override
|
||||
protected ICreateUiForFiltersWorker createContentFilterWorker() {
|
||||
return new BaseCreateSearchFilterUI.CreateContentFilterUI(this, context, logic);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ICreateUiForFiltersWorker createSortFilterWorker() {
|
||||
return new BaseCreateSearchFilterUI.CreateSortFilterUI(this, context, logic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a View that acts as a separator between two other {@link View}-Elements.
|
||||
*
|
||||
* @param layoutParams this layout will be modified to have the height of 1 -> to have a
|
||||
* the actual separator line.
|
||||
* @return the created {@link SeparatorLineView}
|
||||
*/
|
||||
@NonNull
|
||||
protected SeparatorLineView createSeparatorLine(
|
||||
@NonNull final ViewGroup.LayoutParams layoutParams) {
|
||||
final SeparatorLineView separatorLine = new SeparatorLineView(context);
|
||||
separatorLine.setBackgroundColor(getSeparatorLineColorFromTheme());
|
||||
layoutParams.height = 1; // always set the separator to the height of 1
|
||||
separatorLine.setLayoutParams(layoutParams);
|
||||
return separatorLine;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected TextView createTitleText(@NonNull final String name,
|
||||
@NonNull 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A special view to separate two other {@link View}s.
|
||||
* <p>
|
||||
* class only needed to distinct this special view from other View based views.
|
||||
* (eg. instanceof)
|
||||
*/
|
||||
protected static final class SeparatorLineView extends View {
|
||||
|
||||
private SeparatorLineView(@NonNull final Context context) {
|
||||
super(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// 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;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public abstract class BaseUiItemWrapper extends BaseItemWrapper {
|
||||
@NonNull
|
||||
protected final View view;
|
||||
|
||||
protected BaseUiItemWrapper(@NonNull final FilterItem item,
|
||||
@NonNull final View view) {
|
||||
super(item);
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(final boolean visible) {
|
||||
if (visible) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
// 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;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* 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 List<View> views = new ArrayList<>();
|
||||
|
||||
UiItemWrapperViews(final int itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
public void add(@NonNull 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 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…
Reference in New Issue
Block a user