From fe42206e94913c3a35301ac10de2b29e333f98ee Mon Sep 17 00:00:00 2001
From: litetex <40789489+litetex@users.noreply.github.com>
Date: Fri, 3 Dec 2021 20:29:18 +0100
Subject: [PATCH] Code cleanup and minimization * Deduplicated and simplified a
lot of code * Fixed ``invalidSeekConditions`` so that it's possible to seek
while the player is loading (like currently the case)
---
.../org/schabi/newpipe/player/Player.java | 129 ++------
.../player/event/BasePlayerGestureListener.kt | 6 +-
.../player/event/PlayerGestureListener.java | 3 +-
.../newpipe/views/player/CircleClipTapView.kt | 33 +--
.../views/player/PlayerFastSeekOverlay.kt | 136 +++++++++
.../newpipe/views/player/PlayerSeekOverlay.kt | 278 ------------------
.../newpipe/views/player/SecondsView.kt | 30 +-
app/src/main/res/layout-large-land/player.xml | 22 +-
app/src/main/res/layout/player.xml | 22 +-
...erlay.xml => player_fast_seek_overlay.xml} | 3 +-
....xml => player_fast_seek_seconds_view.xml} | 0
11 files changed, 185 insertions(+), 477 deletions(-)
create mode 100644 app/src/main/java/org/schabi/newpipe/views/player/PlayerFastSeekOverlay.kt
delete mode 100644 app/src/main/java/org/schabi/newpipe/views/player/PlayerSeekOverlay.kt
rename app/src/main/res/layout/{player_seek_overlay.xml => player_fast_seek_overlay.xml} (89%)
rename app/src/main/res/layout/{player_seek_seconds_view.xml => player_fast_seek_seconds_view.xml} (100%)
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index 8e340302a..fbfaf7b95 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -51,8 +51,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
@@ -189,8 +187,7 @@ import org.schabi.newpipe.util.StreamTypeUtil;
import org.schabi.newpipe.util.external_communication.KoreUtils;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.views.ExpandableSurfaceView;
-import org.schabi.newpipe.views.player.CircleClipTapView;
-import org.schabi.newpipe.views.player.PlayerSeekOverlay;
+import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
import java.io.IOException;
import java.util.ArrayList;
@@ -454,6 +451,8 @@ public final class Player implements
initPlayer(true);
}
initListeners();
+
+ setupPlayerSeekOverlay();
}
private void initViews(@NonNull final PlayerBinding playerBinding) {
@@ -530,12 +529,6 @@ public final class Player implements
binding.resizeTextView.setOnClickListener(this);
binding.playbackLiveSync.setOnClickListener(this);
- playerGestureListener = new PlayerGestureListener(this, service);
- gestureDetector = new GestureDetectorCompat(context, playerGestureListener);
- //noinspection ClickableViewAccessibility
- binding.getRoot().setOnTouchListener(playerGestureListener);
- setupPlayerSeekOverlay();
-
binding.queueButton.setOnClickListener(this);
binding.segmentsButton.setOnClickListener(this);
binding.repeatButton.setOnClickListener(this);
@@ -586,26 +579,26 @@ public final class Player implements
v.getPaddingBottom()));
}
+ /**
+ * Initializes the Fast-For/Backward overlay.
+ */
private void setupPlayerSeekOverlay() {
- binding.seekOverlay.showCircle(true)
- .circleBackgroundColorInt(CircleClipTapView.COLOR_DARK_TRANSPARENT)
+ playerGestureListener = new PlayerGestureListener(this, service);
+ gestureDetector = new GestureDetectorCompat(context, playerGestureListener);
+ binding.getRoot().setOnTouchListener(playerGestureListener);
+
+ binding.fastSeekOverlay
.seekSeconds((int) (retrieveSeekDurationFromPreferences(this) / 1000.0f))
- .performListener(new PlayerSeekOverlay.PerformListener() {
+ .performListener(new PlayerFastSeekOverlay.PerformListener() {
@Override
- public void onPrepare() {
- if (invalidSeekConditions()) {
- playerGestureListener.endMultiDoubleTap();
- return;
- }
- binding.seekOverlay.arcSize(
- CircleClipTapView.Companion.calculateArcSize(getSurfaceView())
- );
+ public void onDoubleTabStart() {
+ // TODO
}
@Override
- public void onAnimationStart() {
- animate(binding.seekOverlay, true, SEEK_OVERLAY_DURATION);
+ public void onDoubleTab() {
+ animate(binding.fastSeekOverlay, true, SEEK_OVERLAY_DURATION);
animate(binding.playbackControlsShadow,
!simpleExoPlayer.getPlayWhenReady(), SEEK_OVERLAY_DURATION);
animate(binding.playerTopShadow, false, SEEK_OVERLAY_DURATION);
@@ -615,8 +608,8 @@ public final class Player implements
}
@Override
- public void onAnimationEnd() {
- animate(binding.seekOverlay, false, SEEK_OVERLAY_DURATION);
+ public void onDoubleTabEnd() {
+ animate(binding.fastSeekOverlay, false, SEEK_OVERLAY_DURATION);
if (!simpleExoPlayer.getPlayWhenReady()) {
showControls(SEEK_OVERLAY_DURATION);
} else {
@@ -629,6 +622,7 @@ public final class Player implements
// Null indicates an invalid area or condition e.g. the middle portion
// or video start or end was reached during double tap seeking
if (invalidSeekConditions()) {
+ playerGestureListener.endMultiDoubleTap();
return null;
}
if (portion == DisplayPortion.LEFT
@@ -637,9 +631,9 @@ public final class Player implements
return false;
} else if (portion == DisplayPortion.RIGHT) {
return true;
- } else /* portion == DisplayPortion.MIDDLE */ {
- return null;
}
+ /* portion == DisplayPortion.MIDDLE */
+ return null;
}
@Override
@@ -653,12 +647,13 @@ public final class Player implements
}
private boolean invalidSeekConditions() {
- return simpleExoPlayer.getCurrentPosition() == simpleExoPlayer.getDuration()
- || currentState == STATE_COMPLETED
- || !isPrepared;
+ return exoPlayerIsNull()
+ || simpleExoPlayer.getPlaybackState() == SimpleExoPlayer.STATE_ENDED
+ || simpleExoPlayer.getCurrentPosition() >= simpleExoPlayer.getDuration()
+ || currentState == STATE_COMPLETED;
}
});
- playerGestureListener.doubleTapControls(binding.seekOverlay);
+ playerGestureListener.doubleTapControls(binding.fastSeekOverlay);
}
//endregion
@@ -1879,71 +1874,6 @@ public final class Player implements
return binding != null && binding.playbackControlRoot.getVisibility() == View.VISIBLE;
}
- /**
- * Show a animation, and depending on goneOnEnd, will stay on the screen or be gone.
- *
- * @param drawableId the drawable that will be used to animate,
- * pass -1 to clear any animation that is visible
- * @param goneOnEnd will set the animation view to GONE on the end of the animation
- */
- public void showAndAnimateControl(final int drawableId, final boolean goneOnEnd) {
- if (DEBUG) {
- Log.d(TAG, "showAndAnimateControl() called with: "
- + "drawableId = [" + drawableId + "], goneOnEnd = [" + goneOnEnd + "]");
- }
- if (controlViewAnimator != null && controlViewAnimator.isRunning()) {
- if (DEBUG) {
- Log.d(TAG, "showAndAnimateControl: controlViewAnimator.isRunning");
- }
- controlViewAnimator.end();
- }
-
- if (drawableId == -1) {
- if (binding.controlAnimationView.getVisibility() == View.VISIBLE) {
- controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(
- binding.controlAnimationView,
- PropertyValuesHolder.ofFloat(View.ALPHA, 1.0f, 0.0f),
- PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1.0f),
- PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1.0f)
- ).setDuration(DEFAULT_CONTROLS_DURATION);
- controlViewAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(final Animator animation) {
- binding.controlAnimationView.setVisibility(View.GONE);
- }
- });
- controlViewAnimator.start();
- }
- return;
- }
-
- final float scaleFrom = goneOnEnd ? 1f : 1f;
- final float scaleTo = goneOnEnd ? 1.8f : 1.4f;
- final float alphaFrom = goneOnEnd ? 1f : 0f;
- final float alphaTo = goneOnEnd ? 0f : 1f;
-
-
- controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(
- binding.controlAnimationView,
- PropertyValuesHolder.ofFloat(View.ALPHA, alphaFrom, alphaTo),
- PropertyValuesHolder.ofFloat(View.SCALE_X, scaleFrom, scaleTo),
- PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleFrom, scaleTo)
- );
- controlViewAnimator.setDuration(goneOnEnd ? 1000 : 500);
- controlViewAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(final Animator animation) {
- binding.controlAnimationView.setVisibility(goneOnEnd ? View.GONE : View.VISIBLE);
- }
- });
-
-
- binding.controlAnimationView.setVisibility(View.VISIBLE);
- binding.controlAnimationView.setImageDrawable(
- AppCompatResources.getDrawable(context, drawableId));
- controlViewAnimator.start();
- }
-
public void showControlsThenHide() {
if (DEBUG) {
Log.d(TAG, "showControlsThenHide() called");
@@ -2214,8 +2144,6 @@ public final class Player implements
updateStreamRelatedViews();
- showAndAnimateControl(-1, true);
-
binding.playbackSeekBar.setEnabled(true);
binding.playbackSeekBar.getThumb()
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN));
@@ -2295,7 +2223,6 @@ public final class Player implements
if (DEBUG) {
Log.d(TAG, "onPausedSeek() called");
}
- showAndAnimateControl(-1, true);
animatePlayButtons(false, 100);
binding.getRoot().setKeepScreenOn(true);
@@ -4364,8 +4291,8 @@ public final class Player implements
return binding.currentDisplaySeek;
}
- public PlayerSeekOverlay getSeekOverlay() {
- return binding.seekOverlay;
+ public PlayerFastSeekOverlay getFastSeekOverlay() {
+ return binding.fastSeekOverlay;
}
@Nullable
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/BasePlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/event/BasePlayerGestureListener.kt
index 29ae7c5c3..c89eabb47 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/BasePlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/event/BasePlayerGestureListener.kt
@@ -411,7 +411,7 @@ abstract class BasePlayerGestureListener(
var doubleTapControls: DoubleTapListener? = null
private set
- val isDoubleTapEnabled: Boolean
+ private val isDoubleTapEnabled: Boolean
get() = doubleTapDelay > 0
var isDoubleTapping = false
@@ -459,10 +459,6 @@ abstract class BasePlayerGestureListener(
doubleTapControls?.onDoubleTapFinished()
}
- fun enableMultiDoubleTap(enable: Boolean) = apply {
- doubleTapDelay = if (enable) DOUBLE_TAP_DELAY else 0
- }
-
// ///////////////////////////////////////////////////////////////////
// Utils
// ///////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index b215584e8..794fe9b3c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -230,11 +230,10 @@ public class PlayerGestureListener
if (DEBUG) {
Log.d(TAG, "onPopupResizingStart called");
}
- player.showAndAnimateControl(-1, true);
player.getLoadingPanel().setVisibility(View.GONE);
player.hideControls(0, 0);
- animate(player.getSeekOverlay(), false, 0);
+ animate(player.getFastSeekOverlay(), false, 0);
animate(player.getCurrentDisplaySeek(), false, 0, ALPHA, 0);
}
diff --git a/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt b/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt
index 6b22538e0..e3d142916 100644
--- a/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt
+++ b/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt
@@ -6,18 +6,9 @@ import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
-import org.schabi.newpipe.player.event.DisplayPortion
class CircleClipTapView(context: Context?, attrs: AttributeSet) : View(context, attrs) {
- companion object {
- const val COLOR_DARK = 0x45000000
- const val COLOR_DARK_TRANSPARENT = 0x30000000
- const val COLOR_LIGHT_TRANSPARENT = 0x25EEEEEE
-
- fun calculateArcSize(view: View): Float = view.height / 11.4f
- }
-
private var backgroundPaint = Paint()
private var widthPx = 0
@@ -26,6 +17,7 @@ class CircleClipTapView(context: Context?, attrs: AttributeSet) : View(context,
// Background
private var shapePath = Path()
+ private var arcSize: Float = 80f
private var isLeft = true
init {
@@ -34,7 +26,7 @@ class CircleClipTapView(context: Context?, attrs: AttributeSet) : View(context,
backgroundPaint.apply {
style = Paint.Style.FILL
isAntiAlias = true
- color = COLOR_LIGHT_TRANSPARENT
+ color = 0x30000000
}
val dm = context.resources.displayMetrics
@@ -44,24 +36,15 @@ class CircleClipTapView(context: Context?, attrs: AttributeSet) : View(context,
updatePathShape()
}
- var arcSize: Float = 80f
- set(value) {
- field = value
+ fun updateArcSize(baseView: View) {
+ val newArcSize = baseView.height / 11.4f
+ if (arcSize != newArcSize) {
+ arcSize = newArcSize
updatePathShape()
}
+ }
- var circleBackgroundColor: Int
- get() = backgroundPaint.color
- set(value) {
- backgroundPaint.color = value
- }
-
- /*
- Background
- */
-
- fun updatePosition(portion: DisplayPortion) {
- val newIsLeft = portion == DisplayPortion.LEFT
+ fun updatePosition(newIsLeft: Boolean) {
if (isLeft != newIsLeft) {
isLeft = newIsLeft
updatePathShape()
diff --git a/app/src/main/java/org/schabi/newpipe/views/player/PlayerFastSeekOverlay.kt b/app/src/main/java/org/schabi/newpipe/views/player/PlayerFastSeekOverlay.kt
new file mode 100644
index 000000000..90384264b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/views/player/PlayerFastSeekOverlay.kt
@@ -0,0 +1,136 @@
+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
+
+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
+ performListener?.onDoubleTabStart()
+
+ secondsView.stop()
+ }
+
+ override fun onDoubleTapProgressDown(portion: DisplayPortion) {
+ val shouldForward: Boolean = performListener?.shouldFastForward(portion) ?: return
+
+ if (DEBUG)
+ Log.d(
+ TAG,
+ "onDoubleTapProgressDown called with " +
+ "shouldForward = [$shouldForward], " +
+ "wasForwarding = [$wasForwarding], " +
+ "initTap = [$initTap], "
+ )
+
+ /*
+ * Check if a initial tab 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) {
+ // Start animation
+ secondsView.start()
+ initTap = true
+ }
+ }
+
+ performListener?.onDoubleTab()
+
+ secondsView.seconds += seekSeconds
+ performListener?.seek(forward = shouldForward)
+ }
+
+ override fun onDoubleTapFinished() {
+ if (DEBUG)
+ Log.d(TAG, "onDoubleTapFinished called with initTap = [$initTap]")
+
+ if (initTap) performListener?.onDoubleTabEnd()
+ initTap = false
+ }
+
+ 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
+ )
+ secondsView.start()
+ applyTo(rootConstraintLayout)
+ }
+ }
+
+ interface PerformListener {
+ fun onDoubleTabStart() {}
+ fun onDoubleTab()
+ fun onDoubleTabEnd()
+ fun shouldFastForward(portion: DisplayPortion): Boolean?
+ fun seek(forward: Boolean)
+ }
+
+ companion object {
+ private const val TAG = "PlayerSeekOverlay"
+ private val DEBUG = MainActivity.DEBUG
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/views/player/PlayerSeekOverlay.kt b/app/src/main/java/org/schabi/newpipe/views/player/PlayerSeekOverlay.kt
deleted file mode 100644
index d61989d92..000000000
--- a/app/src/main/java/org/schabi/newpipe/views/player/PlayerSeekOverlay.kt
+++ /dev/null
@@ -1,278 +0,0 @@
-package org.schabi.newpipe.views.player
-
-import android.content.Context
-import android.util.AttributeSet
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.View
-import androidx.annotation.ColorInt
-import androidx.annotation.ColorRes
-import androidx.annotation.DimenRes
-import androidx.annotation.DrawableRes
-import androidx.annotation.StyleRes
-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 androidx.core.content.ContextCompat
-import androidx.core.widget.TextViewCompat
-import androidx.preference.PreferenceManager
-import org.schabi.newpipe.MainActivity
-import org.schabi.newpipe.R
-import org.schabi.newpipe.player.event.DisplayPortion
-import org.schabi.newpipe.player.event.DoubleTapListener
-
-class PlayerSeekOverlay(context: Context, private val attrs: AttributeSet?) :
- ConstraintLayout(context, attrs), DoubleTapListener {
-
- private var secondsView: SecondsView
- private var circleClipTapView: CircleClipTapView
- private var rootConstraintLayout: ConstraintLayout
-
- private var isForwarding: Boolean? = null
-
- init {
- LayoutInflater.from(context).inflate(R.layout.player_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)
-
- initializeAttributes()
- secondsView.isForward = true
- isForwarding = null
- changeConstraints(true)
- }
-
- private fun initializeAttributes() {
- circleBackgroundColorInt(CircleClipTapView.COLOR_LIGHT_TRANSPARENT)
- iconAnimationDuration(SecondsView.ICON_ANIMATION_DURATION)
- icon(R.drawable.ic_play_seek_triangle)
-
- val prefs = PreferenceManager.getDefaultSharedPreferences(context)
- val durationKey = context.getString(R.string.seek_duration_key)
- val seekValue = prefs.getString(
- durationKey, context.getString(R.string.seek_duration_default_value)
- )
- seekSeconds(seekValue?.toInt()?.div(1000) ?: 10)
- }
-
- 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
- }
-
- var circleBackgroundColor: Int
- get() = circleClipTapView.circleBackgroundColor
- private set(value) {
- circleClipTapView.circleBackgroundColor = value
- }
-
- fun circleBackgroundColorRes(@ColorRes resId: Int) = apply {
- circleBackgroundColor = ContextCompat.getColor(context, resId)
- }
-
- fun circleBackgroundColorInt(@ColorInt color: Int) = apply {
- circleBackgroundColor = color
- }
-
- var arcSize: Float
- get() = circleClipTapView.arcSize
- internal set(value) {
- circleClipTapView.arcSize = value
- }
-
- fun arcSize(@DimenRes resId: Int) = apply {
- arcSize = context.resources.getDimension(resId)
- }
-
- fun arcSize(px: Float) = apply {
- arcSize = px
- }
-
- var showCircle: Boolean = true
- private set(value) {
- circleClipTapView.visibility = if (value) View.VISIBLE else View.GONE
- field = value
- }
-
- fun showCircle(show: Boolean) = apply {
- showCircle = show
- }
-
- var iconAnimationDuration: Long = SecondsView.ICON_ANIMATION_DURATION
- get() = secondsView.cycleDuration
- private set(value) {
- secondsView.cycleDuration = value
- field = value
- }
-
- fun iconAnimationDuration(duration: Long) = apply {
- iconAnimationDuration = duration
- }
-
- @DrawableRes
- var icon: Int = 0
- get() = secondsView.icon
- private set(value) {
- secondsView.stop()
- secondsView.icon = value
- field = value
- }
-
- fun icon(@DrawableRes resId: Int) = apply {
- icon = resId
- }
-
- @StyleRes
- var textAppearance: Int = 0
- private set(value) {
- TextViewCompat.setTextAppearance(secondsView.textView, value)
- field = value
- }
-
- fun textAppearance(@StyleRes resId: Int) = apply {
- textAppearance = resId
- }
-
- // 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
- performListener?.onPrepare()
-
- changeConstraints(secondsView.isForward)
- if (showCircle) circleClipTapView.updatePosition(portion)
-
- isForwarding = null
-
- if (this.alpha == 0f)
- secondsView.stop()
- }
-
- override fun onDoubleTapProgressDown(portion: DisplayPortion) {
- val shouldForward: Boolean = performListener?.shouldFastForward(portion) ?: return
-
- if (DEBUG)
- Log.d(
- TAG,
- "onDoubleTapProgressDown called with " +
- "shouldForward = [$shouldForward], " +
- "isForwarding = [$isForwarding], " +
- "secondsView#isForward = [${secondsView.isForward}], " +
- "initTap = [$initTap], "
- )
-
- // Using this check prevents from fast switching (one touches)
- if (isForwarding != null && isForwarding != shouldForward) {
- isForwarding = shouldForward
- return
- }
- isForwarding = shouldForward
-
- if (this.visibility != View.VISIBLE || !initTap) {
- if (!initTap) {
- secondsView.seconds = 0
- performListener?.onAnimationStart()
- secondsView.start()
- initTap = true
- }
- }
-
- if (shouldForward)
- forwarding()
- else
- rewinding()
- }
-
- override fun onDoubleTapFinished() {
- if (DEBUG)
- Log.d(TAG, "onDoubleTapFinished called with initTap = [$initTap]")
-
- if (initTap) performListener?.onAnimationEnd()
- initTap = false
- }
-
- private fun forwarding() {
- if (DEBUG)
- Log.d(TAG, "forwarding called")
-
- // First time tap or switched
- if (!secondsView.isForward) {
- changeConstraints(true)
- if (showCircle) circleClipTapView.updatePosition(DisplayPortion.RIGHT)
- secondsView.apply {
- isForward = true
- seconds = 0
- }
- }
- secondsView.seconds += seekSeconds
- performListener?.seek(forward = true)
- }
-
- private fun rewinding() {
- if (DEBUG)
- Log.d(TAG, "rewinding called")
-
- // First time tap or switched
- if (secondsView.isForward) {
- changeConstraints(false)
- if (showCircle) circleClipTapView.updatePosition(DisplayPortion.LEFT)
- secondsView.apply {
- isForward = false
- seconds = 0
- }
- }
- secondsView.seconds += seekSeconds
- performListener?.seek(forward = false)
- }
-
- private fun changeConstraints(forward: Boolean) {
- val constraintSet = ConstraintSet()
- with(constraintSet) {
- clone(rootConstraintLayout)
- if (forward) {
- clear(secondsView.id, START)
- connect(
- secondsView.id, END,
- PARENT_ID, END
- )
- } else {
- clear(secondsView.id, END)
- connect(
- secondsView.id, START,
- PARENT_ID, START
- )
- }
- secondsView.start()
- applyTo(rootConstraintLayout)
- }
- }
-
- interface PerformListener {
- fun onPrepare() {}
- fun onAnimationStart()
- fun onAnimationEnd()
- fun shouldFastForward(portion: DisplayPortion): Boolean?
- fun seek(forward: Boolean)
- }
-
- companion object {
- private const val TAG = "PlayerSeekOverlay"
- private val DEBUG = MainActivity.DEBUG
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/views/player/SecondsView.kt b/app/src/main/java/org/schabi/newpipe/views/player/SecondsView.kt
index 8574d607f..69dd09a07 100644
--- a/app/src/main/java/org/schabi/newpipe/views/player/SecondsView.kt
+++ b/app/src/main/java/org/schabi/newpipe/views/player/SecondsView.kt
@@ -6,10 +6,8 @@ import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.annotation.DrawableRes
import org.schabi.newpipe.R
-import org.schabi.newpipe.databinding.PlayerSeekSecondsViewBinding
+import org.schabi.newpipe.databinding.PlayerFastSeekSecondsViewBinding
class SecondsView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
@@ -35,33 +33,17 @@ class SecondsView(context: Context, attrs: AttributeSet?) : LinearLayout(context
field = value
}
- var isForward: Boolean = true
- set(value) {
- binding.triangleContainer.rotation = if (value) 0f else 180f
- field = value
- }
-
- val binding = PlayerSeekSecondsViewBinding.inflate(LayoutInflater.from(context), this)
-
- val textView: TextView
- get() = binding.tvSeconds
-
- @DrawableRes
- var icon: Int = R.drawable.ic_play_seek_triangle
- set(value) {
- if (value > 0) {
- binding.icon1.setImageResource(value)
- binding.icon2.setImageResource(value)
- binding.icon3.setImageResource(value)
- }
- field = value
- }
+ 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 start() {
stop()
firstAnimator.start()
diff --git a/app/src/main/res/layout-large-land/player.xml b/app/src/main/res/layout-large-land/player.xml
index 520c165cb..71a325cf3 100644
--- a/app/src/main/res/layout-large-land/player.xml
+++ b/app/src/main/res/layout-large-land/player.xml
@@ -647,24 +647,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
-
-
-
-
-
-
-
-
-
-
+ android:focusable="false" />