aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-17 05:09:02 -0700
committerAdam Soltys <[email protected]>2026-10-17 05:09:02 -0700
commitfa3ce973a66a2044c8cc9ac383928d70eb32e3d0 (patch)
tree61d3cdf6a911dc1ac19e85af04d9c5f15954d8c2
parente529ab104a19ceb71f1981016fb3a857a79d3caa (diff)
downloadcoinosv3-fa3ce973a66a2044c8cc9ac383928d70eb32e3d0.tar.gz
coinosv3-fa3ce973a66a2044c8cc9ac383928d70eb32e3d0.zip
A flick near the end of the pager coasts round to the first post, rather than stopping on the last.
A fling whose coast ran past the end used to land on the last post, and a second flick was needed to wrap. Near the end of a video pager the clips still warming join the carousel one by one, so that second flick usually landed on the newest clip instead, and getting back to 1 took flick after flick (Adam, 2026-10-17: "it's a bit difficult to get back around to 1 … can we do something to make it coast right around to the start again even if a video near the end is loading in?"). Now when most of the coast lies beyond the end (fewer posts left before it than half the flick's worth), the flick wraps straight to the first post; flung up from near the top, to the last. A big flick from further back still flies to the last post. tools/pager-swipe-fly-test.js: from post 7 of 9 a flick lands on 1, a flick up from 1 lands on 9, down again to 1, a gentle swipe from 1 is 2; the long flight from post 2 still lands on 9. pager-ready-gate, pager-tap-slop, pager-wheel and pager-close pass; feed-video-pager fails the same two checks as on a clean checkout. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
-rw-r--r--src/features/messages.js12
-rw-r--r--tools/pager-swipe-fly-test.js10
2 files changed, 17 insertions, 5 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 82b1986..326c420 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -13324,12 +13324,20 @@ export function messagesFeature(ctx) {
const from = stops.reduce((bi, p, i) => (Math.abs(p - d.start) < Math.abs(stops[bi] - d.start) ? i : bi), 0);
const posts = y && step && Math.abs(vel) >= FLY_V ? Math.min(FLY_MAX, Math.max(1, Math.round(Math.abs(vel) * FLY_TAU / Math.max(1, box.clientHeight)))) : 1;
const next = from + step * posts;
+ // Past either end, round to the other: the first post (going up, the
+ // last) — a step, or a fling whose coast is mostly beyond the end. A
+ // fling from near the end used to stop on the last post, and there,
+ // where the clips still warming join one by one, each flick landed on
+ // the newest instead of getting round (Adam, 2026-10-17: "make it
+ // coast right around to the start again even if a video near the end
+ // is loading in"). A fling from further back, only its tail past the
+ // end, flies to the last post.
+ const left = step > 0 ? stops.length - 1 - from : from; // posts between here and the end it heads for
+ if (y && (next < 0 || next >= stops.length) && left * 2 < posts) { const g = pagerGroups(); pagerWrap(next < 0 ? g[g.length - 1] : g[0]); return; }
if (y && posts > 1) {
const i = Math.min(stops.length - 1, Math.max(0, next));
if (i !== from) { pagerFlyTo(pagerGroups()[i], { vel, pace: 260, most: 4000 }); return; }
}
- // past either end: round to the other (a fling at the end too — one post of wrap, not its whole count)
- if (y && (next < 0 || next >= stops.length)) { pagerWrap(pagerGroups()[(from + step + stops.length) % stops.length]); return; }
pagerGlide(box, d.axis, stops[Math.min(stops.length - 1, Math.max(0, next))], vel);
}
el.addEventListener('touchend', (e) => {
diff --git a/tools/pager-swipe-fly-test.js b/tools/pager-swipe-fly-test.js
index d809793..aec8fdd 100644
--- a/tools/pager-swipe-fly-test.js
+++ b/tools/pager-swipe-fly-test.js
@@ -99,13 +99,17 @@ try {
const seen = await page.evaluate(() => document.querySelector('.mp-position').textContent);
check('the counter says where it landed', seen === landed + ' / ' + N, seen);
- console.log('\n[a flick near the end: the last post, not past it]');
+ console.log('\n[a flick near the end coasts round to the start]');
while ((await at()) !== 7) { await page.keyboard.press((await at()) < 7 ? 'ArrowDown' : 'ArrowUp'); await settled(); }
const before = await at();
await swipe(600, 80, 3); await settled();
- check('from post ' + before + ' (a flight\'s worth would be past the end), a flick lands on the last post', before >= 7 && (await at()) === N, String(await at()));
+ check('from post ' + before + ' (a flight\'s worth would be past the end), a flick comes round to the first post', before >= 7 && (await at()) === 1, String(await at()));
+ await swipe(-600, 80, 3); await settled();
+ check('…and a flick back up from the first comes round to the last', (await at()) === N, String(await at()));
await swipe(600, 80, 3); await settled();
- check('…and one more flick at the end wraps to the first', (await at()) === 1, String(await at()));
+ check('…a flick down from the last, to the first again', (await at()) === 1, String(await at()));
+ await swipe(320, 130); await settled();
+ check('a gentle swipe from the first: the second, as ever', (await at()) === 2, String(await at()));
console.log('\n[a finger down mid-flight catches it]');
await swipe(600, 80, 3);