diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelTabFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelTabFragment.java index feb23b6ac9f..58b1548e30a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelTabFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelTabFragment.java @@ -31,6 +31,17 @@ import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.PlayButtonHelper; +import android.content.SharedPreferences; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceManager; + +import org.schabi.newpipe.database.stream.model.StreamStateEntity; +import org.schabi.newpipe.local.history.HistoryRecordManager; + import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -70,7 +81,7 @@ public ChannelTabFragment() { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setHasOptionsMenu(false); + setHasOptionsMenu(true); } @Override @@ -92,6 +103,69 @@ public void onDestroyView() { playlistControlBinding = null; } + @Override + public void onCreateOptionsMenu(@NonNull final Menu menu, + @NonNull final MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + if (ChannelTabHelper.isStreamsTab(tabHandler)) { + final MenuItem item = menu.add(Menu.NONE, R.id.menu_item_feed_toggle_played_items, + Menu.NONE, R.string.feed_show_hide_streams); + item.setIcon(R.drawable.ic_visibility_on); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } + } + + @Override + public boolean onOptionsItemSelected(@NonNull final MenuItem item) { + if (item.getItemId() == R.id.menu_item_feed_toggle_played_items) { + showStreamVisibilityDialog(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void showStreamVisibilityDialog() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + final String showWatchedKey = getString(R.string.feed_show_watched_items_key); + final String showPartiallyWatchedKey = + getString(R.string.feed_show_partially_watched_items_key); + + final String[] dialogItems = { + getString(R.string.feed_show_watched), + getString(R.string.feed_show_partially_watched) + }; + + final boolean[] checkedDialogItems = { + prefs.getBoolean(showWatchedKey, true), + prefs.getBoolean(showPartiallyWatchedKey, true) + }; + + new AlertDialog.Builder(requireContext()) + .setTitle(R.string.feed_hide_streams_title) + .setMultiChoiceItems(dialogItems, checkedDialogItems, + (dialog, which, isChecked) -> checkedDialogItems[which] = isChecked) + .setPositiveButton(R.string.ok, (dialog, which) -> { + boolean changed = false; + final SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(showWatchedKey, true) != checkedDialogItems[0]) { + editor.putBoolean(showWatchedKey, checkedDialogItems[0]); + changed = true; + } + if (prefs.getBoolean(showPartiallyWatchedKey, true) != checkedDialogItems[1]) { + editor.putBoolean(showPartiallyWatchedKey, checkedDialogItems[1]); + changed = true; + } + + if (changed) { + editor.apply(); + startLoading(true); + } + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } + @Override protected Supplier getListHeaderSupplier() { if (ChannelTabHelper.isStreamsTab(tabHandler)) { @@ -104,12 +178,102 @@ protected Supplier getListHeaderSupplier() { @Override protected Single loadResult(final boolean forceLoad) { - return ExtractorHelper.getChannelTab(serviceId, tabHandler, forceLoad); + final SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(requireContext()); + final boolean showPlayed = prefs.getBoolean( + getString(R.string.feed_show_watched_items_key), true); + final boolean showPartiallyPlayed = prefs.getBoolean( + getString(R.string.feed_show_partially_watched_items_key), true); + + final HistoryRecordManager historyRecordManager = new HistoryRecordManager( + requireContext().getApplicationContext()); + + return ExtractorHelper.getChannelTab(serviceId, tabHandler, forceLoad) + .map(info -> filterStreams(info, showPlayed, showPartiallyPlayed, + historyRecordManager)); } @Override protected Single> loadMoreItemsLogic() { - return ExtractorHelper.getMoreChannelTabItems(serviceId, tabHandler, currentNextPage); + final SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(requireContext()); + final boolean showPlayed = prefs.getBoolean( + getString(R.string.feed_show_watched_items_key), true); + final boolean showPartiallyPlayed = prefs.getBoolean( + getString(R.string.feed_show_partially_watched_items_key), true); + + final HistoryRecordManager historyRecordManager = new HistoryRecordManager( + requireContext().getApplicationContext()); + + return ExtractorHelper.getMoreChannelTabItems(serviceId, tabHandler, currentNextPage) + .map(page -> filterStreamsPage(page, showPlayed, showPartiallyPlayed, + historyRecordManager)); + } + + private boolean shouldIncludeItem(final InfoItem item, + final boolean showPlayed, + final boolean showPartiallyPlayed, + final HistoryRecordManager historyRecordManager) { + if (!(item instanceof StreamInfoItem)) { + return true; + } + final StreamInfoItem streamItem = (StreamInfoItem) item; + try { + final StreamStateEntity state = + historyRecordManager.loadStreamState(streamItem).blockingGet(); + if (state != null) { + final long duration = streamItem.getDuration(); + final boolean isFinished = state.isFinished(duration); + final boolean isPartiallyPlayed = state.isValid(duration) && !isFinished; + + if (!showPlayed && isFinished) { + return false; + } + if (!showPartiallyPlayed && isPartiallyPlayed) { + return false; + } + } + } catch (final Exception e) { + Log.w(TAG, "Could not load stream state", e); + } + return true; + } + + private ChannelTabInfo filterStreams(final ChannelTabInfo info, + final boolean showPlayed, + final boolean showPartiallyPlayed, + final HistoryRecordManager historyRecordManager) { + if (!ChannelTabHelper.isStreamsTab(tabHandler) + || (showPlayed && showPartiallyPlayed)) { + return info; + } + + final List filteredItems = info.getRelatedItems().stream() + .filter(item -> shouldIncludeItem(item, showPlayed, + showPartiallyPlayed, historyRecordManager)) + .collect(Collectors.toList()); + + info.setRelatedItems(filteredItems); + + return info; + } + + private ListExtractor.InfoItemsPage filterStreamsPage( + final ListExtractor.InfoItemsPage page, + final boolean showPlayed, + final boolean showPartiallyPlayed, + final HistoryRecordManager historyRecordManager) { + if (!ChannelTabHelper.isStreamsTab(tabHandler) + || (showPlayed && showPartiallyPlayed)) { + return page; + } + + final List filtered = page.getItems().stream() + .filter(item -> shouldIncludeItem(item, showPlayed, + showPartiallyPlayed, historyRecordManager)) + .collect(Collectors.toList()); + + return new ListExtractor.InfoItemsPage<>(filtered, page.getNextPage(), page.getErrors()); } @Override