Refactor reactions / hand raised to use rxjs and start ordering tiles based on hand raised. (#2885)

* Add support for using CallViewModel for reactions sounds.

* Drop setting

* Convert reaction sounds to call view model / rxjs

* Use call view model for hand raised reactions

* Support raising reactions for matrix rtc members.

* Tie up last bits of useReactions

* linting

* Update calleventaudiorenderer

* Update reaction audio renderer

* more test bits

* All the test bits and pieces

* More refactors

* Refactor reactions into a sender and receiver.

* Fixup reaction toggle button

* Adapt reactions test

* Tests all pass.

* lint

* fix a couple of bugs

* remove unused helper file

* lint

* finnish notation

* Add tests for useReactionsReader

* remove mistaken vitest file

* fix

* filter

* invert

* fixup tests with fake timers

* Port useReactionsReader hook to ReactionsReader class.

* lint

* exclude some files from coverage

* Add screen share sound effect.

* cancel sub on destroy

* tidy tidy
This commit is contained in:
Will Hunt
2024-12-19 15:54:28 +00:00
committed by GitHub
parent 7d00f85abc
commit abf2ecd521
28 changed files with 1835 additions and 1184 deletions

View File

@@ -7,6 +7,7 @@ Please see LICENSE in the repository root for full details.
import { test, vi, onTestFinished, it } from "vitest";
import {
BehaviorSubject,
combineLatest,
debounceTime,
distinctUntilChanged,
@@ -46,6 +47,7 @@ import {
type ECConnectionState,
} from "../livekit/useECConnectionState";
import { E2eeType } from "../e2ee/e2eeType";
import type { RaisedHandInfo } from "../reactions";
import { showNonMemberTiles } from "../settings/settings";
vi.mock("@livekit/components-core");
@@ -190,7 +192,10 @@ function withCallViewModel(
rtcMembers$: Observable<Partial<CallMembership>[]>,
connectionState$: Observable<ECConnectionState>,
speaking: Map<Participant, Observable<boolean>>,
continuation: (vm: CallViewModel) => void,
continuation: (
vm: CallViewModel,
subjects: { raisedHands$: BehaviorSubject<Record<string, RaisedHandInfo>> },
) => void,
): void {
const room = mockMatrixRoom({
client: {
@@ -235,6 +240,8 @@ function withCallViewModel(
{ remoteParticipants$ },
);
const raisedHands$ = new BehaviorSubject<Record<string, RaisedHandInfo>>({});
const vm = new CallViewModel(
rtcSession as unknown as MatrixRTCSession,
liveKitRoom,
@@ -242,6 +249,8 @@ function withCallViewModel(
kind: E2eeType.PER_PARTICIPANT,
},
connectionState$,
raisedHands$,
new BehaviorSubject({}),
);
onTestFinished(() => {
@@ -252,7 +261,7 @@ function withCallViewModel(
roomEventSelectorSpy!.mockRestore();
});
continuation(vm);
continuation(vm, { raisedHands$: raisedHands$ });
}
test("participants are retained during a focus switch", () => {
@@ -782,3 +791,62 @@ it("should show at least one tile per MatrixRTCSession", () => {
);
});
});
it("should rank raised hands above video feeds and below speakers and presenters", () => {
withTestScheduler(({ schedule, expectObservable }) => {
// There should always be one tile for each MatrixRTCSession
const expectedLayoutMarbles = "ab";
withCallViewModel(
of([aliceParticipant, bobParticipant]),
of([aliceRtcMember, bobRtcMember]),
of(ConnectionState.Connected),
new Map(),
(vm, { raisedHands$ }) => {
schedule("ab", {
a: () => {
// We imagine that only two tiles (the first two) will be visible on screen at a time
vm.layout$.subscribe((layout) => {
if (layout.type === "grid") {
layout.setVisibleTiles(2);
}
});
},
b: () => {
raisedHands$.next({
[`${bobRtcMember.sender}:${bobRtcMember.deviceId}`]: {
time: new Date(),
reactionEventId: "",
membershipEventId: "",
},
});
},
});
expectObservable(summarizeLayout$(vm.layout$)).toBe(
expectedLayoutMarbles,
{
a: {
type: "grid",
spotlight: undefined,
grid: [
"local:0",
"@alice:example.org:AAAA:0",
"@bob:example.org:BBBB:0",
],
},
b: {
type: "grid",
spotlight: undefined,
grid: [
"local:0",
// Bob shifts up!
"@bob:example.org:BBBB:0",
"@alice:example.org:AAAA:0",
],
},
},
);
},
);
});
});