mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-01-07 18:10:31 +05:30
Merge pull request #998 from Bnyro/master
previous and next buttons for the player
This commit is contained in:
commit
45b10393e3
@ -164,6 +164,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
private var defaultSubtitleCode = ""
|
private var defaultSubtitleCode = ""
|
||||||
private var sponsorBlockEnabled = true
|
private var sponsorBlockEnabled = true
|
||||||
private var sponsorBlockNotifications = true
|
private var sponsorBlockNotifications = true
|
||||||
|
private var skipButtonsEnabled = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for autoplay
|
* for autoplay
|
||||||
@ -176,6 +177,11 @@ class PlayerFragment : BaseFragment() {
|
|||||||
*/
|
*/
|
||||||
private lateinit var nowPlayingNotification: NowPlayingNotification
|
private lateinit var nowPlayingNotification: NowPlayingNotification
|
||||||
|
|
||||||
|
/**
|
||||||
|
* history of played videos in the current lifecycle
|
||||||
|
*/
|
||||||
|
val videoIds = mutableListOf<String>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
arguments?.let {
|
arguments?.let {
|
||||||
@ -204,7 +210,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
|
|
||||||
setUserPrefs()
|
setUserPrefs()
|
||||||
|
|
||||||
if (autoplayEnabled == true) playerBinding.autoplayIV.setImageResource(R.drawable.ic_toggle_on)
|
if (autoplayEnabled) playerBinding.autoplayIV.setImageResource(R.drawable.ic_toggle_on)
|
||||||
|
|
||||||
val mainActivity = activity as MainActivity
|
val mainActivity = activity as MainActivity
|
||||||
if (autoRotationEnabled) {
|
if (autoRotationEnabled) {
|
||||||
@ -314,6 +320,11 @@ class PlayerFragment : BaseFragment() {
|
|||||||
if (defaultSubtitleCode.contains("-")) {
|
if (defaultSubtitleCode.contains("-")) {
|
||||||
defaultSubtitleCode = defaultSubtitleCode.split("-")[0]
|
defaultSubtitleCode = defaultSubtitleCode.split("-")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skipButtonsEnabled = PreferenceHelper.getBoolean(
|
||||||
|
PreferenceKeys.SKIP_BUTTONS,
|
||||||
|
false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeTransitionLayout() {
|
private fun initializeTransitionLayout() {
|
||||||
@ -566,8 +577,6 @@ class PlayerFragment : BaseFragment() {
|
|||||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen_exit)
|
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen_exit)
|
||||||
playerBinding.exoTitle.visibility = View.VISIBLE
|
playerBinding.exoTitle.visibility = View.VISIBLE
|
||||||
|
|
||||||
scaleControls(1.3F)
|
|
||||||
|
|
||||||
val mainActivity = activity as MainActivity
|
val mainActivity = activity as MainActivity
|
||||||
if (!autoRotationEnabled) {
|
if (!autoRotationEnabled) {
|
||||||
// different orientations of the video are only available when auto rotation is disabled
|
// different orientations of the video are only available when auto rotation is disabled
|
||||||
@ -602,8 +611,6 @@ class PlayerFragment : BaseFragment() {
|
|||||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
||||||
playerBinding.exoTitle.visibility = View.INVISIBLE
|
playerBinding.exoTitle.visibility = View.INVISIBLE
|
||||||
|
|
||||||
scaleControls(1F)
|
|
||||||
|
|
||||||
if (!autoRotationEnabled) {
|
if (!autoRotationEnabled) {
|
||||||
// switch back to portrait mode if auto rotation disabled
|
// switch back to portrait mode if auto rotation disabled
|
||||||
val mainActivity = activity as MainActivity
|
val mainActivity = activity as MainActivity
|
||||||
@ -613,11 +620,6 @@ class PlayerFragment : BaseFragment() {
|
|||||||
Globals.IS_FULL_SCREEN = false
|
Globals.IS_FULL_SCREEN = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scaleControls(scaleFactor: Float) {
|
|
||||||
playerBinding.exoPlayPause.scaleX = scaleFactor
|
|
||||||
playerBinding.exoPlayPause.scaleY = scaleFactor
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleDescription() {
|
private fun toggleDescription() {
|
||||||
if (binding.descLinLayout.isVisible) {
|
if (binding.descLinLayout.isVisible) {
|
||||||
// hide the description and chapters
|
// hide the description and chapters
|
||||||
@ -746,6 +748,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
videoIds += videoId!!
|
||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
@ -754,7 +757,18 @@ class PlayerFragment : BaseFragment() {
|
|||||||
* set the videoId of the next stream for autoplay
|
* set the videoId of the next stream for autoplay
|
||||||
*/
|
*/
|
||||||
private fun setNextStream() {
|
private fun setNextStream() {
|
||||||
nextStreamId = streams.relatedStreams!![0].url.toID()
|
// don't play a video if it got played before already
|
||||||
|
var index = 0
|
||||||
|
while (nextStreamId == null || nextStreamId == videoId!! ||
|
||||||
|
(
|
||||||
|
videoIds.contains(nextStreamId) &&
|
||||||
|
videoIds.indexOf(videoId) > videoIds.indexOf(nextStreamId)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
nextStreamId = streams.relatedStreams!![index].url.toID()
|
||||||
|
if (index + 1 < streams.relatedStreams!!.size) index += 1
|
||||||
|
else break
|
||||||
|
}
|
||||||
if (playlistId == null) return
|
if (playlistId == null) return
|
||||||
if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!)
|
if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!)
|
||||||
// search for the next videoId in the playlist
|
// search for the next videoId in the playlist
|
||||||
@ -823,18 +837,17 @@ class PlayerFragment : BaseFragment() {
|
|||||||
|
|
||||||
// used for autoplay and skipping to next video
|
// used for autoplay and skipping to next video
|
||||||
private fun playNextVideo() {
|
private fun playNextVideo() {
|
||||||
|
if (nextStreamId == null) return
|
||||||
// check whether there is a new video in the queue
|
// check whether there is a new video in the queue
|
||||||
// by making sure that the next and the current video aren't the same
|
// by making sure that the next and the current video aren't the same
|
||||||
saveWatchPosition()
|
saveWatchPosition()
|
||||||
// forces the comments to reload for the new video
|
// forces the comments to reload for the new video
|
||||||
commentsLoaded = false
|
commentsLoaded = false
|
||||||
binding.commentsRecView.adapter = null
|
binding.commentsRecView.adapter = null
|
||||||
if (videoId != nextStreamId) {
|
|
||||||
// save the id of the next stream as videoId and load the next video
|
// save the id of the next stream as videoId and load the next video
|
||||||
videoId = nextStreamId
|
videoId = nextStreamId
|
||||||
playVideo()
|
playVideo()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun prepareExoPlayerView() {
|
private fun prepareExoPlayerView() {
|
||||||
exoPlayerView.apply {
|
exoPlayerView.apply {
|
||||||
@ -882,7 +895,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// duration that's not greater than 0 indicates that the video is live
|
// duration that's not greater than 0 indicates that the video is live
|
||||||
if (!(response.duration!! > 0)) {
|
if (response.duration!! <= 0) {
|
||||||
isLive = true
|
isLive = true
|
||||||
handleLiveVideo()
|
handleLiveVideo()
|
||||||
}
|
}
|
||||||
@ -1052,6 +1065,22 @@ class PlayerFragment : BaseFragment() {
|
|||||||
Toast.makeText(context, R.string.login_first, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.login_first, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// next and previous buttons
|
||||||
|
playerBinding.skipPrev.visibility = if (
|
||||||
|
skipButtonsEnabled && videoIds.indexOf(videoId!!) != 0
|
||||||
|
) View.VISIBLE else View.INVISIBLE
|
||||||
|
playerBinding.skipNext.visibility = if (skipButtonsEnabled) View.VISIBLE else View.INVISIBLE
|
||||||
|
|
||||||
|
playerBinding.skipPrev.setOnClickListener {
|
||||||
|
val index = videoIds.indexOf(videoId!!) - 1
|
||||||
|
videoId = videoIds[index]
|
||||||
|
playVideo()
|
||||||
|
}
|
||||||
|
|
||||||
|
playerBinding.skipNext.setOnClickListener {
|
||||||
|
playNextVideo()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableDoubleTapToSeek() {
|
private fun enableDoubleTapToSeek() {
|
||||||
|
@ -58,6 +58,7 @@ object PreferenceKeys {
|
|||||||
const val PLAYER_AUDIO_FORMAT = "player_audio_format"
|
const val PLAYER_AUDIO_FORMAT = "player_audio_format"
|
||||||
const val PLAYER_AUDIO_QUALITY = "player_audio_quality"
|
const val PLAYER_AUDIO_QUALITY = "player_audio_quality"
|
||||||
const val DEFAULT_SUBTITLE = "default_subtitle"
|
const val DEFAULT_SUBTITLE = "default_subtitle"
|
||||||
|
const val SKIP_BUTTONS = "skip_buttons"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download
|
* Download
|
||||||
|
10
app/src/main/res/drawable/ic_next.xml
Normal file
10
app/src/main/res/drawable/ic_next.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z" />
|
||||||
|
</vector>
|
10
app/src/main/res/drawable/ic_prev.xml
Normal file
10
app/src/main/res/drawable/ic_prev.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z" />
|
||||||
|
</vector>
|
@ -19,7 +19,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginStart="30dp"
|
|
||||||
android:visibility="invisible">
|
android:visibility="invisible">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -61,7 +60,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginEnd="30dp"
|
|
||||||
android:visibility="invisible">
|
android:visibility="invisible">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -291,12 +291,28 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="20dp">
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/skip_prev"
|
||||||
|
style="@style/PlayerControlCenter"
|
||||||
|
android:background="?android:selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_prev"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@id/exo_play_pause"
|
android:id="@id/exo_play_pause"
|
||||||
style="@style/ExoStyledControls.Button.Center.PlayPause"
|
style="@style/ExoStyledControls.Button.Center.PlayPause"
|
||||||
android:background="?android:selectableItemBackgroundBorderless"
|
android:background="?android:selectableItemBackgroundBorderless"
|
||||||
app:tint="@android:color/white" />
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/skip_next"
|
||||||
|
style="@style/PlayerControlCenter"
|
||||||
|
android:background="?android:selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_next"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:tint="@android:color/white" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</merge>
|
</merge>
|
@ -292,4 +292,6 @@
|
|||||||
<string name="downloadsucceeded">Download succeeded</string>
|
<string name="downloadsucceeded">Download succeeded</string>
|
||||||
<string name="share_with_time">Share with start time</string>
|
<string name="share_with_time">Share with start time</string>
|
||||||
<string name="export_subscriptions">Export Subscriptions</string>
|
<string name="export_subscriptions">Export Subscriptions</string>
|
||||||
|
<string name="skip_buttons">Skip buttons</string>
|
||||||
|
<string name="skip_buttons_summary">Show buttons to skip to the next or previous video.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -107,6 +107,14 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="PlayerControlCenter">
|
||||||
|
<item name="android:layout_width">42dp</item>
|
||||||
|
<item name="android:layout_height">42dp</item>
|
||||||
|
<item name="android:backgroundTint">@android:color/white</item>
|
||||||
|
<item name="android:layout_marginStart">10dp</item>
|
||||||
|
<item name="android:layout_marginEnd">10dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="PlayerControlTop">
|
<style name="PlayerControlTop">
|
||||||
|
|
||||||
<item name="android:padding">9dp</item>
|
<item name="android:padding">9dp</item>
|
||||||
|
@ -77,6 +77,13 @@
|
|||||||
app:key="default_subtitle"
|
app:key="default_subtitle"
|
||||||
app:title="@string/default_subtitle_language" />
|
app:title="@string/default_subtitle_language" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:icon="@drawable/ic_next"
|
||||||
|
android:summary="@string/skip_buttons_summary"
|
||||||
|
app:key="skip_buttons"
|
||||||
|
app:title="@string/skip_buttons" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory app:title="@string/behavior">
|
<PreferenceCategory app:title="@string/behavior">
|
||||||
|
Loading…
Reference in New Issue
Block a user