diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt
index 867c54936..caf20f36e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt
@@ -2,10 +2,7 @@ package com.simplemobiletools.gallery.pro.fragments
import android.content.Intent
import android.content.res.Configuration
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.Color
-import android.graphics.Matrix
+import android.graphics.*
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.PictureDrawable
import android.media.ExifInterface.*
@@ -292,6 +289,7 @@ class PhotoFragment : ViewPagerFragment() {
}
private fun loadImage() {
+ checkScreenDimensions()
mImageOrientation = getImageOrientation()
when {
mMedium.isGIF() -> loadGif()
@@ -310,8 +308,11 @@ class PhotoFragment : ViewPagerFragment() {
}
mView.photo_view.beGone()
- mView.gif_view.beVisible()
- mView.gif_view.setInputSource(source)
+ val resolution = mMedium.path.getImageResolution() ?: Point(0, 0)
+ mView.gif_view.apply {
+ setInputSource(source)
+ setupSizes(resolution.x, resolution.y, mScreenWidth, mScreenHeight)
+ }
} catch (e: Exception) {
loadBitmap()
} catch (e: OutOfMemoryError) {
@@ -328,7 +329,6 @@ class PhotoFragment : ViewPagerFragment() {
}
private fun loadBitmap(degrees: Int = 0) {
- checkScreenDimensions()
var pathToLoad = if (mMedium.path.startsWith("content://")) mMedium.path else "file://${mMedium.path}"
pathToLoad = pathToLoad.replace("%", "%25").replace("#", "%23")
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/views/MyZoomableGifTextureView.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/views/MyZoomableGifTextureView.kt
new file mode 100644
index 000000000..5d2819909
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/views/MyZoomableGifTextureView.kt
@@ -0,0 +1,195 @@
+package com.simplemobiletools.gallery.pro.views
+
+import android.content.Context
+import android.graphics.Matrix
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.ScaleGestureDetector
+import android.widget.ImageView
+import com.simplemobiletools.commons.extensions.beVisible
+import com.simplemobiletools.gallery.pro.helpers.*
+import pl.droidsonroids.gif.GifTextureView
+
+// allow horizontal swipes through the layout, else it can cause glitches at zoomed in images
+class MyZoomableGifTextureView(context: Context, attrs: AttributeSet) : GifTextureView(context, attrs) {
+ private var mSaveScale = 1f
+ private var mRight = 0f
+ private var mBottom = 0f
+ private var mLastTouchX = 0f
+ private var mLastTouchY = 0f
+ private var mTouchDownTime = 0L
+ private var mTouchDownX = 0f
+ private var mTouchDownY = 0f
+ private var mGifWidth = 0f
+ private var mGifHeight = 0f
+ private var mScreenWidth = 0f
+ private var mScreenHeight = 0f
+ private var mLastFocusX = 0f
+ private var mLastFocusY = 0f
+ private var mCurrZoomMode = ZOOM_MODE_NONE
+
+ private var mScaleDetector: ScaleGestureDetector? = null
+ private var mMatrices = FloatArray(9)
+ private val mMatrix = Matrix()
+ private var mOrigRect = RectF()
+ private var mWantedRect = RectF()
+
+ init {
+ mScaleDetector = ScaleGestureDetector(context, ScaleListener())
+ }
+
+ fun setupSizes(gifWidth: Int, gifHeight: Int, screenWidth: Int, screenHeight: Int) {
+ // if we don't know the gifs' resolution, just display it and disable zooming
+ if (gifWidth == 0 || gifHeight == 0) {
+ scaleType = ImageView.ScaleType.FIT_CENTER
+ mScaleDetector = null
+ beVisible()
+ return
+ }
+
+ mGifWidth = gifWidth.toFloat()
+ mGifHeight = gifHeight.toFloat()
+ mScreenWidth = screenWidth.toFloat()
+ mScreenHeight = screenHeight.toFloat()
+
+ // we basically want scaleType fitCenter, but we have to use matrices to reach that
+ mOrigRect = RectF(0f, 0f, mGifWidth, mGifHeight)
+ mWantedRect = RectF(0f, 0f, mScreenWidth, mScreenHeight)
+ mMatrix.setRectToRect(mOrigRect, mWantedRect, Matrix.ScaleToFit.CENTER)
+ setTransform(mMatrix)
+ invalidate()
+ beVisible()
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ mScaleDetector?.onTouchEvent(event)
+
+ mMatrix.getValues(mMatrices)
+ mMatrix.setRectToRect(mOrigRect, mWantedRect, Matrix.ScaleToFit.CENTER)
+ mMatrix.postScale(mSaveScale, mSaveScale, mLastFocusX, mLastFocusY)
+
+ 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
+ }
+ MotionEvent.ACTION_UP -> {
+ mCurrZoomMode = ZOOM_MODE_NONE
+ if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) {
+ performClick()
+ }
+ }
+ MotionEvent.ACTION_POINTER_DOWN -> {
+ mLastTouchX = event.x
+ mLastTouchY = event.y
+ mCurrZoomMode = ZOOM_MODE_ZOOM
+ }
+ MotionEvent.ACTION_MOVE -> {
+ if (mCurrZoomMode == ZOOM_MODE_ZOOM || mCurrZoomMode == ZOOM_MODE_DRAG && mSaveScale > MIN_VIDEO_ZOOM_SCALE) {
+ 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 + diffX > 0) {
+ diffX = -x
+ } else if (x + diffX < -mRight) {
+ diffX = -(x + mRight)
+ }
+
+ mMatrix.postTranslate(diffX, diffY)
+ mLastTouchX = event.x
+ mLastTouchY = event.y
+ }
+ }
+ MotionEvent.ACTION_POINTER_UP -> {
+ mCurrZoomMode = ZOOM_MODE_NONE
+ }
+ }
+
+ setTransform(mMatrix)
+ invalidate()
+ return true
+ }
+
+ // 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 {
+ mLastFocusX = detector.focusX
+ mLastFocusY = detector.focusY
+ var scaleFactor = detector.scaleFactor
+ 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 = 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/res/layout/pager_photo_item.xml b/app/src/main/res/layout/pager_photo_item.xml
index 46ed641d6..bc3ec30e8 100644
--- a/app/src/main/res/layout/pager_photo_item.xml
+++ b/app/src/main/res/layout/pager_photo_item.xml
@@ -11,10 +11,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
-