NewPipe/app/src/main/java/org/schabi/newpipe/views/player/PlayerFastSeekOverlay.kt

137 lines
4.3 KiB
Kotlin
Raw Normal View History

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
import java.util.Optional
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()
}
override fun onDoubleTapProgressDown(portion: DisplayPortion) {
val shouldForward: Boolean =
performListener?.shouldFastForward(portion)?.orElse(null) ?: return
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
*/
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()
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()
initTap = false
2021-12-14 20:52:46 +01:00
secondsView.stopAnimation()
}
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()
applyTo(rootConstraintLayout)
}
}
interface PerformListener {
2021-12-31 20:58:23 +01:00
fun onDoubleTap()
fun onDoubleTapEnd()
fun shouldFastForward(portion: DisplayPortion): Optional<Boolean>
fun seek(forward: Boolean)
}
companion object {
private const val TAG = "PlayerSeekOverlay"
private val DEBUG = MainActivity.DEBUG
}
}