feat: show repeat button in audio player when playback finished

This commit is contained in:
Bnyro 2024-01-08 19:17:09 +01:00
parent 73c98368a7
commit 46acd28c26
5 changed files with 43 additions and 55 deletions

View File

@ -41,11 +41,11 @@ import com.github.libretube.enums.SbSkipOptions
import com.github.libretube.extensions.updateParameters
import com.github.libretube.obj.VideoStats
import com.github.libretube.util.TextUtils
import kotlinx.coroutines.runBlocking
import java.util.Locale
import java.util.concurrent.Executors
import kotlin.math.absoluteValue
import kotlin.math.roundToInt
import kotlinx.coroutines.runBlocking
object PlayerHelper {
private const val ACTION_MEDIA_CONTROL = "media_control"
@ -334,11 +334,11 @@ object PlayerHelper {
fun shouldPlayNextVideo(isPlaylist: Boolean = false): Boolean {
return autoPlayEnabled || (
isPlaylist && PreferenceHelper.getBoolean(
PreferenceKeys.AUTOPLAY_PLAYLISTS,
false
)
)
isPlaylist && PreferenceHelper.getBoolean(
PreferenceKeys.AUTOPLAY_PLAYLISTS,
false
)
)
}
private val handleAudioFocus
@ -552,9 +552,9 @@ object PlayerHelper {
if (currentPosition in segmentStart until segmentEnd) {
if (sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC ||
(
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
!segment.skipped
)
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
!segment.skipped
)
) {
if (sponsorBlockNotifications) {
runCatching {
@ -566,9 +566,9 @@ object PlayerHelper {
segment.skipped = true
} else if (sponsorBlockConfig[segment.category] == SbSkipOptions.MANUAL ||
(
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
segment.skipped
)
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
segment.skipped
)
) {
return segment
}
@ -598,7 +598,8 @@ object PlayerHelper {
val chapter = chapters[index]
// remove the video highlight if it's already longer ago than [ChapterSegment.HIGHLIGHT_LENGTH],
// otherwise the SponsorBlock highlight would be shown from its starting point to the end
val isWithinMaxHighlightDuration = (currentPositionSeconds - chapter.start) < ChapterSegment.HIGHLIGHT_LENGTH
val isWithinMaxHighlightDuration =
(currentPositionSeconds - chapter.start) < ChapterSegment.HIGHLIGHT_LENGTH
chapter.highlightDrawable == null || isWithinMaxHighlightDuration
}
}
@ -752,9 +753,9 @@ object PlayerHelper {
*/
fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean {
return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) ||
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
}
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@ -771,4 +772,10 @@ object PlayerHelper {
"${player.videoFormat?.width}x${player.videoFormat?.height} ${player.videoFormat?.frameRate?.toInt()}fps"
return VideoStats(videoId, videoInfo, videoQuality, audioInfo)
}
fun getPlayPauseActionIcon(player: Player) = when {
player.isPlaying -> R.drawable.ic_pause
player.playbackState == Player.STATE_ENDED -> R.drawable.ic_restart
else -> R.drawable.ic_play
}
}

View File

@ -100,16 +100,18 @@ class OnlinePlayerService : LifecycleService() {
/**
* Listener for passing playback state changes to the AudioPlayerFragment
*/
var onIsPlayingChanged: ((isPlaying: Boolean) -> Unit)? = null
var onStateOrPlayingChanged: ((isPlaying: Boolean) -> Unit)? = null
var onNewVideo: ((streams: Streams, videoId: String) -> Unit)? = null
private val playerListener = object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
super.onIsPlayingChanged(isPlaying)
onIsPlayingChanged?.invoke(isPlaying)
onStateOrPlayingChanged?.invoke(isPlaying)
}
override fun onPlaybackStateChanged(state: Int) {
onStateOrPlayingChanged?.invoke(player?.isPlaying ?: false)
when (state) {
Player.STATE_ENDED -> {
if (PlayerHelper.shouldPlayNextVideo(playlistId != null) && !isTransitioning) playNextVideo()
@ -411,12 +413,4 @@ class OnlinePlayerService : LifecycleService() {
fun getDuration() = player?.duration
fun seekToPosition(position: Long) = player?.seekTo(position)
fun pause() {
player?.pause()
}
fun play() {
player?.play()
}
}

View File

@ -30,6 +30,7 @@ import com.github.libretube.databinding.FragmentAudioPlayerBinding
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.helpers.AudioHelper
import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.ImageHelper
@ -188,11 +189,11 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
binding.thumbnail.setOnTouchListener(listener)
binding.playPause.setOnClickListener {
if (isPaused) playerService?.play() else playerService?.pause()
playerService?.player?.togglePlayPauseState()
}
binding.miniPlayerPause.setOnClickListener {
if (isPaused) playerService?.play() else playerService?.pause()
playerService?.player?.togglePlayPauseState()
}
binding.showMore.setOnClickListener {
@ -207,7 +208,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
bar.progress = audioHelper.getVolumeWithScale(bar.max)
}
if (!PlayerHelper.playAutomatically) updatePlayPauseButton(false)
if (!PlayerHelper.playAutomatically) updatePlayPauseButton()
}
private fun killFragment() {
@ -347,16 +348,18 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
handler.postDelayed(this::updateSeekBar, 200)
}
private fun updatePlayPauseButton(isPlaying: Boolean) {
val iconResource = if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play
binding.playPause.setIconResource(iconResource)
binding.miniPlayerPause.setImageResource(iconResource)
private fun updatePlayPauseButton() {
playerService?.player?.let {
val iconRes = PlayerHelper.getPlayPauseActionIcon(it)
binding.playPause.setIconResource(iconRes)
binding.miniPlayerPause.setImageResource(iconRes)
}
}
private fun handleServiceConnection() {
viewModel.player = playerService?.player
playerService?.onIsPlayingChanged = { isPlaying ->
updatePlayPauseButton(isPlaying)
playerService?.onStateOrPlayingChanged = { isPlaying ->
updatePlayPauseButton()
isPaused = !isPlaying
}
playerService?.onNewVideo = { streams, videoId ->
@ -373,7 +376,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
override fun onDestroy() {
// unregister all listeners and the connected [playerService]
playerService?.onIsPlayingChanged = null
playerService?.onStateOrPlayingChanged = null
runCatching {
activity?.unbindService(connection)
}
@ -384,7 +387,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
}
override fun onSingleTap() {
if (isPaused) playerService?.play() else playerService?.pause()
playerService?.player?.togglePlayPauseState()
}
override fun onLongTap() {

View File

@ -1160,13 +1160,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
}
private fun updatePlayPauseButton() {
binding.playImageView.setImageResource(
when {
exoPlayer.isPlaying -> R.drawable.ic_pause
exoPlayer.playbackState == Player.STATE_ENDED -> R.drawable.ic_restart
else -> R.drawable.ic_play
}
)
binding.playImageView.setImageResource(PlayerHelper.getPlayPauseActionIcon(exoPlayer))
}
private suspend fun initializeHighlight(highlight: Segment) {

View File

@ -168,7 +168,7 @@ open class CustomExoPlayerView(
Player.EVENT_PLAY_WHEN_READY_CHANGED
)
) {
updatePlayPauseButton()
binding.playPauseBTN.setImageResource(PlayerHelper.getPlayPauseActionIcon(player))
// keep screen on if the video is playing
keepScreenOn = player.isPlaying == true
@ -226,16 +226,6 @@ open class CustomExoPlayerView(
open fun onPlayerEvent(player: Player, playerEvents: Player.Events) = Unit
private fun updatePlayPauseButton() {
binding.playPauseBTN.setImageResource(
when {
player?.isPlaying == true -> R.drawable.ic_pause
player?.playbackState == Player.STATE_ENDED -> R.drawable.ic_restart
else -> R.drawable.ic_play
}
)
}
private fun updateDisplayedDurationType(showTimeLeft: Boolean? = null) {
var shouldShowTimeLeft = showTimeLeft ?: PreferenceHelper
.getBoolean(PreferenceKeys.SHOW_TIME_LEFT, false)