diff options
Diffstat (limited to 'app/src/main/java/de')
28 files changed, 691 insertions, 583 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index c5d656aa0..031117170 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -36,6 +36,7 @@ import de.danoeh.antennapod.core.feed.FeedUrlNotFoundException; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.service.playback.PlaybackServiceInterface; import de.danoeh.antennapod.core.util.DownloadErrorLabel; +import de.danoeh.antennapod.databinding.EditTextDialogBinding; import de.danoeh.antennapod.databinding.OnlinefeedviewHeaderBinding; import de.danoeh.antennapod.event.EpisodeDownloadEvent; import de.danoeh.antennapod.event.FeedListUpdateEvent; @@ -95,7 +96,7 @@ import java.util.Map; public class OnlineFeedViewActivity extends AppCompatActivity { public static final String ARG_FEEDURL = "arg.feedurl"; - // Optional argument: specify a title for the actionbar. + public static final String ARG_WAS_MANUAL_URL = "manual_url"; private static final int RESULT_ERROR = 2; private static final String TAG = "OnlineFeedViewActivity"; private static final String PREFS = "OnlineFeedViewActivityPreferences"; @@ -598,7 +599,10 @@ public class OnlineFeedViewActivity extends AppCompatActivity { builder.setMessage(R.string.download_error_error_unknown); } builder.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.cancel()); - builder.setOnDismissListener(dialog -> { + if (getIntent().getBooleanExtra(ARG_WAS_MANUAL_URL, false)) { + builder.setNeutralButton(R.string.edit_url_menu, (dialog, which) -> editUrl()); + } + builder.setOnCancelListener(dialog -> { setResult(RESULT_ERROR); finish(); }); @@ -609,6 +613,26 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } } + private void editUrl() { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); + builder.setTitle(R.string.edit_url_menu); + final EditTextDialogBinding dialogBinding = EditTextDialogBinding.inflate(getLayoutInflater()); + if (downloader != null) { + dialogBinding.urlEditText.setText(downloader.getDownloadRequest().getSource()); + } + builder.setView(dialogBinding.getRoot()); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { + setLoadingLayout(); + lookupUrlAndDownload(dialogBinding.urlEditText.getText().toString()); + }); + builder.setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel()); + builder.setOnCancelListener(dialog1 -> { + setResult(RESULT_ERROR); + finish(); + }); + builder.show(); + } + @Subscribe(threadMode = ThreadMode.MAIN) public void playbackStateChanged(PlayerStatusEvent event) { boolean isPlayingPreview = diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java index 10a41057c..3f1c17cdc 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java @@ -6,7 +6,9 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; import android.util.Log; import android.util.SparseBooleanArray; import android.view.Menu; @@ -45,6 +47,7 @@ import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * Activity for Opml Import. @@ -140,15 +143,6 @@ public class OpmlImportActivity extends AppCompatActivity { return; } this.uri = uri; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && uri.toString().contains(Environment.getExternalStorageDirectory().toString())) { - int permission = ActivityCompat.checkSelfPermission(this, - android.Manifest.permission.READ_EXTERNAL_STORAGE); - if (permission != PackageManager.PERMISSION_GRANTED) { - requestPermission(); - return; - } - } startImport(); } @@ -244,12 +238,29 @@ public class OpmlImportActivity extends AppCompatActivity { getTitleList()); viewBinding.feedlist.setAdapter(listAdapter); }, e -> { + Log.d(TAG, Log.getStackTraceString(e)); + String message = e.getMessage() == null ? "" : e.getMessage(); + if (message.toLowerCase(Locale.ROOT).contains("permission") + && Build.VERSION.SDK_INT >= 23) { + int permission = ActivityCompat.checkSelfPermission(this, + android.Manifest.permission.READ_EXTERNAL_STORAGE); + if (permission != PackageManager.PERMISSION_GRANTED) { + requestPermission(); + return; + } + } viewBinding.progressBar.setVisibility(View.GONE); MaterialAlertDialogBuilder alert = new MaterialAlertDialogBuilder(this); alert.setTitle(R.string.error_label); - alert.setMessage(getString(R.string.opml_reader_error) + e.getMessage()); - alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); - alert.create().show(); + String userReadable = getString(R.string.opml_reader_error); + String details = e.getMessage(); + String total = userReadable + "\n\n" + details; + SpannableString errorMessage = new SpannableString(total); + errorMessage.setSpan(new ForegroundColorSpan(0x88888888), + userReadable.length(), total.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + alert.setMessage(errorMessage); + alert.setPositiveButton(android.R.string.ok, (dialog, which) -> finish()); + alert.show(); }); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index e3473937e..fc371090e 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -567,7 +567,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive()); menu.findItem(R.id.player_switch_to_audio_only).setVisible(true); - menu.findItem(R.id.audio_controls).setIcon(R.drawable.ic_sliders); + + menu.findItem(R.id.audio_controls).setVisible(controller.getAudioTracks().size() >= 2); menu.findItem(R.id.playback_speed).setVisible(true); menu.findItem(R.id.player_show_chapters).setVisible(true); return true; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index 8d220c90d..a304ead3c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -261,7 +261,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder> int spaceUsed = itemAccess.getNumberOfDownloadedItems() - itemAccess.getReclaimableItems(); if (epCacheSize > 0 && spaceUsed >= epCacheSize) { - holder.count.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_disc_full, 0); + holder.count.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_disc_alert, 0); holder.count.setVisibility(View.VISIBLE); holder.count.setOnClickListener(v -> new MaterialAlertDialogBuilder(context) diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java deleted file mode 100644 index dc8cf65ba..000000000 --- a/app/src/main/java/de/danoeh/antennapod/dialog/IntraFeedSortDialog.java +++ /dev/null @@ -1,68 +0,0 @@ -package de.danoeh.antennapod.dialog; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.model.feed.SortOrder; - -public abstract class IntraFeedSortDialog { - - @Nullable - protected SortOrder currentSortOrder; - @NonNull - protected Context context; - - private final String[] sortItems; - private final SortOrder[] sortValues; - - public IntraFeedSortDialog(@NonNull Context context, @Nullable SortOrder sortOrder, @NonNull boolean isLocalFeed) { - this.context = context; - this.currentSortOrder = sortOrder; - - if (isLocalFeed) { - sortItems = context.getResources().getStringArray(R.array.local_feed_episodes_sort_options); - final String[] localSortStringValues = - context.getResources().getStringArray(R.array.local_feed_episodes_sort_values); - sortValues = SortOrder.valuesOf(localSortStringValues); - } else { - sortItems = context.getResources().getStringArray(R.array.feed_episodes_sort_options); - final String[] commonSortStringValues = - context.getResources().getStringArray(R.array.feed_episodes_sort_values); - sortValues = SortOrder.valuesOf(commonSortStringValues); - } - } - - public void openDialog() { - int idxCurrentSort = getCurrentSortOrderIndex(); - - MaterialAlertDialogBuilder builder = - new MaterialAlertDialogBuilder(context) - .setTitle(R.string.sort) - .setSingleChoiceItems(sortItems, idxCurrentSort, (dialog, idxNewSort) -> { - updateSort(sortValues[idxNewSort]); - dialog.dismiss(); - }) - .setNegativeButton(R.string.cancel_label, null); - builder.create().show(); - } - - /** - * Retrieves index of currentSortOrder index in values array. - * @return if currentSortOrder is found in array - returns index of that element, - * otherwise returns 0, the default sort option; - */ - private int getCurrentSortOrderIndex() { - for (int i = 0; i < sortValues.length; i++) { - if (currentSortOrder == sortValues[i]) { - return i; - } - } - return 0; - } - - protected abstract void updateSort(@NonNull SortOrder sortOrder); -} diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ItemFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ItemFilterDialog.java index 92c143992..359c513af 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/ItemFilterDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ItemFilterDialog.java @@ -18,11 +18,13 @@ import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.button.MaterialButtonToggleGroup; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItemFilterGroup; +import de.danoeh.antennapod.databinding.FilterDialogBinding; import de.danoeh.antennapod.databinding.FilterDialogRowBinding; import de.danoeh.antennapod.model.feed.FeedItemFilter; @@ -36,24 +38,36 @@ public abstract class ItemFilterDialog extends BottomSheetDialogFragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.filter_dialog, null, false); - rows = layout.findViewById(R.id.filter_rows); + FilterDialogBinding binding = FilterDialogBinding.bind(layout); + rows = binding.filterRows; FeedItemFilter filter = (FeedItemFilter) getArguments().getSerializable(ARGUMENT_FILTER); + //add filter rows for (FeedItemFilterGroup item : FeedItemFilterGroup.values()) { - FilterDialogRowBinding binding = FilterDialogRowBinding.inflate(inflater); - binding.getRoot().addOnButtonCheckedListener( + FilterDialogRowBinding rowBinding = FilterDialogRowBinding.inflate(inflater); + rowBinding.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); - binding.filterButton1.setMaxLines(3); - binding.filterButton1.setSingleLine(false); - binding.filterButton2.setMaxLines(3); - binding.filterButton2.setSingleLine(false); - rows.addView(binding.getRoot()); + rowBinding.filterButton1.setText(item.values[0].displayName); + rowBinding.filterButton1.setTag(item.values[0].filterId); + rowBinding.filterButton2.setText(item.values[1].displayName); + rowBinding.filterButton2.setTag(item.values[1].filterId); + rowBinding.filterButton1.setMaxLines(3); + rowBinding.filterButton1.setSingleLine(false); + rowBinding.filterButton2.setMaxLines(3); + rowBinding.filterButton2.setSingleLine(false); + rows.addView(rowBinding.getRoot(), rows.getChildCount() - 1); } + binding.confirmFiltermenu.setOnClickListener(view1 -> dismiss()); + binding.resetFiltermenu.setOnClickListener(view1 -> { + onFilterChanged(Collections.emptySet()); + for (int i = 0; i < rows.getChildCount(); i++) { + if (rows.getChildAt(i) instanceof MaterialButtonToggleGroup) { + ((MaterialButtonToggleGroup) rows.getChildAt(i)).clearChecked(); + } + } + }); + for (String filterId : filter.getValues()) { if (!TextUtils.isEmpty(filterId)) { Button button = layout.findViewWithTag(filterId); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ItemSortDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ItemSortDialog.java new file mode 100644 index 000000000..cd6cc4b0a --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ItemSortDialog.java @@ -0,0 +1,104 @@ +package de.danoeh.antennapod.dialog; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.databinding.SortDialogBinding; +import de.danoeh.antennapod.databinding.SortDialogItemActiveBinding; +import de.danoeh.antennapod.databinding.SortDialogItemBinding; +import de.danoeh.antennapod.model.feed.SortOrder; + +public class ItemSortDialog extends BottomSheetDialogFragment { + protected SortOrder sortOrder; + protected SortDialogBinding viewBinding; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + viewBinding = SortDialogBinding.inflate(inflater); + populateList(); + viewBinding.keepSortedCheckbox.setOnCheckedChangeListener( + (buttonView, isChecked) -> ItemSortDialog.this.onSelectionChanged()); + return viewBinding.getRoot(); + } + + private void populateList() { + viewBinding.gridLayout.removeAllViews(); + onAddItem(R.string.episode_title, SortOrder.EPISODE_TITLE_A_Z, SortOrder.EPISODE_TITLE_Z_A, true); + onAddItem(R.string.feed_title, SortOrder.FEED_TITLE_A_Z, SortOrder.FEED_TITLE_Z_A, true); + onAddItem(R.string.duration, SortOrder.DURATION_SHORT_LONG, SortOrder.DURATION_LONG_SHORT, true); + onAddItem(R.string.date, SortOrder.DATE_OLD_NEW, SortOrder.DATE_NEW_OLD, false); + onAddItem(R.string.size, SortOrder.SIZE_SMALL_LARGE, SortOrder.SIZE_LARGE_SMALL, false); + onAddItem(R.string.filename, SortOrder.EPISODE_FILENAME_A_Z, SortOrder.EPISODE_FILENAME_Z_A, true); + onAddItem(R.string.random, SortOrder.RANDOM, SortOrder.RANDOM, true); + onAddItem(R.string.smart_shuffle, SortOrder.SMART_SHUFFLE_OLD_NEW, SortOrder.SMART_SHUFFLE_NEW_OLD, false); + } + + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (sortOrder == ascending || sortOrder == descending) { + SortDialogItemActiveBinding item = SortDialogItemActiveBinding.inflate( + getLayoutInflater(), viewBinding.gridLayout, false); + SortOrder other; + if (ascending == descending) { + item.button.setText(title); + other = ascending; + } else if (sortOrder == ascending) { + item.button.setText(getString(title) + "\u00A0▲"); + other = descending; + } else { + item.button.setText(getString(title) + "\u00A0▼"); + other = ascending; + } + item.button.setOnClickListener(v -> { + sortOrder = other; + populateList(); + onSelectionChanged(); + }); + viewBinding.gridLayout.addView(item.getRoot()); + } else { + SortDialogItemBinding item = SortDialogItemBinding.inflate( + getLayoutInflater(), viewBinding.gridLayout, false); + item.button.setText(title); + item.button.setOnClickListener(v -> { + sortOrder = ascendingIsDefault ? ascending : descending; + populateList(); + onSelectionChanged(); + }); + viewBinding.gridLayout.addView(item.getRoot()); + } + } + + protected void onSelectionChanged() { + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.setOnShowListener(dialogInterface -> { + BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface; + setupFullHeight(bottomSheetDialog); + }); + return dialog; + } + + private void setupFullHeight(BottomSheetDialog bottomSheetDialog) { + FrameLayout bottomSheet = bottomSheetDialog.findViewById(R.id.design_bottom_sheet); + if (bottomSheet != null) { + BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet); + ViewGroup.LayoutParams layoutParams = bottomSheet.getLayoutParams(); + bottomSheet.setLayoutParams(layoutParams); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java index a87dccdf5..009f33fe2 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java @@ -10,9 +10,7 @@ import androidx.appcompat.app.AlertDialog; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import androidx.fragment.app.DialogFragment; import android.widget.Button; -import android.widget.CheckBox; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.core.util.playback.PlaybackController; import java.util.List; @@ -37,12 +35,10 @@ public class PlaybackControlsDialog extends DialogFragment { controller = new PlaybackController(getActivity()) { @Override public void loadMediaInfo() { - setupUi(); setupAudioTracks(); } }; controller.init(); - setupUi(); } @Override @@ -62,15 +58,6 @@ public class PlaybackControlsDialog extends DialogFragment { return dialog; } - private void setupUi() { - final CheckBox skipSilence = dialog.findViewById(R.id.skipSilence); - skipSilence.setChecked(UserPreferences.isSkipSilence()); - skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> { - UserPreferences.setSkipSilence(isChecked); - controller.setSkipSilence(isChecked); - }); - } - private void setupAudioTracks() { List<String> audioTracks = controller.getAudioTracks(); int selectedAudioTrack = controller.getSelectedAudioTrack(); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java index cf77c2838..929e6b1ad 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java @@ -1,42 +1,49 @@ package de.danoeh.antennapod.dialog; -import android.content.Context; +import android.app.Dialog; +import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.Button; +import android.widget.FrameLayout; import android.widget.LinearLayout; - +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.button.MaterialButtonToggleGroup; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.greenrobot.eventbus.EventBus; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup; +import de.danoeh.antennapod.databinding.FilterDialogBinding; import de.danoeh.antennapod.databinding.FilterDialogRowBinding; import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.model.feed.SubscriptionsFilter; import de.danoeh.antennapod.storage.preferences.UserPreferences; +import org.greenrobot.eventbus.EventBus; -public class SubscriptionsFilterDialog { - public static void showDialog(Context context) { - SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter(); - final Set<String> filterValues = new HashSet<>(Arrays.asList(subscriptionsFilter.getValues())); - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(context.getString(R.string.pref_filter_feed_title)); +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; - LayoutInflater inflater = LayoutInflater.from(context); - View layout = inflater.inflate(R.layout.filter_dialog, null, false); - LinearLayout rows = layout.findViewById(R.id.filter_rows); - builder.setView(layout); +public class SubscriptionsFilterDialog extends BottomSheetDialogFragment { + private LinearLayout rows; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter(); + FilterDialogBinding dialogBinding = FilterDialogBinding.inflate(inflater); + rows = dialogBinding.filterRows; for (SubscriptionsFilterGroup item : SubscriptionsFilterGroup.values()) { FilterDialogRowBinding binding = FilterDialogRowBinding.inflate(inflater); + binding.getRoot().addOnButtonCheckedListener( + (group, checkedId, isChecked) -> updateFilter(getFilterValues())); binding.buttonGroup.setWeightSum(item.values.length); binding.filterButton1.setText(item.values[0].displayName); binding.filterButton1.setTag(item.values[0].filterId); @@ -50,38 +57,72 @@ public class SubscriptionsFilterDialog { binding.filterButton1.setSingleLine(false); binding.filterButton2.setMaxLines(3); binding.filterButton2.setSingleLine(false); - rows.addView(binding.getRoot()); + rows.addView(binding.getRoot(), rows.getChildCount() - 1); } + final Set<String> filterValues = new HashSet<>(Arrays.asList(subscriptionsFilter.getValues())); for (String filterId : filterValues) { if (!TextUtils.isEmpty(filterId)) { - Button button = layout.findViewWithTag(filterId); + Button button = dialogBinding.getRoot().findViewWithTag(filterId); if (button != null) { ((MaterialButtonToggleGroup) button.getParent()).check(button.getId()); } } } - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - filterValues.clear(); + dialogBinding.confirmFiltermenu.setOnClickListener(view -> { + updateFilter(getFilterValues()); + dismiss(); + }); + dialogBinding.resetFiltermenu.setOnClickListener(view -> { + updateFilter(Collections.emptySet()); for (int i = 0; i < rows.getChildCount(); i++) { - if (!(rows.getChildAt(i) instanceof MaterialButtonToggleGroup)) { - continue; - } - 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; + if (rows.getChildAt(i) instanceof MaterialButtonToggleGroup) { + ((MaterialButtonToggleGroup) rows.getChildAt(i)).clearChecked(); } - filterValues.add(tag); } - updateFilter(filterValues); }); - builder.setNegativeButton(R.string.cancel_label, null); - builder.show(); + return dialogBinding.getRoot(); + } + + private Set<String> getFilterValues() { + Set<String> filterValues = new HashSet<>(); + for (int i = 0; i < rows.getChildCount(); i++) { + if (!(rows.getChildAt(i) instanceof MaterialButtonToggleGroup)) { + continue; + } + 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); + } + return filterValues; + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.setOnShowListener(dialogInterface -> { + BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface; + setupFullHeight(bottomSheetDialog); + }); + return dialog; + } + + private void setupFullHeight(BottomSheetDialog bottomSheetDialog) { + FrameLayout bottomSheet = bottomSheetDialog.findViewById(R.id.design_bottom_sheet); + if (bottomSheet != null) { + BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet); + ViewGroup.LayoutParams layoutParams = bottomSheet.getLayoutParams(); + bottomSheet.setLayoutParams(layoutParams); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } } private static void updateFilter(Set<String> filterValues) { diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index 0367e717b..8de7dce04 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -6,6 +6,8 @@ import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; @@ -94,6 +96,13 @@ public class VariableSpeedDialog extends BottomSheetDialogFragment { addCurrentSpeedChip.setOnCloseIconClickListener(v -> addCurrentSpeed()); addCurrentSpeedChip.setCloseIconContentDescription(getString(R.string.add_preset)); addCurrentSpeedChip.setOnClickListener(v -> addCurrentSpeed()); + + final CheckBox skipSilence = root.findViewById(R.id.skipSilence); + skipSilence.setChecked(UserPreferences.isSkipSilence()); + skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> { + UserPreferences.setSkipSilence(isChecked); + controller.setSkipSilence(isChecked); + }); return root; } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java index 29be41727..20cdd2718 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -147,6 +147,7 @@ public class AddFeedFragment extends Fragment { private void addUrl(String url) { Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url); + intent.putExtra(OnlineFeedViewActivity.ARG_WAS_MANUAL_URL, true); startActivity(intent); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 7061a69f3..ab5039ec2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -1,20 +1,23 @@ package de.danoeh.antennapod.fragment; -import android.content.Context; -import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.dialog.AllEpisodesFilterDialog; +import de.danoeh.antennapod.dialog.ItemSortDialog; +import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItemFilter; import de.danoeh.antennapod.model.feed.SortOrder; +import de.danoeh.antennapod.storage.preferences.UserPreferences; import org.apache.commons.lang3.StringUtils; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; @@ -26,48 +29,33 @@ import java.util.List; */ public class AllEpisodesFragment extends EpisodesListFragment { public static final String TAG = "EpisodesFragment"; - private static final String PREF_NAME = "PrefAllEpisodesFragment"; - private static final String PREF_FILTER = "filter"; - public static final String PREF_SORT = "prefEpisodesSort"; - private SharedPreferences prefs; + public static final String PREF_NAME = "PrefAllEpisodesFragment"; @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View root = super.onCreateView(inflater, container, savedInstanceState); toolbar.inflateMenu(R.menu.episodes); - inflateSortMenu(); toolbar.setTitle(R.string.episodes_label); updateToolbar(); updateFilterUi(); - prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); txtvInformation.setOnClickListener( v -> AllEpisodesFilterDialog.newInstance(getFilter()).show(getChildFragmentManager(), null)); return root; } - private void inflateSortMenu() { - MenuItem sortItem = toolbar.getMenu().findItem(R.id.episodes_sort); - getActivity().getMenuInflater().inflate(R.menu.sort_menu, sortItem.getSubMenu()); - - // Remove the sorting options that are not needed in this fragment - toolbar.getMenu().findItem(R.id.sort_episode_title).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_feed_title).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_random).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_smart_shuffle).setVisible(false); - toolbar.getMenu().findItem(R.id.keep_sorted).setVisible(false); - } - @NonNull @Override protected List<FeedItem> loadData() { - return DBReader.getEpisodes(0, page * EPISODES_PER_PAGE, getFilter(), getSortOrder()); + return DBReader.getEpisodes(0, page * EPISODES_PER_PAGE, getFilter(), + UserPreferences.getAllEpisodesSortOrder()); } @NonNull @Override protected List<FeedItem> loadMoreData(int page) { - return DBReader.getEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, getFilter(), getSortOrder()); + return DBReader.getEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, getFilter(), + UserPreferences.getAllEpisodesSortOrder()); } @Override @@ -77,8 +65,7 @@ public class AllEpisodesFragment extends EpisodesListFragment { @Override protected FeedItemFilter getFilter() { - SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); - return new FeedItemFilter(prefs.getString(PREF_FILTER, "")); + return new FeedItemFilter(UserPreferences.getPrefFilterAllEpisodes()); } @Override @@ -108,24 +95,16 @@ public class AllEpisodesFragment extends EpisodesListFragment { } onFilterChanged(new AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent(new HashSet<>(filter))); return true; - } else { - SortOrder sortOrder = MenuItemToSortOrderConverter.convert(item); - if (sortOrder != null) { - saveSortOrderAndRefresh(sortOrder); - return true; - } + } else if (item.getItemId() == R.id.episodes_sort) { + new AllEpisodesSortDialog().show(getChildFragmentManager().beginTransaction(), "SortDialog"); + return true; } return false; } - private void saveSortOrderAndRefresh(SortOrder type) { - prefs.edit().putString(PREF_SORT, "" + type.code).apply(); - loadItems(); - } - @Subscribe public void onFilterChanged(AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent event) { - prefs.edit().putString(PREF_FILTER, StringUtils.join(event.filterValues, ",")).apply(); + UserPreferences.setPrefFilterAllEpisodes(StringUtils.join(event.filterValues, ",")); updateFilterUi(); page = 1; loadItems(); @@ -144,7 +123,25 @@ public class AllEpisodesFragment extends EpisodesListFragment { getFilter().showIsFavorite ? R.drawable.ic_star : R.drawable.ic_star_border); } - private SortOrder getSortOrder() { - return SortOrder.fromCodeString(prefs.getString(PREF_SORT, "" + SortOrder.DATE_NEW_OLD.code)); + public static class AllEpisodesSortDialog extends ItemSortDialog { + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sortOrder = UserPreferences.getAllEpisodesSortOrder(); + } + + @Override + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG) { + super.onAddItem(title, ascending, descending, ascendingIsDefault); + } + } + + @Override + protected void onSelectionChanged() { + super.onSelectionChanged(); + UserPreferences.setAllEpisodesSortOrder(sortOrder); + EventBus.getDefault().post(new FeedListUpdateEvent(0)); + } } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java index f2a53ab7e..8b25c0e6a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java @@ -15,25 +15,16 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.android.material.appbar.MaterialToolbar; import androidx.cardview.widget.CardView; import androidx.fragment.app.Fragment; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.elevation.SurfaceColors; -import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; -import de.danoeh.antennapod.core.util.playback.PlaybackController; -import de.danoeh.antennapod.dialog.MediaPlayerErrorDialog; -import de.danoeh.antennapod.event.playback.BufferUpdateEvent; -import de.danoeh.antennapod.event.playback.PlaybackServiceEvent; -import de.danoeh.antennapod.event.PlayerErrorEvent; -import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent; -import de.danoeh.antennapod.event.playback.SpeedChangedEvent; -import de.danoeh.antennapod.playback.cast.CastEnabledActivity; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -44,23 +35,31 @@ import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.event.FavoritesEvent; -import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; -import de.danoeh.antennapod.model.feed.Chapter; -import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; -import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils; -import de.danoeh.antennapod.storage.preferences.UserPreferences; +import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.TimeSpeedConverter; -import de.danoeh.antennapod.model.playback.Playable; -import de.danoeh.antennapod.dialog.PlaybackControlsDialog; +import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.dialog.MediaPlayerErrorDialog; import de.danoeh.antennapod.dialog.SkipPreferenceDialog; import de.danoeh.antennapod.dialog.SleepTimerDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import de.danoeh.antennapod.event.FavoritesEvent; +import de.danoeh.antennapod.event.PlayerErrorEvent; +import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; +import de.danoeh.antennapod.event.playback.BufferUpdateEvent; +import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; +import de.danoeh.antennapod.event.playback.PlaybackServiceEvent; +import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent; +import de.danoeh.antennapod.event.playback.SpeedChangedEvent; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; +import de.danoeh.antennapod.model.feed.Chapter; +import de.danoeh.antennapod.model.feed.FeedItem; +import de.danoeh.antennapod.model.feed.FeedMedia; +import de.danoeh.antennapod.model.playback.Playable; +import de.danoeh.antennapod.playback.cast.CastEnabledActivity; +import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.ui.common.PlaybackSpeedIndicatorView; import de.danoeh.antennapod.view.ChapterSeekBar; import de.danoeh.antennapod.view.PlayButton; @@ -503,10 +502,6 @@ public class AudioPlayerFragment extends Fragment implements if (itemId == R.id.disable_sleeptimer_item || itemId == R.id.set_sleeptimer_item) { new SleepTimerDialog().show(getChildFragmentManager(), "SleepTimerDialog"); return true; - } else if (itemId == R.id.audio_controls) { - PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(); - dialog.show(getChildFragmentManager(), "playback_controls"); - return true; } else if (itemId == R.id.open_feed_item) { if (feedItem != null) { Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feedItem.getFeedId()); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java index 730a39189..ec7a35466 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -4,16 +4,14 @@ import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.android.material.appbar.MaterialToolbar; import androidx.fragment.app.Fragment; +import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.snackbar.Snackbar; import com.leinardi.android.speeddial.SpeedDialView; import de.danoeh.antennapod.R; @@ -25,6 +23,7 @@ import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.download.FeedUpdateManager; +import de.danoeh.antennapod.dialog.ItemSortDialog; import de.danoeh.antennapod.event.EpisodeDownloadEvent; import de.danoeh.antennapod.event.FeedItemEvent; import de.danoeh.antennapod.event.PlayerStatusEvent; @@ -84,8 +83,6 @@ public class CompletedDownloadsFragment extends Fragment toolbar = root.findViewById(R.id.toolbar); toolbar.setTitle(R.string.downloads_label); toolbar.inflateMenu(R.menu.downloads_completed); - inflateSortMenu(toolbar); - toolbar.setOnMenuItemClickListener(this); toolbar.setOnLongClickListener(v -> { recyclerView.scrollToPosition(5); @@ -148,20 +145,6 @@ public class CompletedDownloadsFragment extends Fragment return root; } - private void inflateSortMenu(MaterialToolbar toolbar) { - Menu menu = toolbar.getMenu(); - MenuItem downloadsItem = menu.findItem(R.id.downloads_sort); - MenuInflater menuInflater = getActivity().getMenuInflater(); - menuInflater.inflate(R.menu.sort_menu, downloadsItem.getSubMenu()); - - // Remove the sorting options that are not needed in this fragment - menu.findItem(R.id.sort_feed_title).setVisible(false); - menu.findItem(R.id.sort_random).setVisible(false); - menu.findItem(R.id.sort_smart_shuffle).setVisible(false); - menu.findItem(R.id.keep_sorted).setVisible(false); - menu.findItem(R.id.sort_size).setVisible(true); - } - @Override public void onSaveInstanceState(@NonNull Bundle outState) { outState.putBoolean(KEY_UP_ARROW, displayUpArrow); @@ -204,21 +187,13 @@ public class CompletedDownloadsFragment extends Fragment } else if (item.getItemId() == R.id.action_search) { ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance()); return true; - } else { - SortOrder sortOrder = MenuItemToSortOrderConverter.convert(item); - if (sortOrder != null) { - setSortOrder(sortOrder); - return true; - } + } else if (item.getItemId() == R.id.downloads_sort) { + new DownloadsSortDialog().show(getChildFragmentManager(), "SortDialog"); + return true; } return false; } - private void setSortOrder(SortOrder sortOrder) { - UserPreferences.setDownloadsSortedOrder(sortOrder); - loadItems(); - } - @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(EpisodeDownloadEvent event) { Set<String> newRunningDownloads = new HashSet<>(); @@ -391,4 +366,27 @@ public class CompletedDownloadsFragment extends Fragment MenuItemUtils.setOnClickListeners(menu, CompletedDownloadsFragment.this::onContextItemSelected); } } + + public static class DownloadsSortDialog extends ItemSortDialog { + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sortOrder = UserPreferences.getDownloadsSortedOrder(); + } + + @Override + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG + || ascending == SortOrder.EPISODE_TITLE_A_Z || ascending == SortOrder.SIZE_SMALL_LARGE) { + super.onAddItem(title, ascending, descending, ascendingIsDefault); + } + } + + @Override + protected void onSelectionChanged() { + super.onSelectionChanged(); + UserPreferences.setDownloadsSortedOrder(sortOrder); + EventBus.getDefault().post(DownloadLogEvent.listUpdated()); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 00d671d36..0cbc23a56 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -2,8 +2,6 @@ package de.danoeh.antennapod.fragment; import android.content.DialogInterface; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.ContextMenu; import android.view.KeyEvent; @@ -13,6 +11,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; import androidx.core.util.Pair; @@ -20,9 +19,19 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.snackbar.Snackbar; import com.leinardi.android.speeddial.SpeedDialView; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; @@ -51,13 +60,6 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; /** * Shows unread or recently published episodes @@ -77,6 +79,7 @@ public abstract class EpisodesListFragment extends Fragment EmptyViewHandler emptyView; SpeedDialView speedDialView; MaterialToolbar toolbar; + SwipeRefreshLayout swipeRefreshLayout; SwipeActions swipeActions; private ProgressBar progressBar; @@ -180,13 +183,9 @@ public abstract class EpisodesListFragment extends Fragment ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); } - SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); + swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance)); - swipeRefreshLayout.setOnRefreshListener(() -> { - FeedUpdateManager.runOnceOrAsk(requireContext()); - new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false), - getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms)); - }); + swipeRefreshLayout.setOnRefreshListener(() -> FeedUpdateManager.runOnceOrAsk(requireContext())); listAdapter = new EpisodeItemListAdapter((MainActivity) getActivity()) { @Override @@ -456,9 +455,7 @@ public abstract class EpisodesListFragment extends Fragment @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedUpdateRunningEvent event) { - if (toolbar.getMenu().findItem(R.id.refresh_item) != null) { - MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning); - } + swipeRefreshLayout.setRefreshing(event.isFeedUpdateRunning); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java index b4fa77c75..f62bdaf84 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -22,25 +22,24 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; import androidx.appcompat.content.res.AppCompatResources; -import com.google.android.material.appbar.MaterialToolbar; import androidx.documentfile.provider.DocumentFile; import androidx.fragment.app.Fragment; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; +import com.google.android.material.appbar.MaterialToolbar; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; -import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.ShareUtils; import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; import de.danoeh.antennapod.dialog.EditUrlSettingsDialog; -import de.danoeh.antennapod.menuhandler.FeedMenuHandler; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedFunding; import de.danoeh.antennapod.ui.glide.FastBlurTransformation; @@ -228,7 +227,8 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu txtvAuthorHeader.setText(feed.getAuthor()); } - txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); + txtvUrl.setText(feed.getDownload_url()); + txtvUrl.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_paperclip, 0); if (feed.getPaymentLinks() == null || feed.getPaymentLinks().size() == 0) { lblSupport.setVisibility(View.GONE); @@ -263,7 +263,6 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu txtvFundingUrl.setText(str.toString()); } - Iconify.addIcons(txtvUrl); refreshToolbarState(); } @@ -290,9 +289,11 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu R.string.please_wait_for_data, Toast.LENGTH_LONG); return false; } - boolean handled = FeedMenuHandler.onOptionsItemClicked(getContext(), item, feed); - - if (item.getItemId() == R.id.reconnect_local_folder) { + if (item.getItemId() == R.id.visit_website_item) { + IntentUtils.openInBrowser(getContext(), feed.getLink()); + } else if (item.getItemId() == R.id.share_item) { + ShareUtils.shareFeedLink(getContext(), feed); + } else if (item.getItemId() == R.id.reconnect_local_folder) { MaterialAlertDialogBuilder alert = new MaterialAlertDialogBuilder(getContext()); alert.setMessage(R.string.reconnect_local_folder_warning); alert.setPositiveButton(android.R.string.ok, (dialog, which) -> { @@ -304,23 +305,19 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu }); alert.setNegativeButton(android.R.string.cancel, null); alert.show(); - return true; - } - - if (item.getItemId() == R.id.edit_feed_url_item) { + } else if (item.getItemId() == R.id.edit_feed_url_item) { new EditUrlSettingsDialog(getActivity(), feed) { @Override protected void setUrl(String url) { feed.setDownload_url(url); - txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); - Iconify.addIcons(txtvUrl); + txtvUrl.setText(feed.getDownload_url()); + txtvUrl.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_paperclip, 0); } }.show(); - - return true; + } else { + return false; } - - return handled; + return true; } private void addLocalFolderResult(final Uri uri) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 1c949218a..8020235b9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -4,8 +4,6 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.LightingColorFilter; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.ContextMenu; import android.view.KeyEvent; @@ -15,31 +13,48 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Toast; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; -import com.google.android.material.appbar.MaterialToolbar; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; + import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.snackbar.Snackbar; import com.joanzapata.iconify.Iconify; import com.leinardi.android.speeddial.SpeedDialView; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; import de.danoeh.antennapod.core.feed.FeedEvent; import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.FeedItemPermutors; import de.danoeh.antennapod.core.util.FeedItemUtil; +import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.ShareUtils; import de.danoeh.antennapod.core.util.download.FeedUpdateManager; import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil; import de.danoeh.antennapod.databinding.FeedItemListFragmentBinding; import de.danoeh.antennapod.databinding.MultiSelectSpeedDialBinding; import de.danoeh.antennapod.dialog.DownloadLogDetailsDialog; import de.danoeh.antennapod.dialog.FeedItemFilterDialog; +import de.danoeh.antennapod.dialog.ItemSortDialog; import de.danoeh.antennapod.dialog.RemoveFeedDialog; import de.danoeh.antennapod.dialog.RenameItemDialog; import de.danoeh.antennapod.event.EpisodeDownloadEvent; @@ -54,11 +69,11 @@ import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler; import de.danoeh.antennapod.fragment.swipeactions.SwipeActions; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; -import de.danoeh.antennapod.menuhandler.FeedMenuHandler; import de.danoeh.antennapod.model.download.DownloadResult; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.model.feed.SortOrder; import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.ui.glide.FastBlurTransformation; import de.danoeh.antennapod.view.ToolbarIconTintManager; @@ -68,13 +83,6 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import org.apache.commons.lang3.Validate; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import java.util.Collections; -import java.util.List; /** * Displays a list of FeedItems. @@ -183,11 +191,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem EventBus.getDefault().register(this); viewBinding.swipeRefresh.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance)); - viewBinding.swipeRefresh.setOnRefreshListener(() -> { - FeedUpdateManager.runOnceOrAsk(requireContext(), feed); - new Handler(Looper.getMainLooper()).postDelayed(() -> viewBinding.swipeRefresh.setRefreshing(false), - getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms)); - }); + viewBinding.swipeRefresh.setOnRefreshListener(() -> FeedUpdateManager.runOnceOrAsk(requireContext(), feed)); loadItems(); @@ -240,8 +244,13 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem return; } viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(feed.getLink() != null); - - FeedMenuHandler.onPrepareOptionsMenu(viewBinding.toolbar.getMenu(), feed); + viewBinding.toolbar.getMenu().findItem(R.id.refresh_complete_item).setVisible(feed.isPaged()); + if (StringUtils.isBlank(feed.getLink())) { + viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(false); + } + if (feed.isLocalFeed()) { + viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(false); + } } @Override @@ -260,26 +269,39 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem R.string.please_wait_for_data, Toast.LENGTH_LONG); return true; } - boolean feedMenuHandled = FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed); - if (feedMenuHandled) { - return true; - } - final int itemId = item.getItemId(); - if (itemId == R.id.rename_item) { + if (item.getItemId() == R.id.visit_website_item) { + IntentUtils.openInBrowser(getContext(), feed.getLink()); + } else if (item.getItemId() == R.id.share_item) { + ShareUtils.shareFeedLink(getContext(), feed); + } else if (item.getItemId() == R.id.refresh_item) { + FeedUpdateManager.runOnceOrAsk(getContext(), feed); + } else if (item.getItemId() == R.id.refresh_complete_item) { + new Thread(() -> { + feed.setNextPageLink(feed.getDownload_url()); + feed.setPageNr(0); + try { + DBWriter.resetPagedFeedPage(feed).get(); + FeedUpdateManager.runOnce(getContext(), feed); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + }).start(); + } else if (item.getItemId() == R.id.sort_items) { + SingleFeedSortDialog.newInstance(feed).show(getChildFragmentManager(), "SortDialog"); + } else if (item.getItemId() == R.id.rename_item) { new RenameItemDialog(getActivity(), feed).show(); - return true; - } else if (itemId == R.id.remove_feed) { + } else if (item.getItemId() == R.id.remove_feed) { RemoveFeedDialog.show(getContext(), feed, () -> { ((MainActivity) getActivity()).loadFragment(UserPreferences.getDefaultPage(), null); // Make sure fragment is hidden before actually starting to delete getActivity().getSupportFragmentManager().executePendingTransactions(); }); - return true; - } else if (itemId == R.id.action_search) { + } else if (item.getItemId() == R.id.action_search) { ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(feed.getId(), feed.getTitle())); - return true; + } else { + return false; } - return false; + return true; } @Override @@ -407,8 +429,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem if (!event.isFeedUpdateRunning) { nextPageLoader.getRoot().setVisibility(View.GONE); } - MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(), - R.id.refresh_item, event.isFeedUpdateRunning); + viewBinding.swipeRefresh.setRefreshing(event.isFeedUpdateRunning); } private void refreshHeaderView() { @@ -592,4 +613,45 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected); } } + + public static class SingleFeedSortDialog extends ItemSortDialog { + private static final String ARG_FEED_ID = "feedId"; + private static final String ARG_FEED_IS_LOCAL = "isLocal"; + private static final String ARG_SORT_ORDER = "sortOrder"; + + private static SingleFeedSortDialog newInstance(Feed feed) { + Bundle bundle = new Bundle(); + bundle.putLong(ARG_FEED_ID, feed.getId()); + bundle.putBoolean(ARG_FEED_IS_LOCAL, feed.isLocalFeed()); + if (feed.getSortOrder() == null) { + bundle.putString(ARG_SORT_ORDER, String.valueOf(SortOrder.DATE_NEW_OLD.code)); + } else { + bundle.putString(ARG_SORT_ORDER, String.valueOf(feed.getSortOrder().code)); + } + SingleFeedSortDialog dialog = new SingleFeedSortDialog(); + dialog.setArguments(bundle); + return dialog; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sortOrder = SortOrder.fromCodeString(getArguments().getString(ARG_SORT_ORDER)); + } + + @Override + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG + || ascending == SortOrder.EPISODE_TITLE_A_Z + || (getArguments().getBoolean(ARG_FEED_IS_LOCAL) && ascending == SortOrder.EPISODE_FILENAME_A_Z)) { + super.onAddItem(title, ascending, descending, ascendingIsDefault); + } + } + + @Override + protected void onSelectionChanged() { + super.onSelectionChanged(); + DBWriter.setFeedItemSortOrder(getArguments().getLong(ARG_FEED_ID), sortOrder); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java index f8bcbb532..497409e70 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/InboxFragment.java @@ -4,26 +4,25 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.Toast; - import androidx.annotation.NonNull; - +import androidx.annotation.Nullable; import com.google.android.material.dialog.MaterialAlertDialogBuilder; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.dialog.ItemSortDialog; +import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItemFilter; import de.danoeh.antennapod.model.feed.SortOrder; import de.danoeh.antennapod.storage.preferences.UserPreferences; +import org.greenrobot.eventbus.EventBus; import java.util.List; @@ -42,8 +41,6 @@ public class InboxFragment extends EpisodesListFragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View root = super.onCreateView(inflater, container, savedInstanceState); toolbar.inflateMenu(R.menu.inbox); - inflateSortMenu(); - toolbar.setTitle(R.string.inbox_label); prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); updateToolbar(); @@ -83,13 +80,9 @@ public class InboxFragment extends EpisodesListFragment { showRemoveAllDialog(); } return true; - } else { - SortOrder sortOrder = MenuItemToSortOrderConverter.convert(item); - if (sortOrder != null) { - UserPreferences.setInboxSortedOrder(sortOrder); - loadItems(); - return true; - } + } else if (item.getItemId() == R.id.inbox_sort) { + new InboxSortDialog().show(getChildFragmentManager(), "SortDialog"); + return true; } return false; } @@ -118,20 +111,6 @@ public class InboxFragment extends EpisodesListFragment { ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.removed_all_inbox_msg, Toast.LENGTH_SHORT); } - private void inflateSortMenu() { - Menu menu = toolbar.getMenu(); - MenuItem downloadsItem = menu.findItem(R.id.inbox_sort); - MenuInflater menuInflater = getActivity().getMenuInflater(); - menuInflater.inflate(R.menu.sort_menu, downloadsItem.getSubMenu()); - - // Remove the sorting options that are not needed in this fragment - toolbar.getMenu().findItem(R.id.sort_episode_title).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_feed_title).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_random).setVisible(false); - toolbar.getMenu().findItem(R.id.sort_smart_shuffle).setVisible(false); - toolbar.getMenu().findItem(R.id.keep_sorted).setVisible(false); - } - private void showRemoveAllDialog() { MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); builder.setTitle(R.string.remove_all_inbox_label); @@ -149,4 +128,26 @@ public class InboxFragment extends EpisodesListFragment { builder.setNegativeButton(R.string.cancel_label, null); builder.show(); } + + public static class InboxSortDialog extends ItemSortDialog { + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sortOrder = UserPreferences.getInboxSortedOrder(); + } + + @Override + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG) { + super.onAddItem(title, ascending, descending, ascendingIsDefault); + } + } + + @Override + protected void onSelectionChanged() { + super.onSelectionChanged(); + UserPreferences.setInboxSortedOrder(sortOrder); + EventBus.getDefault().post(new FeedListUpdateEvent(0)); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/MenuItemToSortOrderConverter.java b/app/src/main/java/de/danoeh/antennapod/fragment/MenuItemToSortOrderConverter.java deleted file mode 100644 index d4150fbdb..000000000 --- a/app/src/main/java/de/danoeh/antennapod/fragment/MenuItemToSortOrderConverter.java +++ /dev/null @@ -1,44 +0,0 @@ -package de.danoeh.antennapod.fragment; - -import android.view.MenuItem; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.model.feed.SortOrder; - -public class MenuItemToSortOrderConverter { - - public static SortOrder convert(MenuItem item) { - final int itemId = item.getItemId(); - - if (itemId == R.id.sort_episode_title_asc) { - return SortOrder.EPISODE_TITLE_A_Z; - } else if (itemId == R.id.sort_episode_title_desc) { - return SortOrder.EPISODE_TITLE_Z_A; - } else if (itemId == R.id.sort_date_asc) { - return SortOrder.DATE_OLD_NEW; - } else if (itemId == R.id.sort_date_desc) { - return SortOrder.DATE_NEW_OLD; - } else if (itemId == R.id.sort_duration_asc) { - return SortOrder.DURATION_SHORT_LONG; - } else if (itemId == R.id.sort_duration_desc) { - return SortOrder.DURATION_LONG_SHORT; - } else if (itemId == R.id.sort_feed_title_asc) { - return SortOrder.FEED_TITLE_A_Z; - } else if (itemId == R.id.sort_feed_title_desc) { - return SortOrder.FEED_TITLE_Z_A; - } else if (itemId == R.id.sort_random) { - return SortOrder.RANDOM; - } else if (itemId == R.id.sort_smart_shuffle_asc) { - return SortOrder.SMART_SHUFFLE_OLD_NEW; - } else if (itemId == R.id.sort_smart_shuffle_desc) { - return SortOrder.SMART_SHUFFLE_NEW_OLD; - } else if (itemId == R.id.sort_size_small_large) { - return SortOrder.SIZE_SMALL_LARGE; - } else if (itemId == R.id.sort_size_large_small) { - return SortOrder.SIZE_LARGE_SMALL; - } - - return null; - } - -} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java index eeca181cf..636c0245b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java @@ -382,7 +382,7 @@ public class NavDrawerFragment extends Fragment implements SharedPreferences.OnS } } else if (UserPreferences.getSubscriptionsFilter().isEnabled() && navAdapter.showSubscriptionList) { - SubscriptionsFilterDialog.showDialog(requireContext()); + new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter"); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 80933023e..003ee23db 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -4,29 +4,36 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.ContextMenu; import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.ProgressBar; import android.widget.TextView; + import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; import com.leinardi.android.speeddial.SpeedDialView; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.EpisodeItemListAdapter; @@ -39,6 +46,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.download.FeedUpdateManager; +import de.danoeh.antennapod.dialog.ItemSortDialog; import de.danoeh.antennapod.event.EpisodeDownloadEvent; import de.danoeh.antennapod.event.FeedItemEvent; import de.danoeh.antennapod.event.FeedUpdateRunningEvent; @@ -61,12 +69,6 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import java.util.List; -import java.util.Locale; /** * Shows all items in the queue. @@ -81,6 +83,7 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte private QueueRecyclerAdapter recyclerAdapter; private EmptyViewHandler emptyView; private MaterialToolbar toolbar; + private SwipeRefreshLayout swipeRefreshLayout; private boolean displayUpArrow; private List<FeedItem> queue; @@ -159,6 +162,8 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte case MOVED: return; } + recyclerAdapter.updateDragDropEnabled(); + refreshToolbarState(); recyclerView.saveScrollPosition(QueueFragment.TAG); refreshInfoBar(); } @@ -258,13 +263,11 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte boolean keepSorted = UserPreferences.isQueueKeepSorted(); toolbar.getMenu().findItem(R.id.queue_lock).setChecked(UserPreferences.isQueueLocked()); toolbar.getMenu().findItem(R.id.queue_lock).setVisible(!keepSorted); - toolbar.getMenu().findItem(R.id.sort_random).setVisible(!keepSorted); - toolbar.getMenu().findItem(R.id.keep_sorted).setChecked(keepSorted); } @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedUpdateRunningEvent event) { - MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning); + swipeRefreshLayout.setRefreshing(event.isFeedUpdateRunning); } @Override @@ -273,6 +276,9 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte if (itemId == R.id.queue_lock) { toggleQueueLock(); return true; + } else if (itemId == R.id.queue_sort) { + new QueueSortDialog().show(getChildFragmentManager().beginTransaction(), "SortDialog"); + return true; } else if (itemId == R.id.refresh_item) { FeedUpdateManager.runOnceOrAsk(requireContext()); return true; @@ -291,28 +297,9 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte }; conDialog.createNewDialog().show(); return true; - } else if (itemId == R.id.keep_sorted) { - boolean keepSortedOld = UserPreferences.isQueueKeepSorted(); - boolean keepSortedNew = !keepSortedOld; - UserPreferences.setQueueKeepSorted(keepSortedNew); - if (keepSortedNew) { - SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder(); - DBWriter.reorderQueue(sortOrder, true); - } - if (recyclerAdapter != null) { - recyclerAdapter.updateDragDropEnabled(); - } - refreshToolbarState(); - return true; } else if (itemId == R.id.action_search) { ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance()); return true; - } else { - SortOrder sortOrder = MenuItemToSortOrderConverter.convert(item); - if (sortOrder != null) { - setSortOrder(sortOrder); - return true; - } } return false; } @@ -359,16 +346,6 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte } } - /** - * This method is called if the user clicks on a sort order menu item. - * - * @param sortOrder New sort order. - */ - private void setSortOrder(SortOrder sortOrder) { - UserPreferences.setQueueKeepSortedOrder(sortOrder); - DBWriter.reorderQueue(sortOrder, true); - } - @Override public boolean onContextItemSelected(MenuItem item) { Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]"); @@ -422,10 +399,6 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte } ((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow); toolbar.inflateMenu(R.menu.queue); - - MenuItem queueItem = toolbar.getMenu().findItem(R.id.queue_sort); - MenuInflater menuInflater = getActivity().getMenuInflater(); - menuInflater.inflate(R.menu.sort_menu, queueItem.getSubMenu()); refreshToolbarState(); progressBar = root.findViewById(R.id.progressBar); progressBar.setVisibility(View.VISIBLE); @@ -454,13 +427,9 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte recyclerAdapter.setOnSelectModeListener(this); recyclerView.setAdapter(recyclerAdapter); - SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); + swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance)); - swipeRefreshLayout.setOnRefreshListener(() -> { - FeedUpdateManager.runOnceOrAsk(requireContext()); - new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false), - getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms)); - }); + swipeRefreshLayout.setOnRefreshListener(() -> FeedUpdateManager.runOnceOrAsk(requireContext())); emptyView = new EmptyViewHandler(getContext()); emptyView.attachToRecyclerView(recyclerView); @@ -507,9 +476,8 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte } private void refreshInfoBar() { - String info = String.format(Locale.getDefault(), "%d%s", - queue.size(), getString(R.string.episodes_suffix)); - if (queue.size() > 0) { + String info = getResources().getQuantityString(R.plurals.num_episodes, queue.size(), queue.size()); + if (!queue.isEmpty()) { long timeLeft = 0; for (FeedItem item : queue) { float playbackSpeed = 1; @@ -567,6 +535,42 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte swipeActions.attachTo(recyclerView); } + public static class QueueSortDialog extends ItemSortDialog { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (UserPreferences.isQueueKeepSorted()) { + sortOrder = UserPreferences.getQueueKeepSortedOrder(); + } + final View view = super.onCreateView(inflater, container, savedInstanceState); + viewBinding.keepSortedCheckbox.setVisibility(View.VISIBLE); + viewBinding.keepSortedCheckbox.setChecked(UserPreferences.isQueueKeepSorted()); + // Disable until something gets selected + viewBinding.keepSortedCheckbox.setEnabled(UserPreferences.isQueueKeepSorted()); + return view; + } + + @Override + protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) { + if (ascending != SortOrder.EPISODE_FILENAME_A_Z && ascending != SortOrder.SIZE_SMALL_LARGE) { + super.onAddItem(title, ascending, descending, ascendingIsDefault); + } + } + + @Override + protected void onSelectionChanged() { + super.onSelectionChanged(); + viewBinding.keepSortedCheckbox.setEnabled(sortOrder != SortOrder.RANDOM); + if (sortOrder == SortOrder.RANDOM) { + viewBinding.keepSortedCheckbox.setChecked(false); + } + UserPreferences.setQueueKeepSorted(viewBinding.keepSortedCheckbox.isChecked()); + UserPreferences.setQueueKeepSortedOrder(sortOrder); + DBWriter.reorderQueue(sortOrder, true); + } + } + private class QueueSwipeActions extends SwipeActions { // Position tracking whilst dragging diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index 93ed4c2c9..e86cd58b9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -3,8 +3,6 @@ package de.danoeh.antennapod.fragment; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -81,6 +79,7 @@ public class SubscriptionFragment extends Fragment private EmptyViewHandler emptyView; private LinearLayout feedsFilteredMsg; private MaterialToolbar toolbar; + private SwipeRefreshLayout swipeRefreshLayout; private ProgressBar progressBar; private String displayedFolder = null; private boolean displayUpArrow; @@ -166,15 +165,12 @@ public class SubscriptionFragment extends Fragment }); feedsFilteredMsg = root.findViewById(R.id.feeds_filtered_message); - feedsFilteredMsg.setOnClickListener((l) -> SubscriptionsFilterDialog.showDialog(requireContext())); + feedsFilteredMsg.setOnClickListener((l) -> + new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter")); - SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); + swipeRefreshLayout = root.findViewById(R.id.swipeRefresh); swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance)); - swipeRefreshLayout.setOnRefreshListener(() -> { - FeedUpdateManager.runOnceOrAsk(requireContext()); - new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false), - getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms)); - }); + swipeRefreshLayout.setOnRefreshListener(() -> FeedUpdateManager.runOnceOrAsk(requireContext())); speedDialView = root.findViewById(R.id.fabSD); speedDialView.setOverlayLayout(root.findViewById(R.id.fabSDOverlay)); @@ -211,7 +207,7 @@ public class SubscriptionFragment extends Fragment @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedUpdateRunningEvent event) { - MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning); + swipeRefreshLayout.setRefreshing(event.isFeedUpdateRunning); } @Override @@ -221,7 +217,7 @@ public class SubscriptionFragment extends Fragment FeedUpdateManager.runOnceOrAsk(requireContext()); return true; } else if (itemId == R.id.subscriptions_filter) { - SubscriptionsFilterDialog.showDialog(requireContext()); + new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter"); return true; } else if (itemId == R.id.subscriptions_sort) { FeedSortDialog.showDialog(requireContext()); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index 66f592af2..0f3320e98 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -1,8 +1,10 @@ package de.danoeh.antennapod.fragment.preferences; import android.content.Context; +import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; +import android.widget.Button; import android.widget.ListView; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; @@ -64,14 +66,14 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { return true; }); - findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS) + findPreference(UserPreferences.PREF_FULL_NOTIFICATION_BUTTONS) .setOnPreferenceClickListener(preference -> { - showNotificationButtonsDialog(); + showFullNotificationButtonsDialog(); return true; }); findPreference(UserPreferences.PREF_FILTER_FEED) .setOnPreferenceClickListener((preference -> { - SubscriptionsFilterDialog.showDialog(requireContext()); + new SubscriptionsFilterDialog().show(getChildFragmentManager(), "filter"); return true; })); @@ -91,48 +93,85 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { } } - private void showNotificationButtonsDialog() { + + private void showFullNotificationButtonsDialog() { final Context context = getActivity(); - final List<Integer> preferredButtons = UserPreferences.getCompactNotificationButtons(); + + final List<Integer> preferredButtons = UserPreferences.getFullNotificationButtons(); final String[] allButtonNames = context.getResources().getStringArray( - R.array.compact_notification_buttons_options); + R.array.full_notification_buttons_options); + final int[] buttonIDs = {2, 3, 4}; + final int exactItems = 2; + final DialogInterface.OnClickListener completeListener = (dialog, which) -> + UserPreferences.setFullNotificationButtons(preferredButtons); + final String title = context.getResources().getString( + R.string.pref_full_notification_buttons_title); + + showNotificationButtonsDialog(preferredButtons, allButtonNames, buttonIDs, title, + exactItems, completeListener + ); + } + + private void showNotificationButtonsDialog(List<Integer> preferredButtons, + String[] allButtonNames, int[] buttonIds, String title, + int exactItems, DialogInterface.OnClickListener completeListener) { boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java + final Context context = getActivity(); + + // Clear buttons that are not part of the setting anymore + for (int i = preferredButtons.size() - 1; i >= 0; i--) { + boolean isValid = false; + for (int j = 0; j < checked.length; j++) { + if (buttonIds[j] == preferredButtons.get(i)) { + isValid = true; + } + } + + if (!isValid) { + preferredButtons.remove(i); + } + } + for(int i=0; i < checked.length; i++) { - if(preferredButtons.contains(i)) { + if (preferredButtons.contains(buttonIds[i])) { checked[i] = true; } } MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(String.format(context.getResources().getString( - R.string.pref_compact_notification_buttons_dialog_title), 2)); + builder.setTitle(title); builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> { checked[which] = isChecked; if (isChecked) { - if (preferredButtons.size() < 2) { - preferredButtons.add(which); - } else { - // Only allow a maximum of two selections. This is because the notification - // on the lock screen can only display 3 buttons, and the play/pause button - // is always included. - checked[which] = false; - ListView selectionView = ((AlertDialog) dialog).getListView(); - selectionView.setItemChecked(which, false); - Snackbar.make( - selectionView, - String.format(context.getResources().getString( - R.string.pref_compact_notification_buttons_dialog_error), 2), - Snackbar.LENGTH_SHORT).show(); - } + preferredButtons.add(buttonIds[which]); } else { - preferredButtons.remove((Integer) which); + preferredButtons.remove((Integer) buttonIds[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> - UserPreferences.setCompactNotificationButtons(preferredButtons)); + builder.setPositiveButton(R.string.confirm_label, null); builder.setNegativeButton(R.string.cancel_label, null); - builder.create().show(); + final AlertDialog dialog = builder.create(); + + dialog.show(); + + Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + + positiveButton.setOnClickListener(v -> { + if (preferredButtons.size() != exactItems) { + ListView selectionView = dialog.getListView(); + Snackbar.make( + selectionView, + String.format(context.getResources().getString( + R.string.pref_compact_notification_buttons_dialog_error_exact), exactItems), + Snackbar.LENGTH_SHORT).show(); + + } else { + completeListener.onClick(dialog, AlertDialog.BUTTON_POSITIVE); + dialog.cancel(); + } + } + ); } } diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java index 7a9eb1bb5..eac1e9304 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -1,103 +1,32 @@ package de.danoeh.antennapod.menuhandler; +import android.annotation.SuppressLint; import android.content.Context; +import android.content.DialogInterface; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; import androidx.annotation.NonNull; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.storage.DBWriter; -import de.danoeh.antennapod.core.util.IntentUtils; -import de.danoeh.antennapod.core.util.ShareUtils; -import de.danoeh.antennapod.core.util.download.FeedUpdateManager; -import de.danoeh.antennapod.dialog.IntraFeedSortDialog; -import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.model.feed.SortOrder; -import org.apache.commons.lang3.StringUtils; -import android.content.DialogInterface; -import android.annotation.SuppressLint; import androidx.fragment.app.Fragment; +import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; +import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.dialog.RemoveFeedDialog; import de.danoeh.antennapod.dialog.RenameItemDialog; import de.danoeh.antennapod.dialog.TagSettingsDialog; +import de.danoeh.antennapod.model.feed.Feed; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; + import java.util.Collections; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; /** * Handles interactions with the FeedItemMenu. */ -public class FeedMenuHandler { - - private FeedMenuHandler(){ } - +public abstract class FeedMenuHandler { private static final String TAG = "FeedMenuHandler"; - public static boolean onPrepareOptionsMenu(Menu menu, Feed selectedFeed) { - if (selectedFeed == null) { - return true; - } - - Log.d(TAG, "Preparing options menu"); - - menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged()); - if (StringUtils.isBlank(selectedFeed.getLink())) { - menu.findItem(R.id.visit_website_item).setVisible(false); - } - if (selectedFeed.isLocalFeed()) { - // hide complete submenu "Share..." as both sub menu items are not visible - menu.findItem(R.id.share_item).setVisible(false); - } - - return true; - } - - /** - * NOTE: This method does not handle clicks on the 'remove feed' - item. - */ - public static boolean onOptionsItemClicked(final Context context, final MenuItem item, final Feed selectedFeed) { - final int itemId = item.getItemId(); - if (itemId == R.id.refresh_item) { - FeedUpdateManager.runOnceOrAsk(context, selectedFeed); - } else if (itemId == R.id.refresh_complete_item) { - new Thread(() -> { - selectedFeed.setNextPageLink(selectedFeed.getDownload_url()); - selectedFeed.setPageNr(0); - try { - DBWriter.resetPagedFeedPage(selectedFeed).get(); - FeedUpdateManager.runOnce(context, selectedFeed); - } catch (ExecutionException | InterruptedException e) { - throw new RuntimeException(e); - } - }).start(); - } else if (itemId == R.id.sort_items) { - showSortDialog(context, selectedFeed); - } else if (itemId == R.id.visit_website_item) { - IntentUtils.openInBrowser(context, selectedFeed.getLink()); - } else if (itemId == R.id.share_item) { - ShareUtils.shareFeedLink(context, selectedFeed); - } else { - return false; - } - return true; - } - - private static void showSortDialog(Context context, Feed selectedFeed) { - IntraFeedSortDialog sortDialog = new IntraFeedSortDialog(context, selectedFeed.getSortOrder(), selectedFeed.isLocalFeed()) { - @Override - protected void updateSort(@NonNull SortOrder sortOrder) { - selectedFeed.setSortOrder(sortOrder); - DBWriter.setFeedItemSortOrder(selectedFeed.getId(), sortOrder); - } - }; - sortDialog.openDialog(); - } - public static boolean onMenuItemClicked(@NonNull Fragment fragment, int menuItemId, @NonNull Feed selectedFeed, Runnable callback) { @NonNull Context context = fragment.requireContext(); @@ -131,5 +60,4 @@ public class FeedMenuHandler { } return true; } - } diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java index cc298b38d..3a3063599 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java @@ -6,12 +6,15 @@ import android.view.KeyEvent; import androidx.core.app.NotificationManagerCompat; import androidx.preference.PreferenceManager; +import org.apache.commons.lang3.StringUtils; + import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; import de.danoeh.antennapod.error.CrashReportWriter; +import de.danoeh.antennapod.fragment.AllEpisodesFragment; import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.storage.preferences.UserPreferences.EnqueueLocation; import de.danoeh.antennapod.fragment.QueueFragment; @@ -149,5 +152,19 @@ public class PreferenceUpgrader { if (oldVersion < 3020000) { NotificationManagerCompat.from(context).deleteNotificationChannel("auto_download"); } + + if (oldVersion < 3030000) { + SharedPreferences allEpisodesPreferences = + context.getSharedPreferences(AllEpisodesFragment.PREF_NAME, Context.MODE_PRIVATE); + String oldEpisodeSort = allEpisodesPreferences.getString(UserPreferences.PREF_SORT_ALL_EPISODES, ""); + if (!StringUtils.isAllEmpty(oldEpisodeSort)) { + prefs.edit().putString(UserPreferences.PREF_SORT_ALL_EPISODES, oldEpisodeSort).apply(); + } + + String oldEpisodeFilter = allEpisodesPreferences.getString("filter", ""); + if (!StringUtils.isAllEmpty(oldEpisodeFilter)) { + prefs.edit().putString(UserPreferences.PREF_FILTER_ALL_EPISODES, oldEpisodeFilter).apply(); + } + } } } diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java index fc925aa03..6f43a8ff4 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java @@ -6,8 +6,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; @@ -21,7 +19,6 @@ import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentContainerView; -import de.danoeh.antennapod.ui.home.sections.EchoSection; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -33,7 +30,6 @@ import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.core.menuhandler.MenuItemUtils; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.download.FeedUpdateManager; import de.danoeh.antennapod.databinding.HomeFragmentBinding; @@ -41,8 +37,10 @@ import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.event.FeedUpdateRunningEvent; import de.danoeh.antennapod.fragment.SearchFragment; import de.danoeh.antennapod.storage.preferences.UserPreferences; +import de.danoeh.antennapod.ui.echo.EchoActivity; import de.danoeh.antennapod.ui.home.sections.AllowNotificationsSection; import de.danoeh.antennapod.ui.home.sections.DownloadsSection; +import de.danoeh.antennapod.ui.home.sections.EchoSection; import de.danoeh.antennapod.ui.home.sections.EpisodesSurpriseSection; import de.danoeh.antennapod.ui.home.sections.InboxSection; import de.danoeh.antennapod.ui.home.sections.QueueSection; @@ -85,11 +83,7 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis updateWelcomeScreenVisibility(); viewBinding.swipeRefresh.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance)); - viewBinding.swipeRefresh.setOnRefreshListener(() -> { - FeedUpdateManager.runOnceOrAsk(requireContext()); - new Handler(Looper.getMainLooper()).postDelayed(() -> viewBinding.swipeRefresh.setRefreshing(false), - getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms)); - }); + viewBinding.swipeRefresh.setOnRefreshListener(() -> FeedUpdateManager.runOnceOrAsk(requireContext())); return viewBinding.getRoot(); } @@ -104,10 +98,10 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis addSection(new AllowNotificationsSection()); } } - if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER - && Calendar.getInstance().get(Calendar.YEAR) == 2023 + if (Calendar.getInstance().get(Calendar.YEAR) == EchoActivity.RELEASE_YEAR + && Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 10 - && prefs.getInt(PREF_HIDE_ECHO, 0) != 2023) { + && prefs.getInt(PREF_HIDE_ECHO, 0) != EchoActivity.RELEASE_YEAR) { addSection(new EchoSection()); } @@ -153,8 +147,7 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedUpdateRunningEvent event) { - MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(), - R.id.refresh_item, event.isFeedUpdateRunning); + viewBinding.swipeRefresh.setRefreshing(event.isFeedUpdateRunning); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java index 7261c6be4..05b716abb 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java @@ -32,13 +32,9 @@ public class EchoSection extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { viewBinding = HomeSectionEchoBinding.inflate(inflater); - viewBinding.titleLabel.setText(getString(R.string.antennapod_echo_year, 2023)); + viewBinding.titleLabel.setText(getString(R.string.antennapod_echo_year, EchoActivity.RELEASE_YEAR)); viewBinding.echoButton.setOnClickListener(v -> startActivity(new Intent(getContext(), EchoActivity.class))); - viewBinding.closeButton.setOnClickListener(v -> { - getContext().getSharedPreferences(HomeFragment.PREF_NAME, Context.MODE_PRIVATE) - .edit().putInt(HomeFragment.PREF_HIDE_ECHO, 2023).apply(); - ((MainActivity) getActivity()).loadFragment(HomeFragment.TAG, null); - }); + viewBinding.closeButton.setOnClickListener(v -> hideThisYear()); updateVisibility(); return viewBinding.getRoot(); } @@ -51,7 +47,7 @@ public class EchoSection extends Fragment { date.set(Calendar.MILLISECOND, 0); date.set(Calendar.DAY_OF_MONTH, 1); date.set(Calendar.MONTH, 0); - date.set(Calendar.YEAR, 2023); + date.set(Calendar.YEAR, EchoActivity.RELEASE_YEAR); return date.getTimeInMillis(); } @@ -70,8 +66,18 @@ public class EchoSection extends Fragment { }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(totalTime -> viewBinding.getRoot() - .setVisibility((totalTime >= 3600 * 10) ? View.VISIBLE : View.GONE), - Throwable::printStackTrace); + .subscribe(totalTime -> { + boolean shouldShow = (totalTime >= 3600 * 10); + viewBinding.getRoot().setVisibility(shouldShow ? View.VISIBLE : View.GONE); + if (!shouldShow) { + hideThisYear(); + } + }, Throwable::printStackTrace); + } + + void hideThisYear() { + getContext().getSharedPreferences(HomeFragment.PREF_NAME, Context.MODE_PRIVATE) + .edit().putInt(HomeFragment.PREF_HIDE_ECHO, EchoActivity.RELEASE_YEAR).apply(); + ((MainActivity) getActivity()).loadFragment(HomeFragment.TAG, null); } } diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java index b4f61a19a..01d4a10f0 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java @@ -100,15 +100,13 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { this.item = item; placeholder.setText(item.getFeed().getTitle()); title.setText(item.getTitle()); - leftPadding.setContentDescription(item.getTitle()); - pubDate.setText(DateFormatter.formatAbbrev(activity, item.getPubDate())); - pubDate.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate())); if (item.isPlayed()) { - cover.setContentDescription(activity.getString(R.string.is_played)); - cover.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); + leftPadding.setContentDescription(item.getTitle() + ". " + activity.getString(R.string.is_played)); } else { - cover.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + leftPadding.setContentDescription(item.getTitle()); } + pubDate.setText(DateFormatter.formatAbbrev(activity, item.getPubDate())); + pubDate.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate())); isInbox.setVisibility(item.isNew() ? View.VISIBLE : View.GONE); isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE); isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); |