32 lines
1.0 KiB
TypeScript
32 lines
1.0 KiB
TypeScript
import { isUserId } from './matrix';
|
|||
|
|
|
||
|
|
/** Minimal shape of a `io.lotus.call_state` participant entry we need here. */
|
||
|
|
export type SpeakingParticipant = { userId: string; speaking: boolean };
|
||
|
|
|
||
|
|
/** True when both sets contain exactly the same members. */
|
||
|
|
export const sameSet = <T>(a: Set<T>, b: Set<T>): boolean => {
|
||
|
|
if (a === b) return true;
|
||
|
|
if (a.size !== b.size) return false;
|
||
|
|
for (const v of a) {
|
||
|
|
if (!b.has(v)) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Derives the speaking-users set from a `io.lotus.call_state` participant
|
||
|
|
* list. Returns `prev` unchanged (same reference) when the derived set is
|
||
|
|
* equal to it, so callers using the functional `setState` form can bail out
|
||
|
|
* of a re-render (#32 — the fork pushes this multiple times per second).
|
||
|
|
*/
|
||
|
|
export const nextSpeakerSet = (
|
||
|
|
prev: Set<string>,
|
||
|
|
participants: readonly SpeakingParticipant[],
|
||
|
|
): Set<string> => {
|
||
|
|
const next = new Set<string>();
|
||
|
|
participants.forEach((p) => {
|
||
|
|
if (p.speaking && isUserId(p.userId)) next.add(p.userId);
|
||
|
|
});
|
||
|
|
return sameSet(prev, next) ? prev : next;
|
||
|
|
};
|