fix: Adjust video playback UX behaviour (#186)
Previously, playing a video would show the controls and associated overlay for five seconds before fading them out. This obscures the video for too long. Fix this by: - Only showing the media description on start, and remove after two seconds - Show the controls (and media description) if the user taps, removing after two seconds - Pausing the video (with the pause control, or tapping on the media description) keeps the controls and description on-screen indefinitely so they are easier to read Fixes #144
This commit is contained in:
parent
8a4ce7f7da
commit
3157f8d946
|
@ -45,7 +45,6 @@ import androidx.media3.exoplayer.ExoPlayer
|
|||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.util.EventLogger
|
||||
import androidx.media3.ui.AspectRatioFrameLayout
|
||||
import androidx.media3.ui.PlayerControlView
|
||||
import app.pachli.BuildConfig
|
||||
import app.pachli.R
|
||||
import app.pachli.ViewMediaActivity
|
||||
|
@ -63,6 +62,17 @@ import okhttp3.OkHttpClient
|
|||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Plays a video, showing media description if available.
|
||||
*
|
||||
* UI behaviour:
|
||||
*
|
||||
* - Fragment starts, media description is visible at top of screen, video starts playing
|
||||
* - Media description + toolbar disappears after CONTROLS_TIMEOUT_MS
|
||||
* - Tapping shows controls + media description + toolbar, which fade after CONTROLS_TIMEOUT_MS
|
||||
* - Tapping pause, or the media description, pauses the video and the controls + media description
|
||||
* remain visible
|
||||
*/
|
||||
@UnstableApi
|
||||
@AndroidEntryPoint
|
||||
class ViewVideoFragment : ViewMediaFragment() {
|
||||
|
@ -126,6 +136,8 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.videoView.controllerShowTimeoutMs = CONTROLS_TIMEOUT_MS
|
||||
|
||||
isAudio = attachment.type == Attachment.Type.AUDIO
|
||||
|
||||
/**
|
||||
|
@ -209,7 +221,6 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
|
||||
binding.progressBar.hide()
|
||||
binding.videoView.useController = true
|
||||
binding.videoView.showController()
|
||||
}
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
|
@ -218,7 +229,7 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
if (isAudio) return
|
||||
if (isPlaying) {
|
||||
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
|
||||
hideToolbarAfterDelay()
|
||||
} else {
|
||||
handler.removeCallbacks(hideToolbar)
|
||||
}
|
||||
|
@ -259,7 +270,7 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
if (Build.VERSION.SDK_INT <= 23 || player == null) {
|
||||
initializePlayer()
|
||||
if (mediaActivity.isToolbarVisible && !isAudio) {
|
||||
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
|
||||
hideToolbarAfterDelay()
|
||||
}
|
||||
binding.videoView.onResume()
|
||||
}
|
||||
|
@ -357,6 +368,15 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
|
||||
binding.videoView.transitionName = attachment.url
|
||||
|
||||
// Clicking the description should play/pause the video
|
||||
binding.mediaDescription.setOnClickListener {
|
||||
if (binding.videoView.player?.isPlaying == true) {
|
||||
binding.videoView.player?.pause()
|
||||
} else {
|
||||
binding.videoView.player?.play()
|
||||
}
|
||||
}
|
||||
|
||||
binding.videoView.requestFocus()
|
||||
|
||||
if (requireArguments().getBoolean(ARG_START_POSTPONED_TRANSITION)) {
|
||||
|
@ -364,8 +384,8 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun hideToolbarAfterDelay(delayMilliseconds: Int) {
|
||||
handler.postDelayed(hideToolbar, delayMilliseconds.toLong())
|
||||
private fun hideToolbarAfterDelay() {
|
||||
handler.postDelayed(hideToolbar, CONTROLS_TIMEOUT_MS.toLong())
|
||||
}
|
||||
|
||||
override fun onToolbarVisibilityChange(visible: Boolean) {
|
||||
|
@ -373,6 +393,8 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
return
|
||||
}
|
||||
|
||||
view ?: return
|
||||
|
||||
isDescriptionVisible = showingDescription && visible
|
||||
val alpha = if (isDescriptionVisible) 1.0f else 0.0f
|
||||
if (isDescriptionVisible) {
|
||||
|
@ -395,7 +417,7 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
.start()
|
||||
|
||||
if (visible && (binding.videoView.player?.isPlaying == true) && !isAudio) {
|
||||
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
|
||||
hideToolbarAfterDelay()
|
||||
} else {
|
||||
handler.removeCallbacks(hideToolbar)
|
||||
}
|
||||
|
@ -405,7 +427,7 @@ class ViewVideoFragment : ViewMediaFragment() {
|
|||
|
||||
companion object {
|
||||
private const val TAG = "ViewVideoFragment"
|
||||
private const val TOOLBAR_HIDE_DELAY_MS = PlayerControlView.DEFAULT_SHOW_TIMEOUT_MS
|
||||
private const val CONTROLS_TIMEOUT_MS = 2000 // Consistent with YouTube player
|
||||
private const val SEEK_POSITION = "seekPosition"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue