Довел pull-анимацию реквестов: моментальный показ первым элементом
This commit is contained in:
@@ -2118,7 +2118,9 @@ fun ChatsListScreen(
|
|||||||
|
|
||||||
val atTop = !chatListState.canScrollBackward
|
val atTop = !chatListState.canScrollBackward
|
||||||
val nearTop =
|
val nearTop =
|
||||||
chatListState.firstVisibleItemIndex == 0
|
chatListState.firstVisibleItemIndex == 0 &&
|
||||||
|
chatListState.firstVisibleItemScrollOffset <=
|
||||||
|
2
|
||||||
|
|
||||||
if (available.y < 0f &&
|
if (available.y < 0f &&
|
||||||
isRequestsVisible &&
|
isRequestsVisible &&
|
||||||
@@ -2132,11 +2134,17 @@ fun ChatsListScreen(
|
|||||||
isRequestsVisible = false
|
isRequestsVisible = false
|
||||||
accumulatedPullUp = 0f
|
accumulatedPullUp = 0f
|
||||||
}
|
}
|
||||||
return androidx.compose.ui.geometry.Offset.Zero
|
return androidx.compose.ui.geometry.Offset(
|
||||||
|
0f,
|
||||||
|
available.y
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
if (available.y >= 0f) {
|
||||||
accumulatedPullUp = 0f
|
accumulatedPullUp = 0f
|
||||||
|
}
|
||||||
|
|
||||||
if (available.y > 0f && atTop && !isRequestsVisible) {
|
if (!isRequestsVisible && atTop) {
|
||||||
|
if (available.y > 0f) {
|
||||||
accumulatedPullDown =
|
accumulatedPullDown =
|
||||||
(accumulatedPullDown + available.y)
|
(accumulatedPullDown + available.y)
|
||||||
.coerceAtMost(
|
.coerceAtMost(
|
||||||
@@ -2157,7 +2165,32 @@ fun ChatsListScreen(
|
|||||||
HapticFeedbackType.LongPress
|
HapticFeedbackType.LongPress
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (available.y <= 0f || !atTop) {
|
return androidx.compose.ui.geometry.Offset(
|
||||||
|
0f,
|
||||||
|
available.y
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available.y < 0f &&
|
||||||
|
accumulatedPullDown > 0f
|
||||||
|
) {
|
||||||
|
accumulatedPullDown =
|
||||||
|
(accumulatedPullDown + available.y)
|
||||||
|
.coerceAtLeast(
|
||||||
|
0f
|
||||||
|
)
|
||||||
|
requestsPullProgress =
|
||||||
|
(accumulatedPullDown / requestsRevealThresholdPx)
|
||||||
|
.coerceIn(
|
||||||
|
0f,
|
||||||
|
1.15f
|
||||||
|
)
|
||||||
|
return androidx.compose.ui.geometry.Offset(
|
||||||
|
0f,
|
||||||
|
available.y
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (!isRequestsVisible && !atTop) {
|
||||||
accumulatedPullDown = 0f
|
accumulatedPullDown = 0f
|
||||||
requestsPullProgress = 0f
|
requestsPullProgress = 0f
|
||||||
}
|
}
|
||||||
@@ -2165,6 +2198,16 @@ fun ChatsListScreen(
|
|||||||
return androidx.compose.ui.geometry.Offset.Zero
|
return androidx.compose.ui.geometry.Offset.Zero
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun onPreFling(
|
||||||
|
available: androidx.compose.ui.unit.Velocity
|
||||||
|
): androidx.compose.ui.unit.Velocity {
|
||||||
|
if (!isRequestsVisible) {
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
requestsPullProgress = 0f
|
||||||
|
}
|
||||||
|
return androidx.compose.ui.unit.Velocity.Zero
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun onPostFling(
|
override suspend fun onPostFling(
|
||||||
consumed: androidx.compose.ui.unit.Velocity,
|
consumed: androidx.compose.ui.unit.Velocity,
|
||||||
available: androidx.compose.ui.unit.Velocity
|
available: androidx.compose.ui.unit.Velocity
|
||||||
@@ -2177,18 +2220,6 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(
|
|
||||||
chatListState.isScrollInProgress,
|
|
||||||
isRequestsVisible
|
|
||||||
) {
|
|
||||||
if (!chatListState.isScrollInProgress &&
|
|
||||||
!isRequestsVisible &&
|
|
||||||
requestsPullProgress != 0f
|
|
||||||
) {
|
|
||||||
requestsPullProgress = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = chatListState,
|
state = chatListState,
|
||||||
modifier =
|
modifier =
|
||||||
@@ -2227,12 +2258,12 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requestsCount > 0) {
|
if (requestsCount > 0) {
|
||||||
if (!isRequestsVisible) {
|
item(key = "requests_section") {
|
||||||
item(key = "requests_reopen_handle") {
|
val requestsSectionProgress by
|
||||||
val animatedPullProgress by
|
|
||||||
animateFloatAsState(
|
animateFloatAsState(
|
||||||
targetValue =
|
targetValue =
|
||||||
requestsPullProgress,
|
if (isRequestsVisible) 1f
|
||||||
|
else requestsPullProgress,
|
||||||
animationSpec =
|
animationSpec =
|
||||||
spring(
|
spring(
|
||||||
dampingRatio =
|
dampingRatio =
|
||||||
@@ -2241,42 +2272,56 @@ fun ChatsListScreen(
|
|||||||
Spring.StiffnessMediumLow
|
Spring.StiffnessMediumLow
|
||||||
),
|
),
|
||||||
label =
|
label =
|
||||||
"requestsPullProgress"
|
"requestsSectionProgress"
|
||||||
)
|
)
|
||||||
RequestsRevealHandle(
|
val clampedProgress =
|
||||||
isDarkTheme = isDarkTheme,
|
requestsSectionProgress
|
||||||
pullProgress =
|
.coerceIn(
|
||||||
animatedPullProgress,
|
0f,
|
||||||
onClick = {
|
1.15f
|
||||||
isRequestsVisible = true
|
|
||||||
requestsPullProgress =
|
|
||||||
0f
|
|
||||||
hapticFeedback.performHapticFeedback(
|
|
||||||
HapticFeedbackType.LongPress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
val revealProgress =
|
val revealProgress =
|
||||||
FastOutSlowInEasing
|
FastOutSlowInEasing
|
||||||
.transform(
|
.transform(
|
||||||
animatedPullProgress
|
clampedProgress
|
||||||
.coerceIn(
|
.coerceIn(
|
||||||
0f,
|
0f,
|
||||||
1f
|
1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (revealProgress > 0.001f) {
|
val stretchOvershoot =
|
||||||
|
(clampedProgress - 1f)
|
||||||
|
.coerceAtLeast(
|
||||||
|
0f
|
||||||
|
)
|
||||||
|
val sectionHeight =
|
||||||
|
76.dp *
|
||||||
|
revealProgress +
|
||||||
|
10.dp *
|
||||||
|
stretchOvershoot
|
||||||
|
val sectionAlpha =
|
||||||
|
(0.55f + revealProgress * 0.45f)
|
||||||
|
.coerceIn(
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isRequestsVisible ||
|
||||||
|
sectionHeight > 0.5.dp
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.fillMaxWidth()
|
Modifier.fillMaxWidth()
|
||||||
.height(
|
.height(
|
||||||
76.dp *
|
sectionHeight
|
||||||
revealProgress
|
|
||||||
)
|
)
|
||||||
.clipToBounds()
|
.clipToBounds()
|
||||||
.graphicsLayer {
|
.graphicsLayer {
|
||||||
alpha =
|
alpha =
|
||||||
revealProgress
|
if (isRequestsVisible)
|
||||||
|
1f
|
||||||
|
else sectionAlpha
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
RequestsSection(
|
RequestsSection(
|
||||||
@@ -2291,83 +2336,10 @@ fun ChatsListScreen(
|
|||||||
true
|
true
|
||||||
requestsPullProgress =
|
requestsPullProgress =
|
||||||
0f
|
0f
|
||||||
hapticFeedback.performHapticFeedback(
|
|
||||||
HapticFeedbackType.LongPress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Divider(
|
|
||||||
color = dividerColor,
|
|
||||||
thickness = 0.5.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item(key = "requests_section") {
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible =
|
|
||||||
isRequestsVisible,
|
|
||||||
enter =
|
|
||||||
expandVertically(
|
|
||||||
expandFrom =
|
|
||||||
Alignment
|
|
||||||
.Top,
|
|
||||||
animationSpec =
|
|
||||||
tween(
|
|
||||||
durationMillis =
|
|
||||||
260,
|
|
||||||
easing =
|
|
||||||
FastOutSlowInEasing
|
|
||||||
)
|
|
||||||
) +
|
|
||||||
fadeIn(
|
|
||||||
animationSpec =
|
|
||||||
tween(
|
|
||||||
durationMillis =
|
|
||||||
180,
|
|
||||||
easing =
|
|
||||||
LinearOutSlowInEasing
|
|
||||||
),
|
|
||||||
initialAlpha =
|
|
||||||
0.7f
|
|
||||||
),
|
|
||||||
exit =
|
|
||||||
shrinkVertically(
|
|
||||||
shrinkTowards =
|
|
||||||
Alignment
|
|
||||||
.Top,
|
|
||||||
animationSpec =
|
|
||||||
tween(
|
|
||||||
durationMillis =
|
|
||||||
220,
|
|
||||||
easing =
|
|
||||||
FastOutSlowInEasing
|
|
||||||
)
|
|
||||||
) +
|
|
||||||
fadeOut(
|
|
||||||
animationSpec =
|
|
||||||
tween(
|
|
||||||
durationMillis =
|
|
||||||
140,
|
|
||||||
easing =
|
|
||||||
FastOutLinearInEasing
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Column {
|
|
||||||
RequestsSection(
|
|
||||||
count =
|
|
||||||
requestsCount,
|
|
||||||
requests =
|
|
||||||
requests,
|
|
||||||
isDarkTheme =
|
|
||||||
isDarkTheme,
|
|
||||||
onClick = {
|
|
||||||
openRequestsRouteSafely()
|
openRequestsRouteSafely()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
Divider(
|
Divider(
|
||||||
color =
|
color =
|
||||||
dividerColor,
|
dividerColor,
|
||||||
@@ -4635,61 +4607,6 @@ fun TypingIndicatorSmall() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun RequestsRevealHandle(
|
|
||||||
isDarkTheme: Boolean,
|
|
||||||
pullProgress: Float,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
val clampedProgress = pullProgress.coerceIn(0f, 1.15f)
|
|
||||||
val revealProgress = FastOutSlowInEasing.transform(clampedProgress.coerceIn(0f, 1f))
|
|
||||||
val stretchOvershoot = (clampedProgress - 1f).coerceAtLeast(0f)
|
|
||||||
|
|
||||||
val textColor =
|
|
||||||
if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.84f + revealProgress * 0.16f)
|
|
||||||
else Color(0xFF6C6C70).copy(alpha = 0.84f + revealProgress * 0.16f)
|
|
||||||
val iconColor =
|
|
||||||
if (isDarkTheme) Color(0xFF7E7E84).copy(alpha = 0.88f + revealProgress * 0.12f)
|
|
||||||
else Color(0xFF8A8A90).copy(alpha = 0.88f + revealProgress * 0.12f)
|
|
||||||
val verticalPadding = 10.dp + (6.dp * revealProgress) + (4.dp * stretchOvershoot)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier =
|
|
||||||
Modifier.fillMaxWidth()
|
|
||||||
.graphicsLayer {
|
|
||||||
val scaleBoost =
|
|
||||||
revealProgress * 0.015f + stretchOvershoot * 0.06f
|
|
||||||
scaleY = 1f + scaleBoost
|
|
||||||
}
|
|
||||||
.clickable(onClick = onClick)
|
|
||||||
.padding(
|
|
||||||
horizontal = TELEGRAM_DIALOG_AVATAR_START,
|
|
||||||
vertical = verticalPadding
|
|
||||||
),
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = TablerIcons.ChevronDown,
|
|
||||||
contentDescription = "Show requests",
|
|
||||||
tint = iconColor,
|
|
||||||
modifier =
|
|
||||||
Modifier.size(18.dp + (2.dp * revealProgress)).graphicsLayer {
|
|
||||||
rotationZ = 180f * revealProgress
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
|
||||||
Text(
|
|
||||||
text =
|
|
||||||
if (clampedProgress >= 0.92f) "Release to open requests"
|
|
||||||
else "Pull down to show requests",
|
|
||||||
color = textColor,
|
|
||||||
fontSize = 13.sp,
|
|
||||||
fontWeight = FontWeight.Medium
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 📬 Секция Requests — Telegram Archived Chats style */
|
/** 📬 Секция Requests — Telegram Archived Chats style */
|
||||||
@Composable
|
@Composable
|
||||||
fun RequestsSection(
|
fun RequestsSection(
|
||||||
|
|||||||
Reference in New Issue
Block a user