mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-10 09:20:31 +00:00
searchfilters: 1st Ui: default dialog for search content and sort filters
This commit is contained in:
parent
7c650f6e9d
commit
05ffe276c0
@ -0,0 +1,41 @@
|
||||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.schabi.newpipe.databinding.SearchFilterDialogFragmentBinding;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
/**
|
||||
* A search filter dialog that also looks like a dialog aka. 'dialog style'.
|
||||
*/
|
||||
public class SearchFilterDialogFragment extends BaseSearchFilterDialogFragment {
|
||||
|
||||
protected SearchFilterDialogFragmentBinding binding;
|
||||
|
||||
@Override
|
||||
protected BaseSearchFilterUiGenerator createSearchFilterDialogGenerator() {
|
||||
return new SearchFilterDialogGenerator(
|
||||
searchViewModel.getSearchFilterLogic(), binding.verticalScroll, requireContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected Toolbar getToolbar() {
|
||||
return binding.toolbarLayout.toolbar;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getRootView(@NonNull final LayoutInflater inflater,
|
||||
@Nullable final ViewGroup container) {
|
||||
binding = SearchFilterDialogFragmentBinding
|
||||
.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
// 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.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class SearchFilterDialogGenerator extends BaseSearchFilterUiDialogGenerator {
|
||||
private static final int CHIP_GROUP_ELEMENTS_THRESHOLD = 2;
|
||||
private static final int CHIP_MIN_TOUCH_TARGET_SIZE_DP = 40;
|
||||
protected final GridLayout globalLayout;
|
||||
|
||||
public SearchFilterDialogGenerator(
|
||||
@NonNull final SearchFilterLogic logic,
|
||||
@NonNull final ViewGroup root,
|
||||
@NonNull final Context context) {
|
||||
super(logic, context);
|
||||
this.globalLayout = createGridLayout();
|
||||
root.addView(globalLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTitle(@NonNull final String name,
|
||||
@NonNull final List<View> titleViewElements) {
|
||||
final TextView titleView = createTitleText(name);
|
||||
final View separatorLine = createSeparatorLine();
|
||||
final View separatorLine2 = createSeparatorLine();
|
||||
|
||||
globalLayout.addView(separatorLine);
|
||||
globalLayout.addView(titleView);
|
||||
globalLayout.addView(separatorLine2);
|
||||
|
||||
titleViewElements.add(titleView);
|
||||
titleViewElements.add(separatorLine);
|
||||
titleViewElements.add(separatorLine2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createFilterGroup(@NonNull final FilterGroup filterGroup,
|
||||
@NonNull final UiWrapperMapDelegate wrapperDelegate,
|
||||
@NonNull final UiSelectorDelegate selectorDelegate) {
|
||||
final GridLayout.LayoutParams layoutParams = getLayoutParamsViews();
|
||||
boolean doSpanDataOverMultipleCells = false;
|
||||
final UiItemWrapperViews viewsWrapper = new UiItemWrapperViews(
|
||||
filterGroup.getIdentifier());
|
||||
|
||||
final TextView filterLabel;
|
||||
if (filterGroup.getNameId() != null) {
|
||||
filterLabel = createFilterLabel(filterGroup, layoutParams);
|
||||
viewsWrapper.add(filterLabel);
|
||||
} else {
|
||||
filterLabel = null;
|
||||
doSpanDataOverMultipleCells = true;
|
||||
}
|
||||
|
||||
if (filterGroup.isOnlyOneCheckable()) {
|
||||
if (filterLabel != null) {
|
||||
globalLayout.addView(filterLabel);
|
||||
}
|
||||
|
||||
final Spinner filterDataSpinner = new Spinner(context, Spinner.MODE_DROPDOWN);
|
||||
|
||||
final GridLayout.LayoutParams spinnerLp =
|
||||
clipFreeRightColumnLayoutParams(doSpanDataOverMultipleCells);
|
||||
setDefaultMargin(spinnerLp);
|
||||
filterDataSpinner.setLayoutParams(spinnerLp);
|
||||
setZeroPadding(filterDataSpinner);
|
||||
|
||||
createUiElementsForSingleSelectableItemsFilterGroup(
|
||||
filterGroup, wrapperDelegate, selectorDelegate, filterDataSpinner);
|
||||
|
||||
viewsWrapper.add(filterDataSpinner);
|
||||
globalLayout.addView(filterDataSpinner);
|
||||
|
||||
} else { // multiple items in FilterGroup selectable
|
||||
final ChipGroup chipGroup = new ChipGroup(context);
|
||||
doSpanDataOverMultipleCells = chooseParentViewForFilterLabelAndAdd(
|
||||
filterGroup, doSpanDataOverMultipleCells, filterLabel, chipGroup);
|
||||
|
||||
viewsWrapper.add(chipGroup);
|
||||
globalLayout.addView(chipGroup);
|
||||
chipGroup.setLayoutParams(
|
||||
clipFreeRightColumnLayoutParams(doSpanDataOverMultipleCells));
|
||||
chipGroup.setSingleLine(false);
|
||||
|
||||
createUiChipElementsForFilterGroupItems(
|
||||
filterGroup, wrapperDelegate, selectorDelegate, chipGroup);
|
||||
}
|
||||
|
||||
wrapperDelegate.put(filterGroup.getIdentifier(), viewsWrapper);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected TextView createFilterLabel(@NonNull final FilterGroup filterGroup,
|
||||
@NonNull final GridLayout.LayoutParams layoutParams) {
|
||||
final TextView filterLabel;
|
||||
filterLabel = new TextView(context);
|
||||
|
||||
filterLabel.setId(filterGroup.getIdentifier());
|
||||
filterLabel.setText(
|
||||
ServiceHelper.getTranslatedFilterString(filterGroup.getNameId(), context));
|
||||
filterLabel.setGravity(Gravity.CENTER_VERTICAL);
|
||||
setDefaultMargin(layoutParams);
|
||||
setZeroPadding(filterLabel);
|
||||
|
||||
filterLabel.setLayoutParams(layoutParams);
|
||||
return filterLabel;
|
||||
}
|
||||
|
||||
private boolean chooseParentViewForFilterLabelAndAdd(
|
||||
@NonNull final FilterGroup filterGroup,
|
||||
final boolean doSpanDataOverMultipleCells,
|
||||
@Nullable final TextView filterLabel,
|
||||
@NonNull final ChipGroup possibleParentView) {
|
||||
|
||||
boolean spanOverMultipleCells = doSpanDataOverMultipleCells;
|
||||
if (filterLabel != null) {
|
||||
// If we have more than CHIP_GROUP_ELEMENTS_THRESHOLD elements to be
|
||||
// displayed as Chips add its filterLabel as first element to ChipGroup.
|
||||
// Now the ChipGroup can be spanned over all the cells to use
|
||||
// the space better.
|
||||
if (filterGroup.getFilterItems().size() > CHIP_GROUP_ELEMENTS_THRESHOLD) {
|
||||
possibleParentView.addView(filterLabel);
|
||||
spanOverMultipleCells = true;
|
||||
} else {
|
||||
globalLayout.addView(filterLabel);
|
||||
}
|
||||
}
|
||||
return spanOverMultipleCells;
|
||||
}
|
||||
|
||||
private void createUiElementsForSingleSelectableItemsFilterGroup(
|
||||
@NonNull final FilterGroup filterGroup,
|
||||
@NonNull final UiWrapperMapDelegate wrapperDelegate,
|
||||
@NonNull final UiSelectorDelegate selectorDelegate,
|
||||
@NonNull final Spinner filterDataSpinner) {
|
||||
filterDataSpinner.setAdapter(new SearchFilterDialogSpinnerAdapter(
|
||||
context, filterGroup, wrapperDelegate, filterDataSpinner));
|
||||
|
||||
final AdapterView.OnItemSelectedListener listener;
|
||||
listener = new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(final AdapterView<?> parent, final View view,
|
||||
final int position, final long id) {
|
||||
if (view != null) {
|
||||
selectorDelegate.selectFilter(view.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(final AdapterView<?> parent) {
|
||||
// we are only interested onItemSelected() -> no implementation here
|
||||
}
|
||||
};
|
||||
|
||||
filterDataSpinner.setOnItemSelectedListener(listener);
|
||||
}
|
||||
|
||||
protected void createUiChipElementsForFilterGroupItems(
|
||||
@NonNull final FilterGroup filterGroup,
|
||||
@NonNull final UiWrapperMapDelegate wrapperDelegate,
|
||||
@NonNull final UiSelectorDelegate selectorDelegate,
|
||||
@NonNull final ChipGroup chipGroup) {
|
||||
for (final FilterItem item : filterGroup.getFilterItems()) {
|
||||
|
||||
if (item instanceof InjectFilterItem.DividerItem) {
|
||||
final InjectFilterItem.DividerItem dividerItem =
|
||||
(InjectFilterItem.DividerItem) item;
|
||||
|
||||
// For the width MATCH_PARENT is necessary as this allows the
|
||||
// dividerLabel to fill one row of ChipGroup exclusively
|
||||
final ChipGroup.LayoutParams layoutParams = new ChipGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
final TextView dividerLabel = createDividerLabel(dividerItem, layoutParams);
|
||||
chipGroup.addView(dividerLabel);
|
||||
} else {
|
||||
final Chip chip = createChipView(chipGroup, item);
|
||||
|
||||
final View.OnClickListener listener;
|
||||
listener = view -> selectorDelegate.selectFilter(view.getId());
|
||||
chip.setOnClickListener(listener);
|
||||
|
||||
chipGroup.addView(chip);
|
||||
wrapperDelegate.put(item.getIdentifier(),
|
||||
new UiItemWrapperChip(item, chip, chipGroup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Chip createChipView(@NonNull final ChipGroup chipGroup,
|
||||
@NonNull final FilterItem item) {
|
||||
final Chip chip = (Chip) LayoutInflater.from(context).inflate(
|
||||
R.layout.chip_search_filter, chipGroup, false);
|
||||
chip.ensureAccessibleTouchTarget(
|
||||
DeviceUtils.dpToPx(CHIP_MIN_TOUCH_TARGET_SIZE_DP, context));
|
||||
chip.setText(ServiceHelper.getTranslatedFilterString(item.getNameId(), context));
|
||||
chip.setId(item.getIdentifier());
|
||||
chip.setCheckable(true);
|
||||
return chip;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TextView createDividerLabel(
|
||||
@NonNull final InjectFilterItem.DividerItem dividerItem,
|
||||
@NonNull final ViewGroup.MarginLayoutParams layoutParams) {
|
||||
final TextView dividerLabel;
|
||||
dividerLabel = new TextView(context);
|
||||
dividerLabel.setEnabled(true);
|
||||
|
||||
dividerLabel.setGravity(Gravity.CENTER_VERTICAL);
|
||||
setDefaultMargin(layoutParams);
|
||||
dividerLabel.setLayoutParams(layoutParams);
|
||||
final String menuDividerTitle =
|
||||
context.getString(dividerItem.getStringResId());
|
||||
dividerLabel.setText(menuDividerTitle);
|
||||
return dividerLabel;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected SeparatorLineView createSeparatorLine() {
|
||||
return createSeparatorLine(clipFreeRightColumnLayoutParams(true));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TextView createTitleText(final String name) {
|
||||
final TextView title = createTitleText(name,
|
||||
clipFreeRightColumnLayoutParams(true));
|
||||
title.setGravity(Gravity.CENTER);
|
||||
return title;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private GridLayout createGridLayout() {
|
||||
final GridLayout layout = new GridLayout(context);
|
||||
|
||||
layout.setColumnCount(2);
|
||||
|
||||
final GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
|
||||
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
setDefaultMargin(layoutParams);
|
||||
layout.setLayoutParams(layoutParams);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected GridLayout.LayoutParams clipFreeRightColumnLayoutParams(final boolean doColumnSpan) {
|
||||
final GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
|
||||
// https://stackoverflow.com/questions/37744672/gridlayout-children-are-being-clipped
|
||||
layoutParams.width = 0;
|
||||
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
layoutParams.setGravity(Gravity.FILL_HORIZONTAL | Gravity.CENTER_VERTICAL);
|
||||
setDefaultMargin(layoutParams);
|
||||
|
||||
if (doColumnSpan) {
|
||||
layoutParams.columnSpec = GridLayout.spec(0, 2, 1.0f);
|
||||
}
|
||||
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private GridLayout.LayoutParams getLayoutParamsViews() {
|
||||
final GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
|
||||
layoutParams.setGravity(Gravity.CENTER_VERTICAL);
|
||||
setDefaultMargin(layoutParams);
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected ViewGroup.MarginLayoutParams setDefaultMargin(
|
||||
@NonNull final ViewGroup.MarginLayoutParams layoutParams) {
|
||||
layoutParams.setMargins(
|
||||
DeviceUtils.dpToPx(4, context),
|
||||
DeviceUtils.dpToPx(2, context),
|
||||
DeviceUtils.dpToPx(4, context),
|
||||
DeviceUtils.dpToPx(2, context)
|
||||
);
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected View setZeroPadding(@NonNull final View view) {
|
||||
view.setPadding(0, 0, 0, 0);
|
||||
return view;
|
||||
}
|
||||
|
||||
public static class UiItemWrapperChip extends BaseUiItemWrapper {
|
||||
|
||||
@NonNull
|
||||
private final ChipGroup chipGroup;
|
||||
|
||||
public UiItemWrapperChip(@NonNull final FilterItem item,
|
||||
@NonNull final View view,
|
||||
@NonNull final ChipGroup chipGroup) {
|
||||
super(item, view);
|
||||
this.chipGroup = chipGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return ((Chip) view).isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(final boolean checked) {
|
||||
((Chip) view).setChecked(checked);
|
||||
|
||||
if (checked) {
|
||||
chipGroup.check(view.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
// Created by evermind-zz 2022, licensed GNU GPL version 3 or later
|
||||
|
||||
package org.schabi.newpipe.fragments.list.search.filter;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterContainer;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.collection.SparseArrayCompat;
|
||||
|
||||
import static org.schabi.newpipe.fragments.list.search.filter.InjectFilterItem.DividerItem;
|
||||
|
||||
public class SearchFilterDialogSpinnerAdapter extends BaseAdapter {
|
||||
|
||||
private final Context context;
|
||||
private final FilterGroup group;
|
||||
private final BaseSearchFilterUiGenerator.UiWrapperMapDelegate wrapperDelegate;
|
||||
private final Spinner spinner;
|
||||
private final SparseIntArray id2PosMap = new SparseIntArray();
|
||||
private final SparseArrayCompat<UiItemWrapperSpinner>
|
||||
viewWrapperMap = new SparseArrayCompat<>();
|
||||
|
||||
public SearchFilterDialogSpinnerAdapter(
|
||||
@NonNull final Context context,
|
||||
@NonNull final FilterGroup group,
|
||||
@NonNull final BaseSearchFilterUiGenerator.UiWrapperMapDelegate wrapperDelegate,
|
||||
@NonNull final Spinner filterDataSpinner) {
|
||||
this.context = context;
|
||||
this.group = group;
|
||||
this.wrapperDelegate = wrapperDelegate;
|
||||
this.spinner = filterDataSpinner;
|
||||
|
||||
createViewWrappers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return group.getFilterItems().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(final int position) {
|
||||
return group.getFilterItems().get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, final View convertView, final ViewGroup parent) {
|
||||
final FilterItem item = group.getFilterItems().get(position);
|
||||
final TextView view;
|
||||
|
||||
if (convertView != null) {
|
||||
view = (TextView) convertView;
|
||||
} else {
|
||||
view = createViewItem();
|
||||
}
|
||||
|
||||
initViewWithData(position, item, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
private void initViewWithData(final int position,
|
||||
final FilterItem item,
|
||||
final TextView view) {
|
||||
final UiItemWrapperSpinner wrappedView =
|
||||
viewWrapperMap.get(position);
|
||||
Objects.requireNonNull(wrappedView);
|
||||
|
||||
view.setId(item.getIdentifier());
|
||||
view.setText(ServiceHelper.getTranslatedFilterString(item.getNameId(), context));
|
||||
view.setVisibility(wrappedView.getVisibility());
|
||||
view.setEnabled(wrappedView.isEnabled());
|
||||
|
||||
if (item instanceof DividerItem) {
|
||||
final DividerItem dividerItem = (DividerItem) item;
|
||||
wrappedView.setEnabled(false);
|
||||
view.setEnabled(wrappedView.isEnabled());
|
||||
final String menuDividerTitle = ">>>"
|
||||
+ context.getString(dividerItem.getStringResId()) + "<<<";
|
||||
view.setText(menuDividerTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private void createViewWrappers() {
|
||||
int position = 0;
|
||||
for (final FilterItem item : this.group.getFilterItems()) {
|
||||
final int initialVisibility = View.VISIBLE;
|
||||
final boolean isInitialEnabled = true;
|
||||
|
||||
final UiItemWrapperSpinner wrappedView =
|
||||
new UiItemWrapperSpinner(
|
||||
item,
|
||||
initialVisibility,
|
||||
isInitialEnabled,
|
||||
spinner);
|
||||
|
||||
if (item instanceof DividerItem) {
|
||||
wrappedView.setEnabled(false);
|
||||
}
|
||||
|
||||
// store wrapper also locally as we refer here regularly
|
||||
viewWrapperMap.put(position, wrappedView);
|
||||
// store wrapper globally in SearchFilterLogic
|
||||
wrapperDelegate.put(item.getIdentifier(), wrappedView);
|
||||
id2PosMap.put(item.getIdentifier(), position);
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TextView createViewItem() {
|
||||
final TextView view = new TextView(context);
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
view.setGravity(Gravity.CENTER_VERTICAL);
|
||||
view.setPadding(
|
||||
DeviceUtils.dpToPx(8, context),
|
||||
DeviceUtils.dpToPx(4, context),
|
||||
DeviceUtils.dpToPx(8, context),
|
||||
DeviceUtils.dpToPx(4, context)
|
||||
);
|
||||
return view;
|
||||
}
|
||||
|
||||
public int getItemPositionForFilterId(final int id) {
|
||||
return id2PosMap.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(final int position) {
|
||||
final UiItemWrapperSpinner wrappedView =
|
||||
viewWrapperMap.get(position);
|
||||
Objects.requireNonNull(wrappedView);
|
||||
return wrappedView.isEnabled();
|
||||
}
|
||||
|
||||
private static class UiItemWrapperSpinner
|
||||
extends BaseItemWrapper {
|
||||
@NonNull
|
||||
private final Spinner spinner;
|
||||
|
||||
/**
|
||||
* We have to store the visibility of the view and if it is enabled.
|
||||
* <p>
|
||||
* Reason: the Spinner adapter reuses {@link View} elements through the parameter
|
||||
* convertView in {@link SearchFilterDialogSpinnerAdapter#getView(int, View, ViewGroup)}
|
||||
* -> this is the Android Adapter's time saving characteristic to rather reuse
|
||||
* than to recreate a {@link View}.
|
||||
* -> so we reuse what Android gives us in above mentioned method.
|
||||
*/
|
||||
private int visibility;
|
||||
private boolean enabled;
|
||||
|
||||
UiItemWrapperSpinner(@NonNull final FilterItem item,
|
||||
final int initialVisibility,
|
||||
final boolean isInitialEnabled,
|
||||
@NonNull final Spinner spinner) {
|
||||
super(item);
|
||||
this.spinner = spinner;
|
||||
|
||||
this.visibility = initialVisibility;
|
||||
this.enabled = isInitialEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(final boolean visible) {
|
||||
if (visible) {
|
||||
visibility = View.VISIBLE;
|
||||
} else {
|
||||
visibility = View.GONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return spinner.getSelectedItem() == item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(final boolean checked) {
|
||||
if (super.getItemId() != FilterContainer.ITEM_IDENTIFIER_UNKNOWN) {
|
||||
final SearchFilterDialogSpinnerAdapter adapter =
|
||||
(SearchFilterDialogSpinnerAdapter) spinner.getAdapter();
|
||||
spinner.setSelection(adapter.getItemPositionForFilterId(super.getItemId()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public int getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
public void setVisibility(final int visibility) {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- adding more contrast than @color/mtrl_chip_background_color if a Chip is selected -->
|
||||
<item android:alpha="0.30" android:color="?attr/colorOnSurface" android:state_enabled="true" android:state_selected="true"/>
|
||||
<item android:alpha="0.18" android:color="?attr/colorOnSurface" android:state_enabled="true" android:state_checked="true"/>
|
||||
<!-- 12% of 87% opacity -->
|
||||
<item android:alpha="0.10" android:color="?attr/colorOnSurface" android:state_enabled="true"/>
|
||||
<item android:alpha="0.12" android:color="?attr/colorOnSurface"/>
|
||||
</selector>
|
9
app/src/main/res/layout/chip_search_filter.xml
Normal file
9
app/src/main/res/layout/chip_search_filter.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This is used to inflate a chip with a Material theme, otherwise it would crash -->
|
||||
<!-- Theme.MaterialComponents.DayNight is used to guarantee auto day/night switching -->
|
||||
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/ChipSearchFilter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/Theme.MaterialComponents.DayNight" />
|
23
app/src/main/res/layout/search_filter_dialog_fragment.xml
Normal file
23
app/src/main/res/layout/search_filter_dialog_fragment.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_layout"
|
||||
layout="@layout/toolbar_layout" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/toolbar_layout">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/vertical_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
</RelativeLayout>
|
15
app/src/main/res/menu/menu_search_filter_dialog_fragment.xml
Normal file
15
app/src/main/res/menu/menu_search_filter_dialog_fragment.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/reset"
|
||||
android:title="@string/playback_reset"
|
||||
android:icon="@drawable/ic_settings_backup_restore"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/search"
|
||||
android:title="@string/search"
|
||||
android:icon="@drawable/ic_search"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
@ -155,4 +155,12 @@
|
||||
|
||||
<style name="RouterActivityThemeDark" parent="Base.RouterActivityThemeDark" />
|
||||
|
||||
<!-- custom Chip style for SearchFilterDialogFragment -->
|
||||
<style name="ChipSearchFilter" parent="Widget.MaterialComponents.Chip.Filter">
|
||||
<item name="checkedIconEnabled">false</item>
|
||||
<item name="checkedIcon">@null</item>
|
||||
<item name="chipBackgroundColor">@color/mtrl_search_filter_chip_background_color</item>
|
||||
<item name="chipStrokeWidth">0.1dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user