From b330cc707fab62365c29b57d414c46aa198febef Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 13 Oct 2026 06:06:40 +0000 Subject: Feed pager: pictures (and clips) in a quoted post are in it too. Adam full-screened the screenshots in a quoted post and couldn't swipe on: a tap on a picture in the feed opens the pager on it only if it is among the pager's slides, and those were each feed post's own pictures — a quoted post's are its own, drawn inside the one quoting it, so the tap fell back to the picture alone (the lightbox), with nothing to swipe to. Now the pager takes, after each post's own pictures (or clips), those of the posts it quotes, as far as they've been fetched (and not hidden or folded as sensitive): swipes walk through them and on to the next post's, the slide's details name the quoted post's author and words, and closing lands on the post that quoted it. tools/quote-pager-test.js (a post with its own picture quoting one with two, served only by a relay: the tap opens the pager on the quoted picture, down through the quote and on, up to the quoting post's own, the quoted author in the details, Escape onto the quoting post) — with the quotes left out it fails as Adam saw, the picture opening alone. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt --- src/features/messages.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'src/features/messages.js') diff --git a/src/features/messages.js b/src/features/messages.js index 598ff39..a3c7cd5 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -11789,16 +11789,33 @@ export function messagesFeature(ctx) { // before the next post's — for the pager opened from one in the feed: the // feed's own list (its order, its moderation), not the media index. Clips // of every shape, not only the tall ones the Videos view flips through. + // The posts a post quotes (drawn inside it), as far as they've been fetched. + function quotedIn(ev) { + const out = []; + for (const m of String(ev.content || '').matchAll(/nostr:((?:note|nevent)1[a-z0-9]+)/gi)) { + const ref = parseNostrRef(m[1].toLowerCase()); + const q = ref && ref.type === 'event' && quoted.get(ref.id); + if (q && q.ev && FEED_KINDS.includes(q.ev.kind) && !hidden(q.ev) && !out.includes(q.ev)) out.push(q.ev); + } + return out; + } function feedMediaItems(c, kind) { const out = []; const list = c.winList ? c.winList() : c.notes; + const sensitive = (e) => modOn('sensitive') && sensitiveWhy(e) !== null && !isMe(e.pubkey); + const add = (e, row) => { + if (kind === 'videos') learnVideoMeta(e); + const urls = kind === 'videos' ? clipUrlsOf(e) + : noteMediaUrls(e.content).filter((u) => !u.startsWith('https://i.ytimg.com/')); + for (const url of urls) out.push({ ev: e, url, row }); + }; for (const row of list) { const ev = row.kind === REPOST ? repostInner(row) || row : row; - if (modOn('sensitive') && sensitiveWhy(ev) !== null && !isMe(ev.pubkey)) continue; - if (kind === 'videos') learnVideoMeta(ev); - const urls = kind === 'videos' ? clipUrlsOf(ev) - : noteMediaUrls(ev.content).filter((u) => !u.startsWith('https://i.ytimg.com/')); - for (const url of urls) out.push({ ev, url, row }); + if (sensitive(ev)) continue; + add(ev, row); + // then the pictures (clips) of the posts it quotes, which are drawn + // inside it: tapped there, one opened alone, with nothing to swipe to + for (const q of quotedIn(ev)) if (!sensitive(q)) add(q, row); } return out; } -- cgit v1.2.3