mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Better backstack, better tablet support, switching players confirmation, fix for background playback
This commit is contained in:
		| @@ -18,6 +18,7 @@ import android.widget.*; | |||||||
| import androidx.annotation.DrawableRes; | import androidx.annotation.DrawableRes; | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
|  | import androidx.appcompat.app.AlertDialog; | ||||||
| import androidx.coordinatorlayout.widget.CoordinatorLayout; | import androidx.coordinatorlayout.widget.CoordinatorLayout; | ||||||
| import com.google.android.exoplayer2.ExoPlaybackException; | import com.google.android.exoplayer2.ExoPlaybackException; | ||||||
| import com.google.android.exoplayer2.PlaybackParameters; | import com.google.android.exoplayer2.PlaybackParameters; | ||||||
| @@ -74,6 +75,7 @@ import org.schabi.newpipe.views.AnimatedProgressBar; | |||||||
|  |  | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.Iterator; | ||||||
| import java.util.LinkedList; | import java.util.LinkedList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| @@ -86,6 +88,7 @@ import io.reactivex.disposables.Disposable; | |||||||
| import io.reactivex.schedulers.Schedulers; | import io.reactivex.schedulers.Schedulers; | ||||||
|  |  | ||||||
| import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; | import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; | ||||||
|  | import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; | ||||||
| import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; | import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; | ||||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||||
|  |  | ||||||
| @@ -237,7 +240,7 @@ public class VideoDetailFragment | |||||||
|  |  | ||||||
|                 if (!player.videoPlayerSelected() && !playAfterConnect) return; |                 if (!player.videoPlayerSelected() && !playAfterConnect) return; | ||||||
|  |  | ||||||
|                 if (playerIsNotStopped()) addVideoPlayerView(); |                 if (playerIsNotStopped() && player.videoPlayerSelected()) addVideoPlayerView(); | ||||||
|  |  | ||||||
|                 // If the video is playing but orientation changed let's make the video in fullscreen again |                 // If the video is playing but orientation changed let's make the video in fullscreen again | ||||||
|                 if (isLandscape()) checkLandscape(); |                 if (isLandscape()) checkLandscape(); | ||||||
| @@ -382,7 +385,7 @@ public class VideoDetailFragment | |||||||
|  |  | ||||||
|         // Check if it was loading when the fragment was stopped/paused |         // Check if it was loading when the fragment was stopped/paused | ||||||
|         if (wasLoading.getAndSet(false) && !wasCleared()) |         if (wasLoading.getAndSet(false) && !wasCleared()) | ||||||
|             selectAndLoadVideo(serviceId, url, name, playQueue); |             startLoading(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -870,16 +873,10 @@ public class VideoDetailFragment | |||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         StackItem currentPeek = stack.peek(); |  | ||||||
|         if (currentPeek != null && !currentPeek.getPlayQueue().equals(playQueue)) { |  | ||||||
|             // When user selected a stream but didn't start playback this stream will not be added to backStack. |  | ||||||
|             // Then he press Back and the last saved item from history will show up |  | ||||||
|             setupFromHistoryItem(currentPeek); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // If we have something in history of played items we replay it here |         // If we have something in history of played items we replay it here | ||||||
|         boolean isPreviousCanBePlayed = player != null && player.getPlayQueue() != null && player.videoPlayerSelected() |         boolean isPreviousCanBePlayed = player != null | ||||||
|  |                 && player.getPlayQueue() != null | ||||||
|  |                 && player.videoPlayerSelected() | ||||||
|                 && player.getPlayQueue().previous(); |                 && player.getPlayQueue().previous(); | ||||||
|         if (isPreviousCanBePlayed) { |         if (isPreviousCanBePlayed) { | ||||||
|             return true; |             return true; | ||||||
| @@ -903,11 +900,15 @@ public class VideoDetailFragment | |||||||
|         setAutoplay(false); |         setAutoplay(false); | ||||||
|         hideMainPlayer(); |         hideMainPlayer(); | ||||||
|  |  | ||||||
|         selectAndLoadVideo( |         setInitialData( | ||||||
|                 item.getServiceId(), |                 item.getServiceId(), | ||||||
|                 item.getUrl(), |                 item.getUrl(), | ||||||
|                 !TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "", |                 !TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "", | ||||||
|                 item.getPlayQueue()); |                 item.getPlayQueue()); | ||||||
|  |         startLoading(false); | ||||||
|  |  | ||||||
|  |         // Maybe an item was deleted in background activity | ||||||
|  |         if (item.getPlayQueue().getItem() == null) return; | ||||||
|  |  | ||||||
|         PlayQueueItem playQueueItem = item.getPlayQueue().getItem(); |         PlayQueueItem playQueueItem = item.getPlayQueue().getItem(); | ||||||
|         // Update title, url, uploader from the last item in the stack (it's current now) |         // Update title, url, uploader from the last item in the stack (it's current now) | ||||||
| @@ -936,7 +937,7 @@ public class VideoDetailFragment | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         setInitialData(serviceId, videoUrl, name, playQueue); |         setInitialData(serviceId, videoUrl, name, playQueue); | ||||||
|         startLoading(false); |         startLoading(false, true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) { |     public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) { | ||||||
| @@ -965,6 +966,20 @@ public class VideoDetailFragment | |||||||
|         currentInfo = null; |         currentInfo = null; | ||||||
|         if (currentWorker != null) currentWorker.dispose(); |         if (currentWorker != null) currentWorker.dispose(); | ||||||
|  |  | ||||||
|  |         runWorker(forceLoad, stack.isEmpty()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void startLoading(boolean forceLoad, boolean addToBackStack) { | ||||||
|  |         super.startLoading(false); | ||||||
|  |  | ||||||
|  |         initTabs(); | ||||||
|  |         currentInfo = null; | ||||||
|  |         if (currentWorker != null) currentWorker.dispose(); | ||||||
|  |  | ||||||
|  |         runWorker(forceLoad, addToBackStack); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void runWorker(boolean forceLoad, boolean addToBackStack) { | ||||||
|         currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad) |         currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad) | ||||||
|                 .subscribeOn(Schedulers.io()) |                 .subscribeOn(Schedulers.io()) | ||||||
|                 .observeOn(AndroidSchedulers.mainThread()) |                 .observeOn(AndroidSchedulers.mainThread()) | ||||||
| @@ -973,12 +988,15 @@ public class VideoDetailFragment | |||||||
|                     hideMainPlayer(); |                     hideMainPlayer(); | ||||||
|                     handleResult(result); |                     handleResult(result); | ||||||
|                     showContent(); |                     showContent(); | ||||||
|  |                     if (addToBackStack) { | ||||||
|  |                         if (playQueue == null) playQueue = new SinglePlayQueue(result); | ||||||
|  |                         stack.push(new StackItem(serviceId, url, name, playQueue)); | ||||||
|  |                     } | ||||||
|                     if (isAutoplayEnabled()) openVideoPlayer(); |                     if (isAutoplayEnabled()) openVideoPlayer(); | ||||||
|                 }, (@NonNull Throwable throwable) -> { |                 }, (@NonNull Throwable throwable) -> { | ||||||
|                     isLoading.set(false); |                     isLoading.set(false); | ||||||
|                     onError(throwable); |                     onError(throwable); | ||||||
|                 }); |                 }); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void initTabs() { |     private void initTabs() { | ||||||
| @@ -1063,7 +1081,9 @@ public class VideoDetailFragment | |||||||
|         if (append) { |         if (append) { | ||||||
|             NavigationHelper.enqueueOnPopupPlayer(activity, queue, false); |             NavigationHelper.enqueueOnPopupPlayer(activity, queue, false); | ||||||
|         } else { |         } else { | ||||||
|             NavigationHelper.playOnPopupPlayer(activity, queue, true); |             Runnable onAllow = () -> NavigationHelper.playOnPopupPlayer(activity, queue, true); | ||||||
|  |             if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow); | ||||||
|  |             else onAllow.run(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1073,7 +1093,9 @@ public class VideoDetailFragment | |||||||
|             VideoStream selectedVideoStream = getSelectedVideoStream(); |             VideoStream selectedVideoStream = getSelectedVideoStream(); | ||||||
|             startOnExternalPlayer(activity, currentInfo, selectedVideoStream); |             startOnExternalPlayer(activity, currentInfo, selectedVideoStream); | ||||||
|         } else { |         } else { | ||||||
|             openNormalPlayer(); |             Runnable onAllow = this::openNormalPlayer; | ||||||
|  |             if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow); | ||||||
|  |             else onAllow.run(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1085,7 +1107,9 @@ public class VideoDetailFragment | |||||||
|         if (append) { |         if (append) { | ||||||
|             NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false); |             NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false); | ||||||
|         } else { |         } else { | ||||||
|             NavigationHelper.playOnBackgroundPlayer(activity, queue, true); |             Runnable onAllow = () -> NavigationHelper.playOnBackgroundPlayer(activity, queue, true); | ||||||
|  |             if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow); | ||||||
|  |             else onAllow.run(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1579,7 +1603,7 @@ public class VideoDetailFragment | |||||||
|                         && prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true); |                         && prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true); | ||||||
|         final boolean showPlaybackPosition = prefs.getBoolean( |         final boolean showPlaybackPosition = prefs.getBoolean( | ||||||
|                 activity.getString(R.string.enable_playback_state_lists_key), true); |                 activity.getString(R.string.enable_playback_state_lists_key), true); | ||||||
|         if (!playbackResumeEnabled || info.getDuration() <= 0) { |         if (!playbackResumeEnabled) { | ||||||
|             if (playQueue == null || playQueue.getStreams().isEmpty() |             if (playQueue == null || playQueue.getStreams().isEmpty() | ||||||
|                     || playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) { |                     || playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) { | ||||||
|                 positionView.setVisibility(View.INVISIBLE); |                 positionView.setVisibility(View.INVISIBLE); | ||||||
| @@ -1605,7 +1629,8 @@ public class VideoDetailFragment | |||||||
|                 }, e -> { |                 }, e -> { | ||||||
|                     if (DEBUG) e.printStackTrace(); |                     if (DEBUG) e.printStackTrace(); | ||||||
|                 }, () -> { |                 }, () -> { | ||||||
|                     // OnComplete, do nothing |                     animateView(positionView, false, 0); | ||||||
|  |                     animateView(detailPositionView, false, 0); | ||||||
|                 }); |                 }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1615,6 +1640,10 @@ public class VideoDetailFragment | |||||||
|         positionView.setMax(durationSeconds); |         positionView.setMax(durationSeconds); | ||||||
|         positionView.setProgress(progressSeconds); |         positionView.setProgress(progressSeconds); | ||||||
|         detailPositionView.setText(Localization.getDurationString(progressSeconds)); |         detailPositionView.setText(Localization.getDurationString(progressSeconds)); | ||||||
|  |         if (positionView.getVisibility() != View.VISIBLE) { | ||||||
|  |             animateView(positionView, true, 100); | ||||||
|  |             animateView(detailPositionView, true, 100); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -1628,11 +1657,11 @@ public class VideoDetailFragment | |||||||
|         // information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items |         // information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items | ||||||
|         if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) { |         if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) { | ||||||
|             stack.push(new StackItem(serviceId, url, name, playQueue)); |             stack.push(new StackItem(serviceId, url, name, playQueue)); | ||||||
|         } else if (stack.peek().getPlayQueue().equals(queue)) { |         } else if (findQueueInStack(queue) != null) { | ||||||
|             // On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress. |             // On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress. | ||||||
|             // That's why we update our cached disposed queue with the new one that is active and have the same history |             // That's why we update our cached disposed queue with the new one that is active and have the same history | ||||||
|             // Without that the cached playQueue will have an old recovery position |             // Without that the cached playQueue will have an old recovery position | ||||||
|             stack.peek().setPlayQueue(queue); |             findQueueInStack(queue).setPlayQueue(queue); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (DEBUG) { |         if (DEBUG) { | ||||||
| @@ -1671,20 +1700,23 @@ public class VideoDetailFragment | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onMetadataUpdate(StreamInfo info) { |     public void onMetadataUpdate(StreamInfo info, PlayQueue queue) { | ||||||
|         if (!stack.isEmpty()) { |         StackItem item = findQueueInStack(queue); | ||||||
|  |         if (item != null) { | ||||||
|             // When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives |             // When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives | ||||||
|             // new title and url. StackItem contains information about first played stream. Let's update it here |             // new title and url. StackItem contains information about first played stream. Let's update it here | ||||||
|             StackItem peek = stack.peek(); |             item.setTitle(info.getName()); | ||||||
|             peek.setTitle(info.getName()); |             item.setUrl(info.getUrl()); | ||||||
|             peek.setUrl(info.getUrl()); |  | ||||||
|         } |         } | ||||||
|  |         // They are not equal when user watches something in popup while browsing in fragment and then changes screen orientation | ||||||
|  |         // In that case the fragment will set itself as a service listener and will receive initial call to onMetadataUpdate() | ||||||
|  |         if (!queue.equals(playQueue)) return; | ||||||
|  |  | ||||||
|         updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); |         updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); | ||||||
|         if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return; |         if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return; | ||||||
|  |  | ||||||
|         currentInfo = info; |         currentInfo = info; | ||||||
|         setInitialData(info.getServiceId(), info.getUrl(),info.getName(), playQueue); |         setInitialData(info.getServiceId(), info.getUrl(),info.getName(), queue); | ||||||
|         setAutoplay(false); |         setAutoplay(false); | ||||||
|         prepareAndHandleInfo(info, true); |         prepareAndHandleInfo(info, true); | ||||||
|     } |     } | ||||||
| @@ -1852,6 +1884,37 @@ public class VideoDetailFragment | |||||||
|         return url == null; |         return url == null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private StackItem findQueueInStack(PlayQueue queue) { | ||||||
|  |         StackItem item = null; | ||||||
|  |         Iterator<StackItem> iterator = stack.descendingIterator(); | ||||||
|  |         while (iterator.hasNext()) { | ||||||
|  |             StackItem next = iterator.next(); | ||||||
|  |             if (next.getPlayQueue().equals(queue)) { | ||||||
|  |                 item = next; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return item; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private boolean shouldAskBeforeClearingQueue() { | ||||||
|  |         PlayQueue activeQueue = player != null ? player.getPlayQueue() : null; | ||||||
|  |         // Player will have STATE_IDLE when a user pressed back button | ||||||
|  |         return isClearingQueueConfirmationRequired(activity) && playerIsNotStopped() | ||||||
|  |                 && activeQueue != null && !activeQueue.equals(playQueue) && activeQueue.getStreams().size() > 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void showClearingQueueConfirmation(Runnable onAllow) { | ||||||
|  |         new AlertDialog.Builder(activity) | ||||||
|  |                 .setTitle(R.string.confirm_prompt) | ||||||
|  |                 .setMessage(R.string.clear_queue_confirmation_description) | ||||||
|  |                 .setNegativeButton(android.R.string.cancel, null) | ||||||
|  |                 .setPositiveButton(android.R.string.yes, (dialog, which) -> { | ||||||
|  |                     onAllow.run(); | ||||||
|  |                     dialog.dismiss(); | ||||||
|  |                 }).show(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|     * Remove unneeded information while waiting for a next task |     * Remove unneeded information while waiting for a next task | ||||||
|     * */ |     * */ | ||||||
| @@ -1905,6 +1968,7 @@ public class VideoDetailFragment | |||||||
|                                 && player != null |                                 && player != null | ||||||
|                                 && player.isPlaying() |                                 && player.isPlaying() | ||||||
|                                 && !player.isInFullscreen() |                                 && !player.isInFullscreen() | ||||||
|  |                                 && !PlayerHelper.isTablet(activity) | ||||||
|                                 && player.videoPlayerSelected(); |                                 && player.videoPlayerSelected(); | ||||||
|                         if (needToExpand) player.toggleFullscreen(); |                         if (needToExpand) player.toggleFullscreen(); | ||||||
|                         break; |                         break; | ||||||
|   | |||||||
| @@ -451,7 +451,7 @@ public final class BackgroundPlayer extends Service { | |||||||
|  |  | ||||||
|         private void updateMetadata() { |         private void updateMetadata() { | ||||||
|             if (activityListener != null && getCurrentMetadata() != null) { |             if (activityListener != null && getCurrentMetadata() != null) { | ||||||
|                 activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata()); |                 activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1236,6 +1236,10 @@ public abstract class BasePlayer implements | |||||||
|         return simpleExoPlayer != null && simpleExoPlayer.isPlaying(); |         return simpleExoPlayer != null && simpleExoPlayer.isPlaying(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public boolean isLoading() { | ||||||
|  |         return simpleExoPlayer != null && simpleExoPlayer.isLoading(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Player.RepeatMode |     @Player.RepeatMode | ||||||
|     public int getRepeatMode() { |     public int getRepeatMode() { | ||||||
|         return simpleExoPlayer == null |         return simpleExoPlayer == null | ||||||
|   | |||||||
| @@ -673,7 +673,7 @@ public final class PopupVideoPlayer extends Service { | |||||||
|  |  | ||||||
|         private void updateMetadata() { |         private void updateMetadata() { | ||||||
|             if (activityListener != null && getCurrentMetadata() != null) { |             if (activityListener != null && getCurrentMetadata() != null) { | ||||||
|                 activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata()); |                 activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -596,7 +596,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onMetadataUpdate(StreamInfo info) { |     public void onMetadataUpdate(StreamInfo info, PlayQueue queue) { | ||||||
|         if (info != null) { |         if (info != null) { | ||||||
|             metadataTitle.setText(info.getName()); |             metadataTitle.setText(info.getName()); | ||||||
|             metadataArtist.setText(info.getUploaderName()); |             metadataArtist.setText(info.getUploaderName()); | ||||||
|   | |||||||
| @@ -761,7 +761,8 @@ public class VideoPlayerImpl extends VideoPlayer | |||||||
|  |  | ||||||
|     private void setupScreenRotationButton() { |     private void setupScreenRotationButton() { | ||||||
|         boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service); |         boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service); | ||||||
|         boolean showButton = (orientationLocked || isVerticalVideo || isTablet(service)) && videoPlayerSelected(); |         boolean tabletInLandscape = isTablet(service) && service.isLandscape(); | ||||||
|  |         boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape); | ||||||
|         screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE); |         screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE); | ||||||
|         screenRotationButton.setImageDrawable(service.getResources().getDrawable( |         screenRotationButton.setImageDrawable(service.getResources().getDrawable( | ||||||
|                 isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white)); |                 isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white)); | ||||||
| @@ -1048,10 +1049,10 @@ public class VideoPlayerImpl extends VideoPlayer | |||||||
|                 useVideoSource(true); |                 useVideoSource(true); | ||||||
|                 break; |                 break; | ||||||
|             case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED: |             case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED: | ||||||
|                 // This will be called when user goes to another app |                 // This will be called when user goes to another app/activity, turns off a screen. | ||||||
|                 // We don't want to interrupt playback and don't want to see notification if player is stopped |                 // We don't want to interrupt playback and don't want to see notification if player is stopped. | ||||||
|                 // since next lines of code will enable background playback if needed |                 // Next lines of code will enable background playback if needed | ||||||
|                 if (videoPlayerSelected() && isPlaying()) { |                 if (videoPlayerSelected() && (isPlaying() || isLoading())) { | ||||||
|                     if (backgroundPlaybackEnabled()) { |                     if (backgroundPlaybackEnabled()) { | ||||||
|                         useVideoSource(false); |                         useVideoSource(false); | ||||||
|                     } else if (minimizeOnPopupEnabled()) { |                     } else if (minimizeOnPopupEnabled()) { | ||||||
| @@ -1076,14 +1077,15 @@ public class VideoPlayerImpl extends VideoPlayer | |||||||
|                 break; |                 break; | ||||||
|             case Intent.ACTION_SCREEN_ON: |             case Intent.ACTION_SCREEN_ON: | ||||||
|                 shouldUpdateOnProgress = true; |                 shouldUpdateOnProgress = true; | ||||||
|                 // Interrupt playback only when screen turns on and user is watching video in fragment |                 // Interrupt playback only when screen turns on and user is watching video in popup player | ||||||
|                 if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading())) |                 // Same action for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED event | ||||||
|  |                 if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading())) | ||||||
|                     useVideoSource(true); |                     useVideoSource(true); | ||||||
|                 break; |                 break; | ||||||
|             case Intent.ACTION_SCREEN_OFF: |             case Intent.ACTION_SCREEN_OFF: | ||||||
|                 shouldUpdateOnProgress = false; |                 shouldUpdateOnProgress = false; | ||||||
|                 // Interrupt playback only when screen turns off with video working |                 // Interrupt playback only when screen turns off with popup player working | ||||||
|                 if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading())) |                 if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading())) | ||||||
|                     useVideoSource(false); |                     useVideoSource(false); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
| @@ -1330,7 +1332,7 @@ public class VideoPlayerImpl extends VideoPlayer | |||||||
|         AppCompatActivity parent = getParentActivity(); |         AppCompatActivity parent = getParentActivity(); | ||||||
|         boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly; |         boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly; | ||||||
|         boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED; |         boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED; | ||||||
|         if (parent != null && videoInLandscapeButNotInFullscreen && playingState) |         if (parent != null && videoInLandscapeButNotInFullscreen && playingState && !PlayerHelper.isTablet(service)) | ||||||
|             toggleFullscreen(); |             toggleFullscreen(); | ||||||
|  |  | ||||||
|         setControlsSize(); |         setControlsSize(); | ||||||
| @@ -1695,10 +1697,10 @@ public class VideoPlayerImpl extends VideoPlayer | |||||||
|  |  | ||||||
|     private void updateMetadata() { |     private void updateMetadata() { | ||||||
|         if (fragmentListener != null && getCurrentMetadata() != null) { |         if (fragmentListener != null && getCurrentMetadata() != null) { | ||||||
|             fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata()); |             fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue); | ||||||
|         } |         } | ||||||
|         if (activityListener != null && getCurrentMetadata() != null) { |         if (activityListener != null && getCurrentMetadata() != null) { | ||||||
|             activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata()); |             activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,6 +35,8 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout> | |||||||
|         // Found that user still swiping, continue following |         // Found that user still swiping, continue following | ||||||
|         if (skippingInterception) return false; |         if (skippingInterception) return false; | ||||||
|  |  | ||||||
|  |         // Don't need to do anything if bottomSheet isn't expanded | ||||||
|  |         if (getState() == BottomSheetBehavior.STATE_EXPANDED) { | ||||||
|             // Without overriding scrolling will not work when user touches these elements |             // Without overriding scrolling will not work when user touches these elements | ||||||
|             for (Integer element : skipInterceptionOfElements) { |             for (Integer element : skipInterceptionOfElements) { | ||||||
|                 ViewGroup viewGroup = child.findViewById(element); |                 ViewGroup viewGroup = child.findViewById(element); | ||||||
| @@ -46,6 +48,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout> | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return super.onInterceptTouchEvent(parent, child, event); |         return super.onInterceptTouchEvent(parent, child, event); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,6 +10,6 @@ public interface PlayerEventListener { | |||||||
|     void onQueueUpdate(PlayQueue queue); |     void onQueueUpdate(PlayQueue queue); | ||||||
|     void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters); |     void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters); | ||||||
|     void onProgressUpdate(int currentProgress, int duration, int bufferPercent); |     void onProgressUpdate(int currentProgress, int duration, int bufferPercent); | ||||||
|     void onMetadataUpdate(StreamInfo info); |     void onMetadataUpdate(StreamInfo info, PlayQueue queue); | ||||||
|     void onServiceStopped(); |     void onServiceStopped(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -200,6 +200,10 @@ public class PlayerHelper { | |||||||
|         return isAutoQueueEnabled(context, false); |         return isAutoQueueEnabled(context, false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) { | ||||||
|  |         return getPreferences(context).getBoolean(context.getString(R.string.clear_queue_confirmation_key), false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @MinimizeMode |     @MinimizeMode | ||||||
|     public static int getMinimizeOnExitAction(@NonNull final Context context) { |     public static int getMinimizeOnExitAction(@NonNull final Context context) { | ||||||
|         final String defaultAction = context.getString(R.string.minimize_on_exit_none_key); |         final String defaultAction = context.getString(R.string.minimize_on_exit_none_key); | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ | |||||||
|     <string name="auto_queue_key" translatable="false">auto_queue_key</string> |     <string name="auto_queue_key" translatable="false">auto_queue_key</string> | ||||||
|     <string name="screen_brightness_key" translatable="false">screen_brightness_key</string> |     <string name="screen_brightness_key" translatable="false">screen_brightness_key</string> | ||||||
|     <string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string> |     <string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string> | ||||||
|  |     <string name="clear_queue_confirmation_key" translatable="false">clear_queue_confirmation_key</string> | ||||||
|  |  | ||||||
|     <string name="seek_duration_key" translatable="false">seek_duration</string> |     <string name="seek_duration_key" translatable="false">seek_duration</string> | ||||||
|     <string name="seek_duration_default_value" translatable="false">10000</string> |     <string name="seek_duration_default_value" translatable="false">10000</string> | ||||||
|   | |||||||
| @@ -71,6 +71,9 @@ | |||||||
|     <string name="use_inexact_seek_title">Use fast inexact seek</string> |     <string name="use_inexact_seek_title">Use fast inexact seek</string> | ||||||
|     <string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string> |     <string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string> | ||||||
|     <string name="seek_duration_title">Fast-forward/-rewind seek duration</string> |     <string name="seek_duration_title">Fast-forward/-rewind seek duration</string> | ||||||
|  |     <string name="clear_queue_confirmation_title">Ask confirmation before clearing a queue</string> | ||||||
|  |     <string name="clear_queue_confirmation_summary">After switching from one player to another your queue may be replaced</string> | ||||||
|  |     <string name="clear_queue_confirmation_description">Queue from the active player will be replaced</string> | ||||||
|     <string name="download_thumbnail_title">Load thumbnails</string> |     <string name="download_thumbnail_title">Load thumbnails</string> | ||||||
|     <string name="show_comments_title">Show comments</string> |     <string name="show_comments_title">Show comments</string> | ||||||
|     <string name="show_comments_summary">Disable to stop showing comments</string> |     <string name="show_comments_summary">Disable to stop showing comments</string> | ||||||
|   | |||||||
| @@ -164,5 +164,13 @@ | |||||||
|           android:key="@string/seek_duration_key" |           android:key="@string/seek_duration_key" | ||||||
|           android:summary="%s" |           android:summary="%s" | ||||||
|           android:title="@string/seek_duration_title"/> |           android:title="@string/seek_duration_title"/> | ||||||
|  |  | ||||||
|  |         <SwitchPreference | ||||||
|  |             app:iconSpaceReserved="false" | ||||||
|  |             android:defaultValue="false" | ||||||
|  |             android:key="@string/clear_queue_confirmation_key" | ||||||
|  |             android:summary="@string/clear_queue_confirmation_summary" | ||||||
|  |             android:title="@string/clear_queue_confirmation_title"/> | ||||||
|  |  | ||||||
|     </PreferenceCategory> |     </PreferenceCategory> | ||||||
| </PreferenceScreen> | </PreferenceScreen> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Avently
					Avently