From ec361d6349ec698437545e207581128415d2c346 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Mon, 9 May 2022 09:20:35 -0300 Subject: [PATCH] Update gift badge open animation to use anticipate interpolator. --- .../securesms/badges/BadgeImageView.kt | 2 -- .../gifts/OpenableGiftItemDecoration.kt | 22 ++++++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeImageView.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeImageView.kt index b30d86e45..c011b6e93 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeImageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeImageView.kt @@ -87,8 +87,6 @@ class BadgeImageView @JvmOverloads constructor( .downsample(DownsampleStrategy.NONE) .transform(BadgeSpriteTransformation(BadgeSpriteTransformation.Size.fromInteger(badgeSize), ScreenDensity.getBestDensityBucketForDevice(), ThemeUtil.isDarkTheme(context))) .into(this) - - isClickable = true } else { glideRequests .clear(this) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration.kt index 007afe2be..7c46bb446 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/OpenableGiftItemDecoration.kt @@ -9,6 +9,7 @@ import android.graphics.RectF import android.graphics.drawable.Drawable import android.provider.Settings import android.view.animation.AccelerateDecelerateInterpolator +import android.view.animation.AnticipateInterpolator import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.core.graphics.toRect @@ -167,14 +168,14 @@ class OpenableGiftItemDecoration(context: Context) : RecyclerView.ItemDecoration animationState[child.getGiftId()] = GiftAnimationState.OpenAnimationState(child, System.currentTimeMillis()) } - sealed class GiftAnimationState(val openableGift: OpenableGift, val startTime: Long) { + sealed class GiftAnimationState(val openableGift: OpenableGift, val startTime: Long, val duration: Long) { /** * Shakes the gift box to the left and right, slightly revealing the contents underneath. * Uses a lag value to keep the bow one "frame" behind the box, to give it the effect of * following behind. */ - class ShakeAnimationState(openableGift: OpenableGift, startTime: Long) : GiftAnimationState(openableGift, startTime) { + class ShakeAnimationState(openableGift: OpenableGift, startTime: Long) : GiftAnimationState(openableGift, startTime, SHAKE_DURATION_MILLIS) { override fun update(canvas: Canvas, projection: Projection, progress: Float, lastFrameProgress: Float, drawBox: (Canvas, Projection) -> Unit, drawBow: (Canvas, Projection) -> Unit) { canvas.withTranslation(x = getTranslation(progress).toFloat()) { drawBox(canvas, projection) @@ -193,12 +194,15 @@ class OpenableGiftItemDecoration(context: Context) : RecyclerView.ItemDecoration } } - class OpenAnimationState(openableGift: OpenableGift, startTime: Long) : GiftAnimationState(openableGift, startTime) { + class OpenAnimationState(openableGift: OpenableGift, startTime: Long) : GiftAnimationState(openableGift, startTime, OPEN_DURATION_MILLIS) { override fun update(canvas: Canvas, projection: Projection, progress: Float, lastFrameProgress: Float, drawBox: (Canvas, Projection) -> Unit, drawBow: (Canvas, Projection) -> Unit) { val interpolatedProgress = INTERPOLATOR.getInterpolation(progress) - val evaluatedValue = EVALUATOR.evaluate(interpolatedProgress, 0f, DimensionUnit.DP.toPixels(300f)) + val evaluatedValue = EVALUATOR.evaluate(interpolatedProgress, 0f, DimensionUnit.DP.toPixels(161f)) - canvas.translate(evaluatedValue, -evaluatedValue) + val interpolatedY = TRANSLATION_Y_INTERPOLATOR.getInterpolation(progress) + val evaluatedY = EVALUATOR.evaluate(interpolatedY, 0f, DimensionUnit.DP.toPixels(355f)) + + canvas.translate(evaluatedValue, evaluatedY) drawBox(canvas, projection) drawBow(canvas, projection) @@ -215,8 +219,8 @@ class OpenableGiftItemDecoration(context: Context) : RecyclerView.ItemDecoration } val currentFrameTime = System.currentTimeMillis() - val lastFrameProgress = max(0f, (currentFrameTime - startTime - ONE_FRAME_RELATIVE_TO_30_FPS_MILLIS) / (DURATION_MILLIS.toFloat() * animatorDurationScale)) - val progress = (currentFrameTime - startTime) / (DURATION_MILLIS.toFloat() * animatorDurationScale) + val lastFrameProgress = max(0f, (currentFrameTime - startTime - ONE_FRAME_RELATIVE_TO_30_FPS_MILLIS) / (duration.toFloat() * animatorDurationScale)) + val progress = (currentFrameTime - startTime) / (duration.toFloat() * animatorDurationScale) if (progress > 1f) { update(canvas, projection, 1f, 1f, drawBox, drawBow) @@ -240,10 +244,12 @@ class OpenableGiftItemDecoration(context: Context) : RecyclerView.ItemDecoration } companion object { + private val TRANSLATION_Y_INTERPOLATOR = AnticipateInterpolator(3f) private val INTERPOLATOR = AccelerateDecelerateInterpolator() private val EVALUATOR = FloatEvaluator() - private const val DURATION_MILLIS = 1000 + private const val SHAKE_DURATION_MILLIS = 1000L + private const val OPEN_DURATION_MILLIS = 700L private const val ONE_FRAME_RELATIVE_TO_30_FPS_MILLIS = 33 } }