Сделал стабильное появление реквестов при оттягивании списка

This commit is contained in:
2026-03-19 16:50:13 +05:00
parent 4d4130fefd
commit 53946e2e6e

View File

@@ -1797,6 +1797,13 @@ fun ChatsListScreen(
var lastAutoScrolledVerificationId by remember { var lastAutoScrolledVerificationId by remember {
mutableStateOf<String?>(null) mutableStateOf<String?>(null)
} }
val localDensity = LocalDensity.current
val requestsRevealThresholdPx =
remember(localDensity) { with(localDensity) { 56.dp.toPx() } }
val requestsHideThresholdPx =
remember(localDensity) { with(localDensity) { 16.dp.toPx() } }
val topOffsetTolerancePx =
remember(localDensity) { with(localDensity) { 3.dp.toPx() } }
AnimatedContent( AnimatedContent(
targetState = showDownloadsScreen, targetState = showDownloadsScreen,
@@ -2061,9 +2068,6 @@ fun ChatsListScreen(
} }
} }
// Track scroll direction to hide/show Requests
val hapticFeedback = LocalHapticFeedback.current
// When a new device confirmation banner appears at the top, // When a new device confirmation banner appears at the top,
// smoothly bring the list to top so the banner is visible. // smoothly bring the list to top so the banner is visible.
LaunchedEffect(pendingDeviceVerification?.deviceId) { LaunchedEffect(pendingDeviceVerification?.deviceId) {
@@ -2087,31 +2091,94 @@ fun ChatsListScreen(
lastAutoScrolledVerificationId = verificationId lastAutoScrolledVerificationId = verificationId
} }
// NestedScroll — ловим направление свайпа даже без скролла // Pull-to-show/hide для реквестов: работаем только когда
// Для появления: накапливаем pull down дельту, нужен сильный жест // список реально дотянут до верха и пользователь тянет вниз.
val requestsNestedScroll = remember(hapticFeedback) { val requestsNestedScroll =
remember(
chatListState,
requestsCount,
requestsRevealThresholdPx,
requestsHideThresholdPx,
topOffsetTolerancePx,
hapticFeedback
) {
var accumulatedPullDown = 0f var accumulatedPullDown = 0f
var hapticSent = false
object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection { object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection {
fun isAtTop(): Boolean {
return chatListState.firstVisibleItemIndex == 0 &&
chatListState.firstVisibleItemScrollOffset <=
topOffsetTolerancePx.roundToInt()
}
override fun onPreScroll( override fun onPreScroll(
available: androidx.compose.ui.geometry.Offset, available: androidx.compose.ui.geometry.Offset,
source: androidx.compose.ui.input.nestedscroll.NestedScrollSource source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
): androidx.compose.ui.geometry.Offset { ): androidx.compose.ui.geometry.Offset {
if (available.y < -10f) { if (source != androidx.compose.ui.input.nestedscroll.NestedScrollSource.Drag ||
// Свайп вверх — прячем легко requestsCount <= 0
) {
accumulatedPullDown = 0f accumulatedPullDown = 0f
hapticSent = false
return androidx.compose.ui.geometry.Offset.Zero
}
if (available.y < -requestsHideThresholdPx) {
// Свайп вверх — быстро прячем блок реквестов.
accumulatedPullDown = 0f
hapticSent = false
if (isRequestsVisible) {
isRequestsVisible = false isRequestsVisible = false
} else if (available.y > 0f && !isRequestsVisible) { }
// Свайп вниз — накапливаем для появления }
accumulatedPullDown += available.y return androidx.compose.ui.geometry.Offset.Zero
if (accumulatedPullDown > 120f) { }
override fun onPostScroll(
consumed: androidx.compose.ui.geometry.Offset,
available: androidx.compose.ui.geometry.Offset,
source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
): androidx.compose.ui.geometry.Offset {
if (source != androidx.compose.ui.input.nestedscroll.NestedScrollSource.Drag ||
requestsCount <= 0
) {
accumulatedPullDown = 0f
hapticSent = false
return androidx.compose.ui.geometry.Offset.Zero
}
if (isRequestsVisible) {
accumulatedPullDown = 0f
hapticSent = false
return androidx.compose.ui.geometry.Offset.Zero
}
val pullDownDelta =
if (available.y > 0f && isAtTop())
available.y
else 0f
if (pullDownDelta > 0f) {
accumulatedPullDown =
(accumulatedPullDown +
pullDownDelta)
.coerceAtMost(
requestsRevealThresholdPx *
2f
)
if (accumulatedPullDown >= requestsRevealThresholdPx) {
isRequestsVisible = true isRequestsVisible = true
accumulatedPullDown = 0f accumulatedPullDown = 0f
if (!hapticSent) {
hapticFeedback.performHapticFeedback( hapticFeedback.performHapticFeedback(
HapticFeedbackType.LongPress HapticFeedbackType.LongPress
) )
hapticSent = true
} }
} else if (available.y <= 0f) { }
} else if (available.y < 0f || !isAtTop()) {
accumulatedPullDown = 0f accumulatedPullDown = 0f
hapticSent = false
} }
return androidx.compose.ui.geometry.Offset.Zero return androidx.compose.ui.geometry.Offset.Zero
} }
@@ -2121,6 +2188,7 @@ fun ChatsListScreen(
available: androidx.compose.ui.unit.Velocity available: androidx.compose.ui.unit.Velocity
): androidx.compose.ui.unit.Velocity { ): androidx.compose.ui.unit.Velocity {
accumulatedPullDown = 0f accumulatedPullDown = 0f
hapticSent = false
return androidx.compose.ui.unit.Velocity.Zero return androidx.compose.ui.unit.Velocity.Zero
} }
} }