feat(groups): audio and video calls in group chats; release v6.6.6
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:
@@ -148,6 +148,29 @@ export function direction(code = currentLocale()) {
|
||||
*/
|
||||
export const LTR_TEXT = { dir: 'ltr', style: { unicodeBidi: 'isolate', textAlign: 'start' } };
|
||||
|
||||
/**
|
||||
* The suggestion is an offer, and an offer that keeps coming back after it was turned
|
||||
* down is an ad. One dismissal is remembered for good; storage can be unavailable, in
|
||||
* which case the bar simply comes back — a worse experience, never a broken one.
|
||||
*/
|
||||
const SUGGEST_KEY = 'securebit-locale-suggest-dismissed';
|
||||
|
||||
export function localeSuggestionDismissed() {
|
||||
try {
|
||||
return localStorage.getItem(SUGGEST_KEY) === '1';
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function dismissLocaleSuggestion() {
|
||||
try {
|
||||
localStorage.setItem(SUGGEST_KEY, '1');
|
||||
} catch (_) {
|
||||
// Nothing to do: the bar reappears next visit, which is not worth an exception.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A locale the visitor would probably rather read, when it is not the one they are on.
|
||||
* Used to offer a link, never to redirect: an automatic redirect sends Googlebot —
|
||||
|
||||
Reference in New Issue
Block a user