diff --git a/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt index ee6e60dd1..81602351a 100644 --- a/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt +++ b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt @@ -15,4 +15,8 @@ interface PlayerGestureOptions { fun onSwipeRightScreen(distanceY: Float) fun onSwipeEnd() + + fun onZoom() + + fun onMinimize() } diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index ccb198f29..9b4ece133 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -492,4 +492,12 @@ internal class CustomExoPlayerView( gestureViewBinding.brightnessControlView.visibility = View.GONE gestureViewBinding.volumeControlView.visibility = View.GONE } + + override fun onZoom() { + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM + } + + override fun onMinimize() { + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + } } diff --git a/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt index d647306b8..13ee55791 100644 --- a/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt +++ b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt @@ -9,11 +9,12 @@ import android.os.Looper import android.os.SystemClock import android.view.GestureDetector import android.view.MotionEvent +import android.view.ScaleGestureDetector import android.view.View import com.github.libretube.ui.interfaces.PlayerGestureOptions import kotlin.math.abs -class PlayerGestureController(context: Context, private val listner: PlayerGestureOptions) : +class PlayerGestureController(context: Context, private val listener: PlayerGestureOptions) : View.OnTouchListener { // width and height should be obtained each time using getter to adopt layout size changes. @@ -24,22 +25,25 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu private val handler: Handler = Handler(Looper.getMainLooper()) private val gestureDetector: GestureDetector + private val scaleGestureDetector: ScaleGestureDetector private var isMoving = false var isEnabled = true init { gestureDetector = GestureDetector(context, GestureListener(), handler) + scaleGestureDetector = ScaleGestureDetector(context, ScaleGestureListener(), handler) } @SuppressLint("ClickableViewAccessibility") override fun onTouch(v: View, event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_UP && isMoving) { isMoving = false - listner.onSwipeEnd() + listener.onSwipeEnd() } // Event can be already consumed by some view which may lead to NPE. try { + scaleGestureDetector.onTouchEvent(event) gestureDetector.onTouchEvent(event) } catch (_: Exception) { } @@ -47,13 +51,34 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu return orientation == Configuration.ORIENTATION_LANDSCAPE } + private inner class ScaleGestureListener : ScaleGestureDetector.OnScaleGestureListener { + var scaleFactor: Float = 1f + + override fun onScale(detector: ScaleGestureDetector): Boolean { + scaleFactor *= detector.scaleFactor + return true + } + + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { + return true + } + + override fun onScaleEnd(detector: ScaleGestureDetector) { + when { + scaleFactor < 0.8 -> listener.onMinimize() + scaleFactor > 1.2 -> listener.onZoom() + } + scaleFactor = 1f + } + } + private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { private var lastClick = 0L private var lastDoubleClick = 0L private var xPos = 0.0F override fun onDown(e: MotionEvent): Boolean { - if (isMoving) return false + if (isMoving || scaleGestureDetector.isInProgress) return false if (isEnabled && isSecondClick()) { handler.removeCallbacks(runnable) @@ -61,9 +86,9 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu val eventPositionPercentageX = xPos / width when { - eventPositionPercentageX < 0.4 -> listner.onDoubleTapLeftScreen() - eventPositionPercentageX > 0.6 -> listner.onDoubleTapRightScreen() - else -> listner.onDoubleTapCenterScreen() + eventPositionPercentageX < 0.4 -> listener.onDoubleTapLeftScreen() + eventPositionPercentageX > 0.6 -> listener.onDoubleTapRightScreen() + else -> listener.onDoubleTapCenterScreen() } } else { if (recentDoubleClick()) return true @@ -81,7 +106,7 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu distanceX: Float, distanceY: Float ): Boolean { - if (!isEnabled) return false + if (!isEnabled || scaleGestureDetector.isInProgress) return false val insideThreshHold = abs(e2.y - e1.y) <= MOVEMENT_THRESHOLD val insideBorder = (e1.x < BORDER_THRESHOLD || e1.y < BORDER_THRESHOLD || e1.x > width - BORDER_THRESHOLD || e1.y > height - BORDER_THRESHOLD) @@ -101,8 +126,8 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu isMoving = true when { - width * 0.5 > e1.x -> listner.onSwipeLeftScreen(distanceY) - width * 0.5 < e1.x -> listner.onSwipeRightScreen(distanceY) + width * 0.5 > e1.x -> listener.onSwipeLeftScreen(distanceY) + width * 0.5 < e1.x -> listener.onSwipeRightScreen(distanceY) } return true } @@ -110,7 +135,7 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu private val runnable = Runnable { // If user is scrolling then avoid single tap call if (isMoving || isSecondClick()) return@Runnable - listner.onSingleTap() + listener.onSingleTap() } private fun isSecondClick(): Boolean {