Fix media transitions, reduce code duplication between media fragments (#894)
* Fix media transitions, reduce code duplication between media fragments * Remove redundant helper * Fix occasional crash when swiping between mixed media * Hide controls when swiping between media
This commit is contained in:
parent
1792a14bb0
commit
4ba6b4adfe
4 changed files with 45 additions and 73 deletions
|
@ -20,18 +20,17 @@ import android.animation.AnimatorListenerAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.view.ViewCompat
|
import android.support.v4.view.ViewCompat
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
import com.github.chrisbanes.photoview.PhotoViewAttacher
|
import com.github.chrisbanes.photoview.PhotoViewAttacher
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.ViewMediaActivity
|
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.util.hide
|
import com.keylesspalace.tusky.util.hide
|
||||||
import com.keylesspalace.tusky.util.show
|
import com.keylesspalace.tusky.util.visible
|
||||||
import com.squareup.picasso.Callback
|
import com.squareup.picasso.Callback
|
||||||
import com.squareup.picasso.NetworkPolicy
|
import com.squareup.picasso.NetworkPolicy
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
@ -48,9 +47,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
private lateinit var attacher: PhotoViewAttacher
|
private lateinit var attacher: PhotoViewAttacher
|
||||||
private lateinit var photoActionsListener: PhotoActionsListener
|
private lateinit var photoActionsListener: PhotoActionsListener
|
||||||
private lateinit var toolbar: View
|
private lateinit var toolbar: View
|
||||||
|
override lateinit var descriptionView : TextView
|
||||||
private var showingDescription = false
|
|
||||||
private var isDescriptionVisible = false
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ViewImageFragment"
|
private const val TAG = "ViewImageFragment"
|
||||||
|
@ -62,6 +59,8 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupMediaView(url: String) {
|
override fun setupMediaView(url: String) {
|
||||||
|
descriptionView = mediaDescription
|
||||||
|
ViewCompat.setTransitionName(photoView, url)
|
||||||
attacher = PhotoViewAttacher(photoView)
|
attacher = PhotoViewAttacher(photoView)
|
||||||
|
|
||||||
// Clicking outside the photo closes the viewer.
|
// Clicking outside the photo closes the viewer.
|
||||||
|
@ -132,38 +131,21 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
val arguments = this.arguments!!
|
val arguments = this.arguments!!
|
||||||
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
||||||
val url: String?
|
val url: String?
|
||||||
|
var description : String? = null
|
||||||
|
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
url = attachment.url
|
url = attachment.url
|
||||||
|
description = attachment.description
|
||||||
val description = attachment.description
|
|
||||||
|
|
||||||
descriptionView.text = description
|
|
||||||
showingDescription = !TextUtils.isEmpty(description)
|
|
||||||
isDescriptionVisible = showingDescription
|
|
||||||
} else {
|
} else {
|
||||||
url = arguments.getString(ARG_AVATAR_URL)
|
url = arguments.getString(ARG_AVATAR_URL)
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw IllegalArgumentException("attachment or avatar url has to be set")
|
throw IllegalArgumentException("attachment or avatar url has to be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
showingDescription = false
|
|
||||||
isDescriptionVisible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting visibility without animations so it looks nice when you scroll images
|
finalizeViewSetup(url, description)
|
||||||
if (showingDescription && (activity as ViewMediaActivity).isToolbarVisible()) {
|
|
||||||
descriptionView.show()
|
|
||||||
} else {
|
|
||||||
descriptionView.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupMediaView(url)
|
|
||||||
|
|
||||||
setupToolbarVisibilityListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun onMediaTap() {
|
private fun onMediaTap() {
|
||||||
photoActionsListener.onPhotoTap()
|
photoActionsListener.onPhotoTap()
|
||||||
}
|
}
|
||||||
|
@ -177,11 +159,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
descriptionView.animate().alpha(alpha)
|
descriptionView.animate().alpha(alpha)
|
||||||
.setListener(object : AnimatorListenerAdapter() {
|
.setListener(object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
if (isDescriptionVisible) {
|
descriptionView.visible(isDescriptionVisible)
|
||||||
descriptionView.show()
|
|
||||||
} else {
|
|
||||||
descriptionView.hide()
|
|
||||||
}
|
|
||||||
animation.removeListener(this)
|
animation.removeListener(this)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -204,13 +182,13 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError() {
|
override fun onError() {
|
||||||
progressBar.hide()
|
progressBar?.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun finishLoadingSuccessfully() {
|
private fun finishLoadingSuccessfully() {
|
||||||
progressBar.hide()
|
progressBar?.hide()
|
||||||
attacher.update()
|
attacher.update()
|
||||||
photoActionsListener.onBringUp()
|
photoActionsListener.onBringUp()
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,22 @@
|
||||||
package com.keylesspalace.tusky.fragment
|
package com.keylesspalace.tusky.fragment
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
import com.keylesspalace.tusky.ViewMediaActivity
|
import com.keylesspalace.tusky.ViewMediaActivity
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
|
import com.keylesspalace.tusky.util.visible
|
||||||
|
|
||||||
abstract class ViewMediaFragment : BaseFragment() {
|
abstract class ViewMediaFragment : BaseFragment() {
|
||||||
private var toolbarVisibiltyDisposable: Function0<Boolean>? = null
|
private var toolbarVisibiltyDisposable: Function0<Boolean>? = null
|
||||||
|
|
||||||
abstract fun setupMediaView(url: String)
|
abstract fun setupMediaView(url: String)
|
||||||
abstract fun onToolbarVisibilityChange(visible: Boolean)
|
abstract fun onToolbarVisibilityChange(visible: Boolean)
|
||||||
|
abstract val descriptionView : TextView
|
||||||
|
|
||||||
|
protected var showingDescription = false
|
||||||
|
protected var isDescriptionVisible = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic protected val ARG_START_POSTPONED_TRANSITION = "startPostponedTransition"
|
@JvmStatic protected val ARG_START_POSTPONED_TRANSITION = "startPostponedTransition"
|
||||||
|
@ -60,7 +67,16 @@ abstract class ViewMediaFragment : BaseFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun setupToolbarVisibilityListener() {
|
protected fun finalizeViewSetup(url: String, description: String?) {
|
||||||
|
val mediaActivity = activity as ViewMediaActivity
|
||||||
|
setupMediaView(url)
|
||||||
|
|
||||||
|
descriptionView.text = description ?: ""
|
||||||
|
showingDescription = !TextUtils.isEmpty(description)
|
||||||
|
isDescriptionVisible = showingDescription
|
||||||
|
|
||||||
|
descriptionView.visible(showingDescription && mediaActivity.isToolbarVisible())
|
||||||
|
|
||||||
toolbarVisibiltyDisposable = (activity as ViewMediaActivity).addToolbarVisibilityListener(object: ViewMediaActivity.ToolbarVisibilityListener {
|
toolbarVisibiltyDisposable = (activity as ViewMediaActivity).addToolbarVisibilityListener(object: ViewMediaActivity.ToolbarVisibilityListener {
|
||||||
override fun onToolbarVisiblityChanged(isVisible: Boolean) {
|
override fun onToolbarVisiblityChanged(isVisible: Boolean) {
|
||||||
onToolbarVisibilityChange(isVisible)
|
onToolbarVisibilityChange(isVisible)
|
||||||
|
|
|
@ -22,17 +22,17 @@ import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.support.v4.view.ViewCompat
|
import android.support.v4.view.ViewCompat
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.MediaController
|
import android.widget.MediaController
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.ViewMediaActivity
|
import com.keylesspalace.tusky.ViewMediaActivity
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.util.hide
|
import com.keylesspalace.tusky.util.hide
|
||||||
import com.keylesspalace.tusky.util.show
|
import com.keylesspalace.tusky.util.visible
|
||||||
import kotlinx.android.synthetic.main.activity_view_media.*
|
import kotlinx.android.synthetic.main.activity_view_media.*
|
||||||
import kotlinx.android.synthetic.main.fragment_view_video.*
|
import kotlinx.android.synthetic.main.fragment_view_video.*
|
||||||
|
|
||||||
|
@ -46,9 +46,8 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
}
|
}
|
||||||
private lateinit var mediaActivity: ViewMediaActivity
|
private lateinit var mediaActivity: ViewMediaActivity
|
||||||
private val TOOLBAR_HIDE_DELAY_MS = 3000L
|
private val TOOLBAR_HIDE_DELAY_MS = 3000L
|
||||||
|
override lateinit var descriptionView : TextView
|
||||||
private var showingDescription = false
|
private lateinit var mediaController : MediaController
|
||||||
private var isDescriptionVisible = false
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ViewVideoFragment"
|
private const val TAG = "ViewVideoFragment"
|
||||||
|
@ -65,20 +64,23 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
if (mediaActivity.isToolbarVisible()) {
|
if (mediaActivity.isToolbarVisible()) {
|
||||||
handler.postDelayed(hideToolbar, TOOLBAR_HIDE_DELAY_MS)
|
handler.postDelayed(hideToolbar, TOOLBAR_HIDE_DELAY_MS)
|
||||||
}
|
}
|
||||||
videoPlayer?.start()
|
videoPlayer.start()
|
||||||
} else {
|
} else {
|
||||||
handler.removeCallbacks(hideToolbar)
|
handler.removeCallbacks(hideToolbar)
|
||||||
videoPlayer?.pause()
|
videoPlayer.pause()
|
||||||
|
mediaController.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun setupMediaView(url: String) {
|
override fun setupMediaView(url: String) {
|
||||||
|
descriptionView = mediaDescription
|
||||||
val videoView = videoPlayer
|
val videoView = videoPlayer
|
||||||
|
ViewCompat.setTransitionName(videoView, url)
|
||||||
videoView.setVideoPath(url)
|
videoView.setVideoPath(url)
|
||||||
val controller = MediaController(mediaActivity)
|
mediaController = MediaController(mediaActivity)
|
||||||
controller.setMediaPlayer(videoView)
|
mediaController.setMediaPlayer(videoPlayer)
|
||||||
videoView.setMediaController(controller)
|
videoPlayer.setMediaController(mediaController)
|
||||||
videoView.requestFocus()
|
videoView.requestFocus()
|
||||||
videoView.setOnTouchListener { _, _ ->
|
videoView.setOnTouchListener { _, _ ->
|
||||||
mediaActivity.onPhotoTap()
|
mediaActivity.onPhotoTap()
|
||||||
|
@ -110,34 +112,14 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val attachment = arguments?.getParcelable<Attachment>(ViewMediaFragment.ARG_ATTACHMENT)
|
||||||
val arguments = this.arguments!!
|
|
||||||
val attachment = arguments.getParcelable<Attachment>(ViewMediaFragment.ARG_ATTACHMENT)
|
|
||||||
val url: String
|
val url: String
|
||||||
|
|
||||||
if (attachment == null) {
|
if (attachment == null) {
|
||||||
throw IllegalArgumentException("attachment has to be set")
|
throw IllegalArgumentException("attachment has to be set")
|
||||||
}
|
}
|
||||||
url = attachment.url
|
url = attachment.url
|
||||||
val description = attachment.description
|
finalizeViewSetup(url, attachment.description)
|
||||||
mediaDescription.text = description
|
|
||||||
showingDescription = !TextUtils.isEmpty(description)
|
|
||||||
isDescriptionVisible = showingDescription
|
|
||||||
|
|
||||||
// Setting visibility without animations so it looks nice when you scroll media
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
if (showingDescription && mediaActivity.isToolbarVisible()) {
|
|
||||||
mediaDescription.show()
|
|
||||||
} else {
|
|
||||||
mediaDescription.hide()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewCompat.setTransitionName(videoPlayer!!, url)
|
|
||||||
|
|
||||||
setupMediaView(url)
|
|
||||||
|
|
||||||
setupToolbarVisibilityListener()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onToolbarVisibilityChange(visible: Boolean) {
|
override fun onToolbarVisibilityChange(visible: Boolean) {
|
||||||
|
@ -147,14 +129,10 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
|
|
||||||
isDescriptionVisible = showingDescription && visible
|
isDescriptionVisible = showingDescription && visible
|
||||||
val alpha = if (isDescriptionVisible) 1.0f else 0.0f
|
val alpha = if (isDescriptionVisible) 1.0f else 0.0f
|
||||||
mediaDescription.animate().alpha(alpha)
|
descriptionView.animate().alpha(alpha)
|
||||||
.setListener(object : AnimatorListenerAdapter() {
|
.setListener(object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
if (isDescriptionVisible) {
|
descriptionView.visible(isDescriptionVisible)
|
||||||
mediaDescription.show()
|
|
||||||
} else {
|
|
||||||
mediaDescription.hide()
|
|
||||||
}
|
|
||||||
animation.removeListener(this)
|
animation.removeListener(this)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/descriptionView"
|
android:id="@+id/mediaDescription"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue