From 3e925a22fef8bf5b5ccdf87e95c597aa007a3454 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Tue, 19 Nov 2024 08:47:24 +0100 Subject: [PATCH 1/3] Animate highlighted text --- .../ui/components/HighlightedText.kt | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt index e8138c6ca..3383fba49 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt @@ -17,11 +17,16 @@ */ package com.infomaniak.swisstransfer.ui.components +import androidx.annotation.FloatRange +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset @@ -60,19 +65,33 @@ fun HighlightedText( val highlightedColor = SwissTransferTheme.colors.highlightedColor - var highlightedPath by remember { mutableStateOf(null) } + var boundingBoxes by remember { mutableStateOf>(emptyList()) } + var animationStarted by rememberSaveable { mutableStateOf(false) } + + LaunchedEffect(Unit) { animationStarted = true } + + val highlightProgress by animateFloatAsState( + targetValue = if (animationStarted) 1f else 0f, + animationSpec = tween( + durationMillis = 600, + easing = FastOutSlowInEasing, + delayMillis = 500, + ), + label = "Highlither progress", + ) Text( text = text, style = style, - onTextLayout = { layoutResult -> - val boundingBoxes = layoutResult.getArgumentBoundingBoxes(text, argument) - highlightedPath = boundingBoxes.transformForHighlightedStyle(verticalPadding, horizontalPadding, angleDegrees) - }, + onTextLayout = { layoutResult -> boundingBoxes = layoutResult.getArgumentBoundingBoxes(text, argument) }, modifier = Modifier.drawBehind { - highlightedPath?.let { - drawPath(path = it, style = Fill, color = highlightedColor) - } + val highlightedPath = boundingBoxes.transformForHighlightedStyle( + verticalPadding, + horizontalPadding, + angleDegrees, + highlightProgress, + ) + drawPath(path = highlightedPath, style = Fill, color = highlightedColor) }, ) } @@ -86,13 +105,19 @@ private fun List.transformForHighlightedStyle( verticalPadding: Float, horizontalPadding: Float, angleDegrees: Float, + @FloatRange(0.0, 1.0) progress: Float, ): Path = Path().apply { forEach { boundingBox -> - addPath(boundingBox.transformForHighlightedStyle(verticalPadding, horizontalPadding, angleDegrees)) + addPath(boundingBox.transformForHighlightedStyle(verticalPadding, horizontalPadding, angleDegrees, progress)) } } -private fun Rect.transformForHighlightedStyle(verticalPadding: Float, horizontalPadding: Float, angleDegrees: Float): Path { +private fun Rect.transformForHighlightedStyle( + verticalPadding: Float, + horizontalPadding: Float, + angleDegrees: Float, + @FloatRange(0.0, 1.0) progress: Float, +): Path { return getRotatedRectanglePath( Rect( left = left - horizontalPadding, @@ -101,10 +126,11 @@ private fun Rect.transformForHighlightedStyle(verticalPadding: Float, horizontal bottom = bottom + verticalPadding, ), angleDegrees = angleDegrees, + progress = progress, ) } -private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Float): Path { +private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Float, @FloatRange(0.0, 1.0) progress: Float): Path { val centerX = rect.left + (rect.width / 2) val centerY = rect.top + (rect.height / 2) @@ -121,9 +147,12 @@ private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Float): Path { return Offset(newX, newY) } + val width = rect.right - rect.left + val right = rect.left + progress * width + val topLeft = rotatePoint(rect.left, rect.top, centerX, centerY, angleRadians) - val topRight = rotatePoint(rect.right, rect.top, centerX, centerY, angleRadians) - val bottomRight = rotatePoint(rect.right, rect.bottom, centerX, centerY, angleRadians) + val topRight = rotatePoint(right, rect.top, centerX, centerY, angleRadians) + val bottomRight = rotatePoint(right, rect.bottom, centerX, centerY, angleRadians) val bottomLeft = rotatePoint(rect.left, rect.bottom, centerX, centerY, angleRadians) return Path().apply { From 89f07bd46b3d3eb564cb4508599ac94e0d39ece6 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Wed, 20 Nov 2024 13:54:59 +0100 Subject: [PATCH 2/3] Fix typo --- .../infomaniak/swisstransfer/ui/components/HighlightedText.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt index 3383fba49..9cd075a94 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt @@ -77,7 +77,7 @@ fun HighlightedText( easing = FastOutSlowInEasing, delayMillis = 500, ), - label = "Highlither progress", + label = "Highlighter progress", ) Text( From 4077c7785cb8389a6bc12a8bd73693de57a40234 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 22 Nov 2024 11:03:47 +0100 Subject: [PATCH 3/3] Change angleDegrees parameter type to Double --- .../swisstransfer/ui/components/HighlightedText.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt index 9cd075a94..a3338a546 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/HighlightedText.kt @@ -48,7 +48,7 @@ import kotlin.math.sin private val VERTICAL_PADDING @Composable get() = with(LocalDensity.current) { 3.sp.toPx() } private val HORIZONTAL_PADDING @Composable get() = with(LocalDensity.current) { 10.sp.toPx() } -private const val ROTATION_ANGLE_DEGREE = -3.0f +private const val ROTATION_ANGLE_DEGREE = -3.0 @Composable fun HighlightedText( @@ -57,7 +57,7 @@ fun HighlightedText( style: TextStyle, verticalPadding: Float = VERTICAL_PADDING, horizontalPadding: Float = HORIZONTAL_PADDING, - angleDegrees: Float = ROTATION_ANGLE_DEGREE, + angleDegrees: Double = ROTATION_ANGLE_DEGREE, ) { val template = stringResource(templateRes) val argument = stringResource(argumentRes) @@ -104,7 +104,7 @@ private fun TextLayoutResult.getArgumentBoundingBoxes(text: String, argument: St private fun List.transformForHighlightedStyle( verticalPadding: Float, horizontalPadding: Float, - angleDegrees: Float, + angleDegrees: Double, @FloatRange(0.0, 1.0) progress: Float, ): Path = Path().apply { forEach { boundingBox -> @@ -115,7 +115,7 @@ private fun List.transformForHighlightedStyle( private fun Rect.transformForHighlightedStyle( verticalPadding: Float, horizontalPadding: Float, - angleDegrees: Float, + angleDegrees: Double, @FloatRange(0.0, 1.0) progress: Float, ): Path { return getRotatedRectanglePath( @@ -130,11 +130,11 @@ private fun Rect.transformForHighlightedStyle( ) } -private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Float, @FloatRange(0.0, 1.0) progress: Float): Path { +private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Double, @FloatRange(0.0, 1.0) progress: Float): Path { val centerX = rect.left + (rect.width / 2) val centerY = rect.top + (rect.height / 2) - val angleRadians = Math.toRadians(angleDegrees.toDouble()) + val angleRadians = Math.toRadians(angleDegrees) // Function to rotate a point around the center fun rotatePoint(x: Float, y: Float, centerX: Float, centerY: Float, angleRadians: Double): Offset {