mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-08 20:09:19 +00:00
Use call view model for hand raised reactions
This commit is contained in:
@@ -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]);
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user