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

@@ -15,7 +15,8 @@ import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSess
import { GridTile } from "./GridTile";
import { mockRtcMembership, withRemoteMedia } from "../utils/test";
import { GridTileViewModel } from "../state/TileViewModel";
import { ReactionsProvider } from "../useReactions";
import { ReactionsSenderProvider } from "../reactions/useReactionsSender";
import type { CallViewModel } from "../state/CallViewModel";
global.IntersectionObserver = class MockIntersectionObserver {
public observe(): void {}
@@ -44,14 +45,19 @@ test("GridTile is accessible", async () => {
off: () => {},
client: {
getUserId: () => null,
getDeviceId: () => null,
on: () => {},
off: () => {},
},
},
memberships: [],
} as unknown as MatrixRTCSession;
const cVm = {
reactions$: of({}),
handsRaised$: of({}),
} as Partial<CallViewModel> as CallViewModel;
const { container } = render(
<ReactionsProvider rtcSession={fakeRtcSession}>
<ReactionsSenderProvider vm={cVm} rtcSession={fakeRtcSession}>
<GridTile
vm={new GridTileViewModel(of(vm))}
onOpenProfile={() => {}}
@@ -59,7 +65,7 @@ test("GridTile is accessible", async () => {
targetHeight={200}
showSpeakingIndicators
/>
</ReactionsProvider>,
</ReactionsSenderProvider>,
);
expect(await axe(container)).toHaveNoViolations();
// Name should be visible

View File

@@ -34,7 +34,7 @@ import {
ToggleMenuItem,
Menu,
} from "@vector-im/compound-web";
import { useObservableEagerState } from "observable-hooks";
import { useObservableEagerState, useObservableState } from "observable-hooks";
import styles from "./GridTile.module.css";
import {
@@ -48,8 +48,7 @@ import { MediaView } from "./MediaView";
import { useLatest } from "../useLatest";
import { type GridTileViewModel } from "../state/TileViewModel";
import { useMergedRefs } from "../useMergedRefs";
import { useReactions } from "../useReactions";
import { type ReactionOption } from "../reactions";
import { useReactionsSender } from "../reactions/useReactionsSender";
interface TileProps {
className?: string;
@@ -82,6 +81,7 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
},
ref,
) => {
const { toggleRaisedHand } = useReactionsSender();
const { t } = useTranslation();
const video = useObservableEagerState(vm.video$);
const unencryptedWarning = useObservableEagerState(vm.unencryptedWarning$);
@@ -97,7 +97,8 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
},
[vm],
);
const { raisedHands, toggleRaisedHand, reactions } = useReactions();
const handRaised = useObservableState(vm.handRaised$);
const reaction = useObservableState(vm.reaction$);
const AudioIcon = locallyMuted
? VolumeOffSolidIcon
@@ -124,9 +125,6 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
</>
);
const handRaised: Date | undefined = raisedHands[vm.member?.userId ?? ""];
const currentReaction: ReactionOption | undefined =
reactions[vm.member?.userId ?? ""];
const raisedHandOnClick = vm.local
? (): void => void toggleRaisedHand()
: undefined;
@@ -144,7 +142,7 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
videoFit={cropVideo ? "cover" : "contain"}
className={classNames(className, styles.tile, {
[styles.speaking]: showSpeaking,
[styles.handRaised]: !showSpeaking && !!handRaised,
[styles.handRaised]: !showSpeaking && handRaised,
})}
nameTagLeadingIcon={
<AudioIcon
@@ -172,8 +170,8 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
{menu}
</Menu>
}
raisedHandTime={handRaised}
currentReaction={currentReaction}
raisedHandTime={handRaised ?? undefined}
currentReaction={reaction ?? undefined}
raisedHandOnClick={raisedHandOnClick}
localParticipant={vm.local}
{...props}