jumpy scroll 2

This commit is contained in:
Ian Gulliver
2026-10-17 10:52:39 -07:00
parent 82d6457d87
commit b85de9a2d0
2 changed files with 16 additions and 3 deletions
+12 -3
View File
@@ -1,5 +1,6 @@
import AppKit
import ByreAPI
import os
import SwiftUI
enum ChatKind: Equatable {
@@ -484,10 +485,13 @@ struct CompactButton: View {
}
}
let scrollLog = Logger(subsystem: "run.fc.byre.mac", category: "scroll")
private struct ScrollMetrics: Equatable {
let content: CGFloat
let visible: CGFloat
let distance: CGFloat
let offset: CGFloat
}
private struct TranscriptScroll: View {
@@ -535,25 +539,30 @@ private struct TranscriptScroll: View {
.scrollPosition($position)
.defaultScrollAnchor(.bottom)
.onScrollGeometryChange(for: ScrollMetrics.self) { g in
ScrollMetrics(content: g.contentSize.height, visible: g.visibleRect.height, distance: g.contentSize.height - g.visibleRect.maxY)
ScrollMetrics(content: g.contentSize.height, visible: g.visibleRect.height, distance: g.contentSize.height - g.visibleRect.maxY, offset: g.contentOffset.y)
} action: { old, new in
let snap = !scrolling && model.stuck && new.distance > 1 && (new.content != old.content || new.visible != old.visible)
scrollLog.notice("geom rows=\(model.builder.root.rows.count) content=\(new.content) dContent=\(new.content - old.content) offset=\(new.offset) dOffset=\(new.offset - old.offset) visible=\(new.visible) distance=\(new.distance) scrolling=\(scrolling) stuck=\(model.stuck) snap=\(snap)")
if scrolling {
model.stuck = new.distance < 80
return
}
if model.stuck && new.distance > 1 && (new.content != old.content || new.visible != old.visible) {
if snap {
position.scrollTo(edge: .bottom)
}
}
.onScrollPhaseChange { _, phase in
.onScrollPhaseChange { old, phase in
scrollLog.notice("phase \(String(describing: old), privacy: .public) -> \(String(describing: phase), privacy: .public)")
scrolling = phase.isScrolling
}
.onChange(of: model.builder.pending.count) {
scrollLog.notice("pending scrollTo bottom")
model.stuck = true
position.scrollTo(edge: .bottom)
}
.onChange(of: model.scrollRequest?.seq, initial: true) {
if let r = model.scrollRequest {
scrollLog.notice("request scrollTo \(String(describing: r.id), privacy: .public)")
position.scrollTo(id: r.id, anchor: r.anchor)
}
}