Use segmented buttons for filter

This commit is contained in:
ByteHamster 2022-08-07 21:36:15 +02:00
parent 2740816bb8
commit 37b49b1e38
14 changed files with 59 additions and 326 deletions

View File

@ -5,15 +5,16 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.button.MaterialButtonToggleGroup;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItemFilterGroup;
import de.danoeh.antennapod.databinding.FilterDialogRowBinding;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.ui.common.RecursiveRadioGroup;
import java.util.HashSet;
import java.util.Set;
@ -32,22 +33,21 @@ public abstract class ItemFilterDialog extends BottomSheetDialogFragment {
FeedItemFilter filter = (FeedItemFilter) getArguments().getSerializable(ARGUMENT_FILTER);
for (FeedItemFilterGroup item : FeedItemFilterGroup.values()) {
RecursiveRadioGroup row = (RecursiveRadioGroup) inflater.inflate(R.layout.filter_dialog_row, null, false);
row.setOnCheckedChangeListener((group, checkedId) -> onFilterChanged(getNewFilterValues()));
RadioButton filter1 = row.findViewById(R.id.filter_dialog_radioButton1);
RadioButton filter2 = row.findViewById(R.id.filter_dialog_radioButton2);
filter1.setText(item.values[0].displayName);
filter1.setTag(item.values[0].filterId);
filter2.setText(item.values[1].displayName);
filter2.setTag(item.values[1].filterId);
rows.addView(row);
FilterDialogRowBinding binding = FilterDialogRowBinding.inflate(inflater);
binding.getRoot().addOnButtonCheckedListener(
(group, checkedId, isChecked) -> onFilterChanged(getNewFilterValues()));
binding.filterButton1.setText(item.values[0].displayName);
binding.filterButton1.setTag(item.values[0].filterId);
binding.filterButton2.setText(item.values[1].displayName);
binding.filterButton2.setTag(item.values[1].filterId);
rows.addView(binding.getRoot());
}
for (String filterId : filter.getValues()) {
if (!TextUtils.isEmpty(filterId)) {
RadioButton button = layout.findViewWithTag(filterId);
Button button = layout.findViewWithTag(filterId);
if (button != null) {
button.setChecked(true);
((MaterialButtonToggleGroup) button.getParent()).check(button.getId());
}
}
}
@ -57,16 +57,18 @@ public abstract class ItemFilterDialog extends BottomSheetDialogFragment {
protected Set<String> getNewFilterValues() {
final Set<String> newFilterValues = new HashSet<>();
for (int i = 0; i < rows.getChildCount(); i++) {
if (!(rows.getChildAt(i) instanceof RecursiveRadioGroup)) {
if (!(rows.getChildAt(i) instanceof MaterialButtonToggleGroup)) {
continue;
}
RecursiveRadioGroup group = (RecursiveRadioGroup) rows.getChildAt(i);
if (group.getCheckedButton() != null) {
String tag = (String) group.getCheckedButton().getTag();
if (tag != null) { // Clear buttons use no tag
newFilterValues.add((String) group.getCheckedButton().getTag());
MaterialButtonToggleGroup group = (MaterialButtonToggleGroup) rows.getChildAt(i);
if (group.getCheckedButtonId() == View.NO_ID) {
continue;
}
String tag = (String) group.findViewById(group.getCheckedButtonId()).getTag();
if (tag == null) { // Clear buttons use no tag
continue;
}
newFilterValues.add(tag);
}
return newFilterValues;
}

View File

@ -4,11 +4,13 @@ import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import com.google.android.material.button.MaterialButtonToggleGroup;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import de.danoeh.antennapod.databinding.FilterDialogRowBinding;
import org.greenrobot.eventbus.EventBus;
import java.util.Arrays;
@ -20,7 +22,6 @@ import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.ui.common.RecursiveRadioGroup;
public class SubscriptionsFilterDialog {
public static void showDialog(Context context) {
@ -35,39 +36,42 @@ public class SubscriptionsFilterDialog {
builder.setView(layout);
for (SubscriptionsFilterGroup item : SubscriptionsFilterGroup.values()) {
RecursiveRadioGroup row = (RecursiveRadioGroup) inflater.inflate(R.layout.filter_dialog_row, null);
RadioButton filter1 = row.findViewById(R.id.filter_dialog_radioButton1);
RadioButton filter2 = row.findViewById(R.id.filter_dialog_radioButton2);
filter1.setText(item.values[0].displayName);
filter1.setTag(item.values[0].filterId);
FilterDialogRowBinding binding = FilterDialogRowBinding.inflate(inflater);
binding.filterButton1.setText(item.values[0].displayName);
binding.filterButton1.setTag(item.values[0].filterId);
if (item.values.length == 2) {
filter2.setText(item.values[1].displayName);
filter2.setTag(item.values[1].filterId);
binding.filterButton2.setText(item.values[1].displayName);
binding.filterButton2.setTag(item.values[1].filterId);
} else {
filter2.setVisibility(View.GONE);
binding.filterButton2.setVisibility(View.GONE);
}
rows.addView(row);
rows.addView(binding.getRoot());
}
for (String filterId : filterValues) {
if (!TextUtils.isEmpty(filterId)) {
((RadioButton) layout.findViewWithTag(filterId)).setChecked(true);
Button button = layout.findViewWithTag(filterId);
if (button != null) {
((MaterialButtonToggleGroup) button.getParent()).check(button.getId());
}
}
}
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
filterValues.clear();
for (int i = 0; i < rows.getChildCount(); i++) {
if (!(rows.getChildAt(i) instanceof RecursiveRadioGroup)) {
if (!(rows.getChildAt(i) instanceof MaterialButtonToggleGroup)) {
continue;
}
RecursiveRadioGroup group = (RecursiveRadioGroup) rows.getChildAt(i);
if (group.getCheckedButton() != null) {
String tag = (String) group.getCheckedButton().getTag();
if (tag != null) { // Clear buttons use no tag
filterValues.add((String) group.getCheckedButton().getTag());
MaterialButtonToggleGroup group = (MaterialButtonToggleGroup) rows.getChildAt(i);
if (group.getCheckedButtonId() == View.NO_ID) {
continue;
}
String tag = (String) group.findViewById(group.getCheckedButtonId()).getTag();
if (tag == null) { // Clear buttons use no tag
continue;
}
filterValues.add(tag);
}
updateFilter(filterValues);
});

View File

@ -1,66 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<de.danoeh.antennapod.ui.common.RecursiveRadioGroup
<com.google.android.material.button.MaterialButtonToggleGroup
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="8dp"
android:orientation="horizontal">
android:layout_height="wrap_content"
android:weightSum="2"
app:singleSelection="true">
<androidx.cardview.widget.CardView
<Button
android:id="@+id/filterButton1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clipChildren="true"
android:layout_gravity="center_vertical"
app:cardCornerRadius="32dp"
app:cardElevation="0dp">
style="?attr/materialButtonOutlinedStyle" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RadioButton
android:id="@+id/filter_dialog_radioButton1"
<Button
android:id="@+id/filterButton2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="2dp"
android:layout_marginRight="2dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?attr/filter_dialog_button_background"
android:minHeight="40dp"
android:foreground="?android:attr/selectableItemBackground"
android:checked="false"
android:gravity="center"
android:textColor="@color/filter_dialog_button_text"
style="@style/NoButtonRadio" />
style="?attr/materialButtonOutlinedStyle" />
<RadioButton
android:id="@+id/filter_dialog_radioButton2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:minHeight="40dp"
android:layout_weight="1"
android:background="?attr/filter_dialog_button_background"
android:foreground="?android:attr/selectableItemBackground"
android:checked="false"
android:gravity="center"
android:textColor="@color/filter_dialog_button_text"
style="@style/NoButtonRadio" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<RadioButton
android:id="@+id/filter_dialog_clear"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/ic_filter_close"
android:foreground="?android:attr/selectableItemBackground"
android:layout_gravity="center_vertical"
android:checked="true"
style="@style/NoButtonRadio" />
</de.danoeh.antennapod.ui.common.RecursiveRadioGroup>
</com.google.android.material.button.MaterialButtonToggleGroup>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorOnSecondary" android:state_checked="true" />
<item android:color="?android:textColorPrimary" />
</selector>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dialog_filter_inactive_dark" android:state_checked="true" />
<item android:color="@color/dialog_filter_clear_inactive_dark" />
</selector>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dialog_filter_inactive_light" android:state_checked="true" />
<item android:color="@color/dialog_filter_clear_inactive_light" />
</selector>

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp">
<shape android:shape="oval">
<stroke
android:width="4dp"
android:color="?attr/filter_dialog_clear" />
</shape>
</item>
<!-- x -->
<item
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp">
<rotate
android:fromDegrees="135"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="135">
<shape android:shape="line">
<stroke
android:width="4dp"
android:color="?attr/filter_dialog_clear" />
</shape>
</rotate>
</item>
<item
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp">
<rotate
android:fromDegrees="45"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="45">
<shape android:shape="line">
<stroke
android:width="4dp"
android:color="?attr/filter_dialog_clear" />
</shape>
</rotate>
</item>
</layer-list>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/accent_dark" android:state_checked="true"/>
<item android:drawable="@color/dialog_filter_inactive_dark" />
</selector>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/accent_light" android:state_checked="true"/>
<item android:drawable="@color/dialog_filter_inactive_light" />
</selector>

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Fall-back for old Android devices that do not support attrs as colors -->
<item
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp">
<shape android:shape="oval">
<stroke
android:width="4dp"
android:color="#555" />
</shape>
</item>
<!-- x -->
<item
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp">
<rotate
android:fromDegrees="135"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="135">
<shape android:shape="line">
<stroke
android:width="4dp"
android:color="#555" />
</shape>
</rotate>
</item>
<item
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp">
<rotate
android:fromDegrees="45"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="45">
<shape android:shape="line">
<stroke
android:width="4dp"
android:color="#555" />
</shape>
</rotate>
</item>
</layer-list>

View File

@ -10,8 +10,6 @@
<attr name="scrollbar_thumb" format="reference"/>
<attr name="background_color" format="color"/>
<attr name="background_elevated" format="color"/>
<attr name="filter_dialog_clear" format="color"/>
<attr name="filter_dialog_button_background" format="reference"/>
<attr name="seek_background" format="color" />
<attr name="icon_red" format="color" />
<attr name="icon_yellow" format="color" />

View File

@ -35,10 +35,4 @@
<color name="master_switch_background_light">#DDDDDD</color>
<color name="master_switch_background_dark">#191919</color>
<!-- filter dialog -->
<color name="dialog_filter_clear_inactive_light">#666666</color>
<color name="dialog_filter_clear_inactive_dark">#bbbbbb</color>
<color name="dialog_filter_inactive_light">#eeeeee</color>
<color name="dialog_filter_inactive_dark">#555555</color>
</resources>

View File

@ -29,8 +29,6 @@
<item name="navigation_up">@drawable/navigation_up</item>
<item name="dragview_background">@drawable/ic_drag_lighttheme</item>
<item name="scrollbar_thumb">@drawable/scrollbar_thumb_light</item>
<item name="filter_dialog_clear">@color/filter_dialog_clear_light</item>
<item name="filter_dialog_button_background">@drawable/filter_dialog_background_light</item>
<item name="icon_red">#CF1800</item>
<item name="icon_yellow">#F59F00</item>
<item name="icon_green">#008537</item>
@ -74,8 +72,6 @@
<item name="navigation_up">@drawable/navigation_up_dark</item>
<item name="dragview_background">@drawable/ic_drag_darktheme</item>
<item name="scrollbar_thumb">@drawable/scrollbar_thumb_dark</item>
<item name="filter_dialog_clear">@color/filter_dialog_clear_dark</item>
<item name="filter_dialog_button_background">@drawable/filter_dialog_background_dark</item>
<item name="icon_red">#CF1800</item>
<item name="icon_yellow">#F59F00</item>
<item name="icon_green">#008537</item>
@ -250,9 +246,4 @@
<item name="android:clickable">true</item>
</style>
<style name="NoButtonRadio" parent="Widget.Material3.CompoundButton.RadioButton">
<item name="buttonCompat">@null</item> <!-- For Android 4.4 -->
<item name="android:button">@null</item>
</style>
</resources>

View File

@ -1,79 +0,0 @@
package de.danoeh.antennapod.ui.common;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import androidx.annotation.Nullable;
import java.util.ArrayList;
/**
* An alternative to {@link android.widget.RadioGroup} that allows to nest children.
* Basend on https://stackoverflow.com/a/14309274.
*/
public class RecursiveRadioGroup extends LinearLayout {
private final ArrayList<RadioButton> radioButtons = new ArrayList<>();
private RadioButton checkedButton = null;
@Nullable
private RadioGroup.OnCheckedChangeListener checkedChangeListener;
public RecursiveRadioGroup(Context context) {
super(context);
}
public RecursiveRadioGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RecursiveRadioGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
parseChild(child);
}
public void setOnCheckedChangeListener(@Nullable RadioGroup.OnCheckedChangeListener listener) {
checkedChangeListener = listener;
}
public void parseChild(final View child) {
if (child instanceof RadioButton) {
RadioButton button = (RadioButton) child;
radioButtons.add(button);
button.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (!isChecked) {
return;
}
checkedButton = (RadioButton) buttonView;
if (checkedChangeListener != null) {
checkedChangeListener.onCheckedChanged(null, checkedButton.getId());
}
for (RadioButton view : radioButtons) {
if (view != buttonView) {
view.setChecked(false);
}
}
});
} else if (child instanceof ViewGroup) {
parseChildren((ViewGroup) child);
}
}
public void parseChildren(final ViewGroup child) {
for (int i = 0; i < child.getChildCount(); i++) {
parseChild(child.getChildAt(i));
}
}
public RadioButton getCheckedButton() {
return checkedButton;
}
}