Round 2 fixes from on-device testing (#2,#3,#6,#8,#9,#13,#14,#18 + call re-ring)

#2  Don't ping/notify when you're ACTIVELY viewing a chat (app visible + chat
    open). Alert only when a different chat, OR the open chat while the app is
    minimised (the backgrounded case that used to stay silent).
#3  A reaction to my message now raises an unread badge on that conversation
    (like a new message), not just a notification.
#6  Image lightbox pulls EVERY image in the conversation via /api/messages/media
    (older images aren't in the DOM yet) — nav arrows reach them all. Nav buttons
    always in the DOM; syncArrows shows/hides at the ends and for a single image.
#8  On app resume (visibilitychange / native appStateChange), reconnect the chat
    socket if it isn't OPEN and re-pull the sidebar so online/last-seen refresh —
    iOS freezes the WebView so the socket can be dead while its onclose lags,
    leaving contacts stuck on a stale "Offline".
#9  Real cause was iOS "sticky :hover": a single tap latched :hover and popped the
    action bar. Gate the hover-reveal behind @media (hover:hover) so touch reveals
    actions ONLY via long-press; a plain tap performs the primary action.
#13 Pinned bar gains a "‹ 1 of n ›" pager to walk through multiple pinned messages
    (shown only when more than one is pinned).
#14 Editing a message no longer eats a half-written draft — the real draft is set
    aside on edit start and restored on save/cancel. edited_at is now in the message
    DTO so the "edited" tag survives a reload.
#18 One "Delete" entry opens a branded dialog with "Delete for me" / "Delete for
    everyone" (icons + descriptions) and a ✕/backdrop cancel, replacing the two
    separate menu items.
New: a participant who LEAVES a still-running call is no longer auto-rung back in
    on every socket reconnect. Track who left per call; replayActiveCalls sends
    them noRing state (refreshes the Join affordance without ringing). An explicit
    re-invite clears that and rings again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 00:22:50 +05:30
parent ad48829337
commit 971a6fdf22
5 changed files with 163 additions and 47 deletions
+4
View File
@@ -406,6 +406,10 @@ async function leaveMeeting(ws) {
if (!peers) { if (leaverId) CHAT.broadcastPresence(leaverId); return; }
try { await require('./calls').finalizeTranscript(room, ws._meetingUserId); } catch (_) {} // save THIS user's transcript
peers.delete(pid);
// #New1: remember this user LEFT, so a later socket reconnect doesn't auto-ring them back into a call that's
// still running for the others (replayActiveCalls sends them noRing state instead). Harmless on a call that
// then ends. Only meaningful for a group/promoted call that survives one person leaving.
try { if (leaverId) require('./calls').markLeft(room, leaverId); } catch (_) {}
// 1:1 call: end it for everyone ONLY when fewer than two people would remain. A DM call that had
// extra people ADDED (via "Add people") is effectively a group now — one participant closing their
// app must NOT hang up the call for the rest (#11). We only tear the whole thing down when ≤1 person