From 73ee088605409cb01ef36b12418e45962a9d6c45 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 9 Dec 2024 15:19:27 +0000 Subject: [PATCH] Use call view model for hand raised reactions --- src/room/CallEventAudioRenderer.tsx | 20 ++++++-------------- src/state/CallViewModel.ts | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/room/CallEventAudioRenderer.tsx b/src/room/CallEventAudioRenderer.tsx index 6f4f0359..6412d23e 100644 --- a/src/room/CallEventAudioRenderer.tsx +++ b/src/room/CallEventAudioRenderer.tsx @@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details. */ 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 joinCallSoundMp3 from "../sound/join_call.mp3"; @@ -51,19 +51,6 @@ export function CallEventAudioRenderer({ }); 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(() => { const joinSub = vm.memberChanges .pipe( @@ -89,9 +76,14 @@ export function CallEventAudioRenderer({ audioEngineRef.current?.playSound("left"); }); + const handRaisedSub = vm.handRaised.subscribe(() => { + audioEngineRef.current?.playSound("raiseHand"); + }); + return (): void => { joinSub.unsubscribe(); leftSub.unsubscribe(); + handRaisedSub.unsubscribe(); }; }, [audioEngineRef, vm]); diff --git a/src/state/CallViewModel.ts b/src/state/CallViewModel.ts index d9f12348..df56fb00 100644 --- a/src/state/CallViewModel.ts +++ b/src/state/CallViewModel.ts @@ -26,7 +26,6 @@ import { Subject, combineLatest, concat, - distinct, distinctUntilChanged, filter, forkJoin, @@ -1099,13 +1098,16 @@ export class CallViewModel extends ViewModel { ); public readonly handsRaised = new Subject>(); - public readonly reactions = new Subject>(); + private readonly reactions = new Subject>(); public updateReactions(data: ReturnType) { this.handsRaised.next(data.raisedHands); this.reactions.next(data.reactions); } + /** + * Emits an array of reactions that should be visible on the screen. + */ public readonly visibleReactions = showReactions.value .pipe(switchMap((show) => (show ? this.reactions : of({})))) .pipe( @@ -1125,6 +1127,9 @@ export class CallViewModel extends ViewModel { ) .pipe(this.scope.state()); + /** + * Emits an array of reactions that should be played. + */ public readonly audibleReactions = playReactionsSound.value .pipe( switchMap((show) => @@ -1147,10 +1152,25 @@ export class CallViewModel extends ViewModel { { playing: [], newSounds: [] }, ), map((v) => v.newSounds), - distinct(), ) .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( // A call is permanently tied to a single Matrix room and LiveKit room private readonly matrixRTCSession: MatrixRTCSession,