fix: low-tail correctness — thread notifs, call audio, OIDC expiry
Verify-then-fix batch of minor bugs; each staged diff reviewed by 2 agents (both SHIP). Two listed items (N6 receipt-avatar refresh, H10 room-name length reject) were already handled and left unchanged. Threads: - T5: a just-sent reply no longer under-notifies — `participated` also checks the local thread timeline for our own events, since the server-bundle `hasCurrentUserParticipated` lags. - T6: a room set to "Mentions & Keywords only" no longer over-notifies Default thread replies — new `roomMentionsOnly` gate (behavior-identical when false; +4 unit tests). - T7: thread-mode account-data writes are serialized with content carried forward (setAccountData is a bare PUT whose result lags the /sync echo, so plain serialization wouldn't stop the lost update); carry only on success. Calls / audio: - C-L2: a real incoming ring cancels a lingering Settings ringtone preview. - C-L3: the ringtone AudioContext is primed on the first page gesture (via the always-mounted CallEmbedProvider) so the first ring after a cold load isn't silent. - C-L5: useCallSpeakers depends on a stable boolean, so the tile MutationObserver + io.lotus.call_state subscription aren't rebuilt on every membership change. Crypto: - F5: the OIDC refresher forwards the freshly-refreshed token expiry (passed on the tokens object at runtime) as expiresInMs, so the persisted expiresAt no longer goes stale across reloads. Gates: tsc 0, eslint 0, prettier clean, 860/860 tests, build ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -42,7 +42,7 @@ import { CallEmbed, useCallControlState } from '../plugins/call';
|
||||
import { useSelectedRoom } from '../hooks/router/useSelectedRoom';
|
||||
import { ScreenSize, useScreenSizeContext } from '../hooks/useScreenSize';
|
||||
import { useMatrixClient } from '../hooks/useMatrixClient';
|
||||
import { previewRingtone, startRingtone } from '../utils/ringtones';
|
||||
import { previewRingtone, startRingtone, unlockRingtoneAudio } from '../utils/ringtones';
|
||||
import { useCallMembersChange, useCallSession } from '../hooks/useCall';
|
||||
import { useCallJoinLeaveSounds } from '../hooks/useCallJoinLeaveSounds';
|
||||
import { useCallQuality } from '../hooks/useCallQuality';
|
||||
@@ -703,6 +703,23 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
|
||||
|
||||
const { screenshare: pipScreenshare } = useCallControlState(callEmbed?.control);
|
||||
|
||||
// C-L3 — prime the ringtone AudioContext on the first user gesture of the
|
||||
// session so the first incoming-call ring isn't silent (a fresh context stays
|
||||
// suspended until a gesture, and an incoming ring has none of its own).
|
||||
useEffect(() => {
|
||||
const prime = () => {
|
||||
unlockRingtoneAudio();
|
||||
window.removeEventListener('pointerdown', prime);
|
||||
window.removeEventListener('keydown', prime);
|
||||
};
|
||||
window.addEventListener('pointerdown', prime, { once: true, passive: true });
|
||||
window.addEventListener('keydown', prime, { once: true, passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('pointerdown', prime);
|
||||
window.removeEventListener('keydown', prime);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Sync pip mode into CallControl so it can adjust behavior accordingly
|
||||
useEffect(() => {
|
||||
if (!callEmbed) return;
|
||||
|
||||
Reference in New Issue
Block a user