Skip to content

Commit 5ed50f5

Browse files
committed
improve fast reply indicator ui
1 parent c85406a commit 5ed50f5

1 file changed

Lines changed: 48 additions & 41 deletions

File tree

  • presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components

presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/FastReplyIndicator.kt

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
package org.monogram.presentation.features.chats.currentChat.components
22

3+
import androidx.compose.animation.AnimatedVisibility
34
import androidx.compose.animation.core.Animatable
45
import androidx.compose.animation.core.AnimationVector1D
56
import androidx.compose.animation.core.Spring
6-
import androidx.compose.animation.core.animateFloatAsState
77
import 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
1012
import androidx.compose.foundation.gestures.awaitEachGesture
1113
import androidx.compose.foundation.gestures.awaitFirstDown
1214
import androidx.compose.foundation.layout.Box
1315
import androidx.compose.foundation.layout.offset
1416
import androidx.compose.foundation.layout.size
15-
import androidx.compose.foundation.shape.CircleShape
1617
import androidx.compose.material.icons.Icons
1718
import androidx.compose.material.icons.automirrored.filled.Reply
19+
import androidx.compose.material3.CircularWavyProgressIndicator
20+
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
1821
import androidx.compose.material3.Icon
1922
import androidx.compose.material3.MaterialTheme
2023
import androidx.compose.runtime.Composable
21-
import androidx.compose.runtime.getValue
2224
import androidx.compose.ui.Alignment
2325
import androidx.compose.ui.Modifier
2426
import androidx.compose.ui.graphics.graphicsLayer
@@ -36,6 +38,7 @@ const val REPLY_TRIGGER_FRACTION = 0.35f
3638
const val MAX_SWIPE_FRACTION = 0.7f
3739
const val ICON_OFFSET_FRACTION = 0.1f
3840

41+
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
3942
@Composable
4043
fun 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

Comments
 (0)