Rewrite include/exclude filter dialog (#6057)
This commit is contained in:
parent
bd0f54dbf6
commit
097a491504
|
@ -0,0 +1,57 @@
|
||||||
|
package de.danoeh.antennapod.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.google.android.material.chip.Chip;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class SimpleChipAdapter extends RecyclerView.Adapter<SimpleChipAdapter.ViewHolder> {
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public SimpleChipAdapter(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
setHasStableIds(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract List<String> getChips();
|
||||||
|
|
||||||
|
protected abstract void onRemoveClicked(int position);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public SimpleChipAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
Chip chip = new Chip(context);
|
||||||
|
chip.setCloseIconVisible(true);
|
||||||
|
chip.setCloseIconResource(R.drawable.ic_delete);
|
||||||
|
return new SimpleChipAdapter.ViewHolder(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull SimpleChipAdapter.ViewHolder holder, int position) {
|
||||||
|
holder.chip.setText(getChips().get(position));
|
||||||
|
holder.chip.setOnCloseIconClickListener(v -> onRemoveClicked(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return getChips().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return getChips().get(position).hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
Chip chip;
|
||||||
|
|
||||||
|
ViewHolder(Chip itemView) {
|
||||||
|
super(itemView);
|
||||||
|
chip = itemView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +1,108 @@
|
||||||
package de.danoeh.antennapod.dialog;
|
package de.danoeh.antennapod.dialog;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.content.DialogInterface;
|
||||||
import android.widget.CheckBox;
|
import android.text.TextUtils;
|
||||||
import android.widget.EditText;
|
import android.view.LayoutInflater;
|
||||||
import android.widget.RadioButton;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.adapter.SimpleChipAdapter;
|
||||||
|
import de.danoeh.antennapod.databinding.EpisodeFilterDialogBinding;
|
||||||
import de.danoeh.antennapod.model.feed.FeedFilter;
|
import de.danoeh.antennapod.model.feed.FeedFilter;
|
||||||
|
import de.danoeh.antennapod.view.ItemOffsetDecoration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
|
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
|
||||||
*/
|
*/
|
||||||
public abstract class EpisodeFilterDialog extends MaterialAlertDialogBuilder {
|
public abstract class EpisodeFilterDialog extends MaterialAlertDialogBuilder {
|
||||||
private final FeedFilter initialFilter;
|
private final EpisodeFilterDialogBinding viewBinding;
|
||||||
|
private final List<String> termList;
|
||||||
|
|
||||||
public EpisodeFilterDialog(Context context, FeedFilter filter) {
|
public EpisodeFilterDialog(Context context, FeedFilter filter) {
|
||||||
|
|
||||||
super(context);
|
super(context);
|
||||||
initialFilter = filter;
|
viewBinding = EpisodeFilterDialogBinding.inflate(LayoutInflater.from(context));
|
||||||
|
|
||||||
setTitle(R.string.episode_filters_label);
|
setTitle(R.string.episode_filters_label);
|
||||||
View rootView = View.inflate(context, R.layout.episode_filter_dialog, null);
|
setView(viewBinding.getRoot());
|
||||||
setView(rootView);
|
|
||||||
|
|
||||||
final EditText etxtEpisodeFilterText = rootView.findViewById(R.id.etxtEpisodeFilterText);
|
if (filter.hasMinimalDurationFilter()) {
|
||||||
final EditText etxtEpisodeFilterDurationText = rootView.findViewById(R.id.etxtEpisodeFilterDurationText);
|
viewBinding.durationCheckBox.setChecked(true);
|
||||||
final RadioButton radioInclude = rootView.findViewById(R.id.radio_filter_include);
|
|
||||||
final RadioButton radioExclude = rootView.findViewById(R.id.radio_filter_exclude);
|
|
||||||
final CheckBox checkboxDuration = rootView.findViewById(R.id.checkbox_filter_duration);
|
|
||||||
|
|
||||||
if (initialFilter.includeOnly()) {
|
|
||||||
radioInclude.setChecked(true);
|
|
||||||
etxtEpisodeFilterText.setText(initialFilter.getIncludeFilter());
|
|
||||||
} else if(initialFilter.excludeOnly()) {
|
|
||||||
radioExclude.setChecked(true);
|
|
||||||
etxtEpisodeFilterText.setText(initialFilter.getExcludeFilter());
|
|
||||||
} else {
|
|
||||||
radioExclude.setChecked(false);
|
|
||||||
radioInclude.setChecked(false);
|
|
||||||
etxtEpisodeFilterText.setText("");
|
|
||||||
}
|
|
||||||
if (initialFilter.hasMinimalDurationFilter()) {
|
|
||||||
checkboxDuration.setChecked(true);
|
|
||||||
// Store minimal duration in seconds, show in minutes
|
// Store minimal duration in seconds, show in minutes
|
||||||
etxtEpisodeFilterDurationText.setText(String.valueOf(initialFilter.getMinimalDurationFilter() / 60));
|
viewBinding.episodeFilterDurationText
|
||||||
|
.setText(String.valueOf(filter.getMinimalDurationFilter() / 60));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter.excludeOnly()) {
|
||||||
|
termList = filter.getExcludeFilter();
|
||||||
|
viewBinding.excludeRadio.setChecked(true);
|
||||||
|
} else {
|
||||||
|
termList = filter.getIncludeFilter();
|
||||||
|
viewBinding.includeRadio.setChecked(true);
|
||||||
|
}
|
||||||
|
setupWordsList();
|
||||||
|
|
||||||
setNegativeButton(R.string.cancel_label, null);
|
setNegativeButton(R.string.cancel_label, null);
|
||||||
setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
setPositiveButton(R.string.confirm_label, this::onConfirmClick);
|
||||||
String includeString = "";
|
|
||||||
String excludeString = "";
|
|
||||||
int minimalDuration = -1;
|
|
||||||
if (radioInclude.isChecked()) {
|
|
||||||
includeString = etxtEpisodeFilterText.getText().toString();
|
|
||||||
} else {
|
|
||||||
excludeString = etxtEpisodeFilterText.getText().toString();
|
|
||||||
}
|
}
|
||||||
if (checkboxDuration.isChecked()) {
|
|
||||||
|
private void setupWordsList() {
|
||||||
|
viewBinding.termsRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||||
|
viewBinding.termsRecycler.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
|
||||||
|
SimpleChipAdapter adapter = new SimpleChipAdapter(getContext()) {
|
||||||
|
@Override
|
||||||
|
protected List<String> getChips() {
|
||||||
|
return termList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemoveClicked(int position) {
|
||||||
|
termList.remove(position);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
viewBinding.termsRecycler.setAdapter(adapter);
|
||||||
|
viewBinding.termsTextInput.setEndIconOnClickListener(v -> {
|
||||||
|
String newWord = viewBinding.termsTextInput.getEditText().getText().toString().replace("\"", "").trim();
|
||||||
|
if (TextUtils.isEmpty(newWord) || termList.contains(newWord)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
termList.add(newWord);
|
||||||
|
viewBinding.termsTextInput.getEditText().setText("");
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void onConfirmed(FeedFilter filter);
|
||||||
|
|
||||||
|
private void onConfirmClick(DialogInterface dialog, int which) {
|
||||||
|
int minimalDuration = -1;
|
||||||
|
if (viewBinding.durationCheckBox.isChecked()) {
|
||||||
try {
|
try {
|
||||||
// Store minimal duration in seconds
|
// Store minimal duration in seconds
|
||||||
minimalDuration = Integer.parseInt(etxtEpisodeFilterDurationText.getText().toString()) * 60;
|
minimalDuration = Integer.parseInt(
|
||||||
|
viewBinding.episodeFilterDurationText.getText().toString()) * 60;
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// Do not change anything on error
|
// Do not change anything on error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onConfirmed(new FeedFilter(includeString, excludeString, minimalDuration));
|
String excludeFilter = "";
|
||||||
|
String includeFilter = "";
|
||||||
|
if (viewBinding.includeRadio.isChecked()) {
|
||||||
|
includeFilter = toFilterString(termList);
|
||||||
|
} else {
|
||||||
|
excludeFilter = toFilterString(termList);
|
||||||
}
|
}
|
||||||
);
|
onConfirmed(new FeedFilter(includeFilter, excludeFilter, minimalDuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void onConfirmed(FeedFilter filter);
|
private String toFilterString(List<String> words) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (String word : words) {
|
||||||
|
result.append("\"").append(word).append("\" ");
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,19 @@ import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import com.google.android.material.chip.Chip;
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.adapter.SimpleChipAdapter;
|
||||||
import de.danoeh.antennapod.core.storage.DBReader;
|
import de.danoeh.antennapod.core.storage.DBReader;
|
||||||
import de.danoeh.antennapod.core.storage.NavDrawerData;
|
|
||||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
|
||||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
|
import de.danoeh.antennapod.core.storage.NavDrawerData;
|
||||||
import de.danoeh.antennapod.databinding.EditTagsDialogBinding;
|
import de.danoeh.antennapod.databinding.EditTagsDialogBinding;
|
||||||
|
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||||
import de.danoeh.antennapod.view.ItemOffsetDecoration;
|
import de.danoeh.antennapod.view.ItemOffsetDecoration;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
@ -36,7 +34,7 @@ public class TagSettingsDialog extends DialogFragment {
|
||||||
private static final String ARG_FEED_PREFERENCES = "feed_preferences";
|
private static final String ARG_FEED_PREFERENCES = "feed_preferences";
|
||||||
private List<String> displayedTags;
|
private List<String> displayedTags;
|
||||||
private EditTagsDialogBinding viewBinding;
|
private EditTagsDialogBinding viewBinding;
|
||||||
private TagSelectionAdapter adapter;
|
private SimpleChipAdapter adapter;
|
||||||
|
|
||||||
public static TagSettingsDialog newInstance(List<FeedPreferences> preferencesList) {
|
public static TagSettingsDialog newInstance(List<FeedPreferences> preferencesList) {
|
||||||
TagSettingsDialog fragment = new TagSettingsDialog();
|
TagSettingsDialog fragment = new TagSettingsDialog();
|
||||||
|
@ -62,12 +60,22 @@ public class TagSettingsDialog extends DialogFragment {
|
||||||
viewBinding = EditTagsDialogBinding.inflate(getLayoutInflater());
|
viewBinding = EditTagsDialogBinding.inflate(getLayoutInflater());
|
||||||
viewBinding.tagsRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
viewBinding.tagsRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||||
viewBinding.tagsRecycler.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
|
viewBinding.tagsRecycler.addItemDecoration(new ItemOffsetDecoration(getContext(), 4));
|
||||||
adapter = new TagSelectionAdapter();
|
adapter = new SimpleChipAdapter(getContext()) {
|
||||||
adapter.setHasStableIds(true);
|
@Override
|
||||||
|
protected List<String> getChips() {
|
||||||
|
return displayedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemoveClicked(int position) {
|
||||||
|
displayedTags.remove(position);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
viewBinding.tagsRecycler.setAdapter(adapter);
|
viewBinding.tagsRecycler.setAdapter(adapter);
|
||||||
viewBinding.rootFolderCheckbox.setChecked(commonTags.contains(FeedPreferences.TAG_ROOT));
|
viewBinding.rootFolderCheckbox.setChecked(commonTags.contains(FeedPreferences.TAG_ROOT));
|
||||||
|
|
||||||
viewBinding.newTagButton.setOnClickListener(v ->
|
viewBinding.newTagTextInput.setEndIconOnClickListener(v ->
|
||||||
addTag(viewBinding.newTagEditText.getText().toString().trim()));
|
addTag(viewBinding.newTagEditText.getText().toString().trim()));
|
||||||
|
|
||||||
loadTags();
|
loadTags();
|
||||||
|
@ -140,44 +148,4 @@ public class TagSettingsDialog extends DialogFragment {
|
||||||
DBWriter.setFeedPreferences(preferences);
|
DBWriter.setFeedPreferences(preferences);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TagSelectionAdapter extends RecyclerView.Adapter<TagSelectionAdapter.ViewHolder> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public TagSelectionAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
Chip chip = new Chip(getContext());
|
|
||||||
chip.setCloseIconVisible(true);
|
|
||||||
chip.setCloseIconResource(R.drawable.ic_delete);
|
|
||||||
return new TagSelectionAdapter.ViewHolder(chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull TagSelectionAdapter.ViewHolder holder, int position) {
|
|
||||||
holder.chip.setText(displayedTags.get(position));
|
|
||||||
holder.chip.setOnCloseIconClickListener(v -> {
|
|
||||||
displayedTags.remove(position);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return displayedTags.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return displayedTags.get(position).hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
Chip chip;
|
|
||||||
|
|
||||||
ViewHolder(Chip itemView) {
|
|
||||||
super(itemView);
|
|
||||||
chip = itemView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,25 +28,24 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/feed_folders_include_root" />
|
android:text="@string/feed_folders_include_root" />
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/newTagTextInput"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
app:endIconMode="custom"
|
||||||
|
app:endIconDrawable="@drawable/ic_add"
|
||||||
|
app:endIconContentDescription="@string/add_tag"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
<AutoCompleteTextView
|
<AutoCompleteTextView
|
||||||
android:id="@+id/newTagEditText"
|
android:id="@+id/newTagEditText"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:ems="10" />
|
android:ems="10" />
|
||||||
|
|
||||||
<ImageButton
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
android:id="@+id/newTagButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:srcCompat="@drawable/ic_add" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,60 +1,99 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<ScrollView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<RadioGroup
|
<LinearLayout
|
||||||
android:id="@+id/radio_filter_group"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<RadioButton
|
<RadioGroup
|
||||||
android:id="@+id/radio_filter_include"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/episode_filters_include" />
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/radio_filter_exclude"
|
android:id="@+id/includeRadio"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/episode_filters_exclude" />
|
android:layout_weight="1"
|
||||||
|
android:text="@string/include_terms" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/excludeRadio"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/exclude_terms" />
|
||||||
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<EditText
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/etxtEpisodeFilterText"
|
android:id="@+id/termsRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
tools:itemCount="2" />
|
||||||
android:cursorVisible="true"
|
|
||||||
android:focusable="true"
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:focusableInTouchMode="true"
|
android:id="@+id/termsTextInput"
|
||||||
android:hint="@string/episode_filters_hint"
|
android:layout_width="match_parent"
|
||||||
android:lines="8"
|
android:layout_height="wrap_content"
|
||||||
android:maxLines="20"
|
app:endIconMode="custom"
|
||||||
android:minLines="1"
|
app:endIconDrawable="@drawable/ic_add"
|
||||||
android:scrollbars="vertical" />
|
app:endIconContentDescription="@string/add_term"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/checkbox_filter_duration"
|
android:id="@+id/durationCheckBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/episode_filters_duration" />
|
android:layout_weight="1"
|
||||||
|
android:text="@string/exclude_episodes_shorter_than" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/etxtEpisodeFilterDurationText"
|
android:id="@+id/episodeFilterDurationText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="50dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
|
||||||
android:cursorVisible="true"
|
android:cursorVisible="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
android:inputType="numberSigned"
|
android:inputType="numberSigned"
|
||||||
android:lines="1" />
|
android:lines="1" />
|
||||||
|
|
||||||
</LinearLayout>
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/time_minutes" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
|
@ -21,8 +21,8 @@ public class FeedFilterTest {
|
||||||
|
|
||||||
assertFalse(filter.excludeOnly());
|
assertFalse(filter.excludeOnly());
|
||||||
assertFalse(filter.includeOnly());
|
assertFalse(filter.includeOnly());
|
||||||
assertEquals("", filter.getExcludeFilter());
|
assertEquals("", filter.getExcludeFilterRaw());
|
||||||
assertEquals("", filter.getIncludeFilter());
|
assertEquals("", filter.getIncludeFilterRaw());
|
||||||
assertTrue(filter.shouldAutoDownload(item));
|
assertTrue(filter.shouldAutoDownload(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ public class FeedFilterTest {
|
||||||
|
|
||||||
assertFalse(filter.excludeOnly());
|
assertFalse(filter.excludeOnly());
|
||||||
assertTrue(filter.includeOnly());
|
assertTrue(filter.includeOnly());
|
||||||
assertEquals("", filter.getExcludeFilter());
|
assertEquals("", filter.getExcludeFilterRaw());
|
||||||
assertEquals(includeFilter, filter.getIncludeFilter());
|
assertEquals(includeFilter, filter.getIncludeFilterRaw());
|
||||||
assertTrue(filter.shouldAutoDownload(item));
|
assertTrue(filter.shouldAutoDownload(item));
|
||||||
assertFalse(filter.shouldAutoDownload(item2));
|
assertFalse(filter.shouldAutoDownload(item2));
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ public class FeedFilterTest {
|
||||||
|
|
||||||
assertTrue(filter.excludeOnly());
|
assertTrue(filter.excludeOnly());
|
||||||
assertFalse(filter.includeOnly());
|
assertFalse(filter.includeOnly());
|
||||||
assertEquals(excludeFilter, filter.getExcludeFilter());
|
assertEquals(excludeFilter, filter.getExcludeFilterRaw());
|
||||||
assertEquals("", filter.getIncludeFilter());
|
assertEquals("", filter.getIncludeFilterRaw());
|
||||||
assertFalse(filter.shouldAutoDownload(item));
|
assertFalse(filter.shouldAutoDownload(item));
|
||||||
assertTrue(filter.shouldAutoDownload(item2));
|
assertTrue(filter.shouldAutoDownload(item2));
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,8 @@ public class FeedFilterTest {
|
||||||
|
|
||||||
assertFalse(filter.excludeOnly());
|
assertFalse(filter.excludeOnly());
|
||||||
assertTrue(filter.includeOnly());
|
assertTrue(filter.includeOnly());
|
||||||
assertEquals("", filter.getExcludeFilter());
|
assertEquals("", filter.getExcludeFilterRaw());
|
||||||
assertEquals(includeFilter, filter.getIncludeFilter());
|
assertEquals(includeFilter, filter.getIncludeFilterRaw());
|
||||||
assertTrue(filter.shouldAutoDownload(item));
|
assertTrue(filter.shouldAutoDownload(item));
|
||||||
assertFalse(filter.shouldAutoDownload(item2));
|
assertFalse(filter.shouldAutoDownload(item2));
|
||||||
assertTrue(filter.shouldAutoDownload(item3));
|
assertTrue(filter.shouldAutoDownload(item3));
|
||||||
|
@ -99,8 +99,8 @@ public class FeedFilterTest {
|
||||||
|
|
||||||
assertTrue(filter.excludeOnly());
|
assertTrue(filter.excludeOnly());
|
||||||
assertFalse(filter.includeOnly());
|
assertFalse(filter.includeOnly());
|
||||||
assertEquals(excludeFilter, filter.getExcludeFilter());
|
assertEquals(excludeFilter, filter.getExcludeFilterRaw());
|
||||||
assertEquals("", filter.getIncludeFilter());
|
assertEquals("", filter.getIncludeFilterRaw());
|
||||||
assertFalse(filter.shouldAutoDownload(item));
|
assertFalse(filter.shouldAutoDownload(item));
|
||||||
assertTrue(filter.shouldAutoDownload(item2));
|
assertTrue(filter.shouldAutoDownload(item2));
|
||||||
assertFalse(filter.shouldAutoDownload(item3));
|
assertFalse(filter.shouldAutoDownload(item3));
|
||||||
|
|
|
@ -102,14 +102,22 @@ public class FeedFilter implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIncludeFilter() {
|
public String getIncludeFilterRaw() {
|
||||||
return includeFilter;
|
return includeFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getExcludeFilter() {
|
public String getExcludeFilterRaw() {
|
||||||
return excludeFilter;
|
return excludeFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getIncludeFilter() {
|
||||||
|
return includeFilter == null ? new ArrayList<>() : parseTerms(includeFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getExcludeFilter() {
|
||||||
|
return excludeFilter == null ? new ArrayList<>() : parseTerms(excludeFilter);
|
||||||
|
}
|
||||||
|
|
||||||
public int getMinimalDurationFilter() {
|
public int getMinimalDurationFilter() {
|
||||||
return minimalDuration;
|
return minimalDuration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,8 +448,8 @@ public class PodDBAdapter {
|
||||||
values.put(KEY_FEED_VOLUME_ADAPTION, prefs.getVolumeAdaptionSetting().toInteger());
|
values.put(KEY_FEED_VOLUME_ADAPTION, prefs.getVolumeAdaptionSetting().toInteger());
|
||||||
values.put(KEY_USERNAME, prefs.getUsername());
|
values.put(KEY_USERNAME, prefs.getUsername());
|
||||||
values.put(KEY_PASSWORD, prefs.getPassword());
|
values.put(KEY_PASSWORD, prefs.getPassword());
|
||||||
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
|
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilterRaw());
|
||||||
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
|
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilterRaw());
|
||||||
values.put(KEY_MINIMAL_DURATION_FILTER, prefs.getFilter().getMinimalDurationFilter());
|
values.put(KEY_MINIMAL_DURATION_FILTER, prefs.getFilter().getMinimalDurationFilter());
|
||||||
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
|
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
|
||||||
values.put(KEY_FEED_TAGS, prefs.getTagsAsString());
|
values.put(KEY_FEED_TAGS, prefs.getTagsAsString());
|
||||||
|
|
|
@ -190,6 +190,7 @@
|
||||||
<item quantity="other">%d subscriptions updated.</item>
|
<item quantity="other">%d subscriptions updated.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="edit_tags">Edit tags</string>
|
<string name="edit_tags">Edit tags</string>
|
||||||
|
<string name="add_tag">Add tag</string>
|
||||||
<string name="rename_tag_label">Rename tag</string>
|
<string name="rename_tag_label">Rename tag</string>
|
||||||
<string name="confirm_mobile_feed_refresh_dialog_message">Refreshing podcasts over mobile data connection is disabled in the settings.\n\nDo you want to refresh anyway?</string>
|
<string name="confirm_mobile_feed_refresh_dialog_message">Refreshing podcasts over mobile data connection is disabled in the settings.\n\nDo you want to refresh anyway?</string>
|
||||||
|
|
||||||
|
@ -690,10 +691,10 @@
|
||||||
<string name="auto_download_settings_label">Auto Download Settings</string>
|
<string name="auto_download_settings_label">Auto Download Settings</string>
|
||||||
<string name="episode_filters_label">Episode Filter</string>
|
<string name="episode_filters_label">Episode Filter</string>
|
||||||
<string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
|
<string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
|
||||||
<string name="episode_filters_include">Include</string>
|
<string name="add_term">Add Term</string>
|
||||||
<string name="episode_filters_exclude">Exclude</string>
|
<string name="exclude_terms">Exclude episodes containing any of the terms below</string>
|
||||||
<string name="episode_filters_duration">Minimal Duration (in minutes)</string>
|
<string name="include_terms">Include only episodes containing any of the terms below</string>
|
||||||
<string name="episode_filters_hint">Single words \n\"Multiple Words\"</string>
|
<string name="exclude_episodes_shorter_than">Exclude episodes shorter than</string>
|
||||||
<string name="keep_updated">Keep Updated</string>
|
<string name="keep_updated">Keep Updated</string>
|
||||||
<string name="keep_updated_summary">Include this podcast when (auto-)refreshing all podcasts</string>
|
<string name="keep_updated_summary">Include this podcast when (auto-)refreshing all podcasts</string>
|
||||||
<string name="auto_download_disabled_globally">Auto download is disabled in the main AntennaPod settings</string>
|
<string name="auto_download_disabled_globally">Auto download is disabled in the main AntennaPod settings</string>
|
||||||
|
|
Loading…
Reference in New Issue