2021-12-03 20:29:18 +01:00
|
|
|
package org.schabi.newpipe.views.player
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import android.util.AttributeSet
|
|
|
|
import android.util.Log
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import androidx.constraintlayout.widget.ConstraintLayout
|
|
|
|
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.END
|
|
|
|
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
|
|
|
|
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.START
|
|
|
|
import androidx.constraintlayout.widget.ConstraintSet
|
|
|
|
import org.schabi.newpipe.MainActivity
|
|
|
|
import org.schabi.newpipe.R
|
|
|
|
import org.schabi.newpipe.player.event.DisplayPortion
|
|
|
|
import org.schabi.newpipe.player.event.DoubleTapListener
|
2021-12-31 21:22:02 +01:00
|
|
|
import java.util.Optional
|
2021-12-03 20:29:18 +01:00
|
|
|
|
|
|
|
class PlayerFastSeekOverlay(context: Context, attrs: AttributeSet?) :
|
|
|
|
ConstraintLayout(context, attrs), DoubleTapListener {
|
|
|
|
|
|
|
|
private var secondsView: SecondsView
|
|
|
|
private var circleClipTapView: CircleClipTapView
|
|
|
|
private var rootConstraintLayout: ConstraintLayout
|
|
|
|
|
|
|
|
private var wasForwarding: Boolean = false
|
|
|
|
|
|
|
|
init {
|
|
|
|
LayoutInflater.from(context).inflate(R.layout.player_fast_seek_overlay, this, true)
|
|
|
|
|
|
|
|
secondsView = findViewById(R.id.seconds_view)
|
|
|
|
circleClipTapView = findViewById(R.id.circle_clip_tap_view)
|
|
|
|
rootConstraintLayout = findViewById(R.id.root_constraint_layout)
|
|
|
|
|
|
|
|
addOnLayoutChangeListener { view, _, _, _, _, _, _, _, _ ->
|
|
|
|
circleClipTapView.updateArcSize(view)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var performListener: PerformListener? = null
|
|
|
|
|
|
|
|
fun performListener(listener: PerformListener) = apply {
|
|
|
|
performListener = listener
|
|
|
|
}
|
|
|
|
|
|
|
|
var seekSeconds: Int = 0
|
|
|
|
private set
|
|
|
|
|
|
|
|
fun seekSeconds(seconds: Int) = apply {
|
|
|
|
seekSeconds = seconds
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indicates whether this (double) tap is the first of a series
|
|
|
|
// Decides whether to call performListener.onAnimationStart or not
|
|
|
|
private var initTap: Boolean = false
|
|
|
|
|
|
|
|
override fun onDoubleTapStarted(portion: DisplayPortion) {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "onDoubleTapStarted called with portion = [$portion]")
|
|
|
|
|
|
|
|
initTap = false
|
|
|
|
|
2021-12-14 20:52:46 +01:00
|
|
|
secondsView.stopAnimation()
|
2021-12-03 20:29:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDoubleTapProgressDown(portion: DisplayPortion) {
|
2021-12-31 21:22:02 +01:00
|
|
|
val shouldForward: Boolean =
|
|
|
|
performListener?.shouldFastForward(portion)?.orElse(null) ?: return
|
2021-12-03 20:29:18 +01:00
|
|
|
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(
|
|
|
|
TAG,
|
|
|
|
"onDoubleTapProgressDown called with " +
|
|
|
|
"shouldForward = [$shouldForward], " +
|
|
|
|
"wasForwarding = [$wasForwarding], " +
|
|
|
|
"initTap = [$initTap], "
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
2021-12-31 20:58:23 +01:00
|
|
|
* Check if a initial tap occurred or if direction was switched
|
2021-12-03 20:29:18 +01:00
|
|
|
*/
|
|
|
|
if (!initTap || wasForwarding != shouldForward) {
|
|
|
|
// Reset seconds and update position
|
|
|
|
secondsView.seconds = 0
|
|
|
|
changeConstraints(shouldForward)
|
|
|
|
circleClipTapView.updatePosition(!shouldForward)
|
|
|
|
secondsView.setForwarding(shouldForward)
|
|
|
|
|
|
|
|
wasForwarding = shouldForward
|
|
|
|
|
|
|
|
if (!initTap) {
|
|
|
|
initTap = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-31 20:58:23 +01:00
|
|
|
performListener?.onDoubleTap()
|
2021-12-03 20:29:18 +01:00
|
|
|
|
|
|
|
secondsView.seconds += seekSeconds
|
|
|
|
performListener?.seek(forward = shouldForward)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDoubleTapFinished() {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "onDoubleTapFinished called with initTap = [$initTap]")
|
|
|
|
|
2021-12-31 20:58:23 +01:00
|
|
|
if (initTap) performListener?.onDoubleTapEnd()
|
2021-12-03 20:29:18 +01:00
|
|
|
initTap = false
|
2021-12-14 20:52:46 +01:00
|
|
|
|
|
|
|
secondsView.stopAnimation()
|
2021-12-03 20:29:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun changeConstraints(forward: Boolean) {
|
|
|
|
val constraintSet = ConstraintSet()
|
|
|
|
with(constraintSet) {
|
|
|
|
clone(rootConstraintLayout)
|
|
|
|
clear(secondsView.id, if (forward) START else END)
|
|
|
|
connect(
|
|
|
|
secondsView.id, if (forward) END else START,
|
|
|
|
PARENT_ID, if (forward) END else START
|
|
|
|
)
|
2021-12-14 20:52:46 +01:00
|
|
|
secondsView.startAnimation()
|
2021-12-03 20:29:18 +01:00
|
|
|
applyTo(rootConstraintLayout)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interface PerformListener {
|
2021-12-31 20:58:23 +01:00
|
|
|
fun onDoubleTap()
|
|
|
|
fun onDoubleTapEnd()
|
2021-12-31 21:22:02 +01:00
|
|
|
fun shouldFastForward(portion: DisplayPortion): Optional<Boolean>
|
2021-12-03 20:29:18 +01:00
|
|
|
fun seek(forward: Boolean)
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val TAG = "PlayerSeekOverlay"
|
|
|
|
private val DEBUG = MainActivity.DEBUG
|
|
|
|
}
|
|
|
|
}
|