Merge pull request #4128 from Bnyro/master

Show time left when clicking player duration
This commit is contained in:
Bnyro 2023-06-27 11:57:21 +02:00 committed by GitHub
commit b771d89067
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 41 deletions

View File

@ -100,6 +100,7 @@ object PreferenceKeys {
const val FULLSCREEN_GESTURES = "fullscreen_gestures" const val FULLSCREEN_GESTURES = "fullscreen_gestures"
const val UNLIMITED_SEARCH_HISTORY = "unlimited_search_history" const val UNLIMITED_SEARCH_HISTORY = "unlimited_search_history"
const val SB_HIGHLIGHTS = "sb_highlights" const val SB_HIGHLIGHTS = "sb_highlights"
const val SHOW_TIME_LEFT = "show_time_left"
/** /**
* Background mode * Background mode

View File

@ -799,25 +799,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
} }
} }
@SuppressLint("SetTextI18n")
private fun refreshLiveStatus() {
// switch back to normal speed when on the end of live stream
if (exoPlayer.duration - exoPlayer.currentPosition < 7000) {
exoPlayer.setPlaybackSpeed(1F)
playerBinding.timeSeparator.visibility = View.GONE
playerBinding.liveDiff.text = ""
} else {
// live stream but not watching at the end/live position
playerBinding.timeSeparator.visibility = View.VISIBLE
val diffText = DateUtils.formatElapsedTime(
(exoPlayer.duration - exoPlayer.currentPosition) / 1000
)
playerBinding.liveDiff.text = "-$diffText"
}
// call the function again after 100ms
handler.postDelayed(this@PlayerFragment::refreshLiveStatus, 100)
}
/** /**
* Seek to saved watch position if available */ * Seek to saved watch position if available */
private fun seekToWatchPosition() { private fun seekToWatchPosition() {
@ -882,16 +863,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
} }
} }
private fun handleLiveVideo() {
playerBinding.exoPosition.visibility = View.GONE
playerBinding.liveDiff.visibility = View.VISIBLE
playerBinding.duration.text = getString(R.string.live)
playerBinding.exoTime.setOnClickListener {
exoPlayer.seekTo(exoPlayer.duration)
}
refreshLiveStatus()
}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun initializePlayerView() { private fun initializePlayerView() {
// initialize the player view actions // initialize the player view actions
@ -916,11 +887,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
R.string.subscribers, R.string.subscribers,
streams.uploaderSubscriberCount.formatShort() streams.uploaderSubscriberCount.formatShort()
) )
player.isLive = streams.livestream
} }
// duration that's not greater than 0 indicates that the video is live
if (streams.livestream) handleLiveVideo()
playerBinding.exoTitle.text = streams.title playerBinding.exoTitle.text = streams.title
// init the chapters recyclerview // init the chapters recyclerview
@ -962,6 +931,13 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
saveWatchPosition() saveWatchPosition()
// set the playback speed to one if having reached the end of a livestream
if (playbackState == Player.STATE_BUFFERING && binding.player.isLive &&
exoPlayer.duration - exoPlayer.currentPosition < 700
) {
exoPlayer.setPlaybackSpeed(1f)
}
// check if video has ended, next video is available and autoplay is enabled. // check if video has ended, next video is available and autoplay is enabled.
if ( if (
playbackState == Player.STATE_ENDED && playbackState == Player.STATE_ENDED &&

View File

@ -7,6 +7,7 @@ import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.text.format.DateUtils
import android.util.AttributeSet import android.util.AttributeSet
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
@ -17,9 +18,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginStart import androidx.core.view.marginStart
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.media3.common.C
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.text.Cue import androidx.media3.common.text.Cue
import androidx.media3.common.util.RepeatModeUtil import androidx.media3.common.util.RepeatModeUtil
@ -30,6 +33,7 @@ import androidx.media3.ui.PlayerView
import androidx.media3.ui.SubtitleView import androidx.media3.ui.SubtitleView
import androidx.media3.ui.TimeBar import androidx.media3.ui.TimeBar
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.DoubleTapOverlayBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.databinding.PlayerGestureControlsViewBinding import com.github.libretube.databinding.PlayerGestureControlsViewBinding
@ -39,6 +43,7 @@ import com.github.libretube.extensions.round
import com.github.libretube.helpers.AudioHelper import com.github.libretube.helpers.AudioHelper
import com.github.libretube.helpers.BrightnessHelper import com.github.libretube.helpers.BrightnessHelper
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.obj.BottomSheetItem import com.github.libretube.obj.BottomSheetItem
import com.github.libretube.ui.base.BaseActivity import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.interfaces.PlayerGestureOptions import com.github.libretube.ui.interfaces.PlayerGestureOptions
@ -72,6 +77,13 @@ open class CustomExoPlayerView(
private val runnableHandler = Handler(Looper.getMainLooper()) private val runnableHandler = Handler(Looper.getMainLooper())
var isPlayerLocked: Boolean = false var isPlayerLocked: Boolean = false
var isLive: Boolean = false
set(value) {
field = value
updateDisplayedDurationType()
updateCurrentPosition()
}
/** /**
* Preferences * Preferences
@ -177,6 +189,21 @@ open class CustomExoPlayerView(
enqueueHideControllerTask() enqueueHideControllerTask()
} }
}) })
// restore the duration type from the previous session
updateDisplayedDurationType()
binding.duration.setOnClickListener {
updateDisplayedDurationType(true)
}
binding.timeLeft.setOnClickListener {
updateDisplayedDurationType(false)
}
binding.position.setOnClickListener {
if (isLive) player?.let { it.seekTo(it.duration) }
}
updateCurrentPosition()
} }
open fun onPlayerEvent(player: Player, playerEvents: Player.Events) = Unit open fun onPlayerEvent(player: Player, playerEvents: Player.Events) = Unit
@ -191,6 +218,19 @@ open class CustomExoPlayerView(
) )
} }
private fun updateDisplayedDurationType(showTimeLeft: Boolean? = null) {
var shouldShowTimeLeft = showTimeLeft ?: PreferenceHelper
.getBoolean(PreferenceKeys.SHOW_TIME_LEFT, false)
// always show the time left only if it's a livestream
if (isLive) shouldShowTimeLeft = true
if (showTimeLeft != null) {
// save whether to show time left or duration for next session
PreferenceHelper.putBoolean(PreferenceKeys.SHOW_TIME_LEFT, shouldShowTimeLeft)
}
binding.timeLeft.isVisible = shouldShowTimeLeft
binding.duration.isGone = shouldShowTimeLeft
}
private fun enqueueHideControllerTask() { private fun enqueueHideControllerTask() {
handler.postDelayed(AUTO_HIDE_CONTROLLER_DELAY, HIDE_CONTROLLER_TOKEN) { handler.postDelayed(AUTO_HIDE_CONTROLLER_DELAY, HIDE_CONTROLLER_TOKEN) {
hideController() hideController()
@ -568,6 +608,19 @@ open class CustomExoPlayerView(
} }
} }
@SuppressLint("SetTextI18n")
private fun updateCurrentPosition() {
val position = player?.currentPosition?.div(1000) ?: 0
val duration = player?.duration?.takeIf { it != C.TIME_UNSET }?.div(1000) ?: 0
val timeLeft = duration - position
binding.position.text =
if (isLive) context.getString(R.string.live) else DateUtils.formatElapsedTime(position)
binding.timeLeft.text = "-${DateUtils.formatElapsedTime(timeLeft)}"
runnableHandler.postDelayed(100, UPDATE_POSITION_TOKEN, this::updateCurrentPosition)
}
open fun getTopBarMarginDp(): Int { open fun getTopBarMarginDp(): Int {
return if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 10 else 0 return if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 10 else 0
} }
@ -676,6 +729,7 @@ open class CustomExoPlayerView(
private const val HIDE_CONTROLLER_TOKEN = "hideController" private const val HIDE_CONTROLLER_TOKEN = "hideController"
private const val HIDE_FORWARD_BUTTON_TOKEN = "hideForwardButton" private const val HIDE_FORWARD_BUTTON_TOKEN = "hideForwardButton"
private const val HIDE_REWIND_BUTTON_TOKEN = "hideRewindButton" private const val HIDE_REWIND_BUTTON_TOKEN = "hideRewindButton"
private const val UPDATE_POSITION_TOKEN = "updatePosition"
private const val SUBTITLE_BOTTOM_PADDING_FRACTION = 0.158f private const val SUBTITLE_BOTTOM_PADDING_FRACTION = 0.158f
private const val ANIMATION_DURATION = 100L private const val ANIMATION_DURATION = 100L

View File

@ -251,19 +251,12 @@
android:layout_marginStart="10dp"> android:layout_marginStart="10dp">
<TextView <TextView
android:id="@id/exo_position" android:id="@+id/position"
style="@style/TimeString" style="@style/TimeString"
android:text="00:00" android:text="00:00"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/liveDiff"
style="@style/TimeString"
android:visibility="gone"
tools:text="05:10" />
<TextView
android:id="@+id/time_separator"
style="@style/TimeString" style="@style/TimeString"
android:text=" • " android:text=" • "
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
@ -274,6 +267,13 @@
android:text="00:00" android:text="00:00"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView
android:id="@+id/timeLeft"
style="@style/TimeString"
android:text="00:00"
android:visibility="gone"
tools:ignore="HardcodedText" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout