diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt index 675f5c198..355c9961e 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt @@ -115,8 +115,8 @@ abstract class DetailFragment
:
val outRatio = min(ratio * 2, 1f)
val detailHeader = binding.detailHeader
- detailHeader.scaleX = 1 - 0.05f * outRatio
- detailHeader.scaleY = 1 - 0.05f * outRatio
+ detailHeader.scaleX = 1 - 0.2f * outRatio / (5f / 3f)
+ detailHeader.scaleY = 1 - 0.2f * outRatio / (5f / 3f)
detailHeader.alpha = 1 - outRatio
val inRatio = max(ratio - 0.5f, 0f) * 2
diff --git a/app/src/main/java/org/oxycblt/auxio/home/ThemedSpeedDialView.kt b/app/src/main/java/org/oxycblt/auxio/home/ThemedSpeedDialView.kt
index 2637fb331..d111899e1 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/ThemedSpeedDialView.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/ThemedSpeedDialView.kt
@@ -46,7 +46,7 @@ import com.leinardi.android.speeddial.SpeedDialView
import kotlin.math.roundToInt
import kotlinx.parcelize.Parcelize
import org.oxycblt.auxio.R
-import org.oxycblt.auxio.ui.StationaryAnim
+import org.oxycblt.auxio.ui.AnimConfig
import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getDimen
import org.oxycblt.auxio.util.getDimenPixels
@@ -78,7 +78,7 @@ class ThemedSpeedDialView : SpeedDialView {
@AttrRes defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
- private val inAnim = StationaryAnim.forMediumComponent(context)
+ private val stationaryConfig = AnimConfig.of(context, AnimConfig.STANDARD, AnimConfig.MEDIUM2)
init {
// Work around ripple bug on Android 12 when useCompatPadding = true.
@@ -142,7 +142,7 @@ class ThemedSpeedDialView : SpeedDialView {
}
private fun createMainFabAnimator(isOpen: Boolean): Animator {
- val totalDuration = inAnim.duration
+ val totalDuration = stationaryConfig.duration
val partialDuration = totalDuration / 2 // This is half of the total duration
val delay = totalDuration / 4 // This is one fourth of the total duration
@@ -174,7 +174,7 @@ class ThemedSpeedDialView : SpeedDialView {
val animatorSet =
AnimatorSet().apply {
playTogether(backgroundTintAnimator, imageTintAnimator, levelAnimator)
- interpolator = inAnim.interpolator
+ interpolator = stationaryConfig.interpolator
}
animatorSet.start()
return animatorSet
diff --git a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt
index 4631750e1..535d47fb8 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt
@@ -18,6 +18,7 @@
package org.oxycblt.auxio.home.fastscroll
+import android.animation.Animator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Rect
@@ -37,8 +38,7 @@ import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.recycler.AuxioRecyclerView
-import org.oxycblt.auxio.ui.InAnim
-import org.oxycblt.auxio.ui.OutAnim
+import org.oxycblt.auxio.ui.MaterialFader
import org.oxycblt.auxio.util.getDimenPixels
import org.oxycblt.auxio.util.getDrawableCompat
import org.oxycblt.auxio.util.isRtl
@@ -84,9 +84,6 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
background = context.getDrawableCompat(R.drawable.ui_scroll_thumb)
}
- private val thumbEnter = InAnim.forSmallComponent(context)
- private val thumbExit = OutAnim.forSmallComponent(context)
-
private val thumbWidth = thumbView.background.intrinsicWidth
private val thumbHeight = thumbView.background.intrinsicHeight
private val thumbPadding = Rect(0, 0, 0, 0)
@@ -114,8 +111,9 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
}
}
- private val popupEnter = InAnim.forSmallComponent(context)
- private val popupExit = OutAnim.forSmallComponent(context)
+ private val fader = MaterialFader.forSmallComponent(context)
+ private var thumbAnimator: Animator? = null
+ private var popupAnimator: Animator? = null
private var showingPopup = false
@@ -426,12 +424,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
}
showingThumb = true
- thumbView
- .animate()
- .scaleX(1f)
- .setInterpolator(thumbEnter.interpolator)
- .setDuration(thumbEnter.duration)
- .start()
+ thumbAnimator?.cancel()
+ thumbAnimator = fader.fadeIn(thumbView).also { it.start() }
}
private fun hideScrollbar() {
@@ -440,12 +434,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
}
showingThumb = false
- thumbView
- .animate()
- .scaleX(0f)
- .setInterpolator(thumbExit.interpolator)
- .setDuration(thumbExit.duration)
- .start()
+ thumbAnimator?.cancel()
+ thumbAnimator = fader.fadeOut(thumbView).also { it.start() }
}
private fun showPopup() {
@@ -458,13 +448,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
popupView.alpha = 1f
showingPopup = true
- popupView
- .animate()
- .scaleX(1f)
- .scaleY(1f)
- .setInterpolator(popupEnter.interpolator)
- .setDuration(popupEnter.duration)
- .start()
+ popupAnimator?.cancel()
+ popupAnimator = fader.fadeIn(popupView).also { it.start() }
}
private fun hidePopup() {
@@ -473,14 +458,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
}
showingPopup = false
- popupView
- .animate()
- .alpha(0f)
- .scaleX(0.75f)
- .scaleY(0.75f)
- .setInterpolator(popupExit.interpolator)
- .setDuration(popupExit.duration)
- .start()
+ popupAnimator?.cancel()
+ popupAnimator = fader.fadeOut(popupView).also { it.start() }
}
// --- LAYOUT STATE ---
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt
index b20d6c47b..29accb6f0 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt
@@ -18,12 +18,12 @@
package org.oxycblt.auxio.playback.ui
-import android.animation.ValueAnimator
+import android.animation.Animator
import android.content.Context
import android.util.AttributeSet
import com.google.android.material.button.MaterialButton
+import org.oxycblt.auxio.ui.MaterialCornerAnim
import org.oxycblt.auxio.ui.RippleFixMaterialButton
-import org.oxycblt.auxio.ui.StationaryAnim
import timber.log.Timber as L
/**
@@ -43,9 +43,8 @@ class AnimatedMaterialButton : RippleFixMaterialButton {
defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
- private var currentCornerRadiusRatio = 0f
- private var animator: ValueAnimator? = null
- private val anim = StationaryAnim.forMediumComponent(context)
+ private var animator: Animator? = null
+ private val anim = MaterialCornerAnim(context)
override fun setActivated(activated: Boolean) {
super.setActivated(activated)
@@ -55,22 +54,12 @@ class AnimatedMaterialButton : RippleFixMaterialButton {
if (!isLaidOut) {
// Not laid out, initialize it without animation before drawing.
L.d("Not laid out, immediately updating corner radius")
- updateCornerRadiusRatio(targetRadius)
+ shapeAppearanceModel = shapeAppearanceModel.withCornerSize { it.width() * targetRadius }
return
}
L.d("Starting corner radius animation")
animator?.cancel()
- animator =
- anim
- .genericFloat(currentCornerRadiusRatio, targetRadius, 0, ::updateCornerRadiusRatio)
- .also { it.start() }
- }
-
- private fun updateCornerRadiusRatio(ratio: Float) {
- currentCornerRadiusRatio = ratio
- // Can't reproduce the intrinsic ratio corner radius, just manually implement it with
- // a dimension value.
- shapeAppearanceModel = shapeAppearanceModel.withCornerSize { it.width() * ratio }
+ animator = anim.animate(this, width * targetRadius).also { it.start() }
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt b/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt
index 20f6befe5..db54ba9eb 100644
--- a/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt
+++ b/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt
@@ -18,14 +18,58 @@
package org.oxycblt.auxio.ui
+import android.animation.Animator
+import android.animation.AnimatorSet
import android.animation.TimeInterpolator
import android.animation.ValueAnimator
import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import androidx.annotation.AttrRes
+import androidx.core.graphics.toRectF
+import androidx.core.view.isInvisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.google.android.material.R as MR
+import com.google.android.material.button.MaterialButton
import com.google.android.material.motion.MotionUtils
-data class Anim(val interpolator: TimeInterpolator, val duration: Long) {
+class AnimConfig(
+ context: Context,
+ @AttrRes interpolatorRes: Int,
+ @AttrRes durationRes: Int,
+ defaultDuration: Int
+) {
+ val interpolator: TimeInterpolator =
+ MotionUtils.resolveThemeInterpolator(context, interpolatorRes, FastOutSlowInInterpolator())
+ val duration: Long =
+ MotionUtils.resolveThemeDuration(context, durationRes, defaultDuration).toLong()
+
+ companion object {
+ val STANDARD = MR.attr.motionEasingStandardInterpolator
+ val EMPHASIZED = MR.attr.motionEasingEmphasizedInterpolator
+ val EMPHASIZED_ACCELERATE = MR.attr.motionEasingEmphasizedAccelerateInterpolator
+ val EMPHASIZED_DECELERATE = MR.attr.motionEasingEmphasizedDecelerateInterpolator
+ val SHORT1 = MR.attr.motionDurationShort1 to 50
+ val SHORT2 = MR.attr.motionDurationShort2 to 100
+ val SHORT3 = MR.attr.motionDurationShort3 to 150
+ val SHORT4 = MR.attr.motionDurationShort4 to 200
+ val MEDIUM1 = MR.attr.motionDurationMedium1 to 250
+ val MEDIUM2 = MR.attr.motionDurationMedium2 to 300
+ val MEDIUM3 = MR.attr.motionDurationMedium3 to 350
+ val MEDIUM4 = MR.attr.motionDurationMedium4 to 400
+ val LONG1 = MR.attr.motionDurationLong1 to 450
+ val LONG2 = MR.attr.motionDurationLong2 to 500
+ val LONG3 = MR.attr.motionDurationLong3 to 550
+ val LONG4 = MR.attr.motionDurationLong4 to 600
+ val EXTRA_LONG1 = MR.attr.motionDurationExtraLong1 to 700
+ val EXTRA_LONG2 = MR.attr.motionDurationExtraLong2 to 800
+ val EXTRA_LONG3 = MR.attr.motionDurationExtraLong3 to 900
+ val EXTRA_LONG4 = MR.attr.motionDurationExtraLong4 to 1000
+
+ fun of(context: Context, @AttrRes interpolator: Int, duration: Pair