refactor: decoupling animation and opened type interface

This commit is contained in:
2024-01-04 02:52:44 +08:00
parent 4c4edde3cd
commit 06de377be1

View File

@@ -59,29 +59,44 @@ import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
@Stable @Stable
internal interface IProgressIndicatorStyle { interface ProgressIndicatorStyle {
val strokeWidth: Dp val strokeWidth: Dp
val strokeCap: StrokeCap val strokeCap: StrokeCap
} }
@Stable
interface ProgressIndicatorAnimation {
val duration: Int
}
@Immutable @Immutable
data class CircularIndicatorStyle( data class CircularIndicatorStyle(
override val strokeWidth: Dp, override val strokeWidth: Dp,
override val strokeCap: StrokeCap, override val strokeCap: StrokeCap,
val radius: Dp, val radius: Dp,
val rotationDuration: Int, val animation: CircularIndicatorAnimation
val rotationsPerCycle: Int, ) : ProgressIndicatorStyle
val startAngleOffset: Float,
val baseRotationAngle: Float,
val jumpRotationAngle: Float
) : IProgressIndicatorStyle
@Immutable @Immutable
data class LinearIndicatorStyle( data class LinearIndicatorStyle(
override val strokeWidth: Dp, override val strokeWidth: Dp,
override val strokeCap: StrokeCap, override val strokeCap: StrokeCap,
val width: Dp, val width: Dp,
val animationDuration: Int, val animation: LinearIndicatorAnimation
) : ProgressIndicatorStyle
@Immutable
data class CircularIndicatorAnimation(
override val duration: Int,
val rotationsPerCycle: Int,
val startAngleOffset: Float,
val baseRotationAngle: Float,
val jumpRotationAngle: Float
) : ProgressIndicatorAnimation
@Immutable
data class LinearIndicatorAnimation(
override val duration: Int,
val firstLineHeadDuration: Int, val firstLineHeadDuration: Int,
val firstLineTailDuration: Int, val firstLineTailDuration: Int,
val secondLineHeadDuration: Int, val secondLineHeadDuration: Int,
@@ -90,7 +105,7 @@ data class LinearIndicatorStyle(
val firstLineTailDelay: Int, val firstLineTailDelay: Int,
val secondLineHeadDelay: Int, val secondLineHeadDelay: Int,
val secondLineTailDelay: Int val secondLineTailDelay: Int
) : IProgressIndicatorStyle ) : ProgressIndicatorAnimation
@Immutable @Immutable
data class ProgressIndicatorColors( data class ProgressIndicatorColors(
@@ -128,54 +143,54 @@ fun CircularProgressIndicator(
val transition = rememberInfiniteTransition() val transition = rememberInfiniteTransition()
val currentRotation by transition.animateValue( val currentRotation by transition.animateValue(
initialValue = 0, initialValue = 0,
style.rotationsPerCycle, style.animation.rotationsPerCycle,
Int.VectorConverter, Int.VectorConverter,
infiniteRepeatable( infiniteRepeatable(
animation = tween( animation = tween(
durationMillis = style.rotationDuration * style.rotationsPerCycle, durationMillis = style.animation.duration * style.animation.rotationsPerCycle,
easing = LinearEasing easing = LinearEasing
) )
) )
) )
val baseRotation by transition.animateFloat( val baseRotation by transition.animateFloat(
initialValue = 0f, initialValue = 0f,
style.baseRotationAngle, style.animation.baseRotationAngle,
infiniteRepeatable( infiniteRepeatable(
animation = tween( animation = tween(
durationMillis = style.rotationDuration, durationMillis = style.animation.duration,
easing = LinearEasing easing = LinearEasing
) )
) )
) )
val headAndTailAnimationDuration = caleHeadAndTailAnimationDuration(style.rotationDuration) val headAndTailAnimationDuration = caleHeadAndTailAnimationDuration(style.animation.duration)
val endAngle by transition.animateFloat( val endAngle by transition.animateFloat(
initialValue = 0f, initialValue = 0f,
style.jumpRotationAngle, style.animation.jumpRotationAngle,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = headAndTailAnimationDuration * 2 durationMillis = headAndTailAnimationDuration * 2
0f at 0 with CircularEasing 0f at 0 with CircularEasing
style.jumpRotationAngle at headAndTailAnimationDuration style.animation.jumpRotationAngle at headAndTailAnimationDuration
} }
) )
) )
val startAngle by transition.animateFloat( val startAngle by transition.animateFloat(
initialValue = 0f, initialValue = 0f,
style.jumpRotationAngle, style.animation.jumpRotationAngle,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = headAndTailAnimationDuration * 2 durationMillis = headAndTailAnimationDuration * 2
0f at headAndTailAnimationDuration with CircularEasing 0f at headAndTailAnimationDuration with CircularEasing
style.jumpRotationAngle at durationMillis style.animation.jumpRotationAngle at durationMillis
} }
) )
) )
Canvas(modifier.progressSemantics().size(diameter)) { Canvas(modifier.progressSemantics().size(diameter)) {
drawCircularIndicatorBackground(colors.backgroundColor, stroke) drawCircularIndicatorBackground(colors.backgroundColor, stroke)
val rotationAngleOffset = caleRotationAngleOffset(style.baseRotationAngle, style.jumpRotationAngle) val rotationAngleOffset = caleRotationAngleOffset(style.animation.baseRotationAngle, style.animation.jumpRotationAngle)
val currentRotationAngleOffset = (currentRotation * rotationAngleOffset) % 360f val currentRotationAngleOffset = (currentRotation * rotationAngleOffset) % 360f
val sweep = abs(endAngle - startAngle) val sweep = abs(endAngle - startAngle)
val offset = style.startAngleOffset + currentRotationAngleOffset + baseRotation val offset = style.animation.startAngleOffset + currentRotationAngleOffset + baseRotation
drawIndeterminateCircularIndicator(startAngle + offset, style.strokeWidth, diameter, sweep, colors.foregroundColor, stroke) drawIndeterminateCircularIndicator(startAngle + offset, style.strokeWidth, diameter, sweep, colors.foregroundColor, stroke)
} }
} }
@@ -211,9 +226,9 @@ fun LinearProgressIndicator(
targetValue = 1f, targetValue = 1f,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = style.animationDuration durationMillis = style.animation.duration
0f at style.firstLineHeadDelay with FirstLineHeadEasing 0f at style.animation.firstLineHeadDelay with FirstLineHeadEasing
1f at style.firstLineHeadDuration + style.firstLineHeadDelay 1f at style.animation.firstLineHeadDuration + style.animation.firstLineHeadDelay
} }
) )
) )
@@ -222,9 +237,9 @@ fun LinearProgressIndicator(
targetValue = 1f, targetValue = 1f,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = style.animationDuration durationMillis = style.animation.duration
0f at style.firstLineTailDelay with FirstLineTailEasing 0f at style.animation.firstLineTailDelay with FirstLineTailEasing
1f at style.firstLineTailDuration + style.firstLineTailDelay 1f at style.animation.firstLineTailDuration + style.animation.firstLineTailDelay
} }
) )
) )
@@ -233,9 +248,9 @@ fun LinearProgressIndicator(
targetValue = 1f, targetValue = 1f,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = style.animationDuration durationMillis = style.animation.duration
0f at style.secondLineHeadDelay with SecondLineHeadEasing 0f at style.animation.secondLineHeadDelay with SecondLineHeadEasing
1f at style.secondLineHeadDuration + style.secondLineHeadDelay 1f at style.animation.secondLineHeadDuration + style.animation.secondLineHeadDelay
} }
) )
) )
@@ -244,9 +259,9 @@ fun LinearProgressIndicator(
targetValue = 1f, targetValue = 1f,
infiniteRepeatable( infiniteRepeatable(
animation = keyframes { animation = keyframes {
durationMillis = style.animationDuration durationMillis = style.animation.duration
0f at style.secondLineTailDelay with SecondLineTailEasing 0f at style.animation.secondLineTailDelay with SecondLineTailEasing
1f at style.secondLineTailDuration + style.secondLineTailDelay 1f at style.animation.secondLineTailDuration + style.animation.secondLineTailDelay
} }
) )
) )
@@ -388,11 +403,13 @@ private fun defaultCircularIndicatorStyle() = CircularIndicatorStyle(
strokeWidth = DefaultIndicatorStrokeWidth, strokeWidth = DefaultIndicatorStrokeWidth,
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
radius = DefaultCircularIndicatorRadius, radius = DefaultCircularIndicatorRadius,
rotationDuration = DefaultRotationDuration, animation = CircularIndicatorAnimation(
rotationsPerCycle = DefaultRotationsPerCycle, duration = DefaultRotationDuration,
startAngleOffset = DefaultStartAngleOffset, rotationsPerCycle = DefaultRotationsPerCycle,
baseRotationAngle = DefaultBaseRotationAngle, startAngleOffset = DefaultStartAngleOffset,
jumpRotationAngle = DefaultJumpRotationAngle baseRotationAngle = DefaultBaseRotationAngle,
jumpRotationAngle = DefaultJumpRotationAngle
)
) )
@Composable @Composable
@@ -401,15 +418,17 @@ private fun defaultLinearIndicatorStyle() = LinearIndicatorStyle(
strokeWidth = DefaultIndicatorStrokeWidth, strokeWidth = DefaultIndicatorStrokeWidth,
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
width = DefaultLinearIndicatorWidth, width = DefaultLinearIndicatorWidth,
animationDuration = DefaultLinearAnimationDuration, animation = LinearIndicatorAnimation(
firstLineHeadDuration = DefaultFirstLineHeadDuration, duration = DefaultLinearAnimationDuration,
firstLineTailDuration = DefaultFirstLineTailDuration, firstLineHeadDuration = DefaultFirstLineHeadDuration,
secondLineHeadDuration = DefaultSecondLineHeadDuration, firstLineTailDuration = DefaultFirstLineTailDuration,
secondLineTailDuration = DefaultSecondLineTailDuration, secondLineHeadDuration = DefaultSecondLineHeadDuration,
firstLineHeadDelay = DefaultFirstLineHeadDelay, secondLineTailDuration = DefaultSecondLineTailDuration,
firstLineTailDelay = DefaultFirstLineTailDelay, firstLineHeadDelay = DefaultFirstLineHeadDelay,
secondLineHeadDelay = DefaultSecondLineHeadDelay, firstLineTailDelay = DefaultFirstLineTailDelay,
secondLineTailDelay = DefaultSecondLineTailDelay secondLineHeadDelay = DefaultSecondLineHeadDelay,
secondLineTailDelay = DefaultSecondLineTailDelay
)
) )
private fun caleRotationAngleOffset(baseRotationAngle: Float, jumpRotationAngle: Float) = (baseRotationAngle + jumpRotationAngle) % 360f private fun caleRotationAngleOffset(baseRotationAngle: Float, jumpRotationAngle: Float) = (baseRotationAngle + jumpRotationAngle) % 360f