mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 06:10:31 +05:30
refactor: move some player view related code to OnlinePlayerView.kt
This commit is contained in:
parent
9f69770b39
commit
df087054d9
@ -838,6 +838,9 @@ object PlayerHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle basic [PlayerEvent]'s that can be handled by the player itself without context
|
||||
*/
|
||||
fun handlePlayerAction(player: Player, playerEvent: PlayerEvent): Boolean {
|
||||
return when (playerEvent) {
|
||||
PlayerEvent.PlayPause -> {
|
||||
|
@ -14,7 +14,6 @@ import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.PowerManager
|
||||
import android.text.format.DateUtils
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -32,7 +31,6 @@ import androidx.core.os.postDelayed
|
||||
import androidx.core.view.SoftwareKeyboardControllerCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
@ -102,7 +100,6 @@ import com.github.libretube.ui.models.CommentsViewModel
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||
import com.github.libretube.ui.sheets.CommentsSheet
|
||||
import com.github.libretube.ui.sheets.PlayingQueueSheet
|
||||
import com.github.libretube.ui.sheets.StatsSheet
|
||||
import com.github.libretube.util.NowPlayingNotification
|
||||
import com.github.libretube.util.OnlineTimeFrameReceiver
|
||||
@ -160,9 +157,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
Executors.newCachedThreadPool()
|
||||
)
|
||||
|
||||
// SponsorBlock
|
||||
private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var seekBarPreviewListener: SeekbarPreviewListener? = null
|
||||
@ -271,7 +265,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
|
||||
override fun onEvents(player: Player, events: Player.Events) {
|
||||
updateDisplayedDuration()
|
||||
super.onEvents(player, events)
|
||||
|
||||
if (events.containsAny(
|
||||
@ -522,7 +515,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
playerBinding.closeImageButton.setOnClickListener {
|
||||
onManualPlayerClose()
|
||||
}
|
||||
playerBinding.autoPlay.isVisible = true
|
||||
|
||||
binding.playImageView.setOnClickListener {
|
||||
exoPlayer.togglePlayPauseState()
|
||||
@ -540,28 +532,12 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
CommentsSheet().show(childFragmentManager)
|
||||
}
|
||||
|
||||
playerBinding.queueToggle.isVisible = true
|
||||
playerBinding.queueToggle.setOnClickListener {
|
||||
PlayingQueueSheet().show(childFragmentManager, null)
|
||||
}
|
||||
|
||||
// FullScreen button trigger
|
||||
// hide fullscreen button if autorotation enabled
|
||||
playerBinding.fullscreen.setOnClickListener {
|
||||
toggleFullscreen()
|
||||
}
|
||||
|
||||
val updateSbImageResource = {
|
||||
playerBinding.sbToggle.setImageResource(
|
||||
if (sponsorBlockEnabled) R.drawable.ic_sb_enabled else R.drawable.ic_sb_disabled
|
||||
)
|
||||
}
|
||||
updateSbImageResource()
|
||||
playerBinding.sbToggle.setOnClickListener {
|
||||
sponsorBlockEnabled = !sponsorBlockEnabled
|
||||
updateSbImageResource()
|
||||
}
|
||||
|
||||
// share button
|
||||
binding.relPlayerShare.setOnClickListener {
|
||||
if (!this::streams.isInitialized) return@setOnClickListener
|
||||
@ -695,16 +671,12 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
updateFullscreenOrientation()
|
||||
|
||||
commentsViewModel.setCommentSheetExpand(null)
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen_exit)
|
||||
playerBinding.exoTitle.isVisible = true
|
||||
|
||||
updateResolutionOnFullscreenChange(true)
|
||||
|
||||
openOrCloseFullscreenDialog(true)
|
||||
|
||||
binding.player.updateMarginsByFullscreenMode()
|
||||
|
||||
updateFullscreenButtonVisibility()
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
@ -718,8 +690,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
|
||||
viewModel.isFullscreen.value = false
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
||||
playerBinding.exoTitle.isInvisible = true
|
||||
|
||||
if (!PlayerHelper.autoFullscreenEnabled) {
|
||||
mainActivity.requestedOrientation = mainActivity.screenOrientationPref
|
||||
@ -729,12 +699,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
updateResolutionOnFullscreenChange(false)
|
||||
|
||||
binding.player.updateMarginsByFullscreenMode()
|
||||
|
||||
updateFullscreenButtonVisibility()
|
||||
}
|
||||
|
||||
private fun updateFullscreenButtonVisibility() {
|
||||
playerBinding.fullscreen.isInvisible = PlayerHelper.autoFullscreenEnabled
|
||||
}
|
||||
|
||||
/**
|
||||
@ -881,7 +845,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
if (!exoPlayer.isPlaying || !PlayerHelper.sponsorBlockEnabled) return
|
||||
|
||||
handler.postDelayed(this::checkForSegments, 100)
|
||||
if (!sponsorBlockEnabled || viewModel.segments.isEmpty()) return
|
||||
if (!viewModel.sponsorBlockEnabled || viewModel.segments.isEmpty()) return
|
||||
|
||||
exoPlayer.checkForSegments(
|
||||
requireContext(),
|
||||
@ -949,7 +913,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
) {
|
||||
setFullscreen()
|
||||
}
|
||||
updateFullscreenButtonVisibility()
|
||||
|
||||
binding.player.apply {
|
||||
useController = false
|
||||
@ -1000,7 +963,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
withContext(Dispatchers.Main) {
|
||||
playerBinding.exoProgress.setSegments(viewModel.segments)
|
||||
playerBinding.sbToggle.isVisible = true
|
||||
updateDisplayedDuration()
|
||||
}
|
||||
viewModel.segments.firstOrNull { it.category == PlayerHelper.SPONSOR_HIGHLIGHT_CATEGORY }
|
||||
?.let {
|
||||
@ -1082,8 +1044,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
this.streams.uploader
|
||||
)
|
||||
|
||||
syncQueueButtons()
|
||||
|
||||
// seekbar preview setup
|
||||
playerBinding.seekbarPreview.isGone = true
|
||||
seekBarPreviewListener?.let { playerBinding.exoProgress.removeListener(it) }
|
||||
@ -1137,39 +1097,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the displayed duration of the video
|
||||
*/
|
||||
private fun updateDisplayedDuration() {
|
||||
if (!this::streams.isInitialized || streams.livestream || _binding == null) return
|
||||
|
||||
val duration = exoPlayer.duration / 1000
|
||||
if (duration < 0) return
|
||||
|
||||
val durationWithoutSegments = duration - viewModel.segments.sumOf {
|
||||
val (start, end) = it.segmentStartAndEnd
|
||||
end.toDouble() - start.toDouble()
|
||||
}.toLong()
|
||||
val durationString = DateUtils.formatElapsedTime(duration)
|
||||
|
||||
playerBinding.duration.text = if (durationWithoutSegments < duration) {
|
||||
"$durationString (${DateUtils.formatElapsedTime(durationWithoutSegments)})"
|
||||
} else {
|
||||
durationString
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncQueueButtons() {
|
||||
if (!PlayerHelper.skipButtonsEnabled) return
|
||||
|
||||
// toggle the visibility of next and prev buttons based on queue and whether the player view is locked
|
||||
val isPlayerLocked = binding.player.isPlayerLocked
|
||||
playerBinding.skipPrev.isInvisible = !PlayingQueue.hasPrev() || isPlayerLocked
|
||||
playerBinding.skipNext.isInvisible = !PlayingQueue.hasNext() || isPlayerLocked
|
||||
|
||||
handler.postDelayed(this::syncQueueButtons, 100)
|
||||
}
|
||||
|
||||
private fun updatePlayPauseButton() {
|
||||
binding.playImageView.setImageResource(PlayerHelper.getPlayPauseActionIcon(exoPlayer))
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ import com.github.libretube.api.obj.Message
|
||||
import com.github.libretube.api.obj.Segment
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.api.obj.Subtitle
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.util.NowPlayingNotification
|
||||
import com.github.libretube.util.deArrow
|
||||
import java.io.IOException
|
||||
@ -51,6 +53,7 @@ class PlayerViewModel : ViewModel() {
|
||||
val chaptersLiveData = MutableLiveData<List<ChapterSegment>>()
|
||||
|
||||
val chapters get() = chaptersLiveData.value.orEmpty()
|
||||
var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled
|
||||
|
||||
/**
|
||||
* @return pair of the stream info and the error message if the request was not successful
|
||||
|
@ -170,20 +170,7 @@ abstract class CustomExoPlayerView(
|
||||
player?.addListener(object : Player.Listener {
|
||||
override fun onEvents(player: Player, events: Player.Events) {
|
||||
super.onEvents(player, events)
|
||||
if (events.containsAny(
|
||||
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||
Player.EVENT_IS_PLAYING_CHANGED,
|
||||
Player.EVENT_PLAY_WHEN_READY_CHANGED
|
||||
)
|
||||
) {
|
||||
binding.playPauseBTN.setImageResource(
|
||||
PlayerHelper.getPlayPauseActionIcon(player)
|
||||
)
|
||||
|
||||
// keep screen on if the video is playing
|
||||
keepScreenOn = player.isPlaying == true
|
||||
onPlayerEvent(player, events)
|
||||
}
|
||||
this@CustomExoPlayerView.onPlaybackEvents(player, events)
|
||||
}
|
||||
})
|
||||
|
||||
@ -820,6 +807,23 @@ abstract class CustomExoPlayerView(
|
||||
return true
|
||||
}
|
||||
|
||||
open fun onPlaybackEvents(player: Player, events: Player.Events) {
|
||||
if (events.containsAny(
|
||||
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||
Player.EVENT_IS_PLAYING_CHANGED,
|
||||
Player.EVENT_PLAY_WHEN_READY_CHANGED
|
||||
)
|
||||
) {
|
||||
binding.playPauseBTN.setImageResource(
|
||||
PlayerHelper.getPlayPauseActionIcon(player)
|
||||
)
|
||||
|
||||
// keep screen on if the video is playing
|
||||
keepScreenOn = player.isPlaying == true
|
||||
onPlayerEvent(player, events)
|
||||
}
|
||||
}
|
||||
|
||||
open fun minimizeOrExitPlayer() = Unit
|
||||
|
||||
abstract fun getChapters(): List<ChapterSegment>
|
||||
|
@ -2,12 +2,15 @@ package com.github.libretube.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.Window
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.trackselection.TrackSelector
|
||||
import com.github.libretube.R
|
||||
@ -24,6 +27,7 @@ import com.github.libretube.ui.dialogs.SubmitDeArrowDialog
|
||||
import com.github.libretube.ui.dialogs.SubmitSegmentDialog
|
||||
import com.github.libretube.ui.interfaces.OnlinePlayerOptions
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.sheets.PlayingQueueSheet
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
|
||||
@UnstableApi
|
||||
@ -154,14 +158,39 @@ class OnlinePlayerView(
|
||||
playerViewModel.isFullscreen.observe(viewLifecycleOwner) { isFullscreen ->
|
||||
WindowHelper.toggleFullscreen(activity.window, isFullscreen)
|
||||
updateTopBarMargin()
|
||||
|
||||
binding.fullscreen.isInvisible = PlayerHelper.autoFullscreenEnabled
|
||||
val fullscreenDrawable = if (isFullscreen) R.drawable.ic_fullscreen_exit else R.drawable.ic_fullscreen
|
||||
binding.fullscreen.setImageResource(fullscreenDrawable)
|
||||
|
||||
binding.exoTitle.isInvisible = !isFullscreen
|
||||
}
|
||||
|
||||
binding.autoPlay.isVisible = true
|
||||
binding.autoPlay.isChecked = PlayerHelper.autoPlayEnabled
|
||||
|
||||
binding.autoPlay.setOnCheckedChangeListener { _, isChecked ->
|
||||
PlayerHelper.autoPlayEnabled = isChecked
|
||||
}
|
||||
|
||||
binding.queueToggle.isVisible = true
|
||||
binding.queueToggle.setOnClickListener {
|
||||
PlayingQueueSheet().show(activity.supportFragmentManager, null)
|
||||
}
|
||||
|
||||
val updateSbImageResource = {
|
||||
binding.sbToggle.setImageResource(
|
||||
if (playerViewModel.sponsorBlockEnabled) R.drawable.ic_sb_enabled else R.drawable.ic_sb_disabled
|
||||
)
|
||||
}
|
||||
updateSbImageResource()
|
||||
binding.sbToggle.setOnClickListener {
|
||||
playerViewModel.sponsorBlockEnabled = !playerViewModel.sponsorBlockEnabled
|
||||
updateSbImageResource()
|
||||
}
|
||||
|
||||
syncQueueButtons()
|
||||
|
||||
binding.sbSubmit.isVisible = PreferenceHelper.getBoolean(PreferenceKeys.CONTRIBUTE_TO_SB, false)
|
||||
binding.sbSubmit.setOnClickListener {
|
||||
val submitSegmentDialog = SubmitSegmentDialog()
|
||||
@ -189,6 +218,38 @@ class OnlinePlayerView(
|
||||
)
|
||||
}
|
||||
|
||||
private fun syncQueueButtons() {
|
||||
if (!PlayerHelper.skipButtonsEnabled) return
|
||||
|
||||
// toggle the visibility of next and prev buttons based on queue and whether the player view is locked
|
||||
binding.skipPrev.isInvisible = !PlayingQueue.hasPrev() || isPlayerLocked
|
||||
binding.skipNext.isInvisible = !PlayingQueue.hasNext() || isPlayerLocked
|
||||
|
||||
handler.postDelayed(this::syncQueueButtons, 100)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the displayed duration of the video
|
||||
*/
|
||||
private fun updateDisplayedDuration() {
|
||||
if (isLive) return
|
||||
|
||||
val duration = player?.duration?.div(1000) ?: return
|
||||
if (duration < 0) return
|
||||
|
||||
val durationWithoutSegments = duration - playerViewModel?.segments.orEmpty().sumOf {
|
||||
val (start, end) = it.segmentStartAndEnd
|
||||
end.toDouble() - start.toDouble()
|
||||
}.toLong()
|
||||
val durationString = DateUtils.formatElapsedTime(duration)
|
||||
|
||||
binding.duration.text = if (durationWithoutSegments < duration) {
|
||||
"$durationString (${DateUtils.formatElapsedTime(durationWithoutSegments)})"
|
||||
} else {
|
||||
durationString
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWindow(): Window = currentWindow ?: activity.window
|
||||
|
||||
override fun hideController() {
|
||||
@ -219,4 +280,9 @@ class OnlinePlayerView(
|
||||
override fun getChapters(): List<ChapterSegment> {
|
||||
return playerViewModel?.chapters.orEmpty()
|
||||
}
|
||||
|
||||
override fun onPlaybackEvents(player: Player, events: Player.Events) {
|
||||
super.onPlaybackEvents(player, events)
|
||||
updateDisplayedDuration()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user