aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-13 04:48:44 +0000
committerAdam Soltys <[email protected]>2026-10-13 04:48:44 +0000
commit75a5bec9490ce1e28b7c37b864f9ca9d6e621204 (patch)
treeda1d61d1cdcba4562a9895662cb80ce70da4fae9 /src
parentb22832ffd5df280811559cdbf0455305321e160c (diff)
downloadcoinosv3-75a5bec9490ce1e28b7c37b864f9ca9d6e621204.tar.gz
coinosv3-75a5bec9490ce1e28b7c37b864f9ca9d6e621204.zip
Feed pager: closing it lands on the post of the slide last looked at, and the clips ahead are looked for sooner. Adam swiped to the last clip (one more loaded, slowly), closed the pager and the feed was somewhere else. Closing used glideToPost: for a row never drawn — a post the pager went on to, maybe paged in while it was open — it guesses the place from the rows' average height, draws there, and glides once to wherever the row then is; rows of very different heights (a long post, a clip finding its shape) put the guess far off, and the glide was never corrected as they settled (in the test: 325px past it; a row still undrawn after the guess sent the feed to the top). Now landOnPost jumps (the pager was covering the feed), draws, and sets the row under the top again each frame until it has sat still a moment, 2.5 s have gone, the reader touches the page, or the page is sent elsewhere. And the pager keeps more ahead before paging the feed on: six slides for clips (fewer and further between, each watched a while), four for pictures (was three). feed-pager-ahead-test: some of the words-only posts are long now, and closing on the second-last picture checks the feed sits on its post after the pictures above have loaded (fails before: row top -325).
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js50
1 files changed, 44 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 2580ed9..9cba810 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -11934,12 +11934,48 @@ export function messagesFeature(ctx) {
let tries = 0;
const go = () => {
if (ui.mediaPager || !document.querySelector('.notes-feed')) { if (++tries < 90) requestAnimationFrame(go); return; }
- const list = c.winList ? c.winList() : c.notes;
- const i = list.findIndex((e) => e.id === rowId);
- if (i >= 0) glideToPost(c, list, i);
+ landOnPost(c, rowId);
};
requestAnimationFrame(go);
}
+ // Put the feed on a post the reader hasn't been near — one the pager went
+ // on to, maybe paged in while it was open and never drawn. Its place is
+ // only a guess until it is drawn, and the rows around it settle as they
+ // draw (a long post, a picture finding its size), so: jump to the guess,
+ // draw, and set the row under the top again each frame — until it has sat
+ // still a moment, a couple of seconds have gone, or the reader touches the
+ // page. A jump, not a glide: the pager was covering the feed.
+ function landOnPost(c, rowId) {
+ const MARGIN = 8, t0 = Date.now();
+ const find = () => document.querySelector('.notes-feed > [data-key="' + CSS.escape(rowId) + '"]');
+ let still = 0, misses = 0, lastY = null;
+ const step = () => {
+ if (c !== feed || ui.mediaPager || !document.querySelector('.notes-feed') || lastInputAt > t0 || Date.now() - t0 > 2500) return;
+ // the page sent somewhere else meanwhile (not by a finger: a glide, a link)
+ if (lastY !== null && Math.abs(window.scrollY - lastY) > window.innerHeight / 2) return;
+ const el = find();
+ if (!el) {
+ const list = c.winList ? c.winList() : c.notes;
+ const i = list.findIndex((e) => e.id === rowId);
+ if (i < 0 || ++misses > 20) return;
+ let sum = 0, n = 0;
+ for (const v of (c.heights || new Map()).values()) { sum += v; n++; }
+ const avg = n ? sum / n : 200;
+ let y = 0;
+ for (let j = 0; j < i; j++) y += ((c.heights && c.heights.get(list[j].id)) || avg) + ROW_GAP;
+ window.scrollTo(0, Math.max(0, (c.listTop || 0) + y - MARGIN));
+ render();
+ requestAnimationFrame(step);
+ return;
+ }
+ const off = el.getBoundingClientRect().top - MARGIN;
+ if (Math.abs(off) > 2) { window.scrollTo(0, Math.max(0, window.scrollY + off)); still = 0; }
+ else if (++still >= 20 && Date.now() - t0 > 600) return;
+ lastY = window.scrollY;
+ requestAnimationFrame(step);
+ };
+ step();
+ }
// Leaving the pager for another page (a profile, sign-in, the zap amount):
// only the feed's own render syncs the pager, and those pages don't paint
// the feed — so the overlay goes now, not on the next feed render.
@@ -12262,11 +12298,13 @@ export function messagesFeature(ctx) {
}
// A pager opened from the feed walks the feed's own posts, which page in
// ten at a time as the feed is scrolled. Swiping is the scrolling here:
- // with only a few slides left past the one on screen, the feed pages on
+ // with only a few slides left past the one on screen (PAGER_AHEAD), the feed pages on
// (the posts it holds, then older ones from the relays) until there are
// more — several pages if those posts carry none. A page that brings
// nothing (the feed busy, or at its end) stops it; the tick tries again.
- const PAGER_AHEAD = 3;
+ // how many slides ahead to keep: clips are fewer and further between
+ // (more pages to find the next) and each is watched a while, so further
+ const PAGER_AHEAD = { images: 4, videos: 6 };
let pagerFeeding = false;
async function pagerFeedAhead() {
if (pagerFeeding || !pager || !pager.fromFeed) return;
@@ -12275,7 +12313,7 @@ export function messagesFeature(ctx) {
const c = feedNow();
for (let pages = 0; pages < 8 && pager && pager.fromFeed; pages++) {
const slides = [...pager.scroller.children];
- if (slides.length - 1 - slides.indexOf(pager.cur) > PAGER_AHEAD) break;
+ if (slides.length - 1 - slides.indexOf(pager.cur) > (PAGER_AHEAD[pager.kind] || 4)) break;
const shown = c.shown, held = c.notes.length;
await loadOlderFeed();
growPager();