mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 06:10:31 +05:30
Merge pull request #4090 from Bnyro/master
Chapters dialog: highlight current chapter and auto scroll to it
This commit is contained in:
commit
a2cc01081b
@ -6,6 +6,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Base64
|
||||
import android.view.accessibility.CaptioningManager
|
||||
@ -16,6 +18,7 @@ import androidx.core.app.RemoteActionCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.children
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.PlaybackParameters
|
||||
@ -46,7 +49,8 @@ object PlayerHelper {
|
||||
"outro",
|
||||
"filler",
|
||||
"music_offtopic",
|
||||
"preview")
|
||||
"preview"
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a base64 encoded DASH stream manifest
|
||||
@ -109,6 +113,7 @@ object PlayerHelper {
|
||||
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
}
|
||||
}
|
||||
|
||||
"auto" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR
|
||||
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
@ -231,7 +236,9 @@ object PlayerHelper {
|
||||
|
||||
private val backgroundSpeed: Float
|
||||
get() = when (PreferenceHelper.getBoolean(PreferenceKeys.CUSTOM_PLAYBACK_SPEED, false)) {
|
||||
true -> PreferenceHelper.getString(PreferenceKeys.BACKGROUND_PLAYBACK_SPEED, "1").toFloat()
|
||||
true -> PreferenceHelper.getString(PreferenceKeys.BACKGROUND_PLAYBACK_SPEED, "1")
|
||||
.toFloat()
|
||||
|
||||
else -> playbackSpeed
|
||||
}
|
||||
|
||||
@ -427,8 +434,7 @@ object PlayerHelper {
|
||||
* Check for SponsorBlock segments matching the current player position
|
||||
* @param context A main dispatcher context
|
||||
* @param segments List of the SponsorBlock segments
|
||||
* @param skipManually Whether the event gets handled by the function caller
|
||||
* @return If segment found and [skipManually] is true, the end position of the segment in ms, otherwise null
|
||||
* @return If segment found and should skip manually, the end position of the segment in ms, otherwise null
|
||||
*/
|
||||
fun ExoPlayer.checkForSegments(
|
||||
context: Context,
|
||||
@ -465,11 +471,19 @@ object PlayerHelper {
|
||||
for (segment in segments) {
|
||||
val segmentStart = (segment.segment[0] * 1000f).toLong()
|
||||
val segmentEnd = (segment.segment[1] * 1000f).toLong()
|
||||
if (currentPosition in segmentStart..segmentEnd) { return true }
|
||||
if (currentPosition in segmentStart..segmentEnd) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the currently played chapter
|
||||
*/
|
||||
fun getCurrentChapterIndex(exoPlayer: ExoPlayer, chapters: List<ChapterSegment>): Int? {
|
||||
val currentPosition = exoPlayer.currentPosition / 1000
|
||||
return chapters.indexOfLast { currentPosition >= it.start }.takeIf { it >= 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a dialog with the chapters provided, even if the list is empty
|
||||
*/
|
||||
@ -477,11 +491,31 @@ object PlayerHelper {
|
||||
val titles = chapters.map { chapter ->
|
||||
"(${DateUtils.formatElapsedTime(chapter.start)}) ${chapter.title}"
|
||||
}
|
||||
MaterialAlertDialogBuilder(context)
|
||||
val dialog = MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.chapters)
|
||||
.setItems(titles.toTypedArray()) { _, index ->
|
||||
player.seekTo(chapters[index].start * 1000)
|
||||
}
|
||||
.show()
|
||||
.create()
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
val updatePosition = Runnable {
|
||||
// scroll to the current playing index in the chapter
|
||||
val currentPosition =
|
||||
getCurrentChapterIndex(player, chapters) ?: return@Runnable
|
||||
dialog.listView.smoothScrollToPosition(currentPosition)
|
||||
val current = dialog.listView.children.toList()[currentPosition]
|
||||
val highlightColor =
|
||||
ThemeHelper.getThemeColor(context, android.R.attr.colorControlHighlight)
|
||||
current.setBackgroundColor(highlightColor)
|
||||
}
|
||||
|
||||
dialog.setOnShowListener {
|
||||
updatePosition.run()
|
||||
// update the position after a short delay
|
||||
if (dialog.isShowing) handler.postDelayed(updatePosition, 200)
|
||||
}
|
||||
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
@ -582,12 +582,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
binding.playerViewsInfo.text = viewInfo
|
||||
|
||||
if (this::chapters.isInitialized && chapters.isNotEmpty()) {
|
||||
val chapterIndex = getCurrentChapterIndex() ?: return
|
||||
// scroll to the current chapter in the chapterRecView in the description
|
||||
binding.chaptersRecView.scrollToPosition(chapterIndex)
|
||||
// set selected item, that should be highlighted
|
||||
val chaptersAdapter = binding.chaptersRecView.adapter as ChaptersAdapter
|
||||
chaptersAdapter.updateSelectedPosition(chapterIndex)
|
||||
setCurrentChapterName(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1198,17 +1193,17 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
|
||||
// set the name of the video chapter in the exoPlayerView
|
||||
private fun setCurrentChapterName(position: Long? = null) {
|
||||
private fun setCurrentChapterName(forceUpdate: Boolean = false, enqueueNew: Boolean = true) {
|
||||
// return if chapters are empty to avoid crashes
|
||||
if (chapters.isEmpty() || _binding == null) return
|
||||
|
||||
// call the function again in 100ms
|
||||
binding.player.postDelayed(this::setCurrentChapterName, 100)
|
||||
if (enqueueNew) binding.player.postDelayed(this::setCurrentChapterName, 100)
|
||||
|
||||
// if the user is scrubbing the time bar, don't update
|
||||
if (scrubbingTimeBar && position == null) return
|
||||
if (scrubbingTimeBar && !forceUpdate) return
|
||||
|
||||
val chapterIndex = getCurrentChapterIndex(position) ?: return
|
||||
val chapterIndex = PlayerHelper.getCurrentChapterIndex(exoPlayer, chapters) ?: return
|
||||
val chapterName = chapters[chapterIndex].title.trim()
|
||||
|
||||
// change the chapter name textView text to the chapterName
|
||||
@ -1220,14 +1215,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the currently played chapter
|
||||
*/
|
||||
private fun getCurrentChapterIndex(position: Long? = null): Int? {
|
||||
val currentPosition = (position ?: exoPlayer.currentPosition) / 1000
|
||||
return chapters.indexOfLast { currentPosition >= it.start }.takeIf { it >= 0 }
|
||||
}
|
||||
|
||||
private fun setMediaSource(uri: Uri, mimeType: String) {
|
||||
val mediaItem = MediaItem.Builder()
|
||||
.setUri(uri)
|
||||
@ -1533,12 +1520,12 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
playerBinding,
|
||||
streams.duration * 1000,
|
||||
onScrub = {
|
||||
setCurrentChapterName(it)
|
||||
setCurrentChapterName(forceUpdate = true, enqueueNew = false)
|
||||
scrubbingTimeBar = true
|
||||
},
|
||||
onScrubEnd = {
|
||||
scrubbingTimeBar = false
|
||||
setCurrentChapterName(it)
|
||||
setCurrentChapterName(forceUpdate = true, enqueueNew = false)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user