Переделал механику реквестов: отдельный pull-gesture и ручка раскрытия
This commit is contained in:
@@ -1799,9 +1799,7 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
val localDensity = LocalDensity.current
|
val localDensity = LocalDensity.current
|
||||||
val requestsRevealThresholdPx =
|
val requestsRevealThresholdPx =
|
||||||
remember(localDensity) { with(localDensity) { 24.dp.toPx() } }
|
remember(localDensity) { with(localDensity) { 28.dp.toPx() } }
|
||||||
val requestsRevealInstantPx =
|
|
||||||
remember(localDensity) { with(localDensity) { 8.dp.toPx() } }
|
|
||||||
val requestsHideThresholdPx =
|
val requestsHideThresholdPx =
|
||||||
remember(localDensity) { with(localDensity) { 16.dp.toPx() } }
|
remember(localDensity) { with(localDensity) { 16.dp.toPx() } }
|
||||||
|
|
||||||
@@ -2091,89 +2089,79 @@ fun ChatsListScreen(
|
|||||||
lastAutoScrolledVerificationId = verificationId
|
lastAutoScrolledVerificationId = verificationId
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull-to-show/hide для реквестов: работаем только когда
|
|
||||||
// список реально дотянут до верха и пользователь тянет вниз.
|
|
||||||
val requestsNestedScroll =
|
|
||||||
remember(
|
|
||||||
chatListState,
|
|
||||||
requestsCount,
|
|
||||||
requestsRevealThresholdPx,
|
|
||||||
requestsRevealInstantPx,
|
|
||||||
requestsHideThresholdPx,
|
|
||||||
hapticFeedback
|
|
||||||
) {
|
|
||||||
var accumulatedPullDown = 0f
|
|
||||||
var hapticSent = false
|
|
||||||
object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection {
|
|
||||||
fun isAtTop(): Boolean {
|
|
||||||
return !chatListState.canScrollBackward
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreScroll(
|
|
||||||
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 (available.y < -requestsHideThresholdPx) {
|
|
||||||
// Свайп вверх — быстро прячем блок реквестов.
|
|
||||||
accumulatedPullDown = 0f
|
|
||||||
hapticSent = false
|
|
||||||
if (isRequestsVisible) {
|
|
||||||
isRequestsVisible = false
|
|
||||||
}
|
|
||||||
} else if (available.y > 0f && !isRequestsVisible && isAtTop()) {
|
|
||||||
// Pull down from top should always reopen requests.
|
|
||||||
val shouldRevealInstantly =
|
|
||||||
available.y >= requestsRevealInstantPx
|
|
||||||
accumulatedPullDown =
|
|
||||||
(accumulatedPullDown + available.y).coerceAtMost(
|
|
||||||
requestsRevealThresholdPx
|
|
||||||
)
|
|
||||||
if (shouldRevealInstantly ||
|
|
||||||
accumulatedPullDown >= requestsRevealThresholdPx
|
|
||||||
) {
|
|
||||||
isRequestsVisible = true
|
|
||||||
accumulatedPullDown = 0f
|
|
||||||
if (!hapticSent) {
|
|
||||||
hapticFeedback.performHapticFeedback(
|
|
||||||
HapticFeedbackType.LongPress
|
|
||||||
)
|
|
||||||
hapticSent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (available.y <= 0f || !isAtTop()) {
|
|
||||||
accumulatedPullDown = 0f
|
|
||||||
hapticSent = false
|
|
||||||
}
|
|
||||||
return androidx.compose.ui.geometry.Offset.Zero
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun onPostFling(
|
|
||||||
consumed: androidx.compose.ui.unit.Velocity,
|
|
||||||
available: androidx.compose.ui.unit.Velocity
|
|
||||||
): androidx.compose.ui.unit.Velocity {
|
|
||||||
accumulatedPullDown = 0f
|
|
||||||
hapticSent = false
|
|
||||||
return androidx.compose.ui.unit.Velocity.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = chatListState,
|
state = chatListState,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.fillMaxSize()
|
Modifier.fillMaxSize()
|
||||||
.then(
|
.pointerInput(
|
||||||
if (requestsCount > 0) Modifier.nestedScroll(requestsNestedScroll)
|
requestsCount,
|
||||||
else Modifier
|
isRequestsVisible,
|
||||||
|
chatListState,
|
||||||
|
requestsRevealThresholdPx,
|
||||||
|
requestsHideThresholdPx
|
||||||
|
) {
|
||||||
|
if (requestsCount <= 0) return@pointerInput
|
||||||
|
|
||||||
|
awaitEachGesture {
|
||||||
|
val down =
|
||||||
|
awaitFirstDown(
|
||||||
|
requireUnconsumed =
|
||||||
|
false
|
||||||
)
|
)
|
||||||
|
var accumulatedPullDown = 0f
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
val event =
|
||||||
|
awaitPointerEvent()
|
||||||
|
val change =
|
||||||
|
event.changes
|
||||||
|
.firstOrNull {
|
||||||
|
it.id ==
|
||||||
|
down
|
||||||
|
.id
|
||||||
|
}
|
||||||
|
?: break
|
||||||
|
if (change.changedToUpIgnoreConsumed()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
val deltaY =
|
||||||
|
change.positionChange()
|
||||||
|
.y
|
||||||
|
val atTop =
|
||||||
|
!chatListState.canScrollBackward
|
||||||
|
|
||||||
|
if (isRequestsVisible &&
|
||||||
|
atTop &&
|
||||||
|
deltaY <
|
||||||
|
-requestsHideThresholdPx
|
||||||
|
) {
|
||||||
|
isRequestsVisible = false
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRequestsVisible &&
|
||||||
|
atTop &&
|
||||||
|
deltaY > 0f
|
||||||
|
) {
|
||||||
|
accumulatedPullDown +=
|
||||||
|
deltaY
|
||||||
|
if (accumulatedPullDown >=
|
||||||
|
requestsRevealThresholdPx
|
||||||
|
) {
|
||||||
|
isRequestsVisible = true
|
||||||
|
hapticFeedback.performHapticFeedback(
|
||||||
|
HapticFeedbackType.LongPress
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (deltaY < 0f || !atTop) {
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.background(
|
.background(
|
||||||
listBackgroundColor
|
listBackgroundColor
|
||||||
)
|
)
|
||||||
@@ -2204,6 +2192,24 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requestsCount > 0) {
|
if (requestsCount > 0) {
|
||||||
|
if (!isRequestsVisible) {
|
||||||
|
item(key = "requests_reopen_handle") {
|
||||||
|
RequestsRevealHandle(
|
||||||
|
isDarkTheme = isDarkTheme,
|
||||||
|
onClick = {
|
||||||
|
isRequestsVisible = true
|
||||||
|
hapticFeedback.performHapticFeedback(
|
||||||
|
HapticFeedbackType.LongPress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = dividerColor,
|
||||||
|
thickness = 0.5.dp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item(key = "requests_section") {
|
item(key = "requests_section") {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible =
|
visible =
|
||||||
@@ -4534,6 +4540,36 @@ fun TypingIndicatorSmall() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RequestsRevealHandle(isDarkTheme: Boolean, onClick: () -> Unit) {
|
||||||
|
val textColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF6C6C70)
|
||||||
|
val iconColor = if (isDarkTheme) Color(0xFF7E7E84) else Color(0xFF8A8A90)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier =
|
||||||
|
Modifier.fillMaxWidth().clickable(onClick = onClick).padding(
|
||||||
|
horizontal = TELEGRAM_DIALOG_AVATAR_START,
|
||||||
|
vertical = 10.dp
|
||||||
|
),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = TablerIcons.ChevronDown,
|
||||||
|
contentDescription = "Show requests",
|
||||||
|
tint = iconColor,
|
||||||
|
modifier = Modifier.size(18.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
|
Text(
|
||||||
|
text = "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