mirror of
https://github.com/FossifyOrg/Gallery.git
synced 2025-03-11 14:10:06 +01:00
Auto rotation enabled and manual rotation with fit zoom
This commit is contained in:
parent
95ff9f4eef
commit
db81f78a5a
2 changed files with 61 additions and 11 deletions
|
@ -1,10 +1,7 @@
|
||||||
package org.fossify.gallery.fragments
|
package org.fossify.gallery.fragments
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Bitmap
|
import android.graphics.*
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.Matrix
|
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.PictureDrawable
|
import android.graphics.drawable.PictureDrawable
|
||||||
|
@ -13,6 +10,7 @@ import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -20,6 +18,7 @@ import android.view.ViewGroup
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.exifinterface.media.ExifInterface.*
|
import androidx.exifinterface.media.ExifInterface.*
|
||||||
import com.alexvasilkov.gestures.GestureController
|
import com.alexvasilkov.gestures.GestureController
|
||||||
|
import com.alexvasilkov.gestures.GravityUtils
|
||||||
import com.alexvasilkov.gestures.State
|
import com.alexvasilkov.gestures.State
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.Priority
|
import com.bumptech.glide.Priority
|
||||||
|
@ -43,6 +42,7 @@ import it.sephiroth.android.library.exif2.ExifInterface
|
||||||
import org.apache.sanselan.common.byteSources.ByteSourceInputStream
|
import org.apache.sanselan.common.byteSources.ByteSourceInputStream
|
||||||
import org.apache.sanselan.formats.jpeg.JpegImageParser
|
import org.apache.sanselan.formats.jpeg.JpegImageParser
|
||||||
import org.fossify.commons.activities.BaseSimpleActivity
|
import org.fossify.commons.activities.BaseSimpleActivity
|
||||||
|
import org.fossify.commons.compose.theme.md_blue
|
||||||
import org.fossify.commons.extensions.*
|
import org.fossify.commons.extensions.*
|
||||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||||
import org.fossify.commons.helpers.isRPlus
|
import org.fossify.commons.helpers.isRPlus
|
||||||
|
@ -62,6 +62,7 @@ import pl.droidsonroids.gif.InputSource
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class PhotoFragment : ViewPagerFragment() {
|
class PhotoFragment : ViewPagerFragment() {
|
||||||
|
@ -90,6 +91,7 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
private var mScreenHeight = 0
|
private var mScreenHeight = 0
|
||||||
private var mCurrentGestureViewZoom = 1f
|
private var mCurrentGestureViewZoom = 1f
|
||||||
private var mIsTouched = false
|
private var mIsTouched = false
|
||||||
|
private var mInitialZoom = 1f
|
||||||
|
|
||||||
private var mStoredShowExtendedDetails = false
|
private var mStoredShowExtendedDetails = false
|
||||||
private var mStoredHideExtendedDetails = false
|
private var mStoredHideExtendedDetails = false
|
||||||
|
@ -126,6 +128,8 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
instantPrevItem.parentView = container
|
instantPrevItem.parentView = container
|
||||||
instantNextItem.parentView = container
|
instantNextItem.parentView = container
|
||||||
|
|
||||||
|
gesturesView.controller.settings.isRotationEnabled = true
|
||||||
|
|
||||||
photoBrightnessController.initialize(activity, slideInfo, true, container, singleTap = { x, y ->
|
photoBrightnessController.initialize(activity, slideInfo, true, container, singleTap = { x, y ->
|
||||||
mView.apply {
|
mView.apply {
|
||||||
if (subsamplingView.isVisible()) {
|
if (subsamplingView.isVisible()) {
|
||||||
|
@ -146,21 +150,27 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
|
|
||||||
gesturesView.controller.addOnStateChangeListener(object : GestureController.OnStateChangeListener {
|
gesturesView.controller.addOnStateChangeListener(object : GestureController.OnStateChangeListener {
|
||||||
override fun onStateChanged(state: State) {
|
override fun onStateChanged(state: State) {
|
||||||
if (!mIsTouched) {
|
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 {
|
gesturesView.controller.settings.apply {
|
||||||
if (hasImageSize() && hasViewportSize()) {
|
if (hasImageSize() && hasViewportSize()) {
|
||||||
doubleTapZoom = (viewportWidth.toFloat() / imageWidth).coerceAtLeast(viewportHeight.toFloat() / imageHeight)
|
mCurrentRotationDegrees = normalizeAngle(rotation)
|
||||||
|
val fitZoom = getFitZoom(mCurrentRotationDegrees)
|
||||||
|
mInitialZoom = fitZoom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
mCurrentGestureViewZoom = state.zoom
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
gesturesView.setOnTouchListener { v, event ->
|
gesturesView.setOnTouchListener { v, event ->
|
||||||
mIsTouched = true
|
mIsTouched = true
|
||||||
if (mCurrentGestureViewZoom == 1f) {
|
if (abs(mCurrentGestureViewZoom - mInitialZoom) < MAX_ZOOM_EQUALITY_TOLERANCE) {
|
||||||
handleEvent(event)
|
handleEvent(event)
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -837,10 +847,45 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
binding.subsamplingView.rotateBy(degrees)
|
binding.subsamplingView.rotateBy(degrees)
|
||||||
} else {
|
} else {
|
||||||
mCurrentRotationDegrees = (mCurrentRotationDegrees + degrees) % 360
|
mCurrentRotationDegrees = (mCurrentRotationDegrees + degrees) % 360
|
||||||
binding.gesturesView.controller.state.rotateTo(mCurrentRotationDegrees.toFloat(), 0f, 0f)
|
|
||||||
mLoadZoomableViewHandler.removeCallbacksAndMessages(null)
|
mLoadZoomableViewHandler.removeCallbacksAndMessages(null)
|
||||||
mIsSubsamplingVisible = false
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,4 +958,8 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
val actionsHeight = if (requireContext().config.bottomActions && !mIsFullscreen) resources.getDimension(R.dimen.bottom_actions_height) else 0f
|
val actionsHeight = if (requireContext().config.bottomActions && !mIsFullscreen) resources.getDimension(R.dimen.bottom_actions_height) else 0f
|
||||||
return requireContext().realScreenSize.y - height - actionsHeight - fullscreenOffset
|
return requireContext().realScreenSize.y - height - actionsHeight - fullscreenOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun normalizeAngle(angle: Int): Int {
|
||||||
|
return ((angle % 360) + 360) % 360
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ const val SHOW_TEMP_HIDDEN_DURATION = 300000L
|
||||||
const val CLICK_MAX_DURATION = 150
|
const val CLICK_MAX_DURATION = 150
|
||||||
const val CLICK_MAX_DISTANCE = 100
|
const val CLICK_MAX_DISTANCE = 100
|
||||||
const val MAX_CLOSE_DOWN_GESTURE_DURATION = 300
|
const val MAX_CLOSE_DOWN_GESTURE_DURATION = 300
|
||||||
|
const val MAX_ZOOM_EQUALITY_TOLERANCE = 0.01
|
||||||
const val DRAG_THRESHOLD = 8
|
const val DRAG_THRESHOLD = 8
|
||||||
const val MONTH_MILLISECONDS = MONTH_SECONDS * 1000L
|
const val MONTH_MILLISECONDS = MONTH_SECONDS * 1000L
|
||||||
const val MIN_SKIP_LENGTH = 2000
|
const val MIN_SKIP_LENGTH = 2000
|
||||||
|
|
Loading…
Add table
Reference in a new issue