mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
Merge pull request #1686 from Bnyro/master
Improved double tab behavior
This commit is contained in:
commit
2055a5d14b
@ -1,7 +1,7 @@
|
|||||||
package com.github.libretube.models.interfaces
|
package com.github.libretube.models.interfaces
|
||||||
|
|
||||||
interface PlayerOptionsInterface {
|
interface OnlinePlayerOptions {
|
||||||
fun onCaptionClicked()
|
fun onCaptionsClicked()
|
||||||
|
|
||||||
fun onQualityClicked()
|
fun onQualityClicked()
|
||||||
}
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.github.libretube.models.interfaces
|
||||||
|
|
||||||
|
interface PlayerOptions {
|
||||||
|
fun onAutoplayClicked()
|
||||||
|
|
||||||
|
fun onPlaybackSpeedClicked()
|
||||||
|
|
||||||
|
fun onResizeModeClicked()
|
||||||
|
|
||||||
|
fun onRepeatModeClicked()
|
||||||
|
}
|
@ -3,5 +3,6 @@ package com.github.libretube.obj
|
|||||||
data class BottomSheetItem(
|
data class BottomSheetItem(
|
||||||
val title: String,
|
val title: String,
|
||||||
val drawable: Int? = null,
|
val drawable: Int? = null,
|
||||||
val currentValue: String? = null
|
val currentValue: String? = null,
|
||||||
|
val onClick: () -> Unit = {}
|
||||||
)
|
)
|
||||||
|
@ -34,6 +34,7 @@ class BottomSheetAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
|
item.onClick.invoke()
|
||||||
listener.invoke(position)
|
listener.invoke(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ import com.github.libretube.extensions.query
|
|||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.extensions.toStreamItem
|
import com.github.libretube.extensions.toStreamItem
|
||||||
import com.github.libretube.models.PlayerViewModel
|
import com.github.libretube.models.PlayerViewModel
|
||||||
import com.github.libretube.models.interfaces.PlayerOptionsInterface
|
import com.github.libretube.models.interfaces.OnlinePlayerOptions
|
||||||
import com.github.libretube.services.BackgroundMode
|
import com.github.libretube.services.BackgroundMode
|
||||||
import com.github.libretube.services.DownloadService
|
import com.github.libretube.services.DownloadService
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
@ -105,7 +105,7 @@ import java.io.IOException
|
|||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class PlayerFragment : BaseFragment() {
|
class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||||
|
|
||||||
lateinit var binding: FragmentPlayerBinding
|
lateinit var binding: FragmentPlayerBinding
|
||||||
private lateinit var playerBinding: ExoStyledPlayerControlViewBinding
|
private lateinit var playerBinding: ExoStyledPlayerControlViewBinding
|
||||||
@ -296,76 +296,6 @@ class PlayerFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val onlinePlayerOptionsInterface = object : PlayerOptionsInterface {
|
|
||||||
override fun onCaptionClicked() {
|
|
||||||
if (!this@PlayerFragment::streams.isInitialized ||
|
|
||||||
streams.subtitles == null ||
|
|
||||||
streams.subtitles!!.isEmpty()
|
|
||||||
) {
|
|
||||||
Toast.makeText(context, R.string.no_subtitles_available, Toast.LENGTH_SHORT).show()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val subtitlesNamesList = mutableListOf(context?.getString(R.string.none)!!)
|
|
||||||
val subtitleCodesList = mutableListOf("")
|
|
||||||
streams.subtitles!!.forEach {
|
|
||||||
subtitlesNamesList += it.name!!
|
|
||||||
subtitleCodesList += it.code!!
|
|
||||||
}
|
|
||||||
|
|
||||||
BottomSheet()
|
|
||||||
.setSimpleItems(subtitlesNamesList) { index ->
|
|
||||||
val newParams = if (index != 0) {
|
|
||||||
// caption selected
|
|
||||||
|
|
||||||
// get the caption language code
|
|
||||||
val captionLanguageCode = subtitleCodesList[index]
|
|
||||||
|
|
||||||
// select the new caption preference
|
|
||||||
trackSelector.buildUponParameters()
|
|
||||||
.setPreferredTextLanguage(captionLanguageCode)
|
|
||||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
|
||||||
} else {
|
|
||||||
// none selected
|
|
||||||
// disable captions
|
|
||||||
trackSelector.buildUponParameters()
|
|
||||||
.setPreferredTextLanguage("")
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the new caption language
|
|
||||||
trackSelector.setParameters(newParams)
|
|
||||||
}
|
|
||||||
.show(childFragmentManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQualityClicked() {
|
|
||||||
// get the available resolutions
|
|
||||||
val (videosNameArray, videosUrlArray) = getAvailableResolutions()
|
|
||||||
|
|
||||||
// Dialog for quality selection
|
|
||||||
val lastPosition = exoPlayer.currentPosition
|
|
||||||
BottomSheet()
|
|
||||||
.setSimpleItems(
|
|
||||||
videosNameArray.toList()
|
|
||||||
) { which ->
|
|
||||||
if (
|
|
||||||
videosNameArray[which] == getString(R.string.hls) ||
|
|
||||||
videosNameArray[which] == "LBRY HLS"
|
|
||||||
) {
|
|
||||||
// set the progressive media source
|
|
||||||
setHLSMediaSource(videosUrlArray[which])
|
|
||||||
} else {
|
|
||||||
val videoUri = videosUrlArray[which]
|
|
||||||
val audioUrl =
|
|
||||||
PlayerHelper.getAudioSource(requireContext(), streams.audioStreams!!)
|
|
||||||
setMediaSource(videoUri, audioUrl)
|
|
||||||
}
|
|
||||||
exoPlayer.seekTo(lastPosition)
|
|
||||||
}
|
|
||||||
.show(childFragmentManager)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// actions that don't depend on video information
|
// actions that don't depend on video information
|
||||||
private fun initializeOnClickActions() {
|
private fun initializeOnClickActions() {
|
||||||
binding.closeImageView.setOnClickListener {
|
binding.closeImageView.setOnClickListener {
|
||||||
@ -814,7 +744,7 @@ class PlayerFragment : BaseFragment() {
|
|||||||
// initialize the player view actions
|
// initialize the player view actions
|
||||||
binding.player.initialize(
|
binding.player.initialize(
|
||||||
childFragmentManager,
|
childFragmentManager,
|
||||||
onlinePlayerOptionsInterface,
|
this,
|
||||||
doubleTapOverlayBinding,
|
doubleTapOverlayBinding,
|
||||||
trackSelector
|
trackSelector
|
||||||
)
|
)
|
||||||
@ -1389,6 +1319,74 @@ class PlayerFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCaptionsClicked() {
|
||||||
|
if (!this@PlayerFragment::streams.isInitialized ||
|
||||||
|
streams.subtitles == null ||
|
||||||
|
streams.subtitles!!.isEmpty()
|
||||||
|
) {
|
||||||
|
Toast.makeText(context, R.string.no_subtitles_available, Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val subtitlesNamesList = mutableListOf(context?.getString(R.string.none)!!)
|
||||||
|
val subtitleCodesList = mutableListOf("")
|
||||||
|
streams.subtitles!!.forEach {
|
||||||
|
subtitlesNamesList += it.name!!
|
||||||
|
subtitleCodesList += it.code!!
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomSheet()
|
||||||
|
.setSimpleItems(subtitlesNamesList) { index ->
|
||||||
|
val newParams = if (index != 0) {
|
||||||
|
// caption selected
|
||||||
|
|
||||||
|
// get the caption language code
|
||||||
|
val captionLanguageCode = subtitleCodesList[index]
|
||||||
|
|
||||||
|
// select the new caption preference
|
||||||
|
trackSelector.buildUponParameters()
|
||||||
|
.setPreferredTextLanguage(captionLanguageCode)
|
||||||
|
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
||||||
|
} else {
|
||||||
|
// none selected
|
||||||
|
// disable captions
|
||||||
|
trackSelector.buildUponParameters()
|
||||||
|
.setPreferredTextLanguage("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the new caption language
|
||||||
|
trackSelector.setParameters(newParams)
|
||||||
|
}
|
||||||
|
.show(childFragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQualityClicked() {
|
||||||
|
// get the available resolutions
|
||||||
|
val (videosNameArray, videosUrlArray) = getAvailableResolutions()
|
||||||
|
|
||||||
|
// Dialog for quality selection
|
||||||
|
val lastPosition = exoPlayer.currentPosition
|
||||||
|
BottomSheet()
|
||||||
|
.setSimpleItems(
|
||||||
|
videosNameArray.toList()
|
||||||
|
) { which ->
|
||||||
|
if (
|
||||||
|
videosNameArray[which] == getString(R.string.hls) ||
|
||||||
|
videosNameArray[which] == "LBRY HLS"
|
||||||
|
) {
|
||||||
|
// set the progressive media source
|
||||||
|
setHLSMediaSource(videosUrlArray[which])
|
||||||
|
} else {
|
||||||
|
val videoUri = videosUrlArray[which]
|
||||||
|
val audioUrl =
|
||||||
|
PlayerHelper.getAudioSource(requireContext(), streams.audioStreams!!)
|
||||||
|
setMediaSource(videoUri, audioUrl)
|
||||||
|
}
|
||||||
|
exoPlayer.seekTo(lastPosition)
|
||||||
|
}
|
||||||
|
.show(childFragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||||
if (isInPictureInPictureMode) {
|
if (isInPictureInPictureMode) {
|
||||||
|
@ -32,18 +32,18 @@ open class BottomSheet : BottomSheetDialogFragment() {
|
|||||||
binding.optionsRecycler.adapter = BottomSheetAdapter(items, listener)
|
binding.optionsRecycler.adapter = BottomSheetAdapter(items, listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setItems(items: List<BottomSheetItem>, listener: (index: Int) -> Unit) = apply {
|
fun setItems(items: List<BottomSheetItem>, listener: ((index: Int) -> Unit)?) = apply {
|
||||||
this.items = items
|
this.items = items
|
||||||
this.listener = { index ->
|
this.listener = { index ->
|
||||||
listener.invoke(index)
|
listener?.invoke(index)
|
||||||
dialog?.dismiss()
|
dialog?.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSimpleItems(titles: List<String>, listener: (index: Int) -> Unit) = apply {
|
fun setSimpleItems(titles: List<String>, listener: ((index: Int) -> Unit)?) = apply {
|
||||||
this.items = titles.map { BottomSheetItem(it) }
|
this.items = titles.map { BottomSheetItem(it) }
|
||||||
this.listener = { index ->
|
this.listener = { index ->
|
||||||
listener.invoke(index)
|
listener?.invoke(index)
|
||||||
dialog?.dismiss()
|
dialog?.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import com.github.libretube.databinding.DoubleTapOverlayBinding
|
|||||||
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
||||||
import com.github.libretube.extensions.toDp
|
import com.github.libretube.extensions.toDp
|
||||||
import com.github.libretube.models.interfaces.DoubleTapInterface
|
import com.github.libretube.models.interfaces.DoubleTapInterface
|
||||||
import com.github.libretube.models.interfaces.PlayerOptionsInterface
|
import com.github.libretube.models.interfaces.OnlinePlayerOptions
|
||||||
|
import com.github.libretube.models.interfaces.PlayerOptions
|
||||||
import com.github.libretube.obj.BottomSheetItem
|
import com.github.libretube.obj.BottomSheetItem
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
import com.github.libretube.ui.sheets.PlaybackSpeedSheet
|
import com.github.libretube.ui.sheets.PlaybackSpeedSheet
|
||||||
@ -30,7 +31,7 @@ import com.google.android.exoplayer2.util.RepeatModeUtil
|
|||||||
internal class CustomExoPlayerView(
|
internal class CustomExoPlayerView(
|
||||||
context: Context,
|
context: Context,
|
||||||
attributeSet: AttributeSet? = null
|
attributeSet: AttributeSet? = null
|
||||||
) : StyledPlayerView(context, attributeSet) {
|
) : StyledPlayerView(context, attributeSet), PlayerOptions {
|
||||||
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this)
|
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this)
|
||||||
private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null
|
private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ internal class CustomExoPlayerView(
|
|||||||
* Objects from the parent fragment
|
* Objects from the parent fragment
|
||||||
*/
|
*/
|
||||||
private var doubleTapListener: DoubleTapInterface? = null
|
private var doubleTapListener: DoubleTapInterface? = null
|
||||||
private var playerOptionsInterface: PlayerOptionsInterface? = null
|
private var playerOptionsInterface: OnlinePlayerOptions? = null
|
||||||
private lateinit var childFragmentManager: FragmentManager
|
private lateinit var childFragmentManager: FragmentManager
|
||||||
private var trackSelector: TrackSelector? = null
|
private var trackSelector: TrackSelector? = null
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ internal class CustomExoPlayerView(
|
|||||||
|
|
||||||
fun initialize(
|
fun initialize(
|
||||||
childFragmentManager: FragmentManager,
|
childFragmentManager: FragmentManager,
|
||||||
playerViewInterface: PlayerOptionsInterface?,
|
playerViewInterface: OnlinePlayerOptions?,
|
||||||
doubleTapOverlayBinding: DoubleTapOverlayBinding,
|
doubleTapOverlayBinding: DoubleTapOverlayBinding,
|
||||||
trackSelector: TrackSelector?
|
trackSelector: TrackSelector?
|
||||||
) {
|
) {
|
||||||
@ -136,78 +137,79 @@ internal class CustomExoPlayerView(
|
|||||||
|
|
||||||
private fun initializeAdvancedOptions(context: Context) {
|
private fun initializeAdvancedOptions(context: Context) {
|
||||||
binding.toggleOptions.setOnClickListener {
|
binding.toggleOptions.setOnClickListener {
|
||||||
val bottomSheetFragment = BottomSheet().apply {
|
val items = mutableListOf(
|
||||||
val items = mutableListOf(
|
BottomSheetItem(
|
||||||
BottomSheetItem(
|
context.getString(R.string.player_autoplay),
|
||||||
context.getString(R.string.player_autoplay),
|
R.drawable.ic_play,
|
||||||
R.drawable.ic_play,
|
if (autoplayEnabled) {
|
||||||
if (autoplayEnabled) {
|
context.getString(R.string.enabled)
|
||||||
context.getString(R.string.enabled)
|
} else {
|
||||||
} else {
|
context.getString(R.string.disabled)
|
||||||
context.getString(R.string.disabled)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
BottomSheetItem(
|
|
||||||
context.getString(R.string.repeat_mode),
|
|
||||||
R.drawable.ic_repeat,
|
|
||||||
if (player?.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) {
|
|
||||||
context.getString(R.string.repeat_mode_none)
|
|
||||||
} else {
|
|
||||||
context.getString(R.string.repeat_mode_current)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
BottomSheetItem(
|
|
||||||
context.getString(R.string.player_resize_mode),
|
|
||||||
R.drawable.ic_aspect_ratio,
|
|
||||||
when (resizeMode) {
|
|
||||||
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(R.string.resize_mode_fit)
|
|
||||||
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(R.string.resize_mode_fill)
|
|
||||||
else -> context.getString(R.string.resize_mode_zoom)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
BottomSheetItem(
|
|
||||||
context.getString(R.string.playback_speed),
|
|
||||||
R.drawable.ic_speed,
|
|
||||||
"${
|
|
||||||
player?.playbackParameters?.speed
|
|
||||||
.toString()
|
|
||||||
.replace(".0", "")
|
|
||||||
}x"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (playerOptionsInterface != null) {
|
|
||||||
items.add(
|
|
||||||
BottomSheetItem(
|
|
||||||
context.getString(R.string.quality),
|
|
||||||
R.drawable.ic_hd,
|
|
||||||
"${player?.videoSize?.height}p"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
items.add(
|
|
||||||
BottomSheetItem(
|
|
||||||
context.getString(R.string.captions),
|
|
||||||
R.drawable.ic_caption,
|
|
||||||
if (trackSelector != null && trackSelector!!.parameters.preferredTextLanguages.isNotEmpty()) {
|
|
||||||
trackSelector!!.parameters.preferredTextLanguages[0]
|
|
||||||
} else {
|
|
||||||
context.getString(R.string.none)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
setItems(items) { index ->
|
|
||||||
when (index) {
|
|
||||||
0 -> onAutoplayClicked()
|
|
||||||
1 -> onRepeatModeClicked()
|
|
||||||
2 -> onResizeModeClicked()
|
|
||||||
3 -> onPlaybackSpeedClicked()
|
|
||||||
4 -> playerOptionsInterface?.onQualityClicked()
|
|
||||||
5 -> playerOptionsInterface?.onCaptionClicked()
|
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
onAutoplayClicked()
|
||||||
|
},
|
||||||
|
BottomSheetItem(
|
||||||
|
context.getString(R.string.repeat_mode),
|
||||||
|
R.drawable.ic_repeat,
|
||||||
|
if (player?.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) {
|
||||||
|
context.getString(R.string.repeat_mode_none)
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.repeat_mode_current)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
onRepeatModeClicked()
|
||||||
|
},
|
||||||
|
BottomSheetItem(
|
||||||
|
context.getString(R.string.player_resize_mode),
|
||||||
|
R.drawable.ic_aspect_ratio,
|
||||||
|
when (resizeMode) {
|
||||||
|
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(R.string.resize_mode_fit)
|
||||||
|
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(R.string.resize_mode_fill)
|
||||||
|
else -> context.getString(R.string.resize_mode_zoom)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
onResizeModeClicked()
|
||||||
|
},
|
||||||
|
BottomSheetItem(
|
||||||
|
context.getString(R.string.playback_speed),
|
||||||
|
R.drawable.ic_speed,
|
||||||
|
"${
|
||||||
|
player?.playbackParameters?.speed
|
||||||
|
.toString()
|
||||||
|
.replace(".0", "")
|
||||||
|
}x"
|
||||||
|
) {
|
||||||
|
onPlaybackSpeedClicked()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (playerOptionsInterface != null) {
|
||||||
|
items.add(
|
||||||
|
BottomSheetItem(
|
||||||
|
context.getString(R.string.quality),
|
||||||
|
R.drawable.ic_hd,
|
||||||
|
"${player?.videoSize?.height}p"
|
||||||
|
) {
|
||||||
|
playerOptionsInterface?.onQualityClicked()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
items.add(
|
||||||
|
BottomSheetItem(
|
||||||
|
context.getString(R.string.captions),
|
||||||
|
R.drawable.ic_caption,
|
||||||
|
if (trackSelector != null && trackSelector!!.parameters.preferredTextLanguages.isNotEmpty()) {
|
||||||
|
trackSelector!!.parameters.preferredTextLanguages[0]
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.none)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
playerOptionsInterface?.onCaptionsClicked()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val bottomSheetFragment = BottomSheet().setItems(items, null)
|
||||||
bottomSheetFragment.show(childFragmentManager, null)
|
bottomSheetFragment.show(childFragmentManager, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +309,7 @@ internal class CustomExoPlayerView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onAutoplayClicked() {
|
override fun onAutoplayClicked() {
|
||||||
// autoplay options dialog
|
// autoplay options dialog
|
||||||
BottomSheet()
|
BottomSheet()
|
||||||
.setSimpleItems(
|
.setSimpleItems(
|
||||||
@ -324,11 +326,11 @@ internal class CustomExoPlayerView(
|
|||||||
.show(childFragmentManager)
|
.show(childFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onPlaybackSpeedClicked() {
|
override fun onPlaybackSpeedClicked() {
|
||||||
player?.let { PlaybackSpeedSheet(it).show(childFragmentManager) }
|
player?.let { PlaybackSpeedSheet(it).show(childFragmentManager) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onResizeModeClicked() {
|
override fun onResizeModeClicked() {
|
||||||
// switching between original aspect ratio (black bars) and zoomed to fill device screen
|
// switching between original aspect ratio (black bars) and zoomed to fill device screen
|
||||||
val aspectRatioModeNames = context.resources?.getStringArray(R.array.resizeMode)
|
val aspectRatioModeNames = context.resources?.getStringArray(R.array.resizeMode)
|
||||||
?.toList().orEmpty()
|
?.toList().orEmpty()
|
||||||
@ -346,7 +348,7 @@ internal class CustomExoPlayerView(
|
|||||||
.show(childFragmentManager)
|
.show(childFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onRepeatModeClicked() {
|
override fun onRepeatModeClicked() {
|
||||||
val repeatModeNames = listOf(
|
val repeatModeNames = listOf(
|
||||||
context.getString(R.string.repeat_mode_none),
|
context.getString(R.string.repeat_mode_none),
|
||||||
context.getString(R.string.repeat_mode_current)
|
context.getString(R.string.repeat_mode_current)
|
||||||
|
@ -3,40 +3,49 @@ package com.github.libretube.util
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
abstract class DoubleTapListener : View.OnClickListener {
|
abstract class DoubleTapListener : View.OnClickListener {
|
||||||
|
|
||||||
private val maximumTimeDifference = 300L
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
private var isSingleEvent = false
|
private var lastClick = 0L
|
||||||
private var timeStampLastClick = 0L
|
private var lastDoubleClick = 0L
|
||||||
private var timeStampLastDoubleClick = 0L
|
|
||||||
|
|
||||||
override fun onClick(v: View?) {
|
|
||||||
if (SystemClock.elapsedRealtime() - timeStampLastClick < maximumTimeDifference) {
|
|
||||||
isSingleEvent = false
|
|
||||||
handler.removeCallbacks(runnable)
|
|
||||||
timeStampLastDoubleClick = SystemClock.elapsedRealtime()
|
|
||||||
onDoubleClick()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isSingleEvent = true
|
|
||||||
handler.removeCallbacks(runnable)
|
|
||||||
handler.postDelayed(runnable, maximumTimeDifference)
|
|
||||||
timeStampLastClick = SystemClock.elapsedRealtime()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun onDoubleClick()
|
abstract fun onDoubleClick()
|
||||||
abstract fun onSingleClick()
|
abstract fun onSingleClick()
|
||||||
|
|
||||||
private val runnable = Runnable {
|
override fun onClick(v: View?) {
|
||||||
if (!isSingleEvent ||
|
if (isSecondClick()) {
|
||||||
SystemClock.elapsedRealtime() - timeStampLastDoubleClick < maximumTimeDifference
|
handler.removeCallbacks(runnable)
|
||||||
) {
|
lastDoubleClick = elapsedTime()
|
||||||
return@Runnable
|
onDoubleClick()
|
||||||
|
} else {
|
||||||
|
if (recentDoubleClick()) return
|
||||||
|
handler.removeCallbacks(runnable)
|
||||||
|
handler.postDelayed(runnable, MAX_TIME_DIFF)
|
||||||
|
lastClick = elapsedTime()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val runnable = Runnable {
|
||||||
|
if (isSecondClick()) return@Runnable
|
||||||
|
Log.e("single", "single")
|
||||||
onSingleClick()
|
onSingleClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isSecondClick(): Boolean {
|
||||||
|
return elapsedTime() - lastClick < MAX_TIME_DIFF
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recentDoubleClick(): Boolean {
|
||||||
|
return elapsedTime() - lastDoubleClick < MAX_TIME_DIFF
|
||||||
|
}
|
||||||
|
|
||||||
|
fun elapsedTime() = SystemClock.elapsedRealtime()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val MAX_TIME_DIFF = 400L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user