fix: scroll button direction follows scroll position
Single button instead of two mutually exclusive ones. Arrow direction is based on proximity to bottom: near bottom → arrow up (scroll to top), not near bottom → arrow down (scroll to end). Updates instantly as the user scrolls. Hidden when already at the target end. Old logic had an if/else that always showed ArrowUp first (because !atTop was always true when scrolled down), making ArrowDown unreachable in most scroll positions.
This commit is contained in:
parent
f855a26b31
commit
fd684fff2e
1 changed files with 22 additions and 25 deletions
|
|
@ -908,15 +908,18 @@ fun ChatScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isStreaming) {
|
if (!isStreaming) {
|
||||||
val atTop by remember { derivedStateOf { listState.firstVisibleItemIndex <= 1 } }
|
|
||||||
val atBottom by remember { derivedStateOf {
|
|
||||||
val info = listState.layoutInfo
|
|
||||||
info.visibleItemsInfo.lastOrNull()?.index == info.totalItemsCount - 1
|
|
||||||
}}
|
|
||||||
val canScrollUp by remember { derivedStateOf { listState.canScrollBackward } }
|
val canScrollUp by remember { derivedStateOf { listState.canScrollBackward } }
|
||||||
val canScrollDown by remember { derivedStateOf { listState.canScrollForward } }
|
val canScrollDown by remember { derivedStateOf { listState.canScrollForward } }
|
||||||
|
val showButton = canScrollUp || canScrollDown
|
||||||
|
val nearBottom by remember { derivedStateOf {
|
||||||
|
val info = listState.layoutInfo
|
||||||
|
val lastVisible = info.visibleItemsInfo.lastOrNull()?.index ?: 0
|
||||||
|
val total = info.totalItemsCount
|
||||||
|
if (total <= 0) true else lastVisible >= total - 2
|
||||||
|
}}
|
||||||
|
val pointsUp = !nearBottom && canScrollUp
|
||||||
|
|
||||||
if (!atTop && canScrollUp) {
|
if (showButton && !(canScrollUp && !canScrollDown && nearBottom)) {
|
||||||
GlassSurface(
|
GlassSurface(
|
||||||
shape = KaizenShapes.circle,
|
shape = KaizenShapes.circle,
|
||||||
tintAlpha = GlassTiers.pill(isSystemInDarkTheme()),
|
tintAlpha = GlassTiers.pill(isSystemInDarkTheme()),
|
||||||
|
|
@ -924,28 +927,22 @@ fun ChatScreen(
|
||||||
cornerRadius = 18.dp,
|
cornerRadius = 18.dp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterEnd)
|
.align(Alignment.CenterEnd)
|
||||||
.padding(end = 8.dp, bottom = 24.dp)
|
.padding(end = 8.dp)
|
||||||
.size(36.dp)
|
.size(36.dp)
|
||||||
.clickable { scope.launch { listState.animateScrollToItem(0) } },
|
.clickable {
|
||||||
|
scope.launch {
|
||||||
|
if (pointsUp) listState.animateScrollToItem(0)
|
||||||
|
else listState.animateScrollToItem(messages.size - 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
Icon(KaizenIcons.ArrowUp, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp))
|
Icon(
|
||||||
}
|
if (pointsUp) KaizenIcons.ArrowUp else KaizenIcons.ArrowDown,
|
||||||
}
|
null,
|
||||||
} else if (!atBottom && canScrollDown) {
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
GlassSurface(
|
modifier = Modifier.size(20.dp),
|
||||||
shape = KaizenShapes.circle,
|
)
|
||||||
tintAlpha = GlassTiers.pill(isSystemInDarkTheme()),
|
|
||||||
shadowStack = KaizenShadows.level1,
|
|
||||||
cornerRadius = 18.dp,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterEnd)
|
|
||||||
.padding(end = 8.dp, top = 24.dp)
|
|
||||||
.size(36.dp)
|
|
||||||
.clickable { scope.launch { listState.animateScrollToItem(messages.size - 1) } },
|
|
||||||
) {
|
|
||||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
|
||||||
Icon(KaizenIcons.ArrowDown, null, tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue