ViewImageFragment: finalize transition to BigImageViewer. Now it should correctly handle EXIF rotation, do not stuck at transition and pick preview image if it's in cache but full image isn't
This commit is contained in:
parent
08780eade8
commit
1e26196e9e
|
@ -25,11 +25,15 @@ import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.DataSource
|
import com.bumptech.glide.load.DataSource
|
||||||
import com.bumptech.glide.load.engine.GlideException
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
import com.bumptech.glide.request.RequestListener
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.target.Target
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.github.piasy.biv.BigImageViewer
|
||||||
import com.github.piasy.biv.loader.ImageLoader
|
import com.github.piasy.biv.loader.ImageLoader
|
||||||
import com.github.piasy.biv.view.GlideImageViewFactory
|
import com.github.piasy.biv.view.GlideImageViewFactory
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
|
@ -42,9 +46,10 @@ import kotlinx.android.synthetic.main.fragment_view_image.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
|
|
||||||
|
|
||||||
class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouchListener {
|
class ViewImageFragment : ViewMediaFragment() {
|
||||||
interface PhotoActionsListener {
|
interface PhotoActionsListener {
|
||||||
fun onBringUp()
|
fun onBringUp()
|
||||||
fun onDismiss()
|
fun onDismiss()
|
||||||
|
@ -60,6 +65,10 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
@Volatile
|
@Volatile
|
||||||
private var startedTransition = false
|
private var startedTransition = false
|
||||||
|
|
||||||
|
private var uri = Uri.EMPTY
|
||||||
|
private var previewUri = Uri.EMPTY
|
||||||
|
private var showingPreview = false
|
||||||
|
|
||||||
override lateinit var descriptionView: TextView
|
override lateinit var descriptionView: TextView
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
|
@ -70,7 +79,11 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
descriptionView = mediaDescription
|
descriptionView = mediaDescription
|
||||||
photoView.transitionName = url
|
photoView.transitionName = url
|
||||||
startedTransition = false
|
startedTransition = false
|
||||||
loadImageFromNetwork(url, previewUrl)
|
uri = Uri.parse(url)
|
||||||
|
if(previewUrl != null && !previewUrl.equals(url)) {
|
||||||
|
previewUri = Uri.parse(previewUrl)
|
||||||
|
}
|
||||||
|
loadImageFromNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
@ -78,9 +91,11 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
return inflater.inflate(R.layout.fragment_view_image, container, false)
|
return inflater.inflate(R.layout.fragment_view_image, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var gestureDetector : GestureDetector
|
||||||
|
|
||||||
|
private val imageOnTouchListener = object : View.OnTouchListener {
|
||||||
private var lastY = 0.0f
|
private var lastY = 0.0f
|
||||||
private var swipeStartedWithOneFinger = false
|
private var swipeStartedWithOneFinger = false
|
||||||
private lateinit var gestureDetector : GestureDetector
|
|
||||||
|
|
||||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||||
// This part is for scaling/translating on vertical move.
|
// This part is for scaling/translating on vertical move.
|
||||||
|
@ -92,8 +107,6 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = false
|
|
||||||
|
|
||||||
when(event.action) {
|
when(event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
swipeStartedWithOneFinger = true
|
swipeStartedWithOneFinger = true
|
||||||
|
@ -115,13 +128,14 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
photoView.scaleX = scale
|
photoView.scaleX = scale
|
||||||
lastY = event.rawY
|
lastY = event.rawY
|
||||||
}
|
}
|
||||||
result = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -135,7 +149,7 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
})
|
})
|
||||||
|
|
||||||
// photoView.setOnTouchListener(this)
|
// photoView.setOnTouchListener(this)
|
||||||
photoView.setImageLoaderCallback(this)
|
photoView.setImageLoaderCallback(imageLoaderCallback)
|
||||||
photoView.setImageViewFactory(GlideImageViewFactory())
|
photoView.setImageViewFactory(GlideImageViewFactory())
|
||||||
|
|
||||||
val arguments = this.requireArguments()
|
val arguments = this.requireArguments()
|
||||||
|
@ -190,33 +204,88 @@ class ViewImageFragment : ViewMediaFragment(), ImageLoader.Callback, View.OnTouc
|
||||||
photoView.ssiv?.recycle()
|
photoView.ssiv?.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadImageFromNetwork(url: String, previewUrl: String?) {
|
private inner class DummyCacheTarget(val ctx: Context, val requestPreview : Boolean) : CustomTarget<File>() {
|
||||||
photoView.showImage(Uri.parse(previewUrl), Uri.parse(url))
|
override fun onLoadCleared(placeholder: Drawable?) {}
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
if(requestPreview) {
|
||||||
|
// no preview, no full image in cache, load full image
|
||||||
|
// forget about fancy transition
|
||||||
|
showingPreview = false
|
||||||
|
photoView.showImage(uri)
|
||||||
|
} else {
|
||||||
|
// let's start downloading full image that we supposedly don't have
|
||||||
|
BigImageViewer.prefetch(uri)
|
||||||
|
|
||||||
|
// meanwhile poke cache about preview image
|
||||||
|
Glide.with(ctx).asFile()
|
||||||
|
.load(previewUri)
|
||||||
|
.dontAnimate()
|
||||||
|
.onlyRetrieveFromCache(true)
|
||||||
|
.into(DummyCacheTarget(ctx, true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(resource: File, transition: Transition<in File>?) {
|
||||||
|
showingPreview = requestPreview
|
||||||
|
if(requestPreview) {
|
||||||
|
// have preview cached but not full image
|
||||||
|
photoView.showImage(previewUri, uri, true)
|
||||||
|
} else {
|
||||||
|
photoView.showImage(uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadImageFromNetwork() {
|
||||||
|
Glide.with(this).asFile()
|
||||||
|
.load(uri)
|
||||||
|
.onlyRetrieveFromCache(true)
|
||||||
|
.dontAnimate()
|
||||||
|
.into(DummyCacheTarget(context!!, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionEnd() {
|
||||||
|
// if we had preview, load full image, as transition has ended
|
||||||
|
if (showingPreview) {
|
||||||
|
showingPreview = false
|
||||||
|
photoView.loadMainImageNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val imageLoaderCallback = object : ImageLoader.Callback {
|
||||||
override fun onSuccess(image: File?) {
|
override fun onSuccess(image: File?) {
|
||||||
progressBar?.hide() // Always hide the progress bar on success
|
if(!showingPreview) {
|
||||||
photoActionsListener.onBringUp()
|
progressBar?.hide()
|
||||||
photoView.ssiv?.setOnTouchListener(this)
|
photoView.ssiv?.let {
|
||||||
|
it.orientation = SubsamplingScaleImageView.ORIENTATION_USE_EXIF
|
||||||
|
it.setOnTouchListener(imageOnTouchListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFail(error: Exception?) {
|
override fun onFail(error: Exception?) {
|
||||||
progressBar?.hide()
|
progressBar?.hide()
|
||||||
photoActionsListener.onBringUp()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCacheHit(imageType: Int, image: File?) {
|
override fun onCacheHit(imageType: Int, image: File?) {
|
||||||
|
// image is here, bring up the activity!
|
||||||
|
photoActionsListener.onBringUp()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
// cache miss but image is downloading, bring up the activity
|
||||||
|
photoActionsListener.onBringUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCacheMiss(imageType: Int, image: File?) {
|
override fun onCacheMiss(imageType: Int, image: File?) {
|
||||||
|
// this callback is useless because it's called after
|
||||||
|
// image is downloaded or pulled from cache
|
||||||
|
// so in case of cache miss, onStart is used
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish() {
|
override fun onFinish() {}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProgress(progress: Int) {
|
override fun onProgress(progress: Int) {
|
||||||
}
|
// TODO: make use of it :)
|
||||||
|
}
|
||||||
override fun onTransitionEnd() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue