diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate.kt index 124daa7ad5..9b61782927 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/spoiler/SpoilerRendererDelegate.kt @@ -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>() private val cachedMeasurements = HashMap() @@ -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 = cachedAnnotations.getFromCache(text) { SpoilerAnnotation.getSpoilerAndClickAnnotations(text) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ViewExtensions.kt index 1c03c60523..e437bd4e2a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewExtensions.kt @@ -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().viewLifecycleOwner.lifecycle + } catch (e: IllegalStateException) { + ViewUtil.getActivityLifecycle(this)!! + } +}