Use call view model for hand raised reactions

This commit is contained in:
Half-Shot
2024-12-09 15:19:27 +00:00
parent 081221731e
commit 73ee088605
2 changed files with 29 additions and 17 deletions

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { ReactNode, useDeferredValue, useEffect, useMemo } from "react"; import { ReactNode, useDeferredValue, useEffect, useMemo } from "react";
import { filter, interval, throttle } from "rxjs"; import { filter, interval, map, scan, throttle } from "rxjs";
import { CallViewModel } from "../state/CallViewModel"; import { CallViewModel } from "../state/CallViewModel";
import joinCallSoundMp3 from "../sound/join_call.mp3"; import joinCallSoundMp3 from "../sound/join_call.mp3";
@@ -51,19 +51,6 @@ export function CallEventAudioRenderer({
}); });
const audioEngineRef = useLatest(audioEngineCtx); const audioEngineRef = useLatest(audioEngineCtx);
const { raisedHands } = useReactions();
const raisedHandCount = useMemo(
() => Object.keys(raisedHands).length,
[raisedHands],
);
const previousRaisedHandCount = useDeferredValue(raisedHandCount);
useEffect(() => {
if (audioEngineRef.current && previousRaisedHandCount < raisedHandCount) {
audioEngineRef.current.playSound("raiseHand");
}
}, [audioEngineRef, previousRaisedHandCount, raisedHandCount]);
useEffect(() => { useEffect(() => {
const joinSub = vm.memberChanges const joinSub = vm.memberChanges
.pipe( .pipe(
@@ -89,9 +76,14 @@ export function CallEventAudioRenderer({
audioEngineRef.current?.playSound("left"); audioEngineRef.current?.playSound("left");
}); });
const handRaisedSub = vm.handRaised.subscribe(() => {
audioEngineRef.current?.playSound("raiseHand");
});
return (): void => { return (): void => {
joinSub.unsubscribe(); joinSub.unsubscribe();
leftSub.unsubscribe(); leftSub.unsubscribe();
handRaisedSub.unsubscribe();
}; };
}, [audioEngineRef, vm]); }, [audioEngineRef, vm]);

View File

@@ -26,7 +26,6 @@ import {
Subject, Subject,
combineLatest, combineLatest,
concat, concat,
distinct,
distinctUntilChanged, distinctUntilChanged,
filter, filter,
forkJoin, forkJoin,
@@ -1099,13 +1098,16 @@ export class CallViewModel extends ViewModel {
); );
public readonly handsRaised = new Subject<Record<string, Date>>(); public readonly handsRaised = new Subject<Record<string, Date>>();
public readonly reactions = new Subject<Record<string, ReactionOption>>(); private readonly reactions = new Subject<Record<string, ReactionOption>>();
public updateReactions(data: ReturnType<typeof useReactions>) { public updateReactions(data: ReturnType<typeof useReactions>) {
this.handsRaised.next(data.raisedHands); this.handsRaised.next(data.raisedHands);
this.reactions.next(data.reactions); this.reactions.next(data.reactions);
} }
/**
* Emits an array of reactions that should be visible on the screen.
*/
public readonly visibleReactions = showReactions.value public readonly visibleReactions = showReactions.value
.pipe(switchMap((show) => (show ? this.reactions : of({})))) .pipe(switchMap((show) => (show ? this.reactions : of({}))))
.pipe( .pipe(
@@ -1125,6 +1127,9 @@ export class CallViewModel extends ViewModel {
) )
.pipe(this.scope.state()); .pipe(this.scope.state());
/**
* Emits an array of reactions that should be played.
*/
public readonly audibleReactions = playReactionsSound.value public readonly audibleReactions = playReactionsSound.value
.pipe( .pipe(
switchMap((show) => switchMap((show) =>
@@ -1147,10 +1152,25 @@ export class CallViewModel extends ViewModel {
{ playing: [], newSounds: [] }, { playing: [], newSounds: [] },
), ),
map((v) => v.newSounds), map((v) => v.newSounds),
distinct(),
) )
.pipe(this.scope.state()); .pipe(this.scope.state());
/**
* Emits an event every time a new hand is raised in
* the call.
*/
public readonly handRaised = this.handsRaised.pipe(
map((v) => Object.keys(v).length),
scan(
(acc, newValue) => ({
value: newValue,
playSounds: newValue > acc.value,
}),
{ value: 0, playSounds: false },
),
filter((v) => v.playSounds),
);
public constructor( public constructor(
// A call is permanently tied to a single Matrix room and LiveKit room // A call is permanently tied to a single Matrix room and LiveKit room
private readonly matrixRTCSession: MatrixRTCSession, private readonly matrixRTCSession: MatrixRTCSession,