diff options
| author | Adam Soltys <[email protected]> | 2026-10-18 06:19:39 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-18 06:19:39 -0700 |
| commit | 7859a2fb3937f44727c9a3408d407da926b4f724 (patch) | |
| tree | 2f54e0c4aa991187ca91642b06e1752a5944540b | |
| parent | 78fbd1fb0be6c7029409c8ab5cb020009853c4c5 (diff) | |
| download | coinosv3-7859a2fb3937f44727c9a3408d407da926b4f724.tar.gz coinosv3-7859a2fb3937f44727c9a3408d407da926b4f724.zip | |
The media pager no longer goes round from its last post to its first (or first to last): a step, a flick or the wheel at an end stays there.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
| -rw-r--r-- | src/features/messages.js | 39 | ||||
| -rw-r--r-- | tools/pager-swipe-fly-test.js | 18 | ||||
| -rw-r--r-- | tools/profile-pager-test.js | 15 |
3 files changed, 26 insertions, 46 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 66bee68..0c69f23 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -13217,12 +13217,9 @@ export function messagesFeature(ctx) { if (v) { const groups = pagerGroups(); const from = here && here.closest('.mp-group'); - const index = groups.indexOf(from) + v; - const to = groups[(index + groups.length) % groups.length]; - if (to) { - if (index < 0 || index >= groups.length) pagerWrap(to); - else pagerGlide(pager.scroller, 'y', pagerAt(pager.scroller, to, true)); - } + // the ends are ends: no going round to the other (Adam, 2026-10-18) + const to = groups[groups.indexOf(from) + v]; + if (to) pagerGlide(pager.scroller, 'y', pagerAt(pager.scroller, to, true)); return !!to; } if (hz) { @@ -13264,10 +13261,10 @@ export function messagesFeature(ctx) { const here = pagerHere(); from = here && here.closest('.mp-group'); } - const next = stops.indexOf(from) + dir * (n <= 2 || !pagerCanFly() ? 1 : 2); - const i = (next % stops.length + stops.length) % stops.length; - if (next < 0 || next >= stops.length) { fly = null; pagerWrap(stops[i]); return; } + // a flight stops at the end it reaches + const i = Math.min(stops.length - 1, Math.max(0, stops.indexOf(from) + dir * (n <= 2 || !pagerCanFly() ? 1 : 2))); const to = stops[i]; + if (to === from && !live) return; fly = { to, n, at: now, dir }; if (live) pager.scroller._onDone = null; // the flight goes on: not a landing pagerFlyTo(to); @@ -13310,17 +13307,6 @@ export function messagesFeature(ctx) { pager.el.classList.toggle('has-right', !!slide.nextElementSibling); } - // Crossing the boundary jumps directly to the other end, without flying - // backwards through every loaded post or waiting for a network request. - function pagerWrap(group) { - if (!pager || !group) return; - pager.scroller._onDone = null; - pagerHold(pager.scroller); - pager.scroller.style.scrollSnapType = ''; - pager.flying = false; - const slide = rowSlide(group); - if (slide) { pagerShow(slide); pagerArrive(slide); } - } // Counted: the posts in the carousel — the ones that can be reached. (All // the posts found, the waiting ones too, was tried and undone: a count // that can't be scrolled to confused — Adam, 2026-10-17.) @@ -13477,17 +13463,10 @@ export function messagesFeature(ctx) { // the stop it set off from, then one along (or back) — or, flung, several 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 && pagerCanFly() && !(d.caught && step !== d.caught) ? Math.min(FLY_MAX, Math.max(1, Math.round(Math.abs(vel) * FLY_TAU / Math.max(1, box.clientHeight)))) : 1; + // past either end, it stops at the end: going round to the other end + // was tried and undone (Adam, 2026-10-18: "let's not make the media + // pager circle around to the start anymore") 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; } diff --git a/tools/pager-swipe-fly-test.js b/tools/pager-swipe-fly-test.js index 707aad6..657ea75 100644 --- a/tools/pager-swipe-fly-test.js +++ b/tools/pager-swipe-fly-test.js @@ -1,8 +1,9 @@ // On a phone, a fast flick up or down in the media pager flies past several // posts and lands snapped on one, the way a spin of the wheel does; a // gentler swipe is one post, as before; a fling at the end lands on the -// last post rather than wrapping past it; a tap mid-flight stops it on the -// post most on screen, and a swipe back from there goes to the one before. +// last post and goes no further (no going round to the first); a tap +// mid-flight stops it on the post most on screen, and a swipe back from +// there goes to the one before. // Run: bun tools/pager-swipe-fly-test.js import puppeteer from './puppeteer.js'; import { cacheKeyFor } from '../src/wallet.js'; @@ -121,15 +122,18 @@ 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 coasts round to the start]'); + console.log('\n[the ends are ends]'); 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 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())); + check('from post ' + before + ', a flick whose flight would be past the end lands on the last post', before === 7 && (await at()) === N, String(await at())); await swipe(600, 80, 3); await settled(); - check('…a flick down from the last, to the first again', (await at()) === 1, String(await at())); + check('…a flick on from the last stays there (no going round to the first)', (await at()) === N, String(await at())); + await page.keyboard.press('ArrowDown'); await settled(); + check('…and so does ↓', (await at()) === N, String(await at())); + while ((await at()) !== 1) { await page.keyboard.press('ArrowUp'); await settled(); } + await swipe(-600, 80, 3); await settled(); + check('a flick back up from the first stays on the first', (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())); diff --git a/tools/profile-pager-test.js b/tools/profile-pager-test.js index aac681a..2a78598 100644 --- a/tools/profile-pager-test.js +++ b/tools/profile-pager-test.js @@ -105,18 +105,15 @@ try { await page.keyboard.press('ArrowDown'); check('down again: her last', await resting('d.png'), await curPic()); await page.keyboard.press('ArrowDown'); await sleep(600); - check('past her last wraps to her first post', await resting('a2.png'), await curPic()); - check('counter counts the first post once', await page.$eval('.mp-position', (e) => e.textContent) === '1 / 3'); + check('past her last it stays on her last (no going round)', await resting('d.png'), await curPic()); + check('counter still at the last post', await page.$eval('.mp-position', (e) => e.textContent) === '3 / 3'); check('no loading slide', await page.$('.mp-tail') === null); - await page.keyboard.press('ArrowUp'); await resting('d.png'); - check('up from first wraps to last', await curPic() === 'd.png'); - check('counter at the last post', await page.$eval('.mp-position', (e) => e.textContent) === '3 / 3'); await page.touchscreen.touchStart(195, 650); for (let i = 1; i <= 8; i++) { await page.touchscreen.touchMove(195, 650 - 40 * i); await sleep(16); } - await page.touchscreen.touchEnd(); - check('touch swipe wraps to first post', await resting('a2.png'), await curPic()); - await page.evaluate(() => document.querySelector('.media-pager').dispatchEvent(new WheelEvent('wheel', { deltaY: -3, deltaMode: 1, bubbles: true, cancelable: true }))); - check('wheel wraps back to last post', await resting('d.png'), await curPic()); + await page.touchscreen.touchEnd(); await sleep(600); + check('a touch swipe on from her last stays there', await resting('d.png'), await curPic()); + await page.evaluate(() => document.querySelector('.media-pager').dispatchEvent(new WheelEvent('wheel', { deltaY: 3, deltaMode: 1, bubbles: true, cancelable: true }))); await sleep(600); + check('…and so does the wheel', await resting('d.png'), await curPic()); await page.keyboard.press('ArrowUp'); check('up: her post before', await resting('b.png'), await curPic()); await page.keyboard.press('Escape'); |
