summaryrefslogtreecommitdiffstats
path: root/doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt
diff options
context:
space:
mode:
Diffstat (limited to 'doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt')
-rw-r--r--doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt201
1 files changed, 201 insertions, 0 deletions
diff --git a/doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt b/doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt
new file mode 100644
index 000000000..6e4c1f339
--- /dev/null
+++ b/doubletapplayerview/src/main/java/com/github/vkay94/dtpv/youtube/views/YouTubeSecondsView.kt
@@ -0,0 +1,201 @@
+package com.github.vkay94.dtpv.youtube.views
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
+import com.github.vkay94.dtpv.R
+
+/**
+ * Layout group which handles the icon animation while forwarding and rewinding.
+ *
+ * Since it's based on view's alpha the fading effect is more fluid (more YouTube-like) than
+ * using static drawables, especially when [cycleDuration] is low.
+ *
+ * Used by [YouTubeOverlay][com.github.vkay94.dtpv.youtube.YouTubeOverlay].
+ */
+class SecondsView(context: Context, attrs: AttributeSet?) :
+ ConstraintLayout(context, attrs) {
+
+ private var trianglesContainer: LinearLayout
+ private var secondsTextView: TextView
+ private var icon1: ImageView
+ private var icon2: ImageView
+ private var icon3: ImageView
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.yt_seconds_view, this, true)
+
+ trianglesContainer = findViewById(R.id.triangle_container)
+ secondsTextView = findViewById(R.id.tv_seconds)
+ icon1 = findViewById(R.id.icon_1)
+ icon2 = findViewById(R.id.icon_2)
+ icon3 = findViewById(R.id.icon_3)
+ }
+
+ /**
+ * Defines the duration for a full cycle of the triangle animation.
+ * Each animation step takes 20% of it.
+ */
+ var cycleDuration: Long = 750L
+ set(value) {
+ firstAnimator.duration = value / 5
+ secondAnimator.duration = value / 5
+ thirdAnimator.duration = value / 5
+ fourthAnimator.duration = value / 5
+ fifthAnimator.duration = value / 5
+ field = value
+ }
+
+ /**
+ * Sets the `TextView`'s seconds text according to the device`s language.
+ */
+ var seconds: Int = 0
+ set(value) {
+ secondsTextView.text = context.resources.getQuantityString(
+ R.plurals.quick_seek_x_second, value, value
+ )
+ field = value
+ }
+
+ /**
+ * Mirrors the triangles depending on what kind of type should be used (forward/rewind).
+ */
+ var isForward: Boolean = true
+ set(value) {
+ trianglesContainer.rotation = if (value) 0f else 180f
+ field = value
+ }
+
+ val textView: TextView
+ get() = secondsTextView
+
+ @DrawableRes
+ var icon: Int = R.drawable.ic_play_triangle
+ set(value) {
+ if (value > 0) {
+ icon1.setImageResource(value)
+ icon2.setImageResource(value)
+ icon3.setImageResource(value)
+ }
+ field = value
+ }
+
+ /**
+ * Starts the triangle animation
+ */
+ fun start() {
+ stop()
+ firstAnimator.start()
+ }
+
+ /**
+ * Stops the triangle animation
+ */
+ fun stop() {
+ firstAnimator.cancel()
+ secondAnimator.cancel()
+ thirdAnimator.cancel()
+ fourthAnimator.cancel()
+ fifthAnimator.cancel()
+ reset()
+ }
+
+ private fun reset() {
+ icon1.alpha = 0f
+ icon2.alpha = 0f
+ icon3.alpha = 0f
+ }
+
+ private val firstAnimator: ValueAnimator by lazy {
+ ValueAnimator.ofFloat(0f, 1f).setDuration(cycleDuration / 5).apply {
+ doOnStart {
+ icon1.alpha = 0f
+ icon2.alpha = 0f
+ icon3.alpha = 0f
+ }
+ addUpdateListener {
+ icon1.alpha = (it.animatedValue as Float)
+ }
+
+ doOnEnd {
+ secondAnimator.start()
+ }
+ }
+ }
+
+ private val secondAnimator: ValueAnimator by lazy {
+ ValueAnimator.ofFloat(0f, 1f).setDuration(cycleDuration / 5).apply {
+ doOnStart {
+ icon1.alpha = 1f
+ icon2.alpha = 0f
+ icon3.alpha = 0f
+ }
+ addUpdateListener {
+ icon2.alpha = (it.animatedValue as Float)
+ }
+ doOnEnd {
+ thirdAnimator.start()
+ }
+ }
+ }
+
+ private val thirdAnimator: ValueAnimator by lazy {
+ ValueAnimator.ofFloat(0f, 1f).setDuration(cycleDuration / 5).apply {
+ doOnStart {
+ icon1.alpha = 1f
+ icon2.alpha = 1f
+ icon3.alpha = 0f
+ }
+ addUpdateListener {
+ icon1.alpha =
+ 1f - icon3.alpha // or 1f - it (t3.alpha => all three stay a little longer together)
+ icon3.alpha = (it.animatedValue as Float)
+ }
+ doOnEnd {
+ fourthAnimator.start()
+ }
+ }
+
+ }
+
+ private val fourthAnimator: ValueAnimator by lazy {
+ ValueAnimator.ofFloat(0f, 1f).setDuration(cycleDuration / 5).apply {
+ doOnStart {
+ icon1.alpha = 0f
+ icon2.alpha = 1f
+ icon3.alpha = 1f
+ }
+ addUpdateListener {
+ icon2.alpha = 1f - (it.animatedValue as Float)
+ }
+ doOnEnd {
+ fifthAnimator.start()
+ }
+
+ }
+ }
+
+ private val fifthAnimator: ValueAnimator by lazy {
+ ValueAnimator.ofFloat(0f, 1f).setDuration(cycleDuration / 5).apply {
+ doOnStart {
+ icon1.alpha = 0f
+ icon2.alpha = 0f
+ icon3.alpha = 1f
+ }
+ addUpdateListener {
+ icon3.alpha = 1f - (it.animatedValue as Float)
+ }
+ doOnEnd {
+ firstAnimator.start()
+ }
+ }
+ }
+} \ No newline at end of file