diff --git a/app/src/main/kotlin/org/fossify/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/org/fossify/gallery/fragments/PhotoFragment.kt index c97d56290..f86ade9e1 100644 --- a/app/src/main/kotlin/org/fossify/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/org/fossify/gallery/fragments/PhotoFragment.kt @@ -1,10 +1,7 @@ package org.fossify.gallery.fragments 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.Drawable import android.graphics.drawable.PictureDrawable @@ -20,6 +17,7 @@ import android.view.ViewGroup import android.widget.RelativeLayout import androidx.exifinterface.media.ExifInterface.* import com.alexvasilkov.gestures.GestureController +import com.alexvasilkov.gestures.GravityUtils import com.alexvasilkov.gestures.State import com.bumptech.glide.Glide import com.bumptech.glide.Priority @@ -62,6 +60,7 @@ import pl.droidsonroids.gif.InputSource import java.io.File import java.io.FileOutputStream import java.util.Locale +import kotlin.math.abs import kotlin.math.ceil class PhotoFragment : ViewPagerFragment() { @@ -89,6 +88,8 @@ class PhotoFragment : ViewPagerFragment() { private var mScreenWidth = 0 private var mScreenHeight = 0 private var mCurrentGestureViewZoom = 1f + private var mIsTouched = false + private var mInitialZoom = 1f private var mStoredShowExtendedDetails = false private var mStoredHideExtendedDetails = false @@ -125,6 +126,8 @@ class PhotoFragment : ViewPagerFragment() { instantPrevItem.parentView = container instantNextItem.parentView = container + gesturesView.controller.settings.isRotationEnabled = true + photoBrightnessController.initialize(activity, slideInfo, true, container, singleTap = { x, y -> mView.apply { if (subsamplingView.isVisible()) { @@ -146,11 +149,26 @@ class PhotoFragment : ViewPagerFragment() { gesturesView.controller.addOnStateChangeListener(object : GestureController.OnStateChangeListener { override fun onStateChanged(state: State) { mCurrentGestureViewZoom = state.zoom + val rotation = normalizeAngle(state.rotation.toInt()) + if (!mIsTouched || (State.equals((state.rotation % 90.0F), 0.0F) && !State.equals( + rotation.toFloat(), + mCurrentRotationDegrees.toFloat() + )) + ) { + gesturesView.controller.settings.apply { + if (hasImageSize() && hasViewportSize()) { + mCurrentRotationDegrees = normalizeAngle(rotation) + val fitZoom = getFitZoom(mCurrentRotationDegrees) + mInitialZoom = fitZoom + } + } + } } }) gesturesView.setOnTouchListener { v, event -> - if (mCurrentGestureViewZoom == 1f) { + mIsTouched = true + if (abs(mCurrentGestureViewZoom - mInitialZoom) < MAX_ZOOM_EQUALITY_TOLERANCE) { handleEvent(event) } false @@ -829,7 +847,43 @@ class PhotoFragment : ViewPagerFragment() { mCurrentRotationDegrees = (mCurrentRotationDegrees + degrees) % 360 mLoadZoomableViewHandler.removeCallbacksAndMessages(null) mIsSubsamplingVisible = false - loadBitmap() + val path = getFilePathToShow() + if (path.isWebP()) { + rotateGestureView() + } else { + loadBitmap() + } + } + } + + private fun rotateGestureView() { + val state = binding.gesturesView.controller.state + binding.gesturesView.controller.settings.apply { + if (hasImageSize() && hasViewportSize()) { + val fitZoom = getFitZoom(mCurrentRotationDegrees) + val point = Point() + GravityUtils.getDefaultPivot(binding.gesturesView.controller.settings, point) + state.rotateTo(mCurrentRotationDegrees.toFloat(), point.x.toFloat(), point.y.toFloat()) + if (abs(mCurrentGestureViewZoom - mInitialZoom) < MAX_ZOOM_EQUALITY_TOLERANCE) { + state.zoomTo(fitZoom, point.x.toFloat(), point.y.toFloat()) + } + mInitialZoom = fitZoom + binding.gesturesView.controller.updateState() + } + } + } + + private fun getFitZoom(rotation: Int): Float { + binding.gesturesView.controller.settings.apply { + val fitZoom: Float + if (State.equals(rotation.toFloat(), 90F) || State.equals(rotation.toFloat(), 270F)) { + fitZoom = (viewportWidth.toFloat() / imageHeight).coerceAtMost(viewportHeight.toFloat() / imageWidth) + doubleTapZoom = (viewportWidth.toFloat() / imageHeight).coerceAtLeast(viewportHeight.toFloat() / imageWidth) + } else { + fitZoom = (viewportWidth.toFloat() / imageWidth).coerceAtMost(viewportHeight.toFloat() / imageHeight) + doubleTapZoom = (viewportWidth.toFloat() / imageWidth).coerceAtLeast(viewportHeight.toFloat() / imageHeight) + } + return fitZoom } } @@ -902,4 +956,8 @@ class PhotoFragment : ViewPagerFragment() { val actionsHeight = if (requireContext().config.bottomActions && !mIsFullscreen) resources.getDimension(R.dimen.bottom_actions_height) else 0f return requireContext().realScreenSize.y - height - actionsHeight - fullscreenOffset } + + fun normalizeAngle(angle: Int): Int { + return ((angle % 360) + 360) % 360 + } } diff --git a/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt index 70c03b259..ce16e644a 100644 --- a/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt @@ -134,6 +134,7 @@ const val SHOW_TEMP_HIDDEN_DURATION = 300000L const val CLICK_MAX_DURATION = 150 const val CLICK_MAX_DISTANCE = 100 const val MAX_CLOSE_DOWN_GESTURE_DURATION = 300 +const val MAX_ZOOM_EQUALITY_TOLERANCE = 0.01 const val DRAG_THRESHOLD = 8 const val MONTH_MILLISECONDS = MONTH_SECONDS * 1000L const val MIN_SKIP_LENGTH = 2000