3131import org .schabi .newpipe .util .ExtractorHelper ;
3232import 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+
3445import java .util .List ;
3546import java .util .function .Supplier ;
3647import 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