Improve spoiler performance by stopping animation when backgrounded.

This commit is contained in:
Cody Henthorne
2023-06-12 13:11:15 -04:00
committed by GitHub
parent 7e24252447
commit 36aa8623da
2 changed files with 39 additions and 2 deletions

View File

@@ -10,19 +10,26 @@ import android.view.View.OnAttachStateChangeListener
import android.view.animation.LinearInterpolator
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.spoiler.SpoilerAnnotation.SpoilerClickableSpan
import org.thoughtcrime.securesms.util.getLifecycle
/**
* Performs initial calculation on how to render spoilers and then delegates to actually drawing the spoiler sparkles.
*/
class SpoilerRendererDelegate @JvmOverloads constructor(private val view: TextView, private val renderForComposing: Boolean = false) {
class SpoilerRendererDelegate @JvmOverloads constructor(
private val view: TextView,
private val renderForComposing: Boolean = false
) {
private val renderer: SpoilerRenderer
private val spoilerDrawable: SpoilerDrawable
private var animatorRunning = false
private var textColor: Int
private var canAnimate = false
private val cachedAnnotations = HashMap<Int, Map<Annotation, SpoilerClickableSpan?>>()
private val cachedMeasurements = HashMap<Int, SpanMeasurements>()
@@ -50,7 +57,18 @@ class SpoilerRendererDelegate @JvmOverloads constructor(private val view: TextVi
view.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
override fun onViewDetachedFromWindow(v: View) = stopAnimating()
override fun onViewAttachedToWindow(v: View) = Unit
override fun onViewAttachedToWindow(v: View) {
view.getLifecycle().addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
canAnimate = true
}
override fun onPause(owner: LifecycleOwner) {
canAnimate = false
stopAnimating()
}
})
}
})
}
@@ -63,6 +81,10 @@ class SpoilerRendererDelegate @JvmOverloads constructor(private val view: TextVi
}
fun draw(canvas: Canvas, text: Spanned, layout: Layout) {
if (!canAnimate) {
return
}
var hasSpoilersToRender = false
val annotations: Map<Annotation, SpoilerClickableSpan?> = cachedAnnotations.getFromCache(text) { SpoilerAnnotation.getSpoilerAndClickAnnotations(text) }

View File

@@ -6,6 +6,9 @@ import androidx.annotation.DrawableRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.doOnNextLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.findFragment
import androidx.lifecycle.Lifecycle
var View.visible: Boolean
get() {
@@ -56,3 +59,15 @@ fun TextView.setRelativeDrawables(
bottom
)
}
/**
* Get a lifecycle associated with this view. Care must be taken to ensure
* if activity fallback occurs that the context of the view is correct.
*/
fun View.getLifecycle(): Lifecycle {
return try {
findFragment<Fragment>().viewLifecycleOwner.lifecycle
} catch (e: IllegalStateException) {
ViewUtil.getActivityLifecycle(this)!!
}
}