mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
Merge pull request #7323 from Bnyro/master
feat: smoothen background player -> new video player and video player -> new background player transitions
This commit is contained in:
commit
cc7aba6830
@ -1,18 +1,14 @@
|
|||||||
package com.github.libretube.helpers
|
package com.github.libretube.helpers
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
import androidx.annotation.OptIn
|
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.os.postDelayed
|
|
||||||
import androidx.fragment.app.commitNow
|
import androidx.fragment.app.commitNow
|
||||||
import androidx.fragment.app.replace
|
import androidx.fragment.app.replace
|
||||||
import androidx.media3.common.util.UnstableApi
|
|
||||||
import com.github.libretube.NavDirections
|
import com.github.libretube.NavDirections
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -29,8 +25,6 @@ import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
|
|||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
|
|
||||||
object NavigationHelper {
|
object NavigationHelper {
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
|
||||||
|
|
||||||
fun navigateChannel(context: Context, channelUrlOrId: String?) {
|
fun navigateChannel(context: Context, channelUrlOrId: String?) {
|
||||||
if (channelUrlOrId == null) return
|
if (channelUrlOrId == null) return
|
||||||
|
|
||||||
@ -52,6 +46,7 @@ object NavigationHelper {
|
|||||||
* Navigate to the given video using the other provided parameters as well
|
* 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
|
* If the audio only mode is enabled, play it in the background, else as a normal video
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("UnsafeOptInUsageError")
|
||||||
fun navigateVideo(
|
fun navigateVideo(
|
||||||
context: Context,
|
context: Context,
|
||||||
videoUrlOrId: String?,
|
videoUrlOrId: String?,
|
||||||
@ -60,22 +55,27 @@ object NavigationHelper {
|
|||||||
keepQueue: Boolean = false,
|
keepQueue: Boolean = false,
|
||||||
timestamp: Long = 0,
|
timestamp: Long = 0,
|
||||||
alreadyStarted: Boolean = false,
|
alreadyStarted: Boolean = false,
|
||||||
forceVideo: Boolean = false
|
forceVideo: Boolean = false,
|
||||||
|
audioOnlyPlayerRequested: Boolean = false,
|
||||||
) {
|
) {
|
||||||
if (videoUrlOrId == null) return
|
if (videoUrlOrId == null) return
|
||||||
|
|
||||||
if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false) && !forceVideo) {
|
// attempt to attach to the current media session first by using the corresponding
|
||||||
navigateAudio(context, videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
// video/audio player instance
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val activity = ContextHelper.unwrapActivity<MainActivity>(context)
|
val activity = ContextHelper.unwrapActivity<MainActivity>(context)
|
||||||
val attachedToRunningPlayer = activity.runOnPlayerFragment {
|
val attachedToRunningPlayer = activity.runOnPlayerFragment {
|
||||||
try {
|
try {
|
||||||
this.playNextVideo(videoUrlOrId.toID())
|
this.playNextVideo(videoUrlOrId.toID())
|
||||||
|
PlayingQueue.clear()
|
||||||
|
|
||||||
|
if (audioOnlyPlayerRequested) {
|
||||||
|
// switch to audio only player
|
||||||
|
this.switchToAudioMode()
|
||||||
|
} else {
|
||||||
// maximize player
|
// maximize player
|
||||||
this.binding.playerMotionLayout.transitionToStart()
|
this.binding.playerMotionLayout.transitionToStart()
|
||||||
PlayingQueue.clear()
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
this.onDestroy()
|
this.onDestroy()
|
||||||
@ -84,45 +84,46 @@ object NavigationHelper {
|
|||||||
}
|
}
|
||||||
if (attachedToRunningPlayer) return
|
if (attachedToRunningPlayer) return
|
||||||
|
|
||||||
val playerData =
|
val attachedToRunningAudioPlayer = activity.runOnAudioPlayerFragment {
|
||||||
PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
this.playNextVideo(videoUrlOrId.toID())
|
||||||
val bundle = bundleOf(
|
PlayingQueue.clear()
|
||||||
IntentData.playerData to playerData,
|
|
||||||
IntentData.alreadyStarted to alreadyStarted
|
if (!audioOnlyPlayerRequested) {
|
||||||
)
|
// switch to video only player
|
||||||
activity.supportFragmentManager.commitNow {
|
this.switchToVideoMode()
|
||||||
replace<PlayerFragment>(R.id.container, args = bundle)
|
} 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<MainActivity>(context)
|
|
||||||
val attachedToRunningPlayer = activity.runOnAudioPlayerFragment {
|
|
||||||
this.playNextVideo(videoId)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
if (attachedToRunningPlayer) return
|
if (attachedToRunningAudioPlayer) return
|
||||||
|
|
||||||
|
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(
|
BackgroundHelper.playOnBackground(
|
||||||
context,
|
context,
|
||||||
videoId,
|
videoUrlOrId.toID(),
|
||||||
timestamp,
|
timestamp,
|
||||||
playlistId,
|
playlistId,
|
||||||
channelId,
|
channelId,
|
||||||
keepQueue
|
keepQueue
|
||||||
)
|
)
|
||||||
|
|
||||||
handler.postDelayed(500) {
|
openAudioPlayerFragment(context, minimizeByDefault = true)
|
||||||
openAudioPlayerFragment(context, minimizeByDefault = minimizeByDefault)
|
} 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<BaseActivity>(context)
|
||||||
|
|
||||||
|
val playerData =
|
||||||
|
PlayerData(videoId, playlistId, channelId, keepQueue, timestamp)
|
||||||
|
val bundle = bundleOf(
|
||||||
|
IntentData.playerData to playerData,
|
||||||
|
IntentData.alreadyStarted to alreadyStarted
|
||||||
|
)
|
||||||
|
activity.supportFragmentManager.commitNow {
|
||||||
|
replace<PlayerFragment>(R.id.container, args = bundle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a large, zoomable image preview
|
* Open a large, zoomable image preview
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +33,7 @@ import com.github.libretube.enums.PlayerCommand
|
|||||||
import com.github.libretube.extensions.navigateVideo
|
import com.github.libretube.extensions.navigateVideo
|
||||||
import com.github.libretube.extensions.normalize
|
import com.github.libretube.extensions.normalize
|
||||||
import com.github.libretube.extensions.seekBy
|
import com.github.libretube.extensions.seekBy
|
||||||
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.extensions.togglePlayPauseState
|
import com.github.libretube.extensions.togglePlayPauseState
|
||||||
import com.github.libretube.extensions.updateIfChanged
|
import com.github.libretube.extensions.updateIfChanged
|
||||||
import com.github.libretube.helpers.AudioHelper
|
import com.github.libretube.helpers.AudioHelper
|
||||||
@ -174,19 +175,7 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.openVideo.setOnClickListener {
|
binding.openVideo.setOnClickListener {
|
||||||
playerController?.sendCustomCommand(
|
switchToVideoMode()
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
childFragmentManager.setFragmentResultListener(
|
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) {
|
private fun killFragment(stopPlayer: Boolean) {
|
||||||
viewModel.isMiniPlayerVisible.value = false
|
viewModel.isMiniPlayerVisible.value = false
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerEvent.Background -> {
|
PlayerEvent.Background -> {
|
||||||
playOnBackground()
|
switchToAudioMode()
|
||||||
// wait some time in order for the service to get started properly
|
// wait some time in order for the service to get started properly
|
||||||
handler.postDelayed(500) {
|
handler.postDelayed(500) {
|
||||||
pipActivity?.moveTaskToBack(false)
|
pipActivity?.moveTaskToBack(false)
|
||||||
@ -698,7 +698,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
|
|
||||||
binding.relPlayerBackground.setOnClickListener {
|
binding.relPlayerBackground.setOnClickListener {
|
||||||
// start the background mode
|
// start the background mode
|
||||||
playOnBackground()
|
switchToAudioMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.relPlayerPip.isVisible =
|
binding.relPlayerPip.isVisible =
|
||||||
@ -777,7 +777,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
chaptersViewModel.maxSheetHeightPx = maxHeight
|
chaptersViewModel.maxSheetHeightPx = maxHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playOnBackground() {
|
fun switchToAudioMode() {
|
||||||
playerController.sendCustomCommand(
|
playerController.sendCustomCommand(
|
||||||
AbstractPlayerService.runPlayerActionCommand,
|
AbstractPlayerService.runPlayerActionCommand,
|
||||||
bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to true)
|
bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to true)
|
||||||
|
@ -57,7 +57,7 @@ class VideoOptionsBottomSheet : BaseBottomSheet() {
|
|||||||
when (optionsList[which]) {
|
when (optionsList[which]) {
|
||||||
// Start the background mode
|
// Start the background mode
|
||||||
R.string.playOnBackground -> {
|
R.string.playOnBackground -> {
|
||||||
NavigationHelper.navigateAudio(requireContext(), videoId, minimizeByDefault = true)
|
NavigationHelper.navigateVideo(requireContext(), videoId, audioOnlyPlayerRequested = true)
|
||||||
}
|
}
|
||||||
// Add Video to Playlist Dialog
|
// Add Video to Playlist Dialog
|
||||||
R.string.addToPlaylist -> {
|
R.string.addToPlaylist -> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user