2 Commits
Author SHA1 Message Date
weishauptandClaude Sonnet 5.5 d58b5772df Bump to 0.1.17
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 14:12:59 -04:00
weishauptandClaude Sonnet 5.5 fff75700ac Fix scrollback snapping back to bottom after scrolling up
Wheel-up now clears stickToBottom immediately on the raw scroll event, wheel-down re-checks the resting position, and the auto-scroll effect re-checks stickToBottom right before scrollToItem(0). The scroll-state effect could miss a wheel scroll that began and ended within one frame, so the next incoming line pulled the buffer back to the bottom.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JW57ZvxRmxcDF7AFACLSoV
2026-10-29 18:09:13 +00:00
2 changed files with 29 additions and 4 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("jvm") version "1.9.24" kotlin("jvm") version "1.9.24"
@@ -6,7 +6,7 @@ plugins {
} }
group = "com.tpuahsiew.wirc" group = "com.tpuahsiew.wirc"
version = "0.1.16" version = "0.1.17"
// No project-level repositories{} block here: settings.gradle.kts sets // No project-level repositories{} block here: settings.gradle.kts sets
// dependencyResolutionManagement.repositoriesMode = FAIL_ON_PROJECT_REPOS and already // dependencyResolutionManagement.repositoriesMode = FAIL_ON_PROJECT_REPOS and already
@@ -40,7 +40,7 @@ compose.desktop {
appResourcesRootDir.set(project.file("installerResources")) appResourcesRootDir.set(project.file("installerResources"))
targetFormats(TargetFormat.Msi, TargetFormat.Exe) targetFormats(TargetFormat.Msi, TargetFormat.Exe)
packageName = "wIRC" packageName = "wIRC"
packageVersion = "0.1.16" packageVersion = "0.1.17"
windows { windows {
menuGroup = "wIRC" menuGroup = "wIRC"
upgradeUuid = "8f14e45f-ceea-4a5e-9c3b-5b1f0e8c2b7a" upgradeUuid = "8f14e45f-ceea-4a5e-9c3b-5b1f0e8c2b7a"
+26 -1
View File
@@ -818,7 +818,7 @@ fun MessageScrollback(
.first { item -> .first { item ->
item == null || (item.index < capturedList.size && item.key == capturedList[item.index].seq) item == null || (item.index < capturedList.size && item.key == capturedList[item.index].seq)
} }
listState.scrollToItem(0) if (stickToBottom) listState.scrollToItem(0)
} }
} }
@@ -923,6 +923,31 @@ fun MessageScrollback(
.height(snappedHeight) .height(snappedHeight)
.onGloballyPositioned { containerCoords[0] = it } .onGloballyPositioned { containerCoords[0] = it }
.pointerHoverIcon(PointerIcon.Text) .pointerHoverIcon(PointerIcon.Text)
// Wheel-up means the user is reading backscroll: stop sticking to the bottom RIGHT NOW,
// on the raw wheel event. The scroll-state effect up top can miss a wheel scroll that starts
// and finishes inside one frame (isScrollInProgress is never seen as true), which left
// stickToBottom set and let the next incoming line yank the buffer back down.
// Wheel-down re-checks the resting position shortly after and re-enables sticking if the
// user is back at the bottom.
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Initial)
if (event.type == PointerEventType.Scroll) {
val dy = event.changes.firstOrNull()?.scrollDelta?.y ?: 0f
if (dy < 0f) {
stickToBottom = false
} else if (dy > 0f) {
coroutineScope.launch {
delay(200)
stickToBottom = listState.firstVisibleItemIndex == 0 &&
listState.firstVisibleItemScrollOffset <= stickToBottomThresholdPx
}
}
}
}
}
}
// Remembers the row under a right-click for the menu's "Copy line". Watches the // Remembers the row under a right-click for the menu's "Copy line". Watches the
// Initial pass, because ContextMenuArea takes the right-press there, before // Initial pass, because ContextMenuArea takes the right-press there, before
// the handler below would see it. // the handler below would see it.