11package org.monogram.presentation.features.chats.currentChat.components
22
3+ import androidx.compose.animation.AnimatedVisibility
34import androidx.compose.animation.core.Animatable
45import androidx.compose.animation.core.AnimationVector1D
56import androidx.compose.animation.core.Spring
6- import androidx.compose.animation.core.animateFloatAsState
77import androidx.compose.animation.core.spring
8- import androidx.compose.animation.core.tween
9- import androidx.compose.foundation.background
8+ import androidx.compose.animation.fadeIn
9+ import androidx.compose.animation.fadeOut
10+ import androidx.compose.animation.scaleIn
11+ import androidx.compose.animation.scaleOut
1012import androidx.compose.foundation.gestures.awaitEachGesture
1113import androidx.compose.foundation.gestures.awaitFirstDown
1214import androidx.compose.foundation.layout.Box
1315import androidx.compose.foundation.layout.offset
1416import androidx.compose.foundation.layout.size
15- import androidx.compose.foundation.shape.CircleShape
1617import androidx.compose.material.icons.Icons
1718import androidx.compose.material.icons.automirrored.filled.Reply
19+ import androidx.compose.material3.CircularWavyProgressIndicator
20+ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
1821import androidx.compose.material3.Icon
1922import androidx.compose.material3.MaterialTheme
2023import androidx.compose.runtime.Composable
21- import androidx.compose.runtime.getValue
2224import androidx.compose.ui.Alignment
2325import androidx.compose.ui.Modifier
2426import androidx.compose.ui.graphics.graphicsLayer
@@ -36,6 +38,7 @@ const val REPLY_TRIGGER_FRACTION = 0.35f
3638const val MAX_SWIPE_FRACTION = 0.7f
3739const val ICON_OFFSET_FRACTION = 0.1f
3840
41+ @OptIn(ExperimentalMaterial3ExpressiveApi ::class )
3942@Composable
4043fun FastReplyIndicator (
4144 modifier : Modifier = Modifier ,
@@ -46,46 +49,44 @@ fun FastReplyIndicator(
4649) {
4750 val triggerDistance = maxWidth.value * REPLY_TRIGGER_FRACTION
4851 val dragged = (- dragOffsetX.value).coerceAtLeast(0f )
49- val progress = ((dragged - 48 .dp.value) / (triggerDistance - 48 .dp.value))
50- .coerceIn(0f , 1f )
5152
52- val iconAlpha by animateFloatAsState(
53- targetValue = progress,
54- animationSpec = tween(durationMillis = 150 )
55- )
56- val iconScale by animateFloatAsState(
57- targetValue = lerp(0.5f , 1f , progress),
58- animationSpec = spring(dampingRatio = Spring .DampingRatioMediumBouncy , stiffness = Spring .StiffnessLow )
59- )
53+ val progress = ((dragged - 48 .dp.value) / (triggerDistance - 48 .dp.value)).coerceIn(0f , 1f )
54+
6055 val iconOffset = maxWidth * ICON_OFFSET_FRACTION
6156
62- if (dragged > 48 .dp.value) {
63- Box (
64- modifier = modifier
65- .offset(x = if (isOutgoing) iconOffset else maxWidth)
66- .size(30 .dp)
67- .graphicsLayer {
68- translationX = when {
69- isOutgoing -> (- dragOffsetX.value - iconOffset.value) * 0.5f
70- inverseOffset -> - iconOffset.value
71- else -> iconOffset.value
72- }
73- scaleX = iconScale
74- scaleY = iconScale
75- alpha = iconAlpha
57+ Box (
58+ modifier = modifier
59+ .offset(x = if (isOutgoing) iconOffset else maxWidth)
60+ .size(34 .dp)
61+ .graphicsLayer {
62+ translationX = when {
63+ isOutgoing -> (- dragOffsetX.value - iconOffset.value) * 0.5f
64+ inverseOffset -> - iconOffset.value
65+ else -> iconOffset.value
7666 }
77- .background(
78- color = MaterialTheme .colorScheme.surfaceContainerHigh.copy(alpha = 0.7f ),
79- shape = CircleShape
80- ),
81- contentAlignment = Alignment .Center
67+ },
68+ contentAlignment = Alignment .Center
69+ ) {
70+ AnimatedVisibility (
71+ visible = dragged > 48 .dp.value,
72+ enter = fadeIn() + scaleIn(initialScale = 0.6f ),
73+ exit = fadeOut() + scaleOut(targetScale = 0.6f )
8274 ) {
83- Icon (
84- imageVector = Icons .AutoMirrored .Filled .Reply ,
85- contentDescription = null ,
86- tint = MaterialTheme .colorScheme.onSurfaceVariant,
87- modifier = Modifier .size(18 .dp)
88- )
75+ Box (
76+ modifier = Modifier .matchParentSize(),
77+ contentAlignment = Alignment .Center
78+ ) {
79+ CircularWavyProgressIndicator (
80+ progress = { progress },
81+ color = MaterialTheme .colorScheme.primary,
82+ )
83+ Icon (
84+ imageVector = Icons .AutoMirrored .Filled .Reply ,
85+ contentDescription = null ,
86+ tint = MaterialTheme .colorScheme.primary,
87+ modifier = Modifier .size(18 .dp)
88+ )
89+ }
8990 }
9091 }
9192}
@@ -135,7 +136,13 @@ fun Modifier.fastReplyPointer(
135136 onReplySwipe()
136137 }
137138 scope.launch {
138- dragOffsetX.animateTo(0f , spring())
139+ dragOffsetX.animateTo(
140+ 0f ,
141+ spring(
142+ dampingRatio = Spring .DampingRatioMediumBouncy ,
143+ stiffness = Spring .StiffnessLow
144+ )
145+ )
139146 }
140147 }
141148 }
0 commit comments