diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt index b09da8cd0..0628708ee 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration import android.graphics.Color +import android.graphics.Matrix import android.graphics.Point import android.graphics.SurfaceTexture import android.graphics.drawable.ColorDrawable @@ -43,19 +44,28 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen private var mScreenWidth = 0 private var mCurrTime = 0 private var mDuration = 0 - private var mVideoSize = Point(0, 0) + private var mSaveScale = 1f + private var mRight = 0f + private var mBottom = 0f + private var mLastTouchX = 0f + private var mLastTouchY = 0f private var mDragThreshold = 0f - - private var mUri: Uri? = null - private var mExoPlayer: SimpleExoPlayer? = null - private var mTimerHandler = Handler() - private var mPlayWhenReadyHandler = Handler() - private var mTouchDownX = 0f private var mTouchDownY = 0f private var mTouchDownTime = 0L private var mProgressAtDown = 0L private var mCloseDownThreshold = 100f + private var mCurrZoomMode = ZOOM_MODE_NONE + + private var mUri: Uri? = null + private var mExoPlayer: SimpleExoPlayer? = null + private var mVideoSize = Point(0, 0) + private var mTimerHandler = Handler() + private var mPlayWhenReadyHandler = Handler() + private var mScaleDetector: ScaleGestureDetector? = null + private var mMatrices = FloatArray(9) + private val mMatrix = Matrix() + private var mIgnoreCloseDown = false public override fun onCreate(savedInstanceState: Bundle?) { @@ -176,7 +186,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } video_surface.setOnTouchListener { view, event -> - handleEvent(event) + handleEventWithZooming(event) true } @@ -185,11 +195,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen if (config.allowVideoGestures) { video_brightness_controller.initialize(this, slide_info, true, video_player_holder) { x, y -> - fullscreenToggled(!mIsFullscreen) + toggleFullscreen() } video_volume_controller.initialize(this, slide_info, false, video_player_holder) { x, y -> - fullscreenToggled(!mIsFullscreen) + toggleFullscreen() } } else { video_brightness_controller.beGone() @@ -199,10 +209,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen if (config.hideSystemUI) { Handler().postDelayed({ fullscreenToggled(true) - }, 500) + }, HIDE_SYSTEM_UI_DELAY) } mDragThreshold = DRAG_THRESHOLD * resources.displayMetrics.density + mScaleDetector = ScaleGestureDetector(applicationContext, ScaleListener()) } private fun initExoPlayer() { @@ -418,6 +429,10 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } } + private fun toggleFullscreen() { + fullscreenToggled(!mIsFullscreen) + } + private fun fullscreenToggled(isFullScreen: Boolean) { mIsFullscreen = isFullScreen if (isFullScreen) { @@ -541,7 +556,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } } else { if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) { - fullscreenToggled(!mIsFullscreen) + toggleFullscreen() } } mIsDragged = false @@ -616,6 +631,226 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen }.start() } - override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) { + override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {} + + private fun handleEventWithZooming(event: MotionEvent) { + mScaleDetector?.onTouchEvent(event) + + mMatrix.getValues(mMatrices) + val x = mMatrices[Matrix.MTRANS_X] + val y = mMatrices[Matrix.MTRANS_Y] + + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + mTouchDownTime = System.currentTimeMillis() + mCurrZoomMode = ZOOM_MODE_DRAG + mLastTouchX = event.x + mLastTouchY = event.y + + mTouchDownX = event.x + mTouchDownY = event.y + mProgressAtDown = mExoPlayer!!.currentPosition + } + MotionEvent.ACTION_UP -> { + mCurrZoomMode = ZOOM_MODE_NONE + val diffX = mTouchDownX - event.x + val diffY = mTouchDownY - event.y + + val downGestureDuration = System.currentTimeMillis() - mTouchDownTime + if (!mIgnoreCloseDown && Math.abs(diffY) > Math.abs(diffX) && diffY < -mCloseDownThreshold && downGestureDuration < MAX_CLOSE_DOWN_GESTURE_DURATION && mSaveScale == 1f) { + supportFinishAfterTransition() + } + mIgnoreCloseDown = false + + if (mIsDragged) { + if (mIsFullscreen) { + arrayOf(video_curr_time, video_seekbar, video_duration).forEach { + it.animate().alpha(0f).start() + } + } + + if (!mIsPlaying) { + togglePlayPause() + } + } else { + if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) { + toggleFullscreen() + } + } + + mIsDragged = false + } + MotionEvent.ACTION_POINTER_DOWN -> { + mLastTouchX = event.x + mLastTouchY = event.y + mCurrZoomMode = ZOOM_MODE_ZOOM + mIgnoreCloseDown = true + } + MotionEvent.ACTION_MOVE -> { + val diffX = event.x - mTouchDownX + val diffY = event.y - mTouchDownY + if (mSaveScale == 1f && (mIsDragged || (Math.abs(diffX) > mDragThreshold && Math.abs(diffX) > Math.abs(diffY)))) { + if (!mIsDragged) { + arrayOf(video_curr_time, video_seekbar, video_duration).forEach { + it.animate().alpha(1f).start() + } + } + mIgnoreCloseDown = true + mIsDragged = true + var percent = ((diffX / mScreenWidth) * 100).toInt() + percent = Math.min(100, Math.max(-100, percent)) + + val skipLength = (mDuration * 1000f) * (percent / 100f) + var newProgress = mProgressAtDown + skipLength + newProgress = Math.max(Math.min(mExoPlayer!!.duration.toFloat(), newProgress), 0f) + val newSeconds = (newProgress / 1000).toInt() + setPosition(newSeconds) + resetPlayWhenReady() + } else if (mCurrZoomMode == ZOOM_MODE_ZOOM || mCurrZoomMode == ZOOM_MODE_DRAG && mSaveScale > MIN_VIDEO_ZOOM_SCALE) { + var deltaX = event.x - mLastTouchX + var deltaY = event.y - mLastTouchY + if (y + deltaY > 0) { + deltaY = -y + } else if (y + deltaY < -mBottom) { + deltaY = -(y + mBottom) + } + + if (x + deltaX > 0) { + deltaX = -x + } else if (x + deltaX < -mRight) { + deltaX = -(x + mRight) + } + + mMatrix.postTranslate(deltaX, deltaY) + mLastTouchX = event.x + mLastTouchY = event.y + } + } + MotionEvent.ACTION_POINTER_UP -> { + mCurrZoomMode = ZOOM_MODE_NONE + } + } + + video_surface.setTransform(mMatrix) + video_surface.invalidate() + } + + private fun handleEventt(event: MotionEvent) { + when (event.actionMasked) { + MotionEvent.ACTION_MOVE -> { + val diffX = event.x - mTouchDownX + val diffY = event.y - mTouchDownY + + if (mIsDragged || (Math.abs(diffX) > mDragThreshold && Math.abs(diffX) > Math.abs(diffY))) { + if (!mIsDragged) { + arrayOf(video_curr_time, video_seekbar, video_duration).forEach { + it.animate().alpha(1f).start() + } + } + mIgnoreCloseDown = true + mIsDragged = true + var percent = ((diffX / mScreenWidth) * 100).toInt() + percent = Math.min(100, Math.max(-100, percent)) + + val skipLength = (mDuration * 1000f) * (percent / 100f) + var newProgress = mProgressAtDown + skipLength + newProgress = Math.max(Math.min(mExoPlayer!!.duration.toFloat(), newProgress), 0f) + val newSeconds = (newProgress / 1000).toInt() + setPosition(newSeconds) + resetPlayWhenReady() + } + } + MotionEvent.ACTION_UP -> { + val diffX = mTouchDownX - event.x + val diffY = mTouchDownY - event.y + + mIgnoreCloseDown = false + if (mIsDragged) { + if (mIsFullscreen) { + arrayOf(video_curr_time, video_seekbar, video_duration).forEach { + it.animate().alpha(0f).start() + } + } + + if (!mIsPlaying) { + togglePlayPause() + } + } else { + if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) { + toggleFullscreen() + } + } + mIsDragged = false + } + } + } + + // taken from https://github.com/Manuiq/ZoomableTextureView + private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() { + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { + mCurrZoomMode = ZOOM_MODE_ZOOM + return true + } + + override fun onScale(detector: ScaleGestureDetector): Boolean { + var scaleFactor = detector.scaleFactor + val width = video_surface.width + val height = video_surface.height + val origScale = mSaveScale + mSaveScale *= scaleFactor + + if (mSaveScale > MAX_VIDEO_ZOOM_SCALE) { + mSaveScale = MAX_VIDEO_ZOOM_SCALE + scaleFactor = MAX_VIDEO_ZOOM_SCALE / origScale + } else if (mSaveScale < MIN_VIDEO_ZOOM_SCALE) { + mSaveScale = MIN_VIDEO_ZOOM_SCALE + scaleFactor = MIN_VIDEO_ZOOM_SCALE / origScale + } + + mRight = width * mSaveScale - width + mBottom = video_surface.height * mSaveScale - height + if (0 <= width || 0 <= height) { + mMatrix.postScale(scaleFactor, scaleFactor, detector.focusX, detector.focusY) + if (scaleFactor < 1) { + mMatrix.getValues(mMatrices) + val x = mMatrices[Matrix.MTRANS_X] + val y = mMatrices[Matrix.MTRANS_Y] + if (scaleFactor < 1) { + if (0 < width) { + if (y < -mBottom) { + mMatrix.postTranslate(0f, -(y + mBottom)) + } else if (y > 0) { + mMatrix.postTranslate(0f, -y) + } + } else { + if (x < -mRight) { + mMatrix.postTranslate(-(x + mRight), 0f) + } else if (x > 0) { + mMatrix.postTranslate(-x, 0f) + } + } + } + } + } else { + mMatrix.postScale(scaleFactor, scaleFactor, detector.focusX, detector.focusY) + mMatrix.getValues(mMatrices) + val x = mMatrices[Matrix.MTRANS_X] + val y = mMatrices[Matrix.MTRANS_Y] + if (scaleFactor < 1) { + if (x < -mRight) { + mMatrix.postTranslate(-(x + mRight), 0f) + } else if (x > 0) { + mMatrix.postTranslate(-x, 0f) + } + + if (y < -mBottom) { + mMatrix.postTranslate(0f, -(y + mBottom)) + } else if (y > 0) { + mMatrix.postTranslate(0f, -y) + } + } + } + return true + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt index 3bef8201c..2100ea9ec 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt @@ -299,7 +299,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View view_pager.onGlobalLayout { Handler().postDelayed({ fragmentClicked() - }, 500) + }, HIDE_SYSTEM_UI_DELAY) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt index 3b3232b40..4005a52c8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt @@ -54,13 +54,13 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private var mBottom = 0f private var mLastTouchX = 0f private var mLastTouchY = 0f - private var mTouchDownTime = 0L + private var mCurrZoomMode = ZOOM_MODE_NONE private var mExoPlayer: SimpleExoPlayer? = null private var mVideoSize = Point(0, 0) private var mTimerHandler = Handler() private var mScaleDetector: ScaleGestureDetector? = null - private var mMatrices = floatArrayOf() + private var mMatrices = FloatArray(9) private val mMatrix = Matrix() private var mStoredShowExtendedDetails = false @@ -82,14 +82,9 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private lateinit var mPlayPauseButton: ImageView private lateinit var mSeekBar: SeekBar - private var mCurrZoomMode = ZOOM_MODE_NONE - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { mConfig = context!!.config - - mMatrices = FloatArray(9) mScaleDetector = ScaleGestureDetector(context, ScaleListener()) - mView = inflater.inflate(R.layout.pager_video_item, container, false).apply { instant_prev_item.setOnClickListener { listener?.goToPrevItem() } instant_next_item.setOnClickListener { listener?.goToNextItem() } @@ -746,21 +741,21 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } MotionEvent.ACTION_MOVE -> { if (mCurrZoomMode == ZOOM_MODE_ZOOM || mCurrZoomMode == ZOOM_MODE_DRAG && mSaveScale > MIN_VIDEO_ZOOM_SCALE) { - var deltaX = event.x - mLastTouchX - var deltaY = event.y - mLastTouchY - if (y + deltaY > 0) { - deltaY = -y - } else if (y + deltaY < -mBottom) { - deltaY = -(y + mBottom) + var diffX = event.x - mLastTouchX + var diffY = event.y - mLastTouchY + if (y + diffY > 0) { + diffY = -y + } else if (y + diffY < -mBottom) { + diffY = -(y + mBottom) } - if (x + deltaX > 0) { - deltaX = -x - } else if (x + deltaX < -mRight) { - deltaX = -(x + mRight) + if (x + diffX > 0) { + diffX = -x + } else if (x + diffX < -mRight) { + diffX = -(x + mRight) } - mMatrix.postTranslate(deltaX, deltaY) + mMatrix.postTranslate(diffX, diffY) mLastTouchX = event.x mLastTouchY = event.y } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/ViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/ViewPagerFragment.kt index 5153859ad..bee1b525b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/ViewPagerFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/ViewPagerFragment.kt @@ -13,6 +13,7 @@ import java.io.File abstract class ViewPagerFragment : Fragment() { var listener: FragmentListener? = null + protected var mTouchDownTime = 0L protected var mTouchDownX = 0f protected var mTouchDownY = 0f protected var mCloseDownThreshold = 100f @@ -98,6 +99,7 @@ abstract class ViewPagerFragment : Fragment() { protected fun handleEvent(event: MotionEvent) { when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { + mTouchDownTime = System.currentTimeMillis() mTouchDownX = event.x mTouchDownY = event.y } @@ -106,7 +108,8 @@ abstract class ViewPagerFragment : Fragment() { val diffX = mTouchDownX - event.x val diffY = mTouchDownY - event.y - if (!mIgnoreCloseDown && Math.abs(diffY) > Math.abs(diffX) && diffY < -mCloseDownThreshold) { + val downGestureDuration = System.currentTimeMillis() - mTouchDownTime + if (!mIgnoreCloseDown && Math.abs(diffY) > Math.abs(diffX) && diffY < -mCloseDownThreshold && downGestureDuration < MAX_CLOSE_DOWN_GESTURE_DURATION) { activity?.supportFinishAfterTransition() } mIgnoreCloseDown = false diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt index bb2b876ab..53714f1db 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt @@ -107,6 +107,7 @@ const val MAX_CLOSE_DOWN_GESTURE_DURATION = 400 const val DRAG_THRESHOLD = 8 const val MONTH_MILLISECONDS = MONTH_SECONDS * 1000L const val MIN_SKIP_LENGTH = 2000 +const val HIDE_SYSTEM_UI_DELAY = 500L const val DIRECTORY = "directory" const val MEDIUM = "medium"