feat(groups): audio and video calls in group chats; release v6.6.6
CodeQL Analysis / Analyze CodeQL (push) Canceled after 0s
Deploy Application / deploy (push) Canceled after 0s
Mirror to Codeberg / mirror (push) Canceled after 0s
Mirror to PrivacyGuides / mirror (push) Canceled after 0s

A group call is N-1 ordinary 1:1 calls, one to each other member, each riding
the pairwise session that member already has — a transport a human already
authenticated by comparing the safety code. No mixer, no SFU, no point at which
two people's media meets anywhere but on a device.

Call control is separate from call media, because the two reach different sets
of people. Who opened a call, who joined and who left travels as group frames
signed with the sender's group identity key, so it reaches members currently
reachable only through a relay — and a relaying member can drop one but cannot
write one. Media flows only where a direct link exists, so a member without one
shows as connecting rather than being omitted. Frames carry a per-sender
sequence checked before the action, so a captured leave cannot end a later call,
and simultaneous calls converge on the lower random call id.

One capture is shared across every leg rather than one getUserMedia per member,
and legs answer without prompting: the flag permitting that is set only locally,
only while this user is in the call, and cleared when they leave.

UI: a gallery that sizes itself from the space it has, a spotlight view, an
active-speaker indicator read from the waveform, and the call surface in the
same visual language as the 1:1 one.

Also in this commit, the v6.5.0 language-suggestion work that had not been
pushed yet; its notes are in the changelog. And two fixes: the safety-code input
asks for digits rather than text, and starting a new chat from inside a group no
longer creates it behind the group where it cannot be seen — which had made it
impossible to connect to anyone new, or to add anyone to a group, while a group
was open.

Claude-Session: https://claude.ai/code/session_01XSxAkET3hQTkYDQfbjCQwZ
This commit is contained in:
lockbitchat
2026-09-01 01:04:11 -04:00
parent 5e32f547b9
commit 113bb107d3
62 changed files with 8412 additions and 1039 deletions
+11 -3
View File
@@ -155,12 +155,20 @@ assert.match(app, /webrtcManager: null/,
// the connection toast must not sit on the header
//
// It is `fixed top-4 left-1/2` (src/pwa/pwa-manager.js), which inside the chat
// lands on the 64px header and covers the peer name.
// lands on the header and covers the peer name. The offset is expressed in the
// same two variables the header's own height is (--sb-bar-h for the content row,
// --sb-safe-top for the status-bar strip an installed app draws under), so the
// toast follows the bar instead of restating a number that only holds in a
// browser tab.
// ---------------------------------------------------------------------------
{
const css = readFileSync(new URL('../src/styles/components.css', import.meta.url), 'utf8');
assert.match(css, /body\.sb-in-chat #pwa-connection-status\s*\{[^}]*top:\s*calc\(64px/,
'the online/offline toast must clear the chat header');
const rule = css.match(/body\.sb-in-chat #pwa-connection-status\s*\{[^}]*\}/);
assert.ok(rule, 'the online/offline toast must be offset inside the chat');
assert.match(rule[0], /top:\s*calc\([^)]*var\(--sb-bar-h/,
'the toast offset must track the header height, not a hard-coded 64px');
assert.match(rule[0], /var\(--sb-safe-top/,
'the toast must also clear the status-bar strip in an installed app');
}
// ---------------------------------------------------------------------------