diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index aedf64231..e3abd32b1 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -20,7 +20,10 @@ package org.schabi.newpipe; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; @@ -101,6 +104,8 @@ public class MainActivity extends AppCompatActivity { private boolean servicesShown = false; private ImageView serviceArrow; + private BroadcastReceiver broadcastReceiver; + private static final int ITEM_ID_SUBSCRIPTIONS = -1; private static final int ITEM_ID_FEED = -2; private static final int ITEM_ID_BOOKMARKS = -3; @@ -147,6 +152,7 @@ public class MainActivity extends AppCompatActivity { if (DeviceUtils.isTv(this)) { FocusOverlayView.setupFocusObserver(this); } + setupBroadcastReceiver(); } private void setupDrawer() throws Exception { @@ -454,6 +460,7 @@ public class MainActivity extends AppCompatActivity { if (!isChangingConfigurations()) { StateSaver.clearStateFiles(); } + unregisterReceiver(broadcastReceiver); } @Override @@ -795,9 +802,24 @@ public class MainActivity extends AppCompatActivity { ErrorActivity.reportUiError(this, e); } } - /* - * Utils - * */ + + private void setupBroadcastReceiver() { + broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + if (intent.getAction().equals(VideoDetailFragment.ACTION_PLAYER_STARTED)) { + final Fragment fragmentPlayer = getSupportFragmentManager() + .findFragmentById(R.id.fragment_player_holder); + if (fragmentPlayer == null) { + NavigationHelper.showMiniPlayer(getSupportFragmentManager()); + } + } + } + }; + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED); + registerReceiver(broadcastReceiver, intentFilter); + } private boolean bottomSheetHiddenOrCollapsed() { final FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 1b62c8ffb..39ee38220 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -146,6 +146,8 @@ public class VideoDetailFragment "org.schabi.newpipe.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER"; public static final String ACTION_HIDE_MAIN_PLAYER = "org.schabi.newpipe.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER"; + public static final String ACTION_PLAYER_STARTED = + "org.schabi.newpipe.VideoDetailFragment.ACTION_PLAYER_STARTED"; public static final String ACTION_VIDEO_FRAGMENT_RESUMED = "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED"; public static final String ACTION_VIDEO_FRAGMENT_STOPPED = @@ -302,6 +304,12 @@ public class VideoDetailFragment return instance; } + public static VideoDetailFragment getInstanceCollapsed() { + final VideoDetailFragment instance = new VideoDetailFragment(); + instance.bottomSheetState = BottomSheetBehavior.STATE_COLLAPSED; + return instance; + } + /*////////////////////////////////////////////////////////////////////////// // Fragment's Lifecycle @@ -518,7 +526,7 @@ public class VideoDetailFragment openVideoPlayer(); } - setOverlayPlayPauseImage(); + setOverlayPlayPauseImage(player != null && player.isPlaying()); break; case R.id.overlay_close_button: bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); @@ -1325,12 +1333,22 @@ public class VideoDetailFragment bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); } else if (intent.getAction().equals(ACTION_HIDE_MAIN_PLAYER)) { bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + } else if (intent.getAction().equals(ACTION_PLAYER_STARTED)) { + // If the state is not hidden we don't need to show the mini player + if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN) { + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } + // Rebound to the service if it was closed via notification or mini player + if (!PlayerHolder.bound) { + PlayerHolder.startService(App.getApp(), false, VideoDetailFragment.this); + } } } }; final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER); intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER); + intentFilter.addAction(ACTION_PLAYER_STARTED); activity.registerReceiver(broadcastReceiver, intentFilter); } @@ -1719,8 +1737,12 @@ public class VideoDetailFragment // It will allow to have live instance of PlayQueue with actual 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)) { - stack.push(new StackItem(serviceId, url, name, playQueue)); + if ((stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue) + && queue.getItem() != null)) { + stack.push(new StackItem(queue.getItem().getServiceId(), + queue.getItem().getUrl(), + queue.getItem().getTitle(), + queue)); } else { final StackItem stackWithQueue = findQueueInStack(queue); if (stackWithQueue != null) { @@ -1744,7 +1766,7 @@ public class VideoDetailFragment final int repeatMode, final boolean shuffled, final PlaybackParameters parameters) { - setOverlayPlayPauseImage(); + setOverlayPlayPauseImage(player != null && player.isPlaying()); switch (state) { case BasePlayer.STATE_PLAYING: @@ -1818,7 +1840,7 @@ public class VideoDetailFragment @Override public void onServiceStopped() { - setOverlayPlayPauseImage(); + setOverlayPlayPauseImage(false); if (currentInfo != null) { updateOverlayData(currentInfo.getName(), currentInfo.getUploaderName(), @@ -2224,6 +2246,9 @@ public class VideoDetailFragment break; case BottomSheetBehavior.STATE_COLLAPSED: moveFocusToMainFragment(true); + manageSpaceAtTheBottom(false); + + bottomSheetBehavior.setPeekHeight(peekHeight); // Re-enable clicks setOverlayElementsClickable(true); @@ -2270,8 +2295,8 @@ public class VideoDetailFragment } } - private void setOverlayPlayPauseImage() { - final int attr = player != null && player.isPlaying() + private void setOverlayPlayPauseImage(final boolean playerIsPlaying) { + final int attr = playerIsPlaying ? R.attr.ic_pause : R.attr.ic_play_arrow; overlayPlayPauseButton.setImageResource( diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java index f93df4d08..e3eb1c9f7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java @@ -255,9 +255,9 @@ public class VideoPlayerImpl extends VideoPlayer onQueueClosed(); // Android TV: without it focus will frame the whole player playPauseButton.requestFocus(); + onPlay(); } - - onPlay(); + NavigationHelper.sendPlayerStartedEvent(service); } VideoPlayerImpl(final MainPlayer service) { @@ -662,6 +662,7 @@ public class VideoPlayerImpl extends VideoPlayer @Override public void onPlayQueueEdited() { updatePlayback(); + showOrHideButtons(); NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false); } @@ -1455,15 +1456,16 @@ public class VideoPlayerImpl extends VideoPlayer return; } - playPreviousButton.setVisibility(playQueue.getIndex() == 0 - ? View.INVISIBLE - : View.VISIBLE); - playNextButton.setVisibility(playQueue.getIndex() + 1 == playQueue.getStreams().size() - ? View.INVISIBLE - : View.VISIBLE); - queueButton.setVisibility(playQueue.getStreams().size() <= 1 || popupPlayerSelected() - ? View.GONE - : View.VISIBLE); + final boolean showPrev = playQueue.getIndex() != 0; + final boolean showNext = playQueue.getIndex() + 1 != playQueue.getStreams().size(); + final boolean showQueue = playQueue.getStreams().size() > 1 && !popupPlayerSelected(); + + playPreviousButton.setVisibility(showPrev ? View.VISIBLE : View.INVISIBLE); + playPreviousButton.setAlpha(showPrev ? 1.0f : 0.0f); + playNextButton.setVisibility(showNext ? View.VISIBLE : View.INVISIBLE); + playNextButton.setAlpha(showNext ? 1.0f : 0.0f); + queueButton.setVisibility(showQueue ? View.VISIBLE : View.GONE); + queueButton.setAlpha(showQueue ? 1.0f : 0.0f); } private void showSystemUIPartially() { @@ -1936,6 +1938,7 @@ public class VideoPlayerImpl extends VideoPlayer getControlsRoot().setPadding(0, 0, 0, 0); } queueLayout.setPadding(0, 0, 0, 0); + updateQueue(); updateMetadata(); updatePlayback(); triggerProgressUpdate(); diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index fc4a6cacc..ac5e9c449 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -384,8 +384,19 @@ public final class NavigationHelper { } public static void expandMainPlayer(final Context context) { - final Intent intent = new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER); - context.sendBroadcast(intent); + context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER)); + } + + public static void sendPlayerStartedEvent(final Context context) { + context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_PLAYER_STARTED)); + } + + public static void showMiniPlayer(final FragmentManager fragmentManager) { + final VideoDetailFragment instance = VideoDetailFragment.getInstanceCollapsed(); + defaultTransaction(fragmentManager) + .replace(R.id.fragment_player_holder, instance) + .runOnCommit(() -> sendPlayerStartedEvent(instance.requireActivity())) + .commit(); } public static void openChannelFragment(final FragmentManager fragmentManager,