Merge pull request #2072 from Bnyro/zoom-fullscreen

Pinch to zoom
This commit is contained in:
Bnyro 2022-11-26 15:11:11 +01:00 committed by GitHub
commit 7289fad18f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 10 deletions

View File

@ -15,4 +15,8 @@ interface PlayerGestureOptions {
fun onSwipeRightScreen(distanceY: Float) fun onSwipeRightScreen(distanceY: Float)
fun onSwipeEnd() fun onSwipeEnd()
fun onZoom()
fun onMinimize()
} }

View File

@ -492,4 +492,12 @@ internal class CustomExoPlayerView(
gestureViewBinding.brightnessControlView.visibility = View.GONE gestureViewBinding.brightnessControlView.visibility = View.GONE
gestureViewBinding.volumeControlView.visibility = View.GONE gestureViewBinding.volumeControlView.visibility = View.GONE
} }
override fun onZoom() {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
}
override fun onMinimize() {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
}
} }

View File

@ -9,11 +9,12 @@ import android.os.Looper
import android.os.SystemClock import android.os.SystemClock
import android.view.GestureDetector import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View import android.view.View
import com.github.libretube.ui.interfaces.PlayerGestureOptions import com.github.libretube.ui.interfaces.PlayerGestureOptions
import kotlin.math.abs import kotlin.math.abs
class PlayerGestureController(context: Context, private val listner: PlayerGestureOptions) : class PlayerGestureController(context: Context, private val listener: PlayerGestureOptions) :
View.OnTouchListener { View.OnTouchListener {
// width and height should be obtained each time using getter to adopt layout size changes. // 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 handler: Handler = Handler(Looper.getMainLooper())
private val gestureDetector: GestureDetector private val gestureDetector: GestureDetector
private val scaleGestureDetector: ScaleGestureDetector
private var isMoving = false private var isMoving = false
var isEnabled = true var isEnabled = true
init { init {
gestureDetector = GestureDetector(context, GestureListener(), handler) gestureDetector = GestureDetector(context, GestureListener(), handler)
scaleGestureDetector = ScaleGestureDetector(context, ScaleGestureListener(), handler)
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean { override fun onTouch(v: View, event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_UP && isMoving) { if (event.action == MotionEvent.ACTION_UP && isMoving) {
isMoving = false isMoving = false
listner.onSwipeEnd() listener.onSwipeEnd()
} }
// Event can be already consumed by some view which may lead to NPE. // Event can be already consumed by some view which may lead to NPE.
try { try {
scaleGestureDetector.onTouchEvent(event)
gestureDetector.onTouchEvent(event) gestureDetector.onTouchEvent(event)
} catch (_: Exception) { } } catch (_: Exception) { }
@ -47,13 +51,34 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu
return orientation == Configuration.ORIENTATION_LANDSCAPE 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 inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
private var lastClick = 0L private var lastClick = 0L
private var lastDoubleClick = 0L private var lastDoubleClick = 0L
private var xPos = 0.0F private var xPos = 0.0F
override fun onDown(e: MotionEvent): Boolean { override fun onDown(e: MotionEvent): Boolean {
if (isMoving) return false if (isMoving || scaleGestureDetector.isInProgress) return false
if (isEnabled && isSecondClick()) { if (isEnabled && isSecondClick()) {
handler.removeCallbacks(runnable) handler.removeCallbacks(runnable)
@ -61,9 +86,9 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu
val eventPositionPercentageX = xPos / width val eventPositionPercentageX = xPos / width
when { when {
eventPositionPercentageX < 0.4 -> listner.onDoubleTapLeftScreen() eventPositionPercentageX < 0.4 -> listener.onDoubleTapLeftScreen()
eventPositionPercentageX > 0.6 -> listner.onDoubleTapRightScreen() eventPositionPercentageX > 0.6 -> listener.onDoubleTapRightScreen()
else -> listner.onDoubleTapCenterScreen() else -> listener.onDoubleTapCenterScreen()
} }
} else { } else {
if (recentDoubleClick()) return true if (recentDoubleClick()) return true
@ -81,7 +106,7 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu
distanceX: Float, distanceX: Float,
distanceY: Float distanceY: Float
): Boolean { ): Boolean {
if (!isEnabled) return false if (!isEnabled || scaleGestureDetector.isInProgress) return false
val insideThreshHold = abs(e2.y - e1.y) <= MOVEMENT_THRESHOLD 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) 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 isMoving = true
when { when {
width * 0.5 > e1.x -> listner.onSwipeLeftScreen(distanceY) width * 0.5 > e1.x -> listener.onSwipeLeftScreen(distanceY)
width * 0.5 < e1.x -> listner.onSwipeRightScreen(distanceY) width * 0.5 < e1.x -> listener.onSwipeRightScreen(distanceY)
} }
return true return true
} }
@ -110,7 +135,7 @@ class PlayerGestureController(context: Context, private val listner: PlayerGestu
private val runnable = Runnable { private val runnable = Runnable {
// If user is scrolling then avoid single tap call // If user is scrolling then avoid single tap call
if (isMoving || isSecondClick()) return@Runnable if (isMoving || isSecondClick()) return@Runnable
listner.onSingleTap() listener.onSingleTap()
} }
private fun isSecondClick(): Boolean { private fun isSecondClick(): Boolean {