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

182 lines
4.8 KiB
Kotlin

package org.schabi.newpipe.views.player
import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import org.schabi.newpipe.R
import org.schabi.newpipe.databinding.PlayerFastSeekSecondsViewBinding
import org.schabi.newpipe.util.DeviceUtils
class SecondsView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
companion object {
const val ICON_ANIMATION_DURATION = 750L
}
var cycleDuration: Long = ICON_ANIMATION_DURATION
set(value) {
firstAnimator.duration = value / 5
secondAnimator.duration = value / 5
thirdAnimator.duration = value / 5
fourthAnimator.duration = value / 5
fifthAnimator.duration = value / 5
field = value
}
var seconds: Int = 0
set(value) {
binding.tvSeconds.text = context.resources.getQuantityString(
R.plurals.seconds, value, value
)
field = value
}
// Done as a field so that we don't have to compute on each tab if animations are enabled
private val animationsEnabled = DeviceUtils.hasAnimationsAnimatorDurationEnabled(context)
val binding = PlayerFastSeekSecondsViewBinding.inflate(LayoutInflater.from(context), this)
init {
orientation = VERTICAL
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
}
fun setForwarding(isForward: Boolean) {
binding.triangleContainer.rotation = if (isForward) 0f else 180f
}
fun startAnimation() {
stopAnimation()
if (animationsEnabled) {
firstAnimator.start()
} else {
// If no animations are enable show the arrow(s) without animation
showWithoutAnimation()
}
}
fun stopAnimation() {
firstAnimator.cancel()
secondAnimator.cancel()
thirdAnimator.cancel()
fourthAnimator.cancel()
fifthAnimator.cancel()
reset()
}
private fun reset() {
binding.icon1.alpha = 0f
binding.icon2.alpha = 0f
binding.icon3.alpha = 0f
}
private fun showWithoutAnimation() {
binding.icon1.alpha = 1f
binding.icon2.alpha = 1f
binding.icon3.alpha = 1f
}
private val firstAnimator: ValueAnimator = CustomValueAnimator(
{
binding.icon1.alpha = 0f
binding.icon2.alpha = 0f
binding.icon3.alpha = 0f
},
{
binding.icon1.alpha = it
},
{
secondAnimator.start()
}
)
private val secondAnimator: ValueAnimator = CustomValueAnimator(
{
binding.icon1.alpha = 1f
binding.icon2.alpha = 0f
binding.icon3.alpha = 0f
},
{
binding.icon2.alpha = it
},
{
thirdAnimator.start()
}
)
private val thirdAnimator: ValueAnimator = CustomValueAnimator(
{
binding.icon1.alpha = 1f
binding.icon2.alpha = 1f
binding.icon3.alpha = 0f
},
{
binding.icon1.alpha = 1f - binding.icon3.alpha
binding.icon3.alpha = it
},
{
fourthAnimator.start()
}
)
private val fourthAnimator: ValueAnimator = CustomValueAnimator(
{
binding.icon1.alpha = 0f
binding.icon2.alpha = 1f
binding.icon3.alpha = 1f
},
{
binding.icon2.alpha = 1f - it
},
{
fifthAnimator.start()
}
)
private val fifthAnimator: ValueAnimator = CustomValueAnimator(
{
binding.icon1.alpha = 0f
binding.icon2.alpha = 0f
binding.icon3.alpha = 1f
},
{
binding.icon3.alpha = 1f - it
},
{
firstAnimator.start()
}
)
private inner class CustomValueAnimator(
start: () -> Unit,
update: (value: Float) -> Unit,
end: () -> Unit
) : ValueAnimator() {
init {
duration = cycleDuration / 5
setFloatValues(0f, 1f)
addUpdateListener { update(it.animatedValue as Float) }
addListener(object : AnimatorListener {
override fun onAnimationStart(animation: Animator?) {
start()
}
override fun onAnimationEnd(animation: Animator?) {
end()
}
override fun onAnimationCancel(animation: Animator?) = Unit
override fun onAnimationRepeat(animation: Animator?) = Unit
})
}
}
}