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" />