Skip to content

Commit 282a8c1

Browse files
committed
Add watched stream filter to channel tabs
1 parent 25c12ef commit 282a8c1

1 file changed

Lines changed: 169 additions & 3 deletions

File tree

app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelTabFragment.java

Lines changed: 169 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131
import org.schabi.newpipe.util.ExtractorHelper;
3232
import org.schabi.newpipe.util.PlayButtonHelper;
3333

34+
import android.content.SharedPreferences;
35+
import android.view.Menu;
36+
import android.view.MenuInflater;
37+
import android.view.MenuItem;
38+
39+
import androidx.appcompat.app.AlertDialog;
40+
import androidx.preference.PreferenceManager;
41+
42+
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
43+
import org.schabi.newpipe.local.history.HistoryRecordManager;
44+
3445
import java.util.List;
3546
import java.util.function.Supplier;
3647
import java.util.stream.Collectors;
@@ -70,7 +81,7 @@ public ChannelTabFragment() {
7081
@Override
7182
public void onCreate(final Bundle savedInstanceState) {
7283
super.onCreate(savedInstanceState);
73-
setHasOptionsMenu(false);
84+
setHasOptionsMenu(true);
7485
}
7586

7687
@Override
@@ -92,6 +103,69 @@ public void onDestroyView() {
92103
playlistControlBinding = null;
93104
}
94105

106+
@Override
107+
public void onCreateOptionsMenu(@NonNull final Menu menu,
108+
@NonNull final MenuInflater inflater) {
109+
super.onCreateOptionsMenu(menu, inflater);
110+
if (ChannelTabHelper.isStreamsTab(tabHandler)) {
111+
final MenuItem item = menu.add(Menu.NONE, R.id.menu_item_feed_toggle_played_items,
112+
Menu.NONE, R.string.feed_show_hide_streams);
113+
item.setIcon(R.drawable.ic_visibility_on);
114+
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
115+
}
116+
}
117+
118+
@Override
119+
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
120+
if (item.getItemId() == R.id.menu_item_feed_toggle_played_items) {
121+
showStreamVisibilityDialog();
122+
return true;
123+
}
124+
return super.onOptionsItemSelected(item);
125+
}
126+
127+
private void showStreamVisibilityDialog() {
128+
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
129+
final String showWatchedKey = getString(R.string.feed_show_watched_items_key);
130+
final String showPartiallyWatchedKey =
131+
getString(R.string.feed_show_partially_watched_items_key);
132+
133+
final String[] dialogItems = {
134+
getString(R.string.feed_show_watched),
135+
getString(R.string.feed_show_partially_watched)
136+
};
137+
138+
final boolean[] checkedDialogItems = {
139+
prefs.getBoolean(showWatchedKey, true),
140+
prefs.getBoolean(showPartiallyWatchedKey, true)
141+
};
142+
143+
new AlertDialog.Builder(requireContext())
144+
.setTitle(R.string.feed_hide_streams_title)
145+
.setMultiChoiceItems(dialogItems, checkedDialogItems,
146+
(dialog, which, isChecked) -> checkedDialogItems[which] = isChecked)
147+
.setPositiveButton(R.string.ok, (dialog, which) -> {
148+
boolean changed = false;
149+
final SharedPreferences.Editor editor = prefs.edit();
150+
151+
if (prefs.getBoolean(showWatchedKey, true) != checkedDialogItems[0]) {
152+
editor.putBoolean(showWatchedKey, checkedDialogItems[0]);
153+
changed = true;
154+
}
155+
if (prefs.getBoolean(showPartiallyWatchedKey, true) != checkedDialogItems[1]) {
156+
editor.putBoolean(showPartiallyWatchedKey, checkedDialogItems[1]);
157+
changed = true;
158+
}
159+
160+
if (changed) {
161+
editor.apply();
162+
startLoading(true);
163+
}
164+
})
165+
.setNegativeButton(R.string.cancel, null)
166+
.show();
167+
}
168+
95169
@Override
96170
protected Supplier<View> getListHeaderSupplier() {
97171
if (ChannelTabHelper.isStreamsTab(tabHandler)) {
@@ -104,12 +178,104 @@ protected Supplier<View> getListHeaderSupplier() {
104178

105179
@Override
106180
protected Single<ChannelTabInfo> loadResult(final boolean forceLoad) {
107-
return ExtractorHelper.getChannelTab(serviceId, tabHandler, forceLoad);
181+
final SharedPreferences prefs =
182+
PreferenceManager.getDefaultSharedPreferences(requireContext());
183+
final boolean showPlayed = prefs.getBoolean(
184+
getString(R.string.feed_show_watched_items_key), true);
185+
final boolean showPartiallyPlayed = prefs.getBoolean(
186+
getString(R.string.feed_show_partially_watched_items_key), true);
187+
188+
final HistoryRecordManager historyRecordManager = new HistoryRecordManager(
189+
requireContext().getApplicationContext());
190+
191+
return ExtractorHelper.getChannelTab(serviceId, tabHandler, forceLoad)
192+
.map(info -> filterStreams(info, showPlayed, showPartiallyPlayed,
193+
historyRecordManager));
108194
}
109195

110196
@Override
111197
protected Single<ListExtractor.InfoItemsPage<InfoItem>> loadMoreItemsLogic() {
112-
return ExtractorHelper.getMoreChannelTabItems(serviceId, tabHandler, currentNextPage);
198+
final SharedPreferences prefs =
199+
PreferenceManager.getDefaultSharedPreferences(requireContext());
200+
final boolean showPlayed = prefs.getBoolean(
201+
getString(R.string.feed_show_watched_items_key), true);
202+
final boolean showPartiallyPlayed = prefs.getBoolean(
203+
getString(R.string.feed_show_partially_watched_items_key), true);
204+
205+
final HistoryRecordManager historyRecordManager = new HistoryRecordManager(
206+
requireContext().getApplicationContext());
207+
208+
return ExtractorHelper.getMoreChannelTabItems(serviceId, tabHandler, currentNextPage)
209+
.map(page -> filterStreamsPage(page, showPlayed, showPartiallyPlayed,
210+
historyRecordManager));
211+
}
212+
213+
private boolean shouldIncludeItem(final InfoItem item,
214+
final boolean showPlayed,
215+
final boolean showPartiallyPlayed,
216+
final HistoryRecordManager historyRecordManager) {
217+
if (!(item instanceof StreamInfoItem)) {
218+
return true;
219+
}
220+
final StreamInfoItem streamItem = (StreamInfoItem) item;
221+
try {
222+
final StreamStateEntity[] result =
223+
historyRecordManager.loadStreamState(streamItem).blockingGet();
224+
final StreamStateEntity state =
225+
(result != null && result.length > 0) ? result[0] : null;
226+
if (state != null) {
227+
final long duration = streamItem.getDuration();
228+
final boolean isFinished = state.isFinished(duration);
229+
final boolean isPartiallyPlayed = state.isValid(duration) && !isFinished;
230+
231+
if (!showPlayed && isFinished) {
232+
return false;
233+
}
234+
if (!showPartiallyPlayed && isPartiallyPlayed) {
235+
return false;
236+
}
237+
}
238+
} catch (final Exception e) {
239+
Log.w(TAG, "Could not load stream state", e);
240+
}
241+
return true;
242+
}
243+
244+
private ChannelTabInfo filterStreams(final ChannelTabInfo info,
245+
final boolean showPlayed,
246+
final boolean showPartiallyPlayed,
247+
final HistoryRecordManager historyRecordManager) {
248+
if (!ChannelTabHelper.isStreamsTab(tabHandler)
249+
|| (showPlayed && showPartiallyPlayed)) {
250+
return info;
251+
}
252+
253+
final List<InfoItem> filteredItems = info.getRelatedItems().stream()
254+
.filter(item -> shouldIncludeItem(item, showPlayed,
255+
showPartiallyPlayed, historyRecordManager))
256+
.collect(Collectors.toList());
257+
258+
info.setRelatedItems(filteredItems);
259+
260+
return info;
261+
}
262+
263+
private ListExtractor.InfoItemsPage<InfoItem> filterStreamsPage(
264+
final ListExtractor.InfoItemsPage<InfoItem> page,
265+
final boolean showPlayed,
266+
final boolean showPartiallyPlayed,
267+
final HistoryRecordManager historyRecordManager) {
268+
if (!ChannelTabHelper.isStreamsTab(tabHandler)
269+
|| (showPlayed && showPartiallyPlayed)) {
270+
return page;
271+
}
272+
273+
final List<InfoItem> filtered = page.getItems().stream()
274+
.filter(item -> shouldIncludeItem(item, showPlayed,
275+
showPartiallyPlayed, historyRecordManager))
276+
.collect(Collectors.toList());
277+
278+
return new ListExtractor.InfoItemsPage<>(filtered, page.getNextPage(), page.getErrors());
113279
}
114280

115281
@Override

0 commit comments

Comments
 (0)