diff options
| author | Adam Soltys <[email protected]> | 2026-10-14 21:48:02 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-14 21:48:02 -0700 |
| commit | c8b7eff398c5a6120434c9a362c3e20edd2d662e (patch) | |
| tree | c13736064b17e348a1a86560ae312b35feb0ccca /src | |
| parent | 928da70638fceb622d5e83ed0792817e1bcd908e (diff) | |
| download | coinosv3-c8b7eff398c5a6120434c9a362c3e20edd2d662e.tar.gz coinosv3-c8b7eff398c5a6120434c9a362c3e20edd2d662e.zip | |
Notifications: a row from someone your follows reported is folded, not dropped. A reply Amethyst showed was missing from Adam's phone (2026-10-14, Johnny's reply to d558ba5d): the row was in the stored list, but two of his follows had filed kind 1984 person reports ("spam") on Johnny, which meets the two-follows bar, and the page filtered every one of Johnny's rows out without a trace — the feed and a thread fold such a post with who flagged it and a Show, the Notifications page simply lost it. Now the page keeps the row and folds it (notifFoldRow): the face, name and what they did, "Reported by mar, Rich" (up to three names, else how many), the time, and Show — which reveals it here and, being the same id, in its thread. Mutes and spam still drop the row; the unread count still leaves flagged rows out. Opening the page also syncs your follows' reports (syncReports, throttled), which only the feed and chat home did. tools/notif-report-fold-test.js.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01J1Kon8bxJoHRpJdSzshCkp
Diffstat (limited to 'src')
| -rw-r--r-- | src/features/messages.js | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 8f5adcb..a8815b0 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -14743,10 +14743,33 @@ export function messagesFeature(ctx) { (ev) => { if (mergeNotifs([ev])) scheduleRepaint(); }); } function stopNotifWatch() { if (notifUnsub) { try { notifUnsub(); } catch {} notifUnsub = null; } } - // Shown as a notification: not from someone hidden, and not something your - // follows flagged — the thread folds that post, so the tap would land on a - // fold instead of the reply it promised (or the author, flagged enough). + // Counted as a notification: not from someone hidden, and not something + // your follows flagged — the page folds that row (notifFoldRow) rather + // than count it as news. const notifShown = (x) => !hiddenPk(x.actor) && !reportsOn({ id: x.id, pubkey: x.actor }); + // Who among your follows flagged this row's author or post, unless you + // asked to see it: the row is folded, not dropped — a reply from someone + // two follows reported as spam vanished from the page without a trace + // (Adam's phone, 2026-10-14), while the thread would have shown a fold. + const notifFlagged = (x) => (ui.revealed && ui.revealed.has(x.id)) ? null : reportsOn({ id: x.id, pubkey: x.actor }); + function notifFoldRow(x, by) { + profileOf(x.actor); + for (const pk of by.slice(0, 3)) profileOf(pk); + const who = by.length <= 3 ? t('foldReported1', { name: by.map((pk) => displayName(pk)).join(', ') }) : t('foldReportedN', { n: by.length }); + return h('div', { class: 'row alert-row note-folded', style: 'gap:10px;align-items:center;padding:10px 0;opacity:.75' }, + avatar(x.actor, 'chat-avatar note-avatar', false), + h('div', { class: 'col grow', style: 'min-width:0;gap:3px' }, + h('div', { class: 'row', style: 'gap:7px;align-items:baseline;min-width:0' }, + h('span', { style: 'font-weight:600;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis' }, displayName(x.actor)), + h('span', { class: 'small', style: 'min-width:0' }, notifLabel(x)), + h('span', { class: 'small faint', style: 'white-space:nowrap;margin-left:auto' }, timeLabel(x.ts * 1000))), + h('div', { class: 'small muted' }, '\u26a0 ' + who)), + // seen here, the reply is seen in its thread too (the same id) + h('button', { + class: 'btn-sm', type: 'button', style: 'flex-shrink:0', + onClick: (e) => { e.stopPropagation(); (ui.revealed ||= new Set()).add(x.id); render(); }, + }, t('foldShow'))); + } const notifUnread = () => notifNow().items.filter((x) => x.ts > notifSeen() && notifShown(x)).length; function markNotifsSeen() { const newest = Math.max(0, ...notifNow().items.map((x) => x.ts)); @@ -14854,9 +14877,10 @@ export function messagesFeature(ctx) { } function notifView() { const c = notifNow(); + syncReports().catch(() => {}); // the folds below follow your follows' flags (throttled inside) markNotifsSeen(); // anything that lands while you look is seen too - const items = c.items.filter(notifShown); // a mute or report made later applies to what was kept - const rows = items.flatMap((x, i) => [i ? noteSep() : null, notifRow(x)]); + const items = c.items.filter((x) => !hiddenPk(x.actor)); // a mute made later applies to what was kept + const rows = items.flatMap((x, i) => { const by = notifFlagged(x); return [i ? noteSep() : null, by ? notifFoldRow(x, by) : notifRow(x)]; }); return h('div', { class: 'card col chat-page', style: 'gap:10px' }, h('div', { class: 'row gap6', style: 'align-items:center' }, backBtn(() => { ui.msgView = 'home'; stopNotifWatch(); render(); }), |
