on main help sign in
fix(scrolling): stale scrolling acceleration (#3197)
commit720698112727dacfd3d468c0414003b427aa7691 authorCharles Dong <chardon_cs@proton.me> dateWed 24 Jun 2026, 23:48 (4 months ago) parent1a7d410
2 files changed+36−1
internal/ui/model/filter.go+10 internal/ui/model/filter_test.go+26−1
internal/ui/model/filter.go+10
@@ -38,6 +38,12 @@ func (f *Filter) Filter(_ tea.Model, msg tea.Msg) tea.Msg {
3838 case tea.MouseWheelMsg:
3939 mouse := typed.Mouse()
4040 dx, dy := wheelDeltas(mouse)
41+ if oppositeSign(f.wheelDX, dx) {
42+ f.wheelDX = 0
43+ }
44+ if oppositeSign(f.wheelDY, dy) {
45+ f.wheelDY = 0
46+ }
4147 f.wheelDX += dx
4248 f.wheelDY += dy
4349 if !f.allow(&f.lastWheel) {
@@ -96,3 +102,7 @@ func wheelDeltas(mouse tea.Mouse) (float64, float64) {
96102 return 0, 0
97103 }
98104}
105+
106+func oppositeSign(a, b float64) bool {
107+ return (a < 0 && b > 0) || (a > 0 && b < 0)
108+}
internal/ui/model/filter_test.go+26−1
@@ -61,7 +61,7 @@ func TestFilter_CoalescesSameDirection(t *testing.T) {
6161 require.Equal(t, float64(3), msg.DeltaY, "should accumulate 3 down events")
6262}
6363
64−func TestFilter_DirectionChangeResetsAccumulator(t *testing.T) {
64+func TestFilter_DirectionChangeWithinWindowAccumulatesNewDirection(t *testing.T) {
6565 t.Parallel()
6666 f, now := newTestFilter(t)
6767
@@ -81,6 +81,31 @@ func TestFilter_DirectionChangeResetsAccumulator(t *testing.T) {
8181 require.Equal(t, float64(-2), msg.DeltaY, "should have 2 accumulated up events")
8282}
8383
84+func TestFilter_DirectionChangeDropsStaleAccumulator(t *testing.T) {
85+ t.Parallel()
86+ f, now := newTestFilter(t)
87+
88+ // Scroll up
89+ f.Filter(nil, wheelUp())
90+
91+ // Scroll up again
92+ *now = now.Add(5 * time.Millisecond)
93+ result := f.Filter(nil, wheelUp())
94+ require.Nil(t, result)
95+
96+ // Scroll down (accumulation should reset)
97+ *now = now.Add(5 * time.Millisecond)
98+ result = f.Filter(nil, wheelDown())
99+ require.Nil(t, result)
100+
101+ // And scroll down again
102+ *now = now.Add(20 * time.Millisecond)
103+ result = f.Filter(nil, wheelDown())
104+ msg, ok := result.(common.CoalescedWheelMsg)
105+ require.True(t, ok)
106+ require.Equal(t, float64(2), msg.DeltaY, "should drop stale opposite-direction events")
107+}
108+
84109func TestFilter_WindowExpiryEmitsAccumulated(t *testing.T) {
85110 t.Parallel()
86111 f, now := newTestFilter(t)