|
1 | 1 | package org.schabi.newpipe.local.playlist; |
2 | 2 |
|
| 3 | +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; |
| 4 | +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; |
3 | 5 | import static org.schabi.newpipe.error.ErrorUtil.showUiErrorSnackbar; |
4 | 6 | import static org.schabi.newpipe.ktx.ViewUtils.animate; |
5 | 7 | import static org.schabi.newpipe.local.playlist.ExportPlaylistKt.export; |
|
22 | 24 | import android.view.MenuItem; |
23 | 25 | import android.view.View; |
24 | 26 | import android.view.ViewGroup; |
| 27 | +import android.widget.LinearLayout; |
| 28 | +import android.widget.LinearLayout.LayoutParams; |
25 | 29 | import android.widget.Toast; |
26 | 30 |
|
27 | 31 | import androidx.annotation.NonNull; |
|
54 | 58 | import org.schabi.newpipe.local.history.HistoryRecordManager; |
55 | 59 | import org.schabi.newpipe.player.playqueue.PlayQueue; |
56 | 60 | import org.schabi.newpipe.player.playqueue.SinglePlayQueue; |
| 61 | +import org.schabi.newpipe.util.DeviceUtils; |
57 | 62 | import org.schabi.newpipe.util.Localization; |
58 | 63 | import org.schabi.newpipe.util.NavigationHelper; |
59 | 64 | import org.schabi.newpipe.util.OnClickGesture; |
@@ -365,17 +370,7 @@ public boolean onOptionsItemSelected(final MenuItem item) { |
365 | 370 | createRenameDialog(); |
366 | 371 | } else if (item.getItemId() == R.id.menu_item_remove_watched) { |
367 | 372 | if (!isRewritingPlaylist) { |
368 | | - new AlertDialog.Builder(requireContext()) |
369 | | - .setMessage(R.string.remove_watched_popup_warning) |
370 | | - .setTitle(R.string.remove_watched_popup_title) |
371 | | - .setPositiveButton(R.string.ok, (d, id) -> |
372 | | - removeWatchedStreams(false)) |
373 | | - .setNeutralButton( |
374 | | - R.string.remove_watched_popup_yes_and_partially_watched_videos, |
375 | | - (d, id) -> removeWatchedStreams(true)) |
376 | | - .setNegativeButton(R.string.cancel, |
377 | | - (d, id) -> d.cancel()) |
378 | | - .show(); |
| 373 | + openRemoveWatchedConfirmationDialog(); |
379 | 374 | } |
380 | 375 | } else if (item.getItemId() == R.id.menu_item_remove_duplicates) { |
381 | 376 | if (!isRewritingPlaylist) { |
@@ -447,39 +442,28 @@ public void removeWatchedStreams(final boolean removePartiallyWatched) { |
447 | 442 | .getIsPlaylistThumbnailPermanent(playlistId); |
448 | 443 | boolean thumbnailVideoRemoved = false; |
449 | 444 |
|
450 | | - if (removePartiallyWatched) { |
451 | | - for (final var playlistItem : playlist) { |
452 | | - final int indexInHistory = Collections.binarySearch(historyStreamIds, |
453 | | - playlistItem.getStreamId()); |
454 | | - |
455 | | - if (indexInHistory < 0) { |
456 | | - itemsToKeep.add(playlistItem); |
457 | | - } else if (!isThumbnailPermanent && !thumbnailVideoRemoved |
458 | | - && playlistManager.getPlaylistThumbnailStreamId(playlistId) |
459 | | - == playlistItem.getStreamEntity().getUid()) { |
460 | | - thumbnailVideoRemoved = true; |
461 | | - } |
462 | | - } |
463 | | - } else { |
464 | | - final var streamStates = recordManager |
465 | | - .loadLocalStreamStateBatch(playlist).blockingGet(); |
466 | | - |
467 | | - for (int i = 0; i < playlist.size(); i++) { |
468 | | - final var playlistItem = playlist.get(i); |
469 | | - final var streamStateEntity = streamStates.get(i); |
470 | | - |
471 | | - final int indexInHistory = Collections.binarySearch(historyStreamIds, |
472 | | - playlistItem.getStreamId()); |
473 | | - final long duration = playlistItem.toStreamInfoItem().getDuration(); |
474 | | - |
475 | | - if (indexInHistory < 0 || (streamStateEntity != null |
476 | | - && !streamStateEntity.isFinished(duration))) { |
477 | | - itemsToKeep.add(playlistItem); |
478 | | - } else if (!isThumbnailPermanent && !thumbnailVideoRemoved |
479 | | - && playlistManager.getPlaylistThumbnailStreamId(playlistId) |
480 | | - == playlistItem.getStreamEntity().getUid()) { |
481 | | - thumbnailVideoRemoved = true; |
482 | | - } |
| 445 | + final var streamStates = recordManager |
| 446 | + .loadLocalStreamStateBatch(playlist).blockingGet(); |
| 447 | + |
| 448 | + for (int i = 0; i < playlist.size(); i++) { |
| 449 | + final var playlistItem = playlist.get(i); |
| 450 | + final var streamStateEntity = streamStates.get(i); |
| 451 | + final int indexInHistory = Collections.binarySearch(historyStreamIds, |
| 452 | + playlistItem.getStreamId()); |
| 453 | + final long duration = playlistItem.toStreamInfoItem().getDuration(); |
| 454 | + |
| 455 | + if (indexInHistory < 0 // stream is not in history |
| 456 | + // stream is in history but the streamStateEntity is null |
| 457 | + // if the stream was played for less than 5 seconds, see |
| 458 | + // StreamStateEntity#PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS |
| 459 | + || streamStateEntity == null |
| 460 | + || (!removePartiallyWatched |
| 461 | + && !streamStateEntity.isFinished(duration))) { |
| 462 | + itemsToKeep.add(playlistItem); |
| 463 | + } else if (!isThumbnailPermanent && !thumbnailVideoRemoved |
| 464 | + && playlistManager.getPlaylistThumbnailStreamId(playlistId) |
| 465 | + == playlistItem.getStreamEntity().getUid()) { |
| 466 | + thumbnailVideoRemoved = true; |
483 | 467 | } |
484 | 468 | } |
485 | 469 |
|
@@ -904,6 +888,35 @@ private void createShareConfirmationDialog() { |
904 | 888 | .show(); |
905 | 889 | } |
906 | 890 |
|
| 891 | + /** |
| 892 | + * Opens a confirmation dialog to remove watched streams from the playlist. |
| 893 | + * The user can also choose to remove partially watched streams. |
| 894 | + */ |
| 895 | + private void openRemoveWatchedConfirmationDialog() { |
| 896 | + final android.widget.CheckBox removePartiallyWatchedCheckbox = |
| 897 | + new android.widget.CheckBox(requireContext()); |
| 898 | + removePartiallyWatchedCheckbox.setText( |
| 899 | + R.string.remove_watched_popup_partially_watched_streams); |
| 900 | + |
| 901 | + // Wrap the checkbox in a container with dialog-like horizontal padding |
| 902 | + // so it aligns with the dialog title and message on the start side. |
| 903 | + final LinearLayout checkboxContainer = new LinearLayout(requireContext()); |
| 904 | + checkboxContainer.setOrientation(LinearLayout.VERTICAL); |
| 905 | + final int padding = DeviceUtils.dpToPx(20, requireContext()); |
| 906 | + checkboxContainer.setPadding(padding, padding, padding, 0); |
| 907 | + checkboxContainer.addView(removePartiallyWatchedCheckbox, |
| 908 | + new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); |
| 909 | + |
| 910 | + new AlertDialog.Builder(requireContext()) |
| 911 | + .setMessage(R.string.remove_watched_popup_warning) |
| 912 | + .setTitle(R.string.remove_watched_popup_title) |
| 913 | + .setView(checkboxContainer) |
| 914 | + .setPositiveButton(R.string.yes, (d, id) -> |
| 915 | + removeWatchedStreams(removePartiallyWatchedCheckbox.isChecked())) |
| 916 | + .setNegativeButton(R.string.cancel, (d, id) -> d.cancel()) |
| 917 | + .show(); |
| 918 | + } |
| 919 | + |
907 | 920 | public void setTabsPagerAdapter( |
908 | 921 | @Nullable final MainFragment.SelectedTabsPagerAdapter tabsPagerAdapter) { |
909 | 922 | this.tabsPagerAdapter = tabsPagerAdapter; |
|
0 commit comments