diff --git a/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt b/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt index b6835b144..ba3824b80 100644 --- a/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt +++ b/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt @@ -1,18 +1,14 @@ package com.github.libretube.helpers +import android.annotation.SuppressLint import android.app.NotificationManager import android.content.Context import android.content.Intent -import android.os.Handler -import android.os.Looper import android.os.Process -import androidx.annotation.OptIn import androidx.core.content.getSystemService import androidx.core.os.bundleOf -import androidx.core.os.postDelayed import androidx.fragment.app.commitNow import androidx.fragment.app.replace -import androidx.media3.common.util.UnstableApi import com.github.libretube.NavDirections import com.github.libretube.R import com.github.libretube.constants.IntentData @@ -29,8 +25,6 @@ import com.github.libretube.ui.views.SingleViewTouchableMotionLayout import com.github.libretube.util.PlayingQueue object NavigationHelper { - private val handler = Handler(Looper.getMainLooper()) - fun navigateChannel(context: Context, channelUrlOrId: String?) { if (channelUrlOrId == null) return @@ -52,6 +46,7 @@ object NavigationHelper { * Navigate to the given video using the other provided parameters as well * If the audio only mode is enabled, play it in the background, else as a normal video */ + @SuppressLint("UnsafeOptInUsageError") fun navigateVideo( context: Context, videoUrlOrId: String?, @@ -60,22 +55,27 @@ object NavigationHelper { keepQueue: Boolean = false, timestamp: Long = 0, alreadyStarted: Boolean = false, - forceVideo: Boolean = false + forceVideo: Boolean = false, + audioOnlyPlayerRequested: Boolean = false, ) { if (videoUrlOrId == null) return - if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false) && !forceVideo) { - navigateAudio(context, videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp) - return - } - + // attempt to attach to the current media session first by using the corresponding + // video/audio player instance val activity = ContextHelper.unwrapActivity(context) val attachedToRunningPlayer = activity.runOnPlayerFragment { try { this.playNextVideo(videoUrlOrId.toID()) - // maximize player - this.binding.playerMotionLayout.transitionToStart() PlayingQueue.clear() + + if (audioOnlyPlayerRequested) { + // switch to audio only player + this.switchToAudioMode() + } else { + // maximize player + this.binding.playerMotionLayout.transitionToStart() + } + true } catch (e: Exception) { this.onDestroy() @@ -84,45 +84,46 @@ object NavigationHelper { } if (attachedToRunningPlayer) return - val playerData = - PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp) - val bundle = bundleOf( - IntentData.playerData to playerData, - IntentData.alreadyStarted to alreadyStarted - ) - activity.supportFragmentManager.commitNow { - replace(R.id.container, args = bundle) - } - } + val attachedToRunningAudioPlayer = activity.runOnAudioPlayerFragment { + this.playNextVideo(videoUrlOrId.toID()) + PlayingQueue.clear() + + if (!audioOnlyPlayerRequested) { + // switch to video only player + this.switchToVideoMode() + } else { + // maximize player + this.binding.playerMotionLayout.transitionToStart() + } - @OptIn(UnstableApi::class) - fun navigateAudio( - context: Context, - videoId: String, - playlistId: String? = null, - channelId: String? = null, - keepQueue: Boolean = false, - timestamp: Long = 0, - minimizeByDefault: Boolean = false - ) { - val activity = ContextHelper.unwrapActivity(context) - val attachedToRunningPlayer = activity.runOnAudioPlayerFragment { - this.playNextVideo(videoId) true } - if (attachedToRunningPlayer) return + if (attachedToRunningAudioPlayer) return - BackgroundHelper.playOnBackground( - context, - videoId, - timestamp, - playlistId, - channelId, - keepQueue - ) + val audioOnlyMode = PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false) + if (audioOnlyPlayerRequested || (audioOnlyMode && !forceVideo)) { + // in contrast to the video player, the audio player doesn't start a media service on + // its own! + BackgroundHelper.playOnBackground( + context, + videoUrlOrId.toID(), + timestamp, + playlistId, + channelId, + keepQueue + ) - handler.postDelayed(500) { - openAudioPlayerFragment(context, minimizeByDefault = minimizeByDefault) + openAudioPlayerFragment(context, minimizeByDefault = true) + } else { + openVideoPlayerFragment( + context, + videoUrlOrId.toID(), + playlistId, + channelId, + keepQueue, + timestamp, + alreadyStarted + ) } } @@ -153,6 +154,31 @@ object NavigationHelper { } } + /** + * Starts the video player fragment for an already existing med + */ + fun openVideoPlayerFragment( + context: Context, + videoId: String, + playlistId: String? = null, + channelId: String? = null, + keepQueue: Boolean = false, + timestamp: Long = 0, + alreadyStarted: Boolean = false + ) { + val activity = ContextHelper.unwrapActivity(context) + + val playerData = + PlayerData(videoId, playlistId, channelId, keepQueue, timestamp) + val bundle = bundleOf( + IntentData.playerData to playerData, + IntentData.alreadyStarted to alreadyStarted + ) + activity.supportFragmentManager.commitNow { + replace(R.id.container, args = bundle) + } + } + /** * Open a large, zoomable image preview */ diff --git a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt index 94d37f78b..f67fc4cc0 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt @@ -33,6 +33,7 @@ import com.github.libretube.enums.PlayerCommand import com.github.libretube.extensions.navigateVideo import com.github.libretube.extensions.normalize import com.github.libretube.extensions.seekBy +import com.github.libretube.extensions.toID import com.github.libretube.extensions.togglePlayPauseState import com.github.libretube.extensions.updateIfChanged import com.github.libretube.helpers.AudioHelper @@ -174,19 +175,7 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye } binding.openVideo.setOnClickListener { - playerController?.sendCustomCommand( - AbstractPlayerService.runPlayerActionCommand, - bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to false) - ) - - killFragment(false) - - NavigationHelper.navigateVideo( - context = requireContext(), - videoUrlOrId = PlayingQueue.getCurrent()?.url, - alreadyStarted = true, - forceVideo = true - ) + switchToVideoMode() } childFragmentManager.setFragmentResultListener( @@ -271,6 +260,21 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye } } + fun switchToVideoMode() { + playerController?.sendCustomCommand( + AbstractPlayerService.runPlayerActionCommand, + bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to false) + ) + + killFragment(false) + + NavigationHelper.openVideoPlayerFragment( + context = requireContext(), + videoId = PlayingQueue.getCurrent()?.url!!.toID(), + alreadyStarted = true, + ) + } + private fun killFragment(stopPlayer: Boolean) { viewModel.isMiniPlayerVisible.value = false diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 0638d4f87..40f05ba6b 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -218,7 +218,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions { } PlayerEvent.Background -> { - playOnBackground() + switchToAudioMode() // wait some time in order for the service to get started properly handler.postDelayed(500) { pipActivity?.moveTaskToBack(false) @@ -698,7 +698,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions { binding.relPlayerBackground.setOnClickListener { // start the background mode - playOnBackground() + switchToAudioMode() } binding.relPlayerPip.isVisible = @@ -777,7 +777,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions { chaptersViewModel.maxSheetHeightPx = maxHeight } - private fun playOnBackground() { + fun switchToAudioMode() { playerController.sendCustomCommand( AbstractPlayerService.runPlayerActionCommand, bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to true) diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt index 65eeaceef..1c0752d89 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt @@ -57,7 +57,7 @@ class VideoOptionsBottomSheet : BaseBottomSheet() { when (optionsList[which]) { // Start the background mode R.string.playOnBackground -> { - NavigationHelper.navigateAudio(requireContext(), videoId, minimizeByDefault = true) + NavigationHelper.navigateVideo(requireContext(), videoId, audioOnlyPlayerRequested = true) } // Add Video to Playlist Dialog R.string.addToPlaylist -> {