finnish notation

This commit is contained in:
Half-Shot
2024-12-17 10:07:42 +00:00
parent 475ff920b7
commit 4164e0a61f
17 changed files with 151 additions and 129 deletions

View File

@@ -53,11 +53,8 @@ test("Can open menu", async () => {
test("Can raise hand", async () => {
const user = userEvent.setup();
const {
vm,
rtcSession,
handRaisedSubject$: handRaisedSubject,
} = getBasicCallViewModelEnvironment([local, alice]);
const { vm, rtcSession, handRaisedSubject$ } =
getBasicCallViewModelEnvironment([local, alice]);
const { getByLabelText, container } = render(
<TestComponent vm={vm} rtcSession={rtcSession} />,
);
@@ -76,7 +73,7 @@ test("Can raise hand", async () => {
);
act(() => {
// Mock receiving a reaction.
handRaisedSubject.next({
handRaisedSubject$.next({
[localIdent]: {
time: new Date(),
reactionEventId: "",
@@ -90,18 +87,15 @@ test("Can raise hand", async () => {
test("Can lower hand", async () => {
const reactionEventId = "$my-reaction-event:example.org";
const user = userEvent.setup();
const {
vm,
rtcSession,
handRaisedSubject$: handRaisedSubject,
} = getBasicCallViewModelEnvironment([local, alice]);
const { vm, rtcSession, handRaisedSubject$ } =
getBasicCallViewModelEnvironment([local, alice]);
const { getByLabelText, container } = render(
<TestComponent vm={vm} rtcSession={rtcSession} />,
);
await user.click(getByLabelText("common.reactions"));
await user.click(getByLabelText("action.raise_hand"));
act(() => {
handRaisedSubject.next({
handRaisedSubject$.next({
[localIdent]: {
time: new Date(),
reactionEventId,
@@ -117,7 +111,7 @@ test("Can lower hand", async () => {
);
act(() => {
// Mock receiving a redacted reaction.
handRaisedSubject.next({});
handRaisedSubject$.next({});
});
expect(container).toMatchSnapshot();
});

View File

@@ -181,10 +181,10 @@ export function ReactionToggleButton({
const [errorText, setErrorText] = useState<string>();
const isHandRaised = useObservableState(
vm.handsRaised.pipe(map((v) => !!v[identifier])),
vm.handsRaised$.pipe(map((v) => !!v[identifier])),
);
const canReact = useObservableState(
vm.reactions.pipe(map((v) => !v[identifier])),
vm.reactions$.pipe(map((v) => !v[identifier])),
);
useEffect(() => {

View File

@@ -36,32 +36,32 @@ const REACTION_ACTIVE_TIME_MS = 3000;
* @param rtcSession
*/
export default function useReactionsReader(rtcSession: MatrixRTCSession): {
raisedHands: Observable<Record<string, RaisedHandInfo>>;
reactions: Observable<Record<string, ReactionInfo>>;
raisedHands$: Observable<Record<string, RaisedHandInfo>>;
reactions$: Observable<Record<string, ReactionInfo>>;
} {
const raisedHandsSubject = useRef(
const raisedHandsSubject$ = useRef(
new BehaviorSubject<Record<string, RaisedHandInfo>>({}),
);
const reactionsSubject = useRef(
const reactionsSubject$ = useRef(
new BehaviorSubject<Record<string, ReactionInfo>>({}),
);
const memberships = useMatrixRTCSessionMemberships(rtcSession);
const latestMemberships = useLatest(memberships);
const latestRaisedHands = useLatest(raisedHandsSubject.current);
const latestRaisedHands = useLatest(raisedHandsSubject$.current);
const room = rtcSession.room;
const addRaisedHand = useCallback((userId: string, info: RaisedHandInfo) => {
raisedHandsSubject.current.next({
...raisedHandsSubject.current.value,
raisedHandsSubject$.current.next({
...raisedHandsSubject$.current.value,
[userId]: info,
});
}, []);
const removeRaisedHand = useCallback((userId: string) => {
raisedHandsSubject.current.next(
raisedHandsSubject$.current.next(
Object.fromEntries(
Object.entries(raisedHandsSubject.current.value).filter(
Object.entries(raisedHandsSubject$.current.value).filter(
([uId]) => uId !== userId,
),
),
@@ -90,7 +90,7 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
};
// Remove any raised hands for users no longer joined to the call.
for (const identifier of Object.keys(raisedHandsSubject).filter(
for (const identifier of Object.keys(raisedHandsSubject$).filter(
(rhId) => !memberships.find((u) => u.sender == rhId),
)) {
removeRaisedHand(identifier);
@@ -104,8 +104,8 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
}
const identifier = `${m.sender}:${m.deviceId}`;
if (
raisedHandsSubject.current.value[identifier] &&
raisedHandsSubject.current.value[identifier].membershipEventId !==
raisedHandsSubject$.current.value[identifier] &&
raisedHandsSubject$.current.value[identifier].membershipEventId !==
m.eventId
) {
// Membership event for sender has changed since the hand
@@ -193,16 +193,16 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
...ReactionSet.find((r) => r.name === content.name),
};
const currentReactions = reactionsSubject.current.value;
const currentReactions = reactionsSubject$.current.value;
if (currentReactions[identifier]) {
// We've still got a reaction from this user, ignore it to prevent spamming
return;
}
const timeout = globalThis.setTimeout(() => {
// Clear the reaction after some time.
reactionsSubject.current.next(
reactionsSubject$.current.next(
Object.fromEntries(
Object.entries(reactionsSubject.current.value).filter(
Object.entries(reactionsSubject$.current.value).filter(
([id]) => id !== identifier,
),
),
@@ -210,7 +210,7 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
reactionTimeouts.delete(timeout);
}, REACTION_ACTIVE_TIME_MS);
reactionTimeouts.add(timeout);
reactionsSubject.current.next({
reactionsSubject$.current.next({
...currentReactions,
[identifier]: {
reactionOption: reaction,
@@ -264,7 +264,7 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
// may still be sending.
room.on(MatrixRoomEvent.LocalEchoUpdated, handleReactionEvent);
const innerReactionsSubject = reactionsSubject.current;
const innerReactionsSubject$ = reactionsSubject$.current;
return (): void => {
room.off(MatrixRoomEvent.Timeline, handleReactionEvent);
room.off(MatrixRoomEvent.Redaction, handleReactionEvent);
@@ -272,7 +272,7 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
room.off(MatrixRoomEvent.LocalEchoUpdated, handleReactionEvent);
reactionTimeouts.forEach((t) => clearTimeout(t));
// If we're clearing timeouts, we also clear all reactions.
innerReactionsSubject.next({});
innerReactionsSubject$.next({});
};
}, [
room,
@@ -283,7 +283,7 @@ export default function useReactionsReader(rtcSession: MatrixRTCSession): {
]);
return {
reactions: reactionsSubject.current.asObservable(),
raisedHands: raisedHandsSubject.current.asObservable(),
reactions$: reactionsSubject$.current.asObservable(),
raisedHands$: raisedHandsSubject$.current.asObservable(),
};
}

View File

@@ -76,7 +76,7 @@ export const ReactionsSenderProvider = ({
}, [memberships, myUserId]);
const myReaction = useObservableEagerState(
vm.reactions.pipe(
vm.reactions$.pipe(
map((v) =>
myMembershipIdentifier !== undefined
? v[myMembershipIdentifier]
@@ -86,7 +86,7 @@ export const ReactionsSenderProvider = ({
);
const myRaisedHand = useObservableEagerState(
vm.handsRaised.pipe(
vm.handsRaised$.pipe(
map((v) =>
myMembershipIdentifier !== undefined
? v[myMembershipIdentifier]

View File

@@ -66,36 +66,42 @@ beforeEach(() => {
* a noise every time.
*/
test("plays one sound when entering a call", () => {
const { vm, remoteRtcMemberships$: remoteRtcMemberships } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, remoteRtcMemberships$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
render(<CallEventAudioRenderer vm={vm} />);
// Joining a call usually means remote participants are added later.
act(() => {
remoteRtcMemberships.next([aliceRtcMember, bobRtcMember]);
remoteRtcMemberships$.next([aliceRtcMember, bobRtcMember]);
});
expect(playSound).toHaveBeenCalledOnce();
});
test("plays a sound when a user joins", () => {
const { vm, remoteRtcMemberships$: remoteRtcMemberships } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, remoteRtcMemberships$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
render(<CallEventAudioRenderer vm={vm} />);
act(() => {
remoteRtcMemberships.next([aliceRtcMember, bobRtcMember]);
remoteRtcMemberships$.next([aliceRtcMember, bobRtcMember]);
});
// Play a sound when joining a call.
expect(playSound).toBeCalledWith("join");
});
test("plays a sound when a user leaves", () => {
const { vm, remoteRtcMemberships$: remoteRtcMemberships } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, remoteRtcMemberships$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
render(<CallEventAudioRenderer vm={vm} />);
act(() => {
remoteRtcMemberships.next([]);
remoteRtcMemberships$.next([]);
});
expect(playSound).toBeCalledWith("left");
});
@@ -108,13 +114,15 @@ test("plays no sound when the participant list is more than the maximum size", (
);
}
const { vm, remoteRtcMemberships$: remoteRtcMemberships } =
getBasicCallViewModelEnvironment([local, alice], mockRtcMemberships);
const { vm, remoteRtcMemberships$ } = getBasicCallViewModelEnvironment(
[local, alice],
mockRtcMemberships,
);
render(<CallEventAudioRenderer vm={vm} />);
expect(playSound).not.toBeCalled();
act(() => {
remoteRtcMemberships.next(
remoteRtcMemberships$.next(
mockRtcMemberships.slice(0, MAX_PARTICIPANT_COUNT_FOR_SOUND - 1),
);
});
@@ -122,12 +130,14 @@ test("plays no sound when the participant list is more than the maximum size", (
});
test("plays one sound when a hand is raised", () => {
const { vm, handRaisedSubject$: handRaisedSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, handRaisedSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
render(<CallEventAudioRenderer vm={vm} />);
act(() => {
handRaisedSubject.next({
handRaisedSubject$.next({
[bobRtcMember.callId]: {
time: new Date(),
membershipEventId: "",
@@ -139,12 +149,14 @@ test("plays one sound when a hand is raised", () => {
});
test("should not play a sound when a hand raise is retracted", () => {
const { vm, handRaisedSubject$: handRaisedSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, handRaisedSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
render(<CallEventAudioRenderer vm={vm} />);
act(() => {
handRaisedSubject.next({
handRaisedSubject$.next({
["foo"]: {
time: new Date(),
membershipEventId: "",
@@ -159,7 +171,7 @@ test("should not play a sound when a hand raise is retracted", () => {
});
expect(playSound).toHaveBeenCalledTimes(2);
act(() => {
handRaisedSubject.next({
handRaisedSubject$.next({
["foo"]: {
time: new Date(),
membershipEventId: "",

View File

@@ -75,7 +75,7 @@ export function CallEventAudioRenderer({
void audioEngineRef.current?.playSound("left");
});
const handRaisedSub = vm.newHandRaised.subscribe(() => {
const handRaisedSub = vm.newHandRaised$.subscribe(() => {
void audioEngineRef.current?.playSound("raiseHand");
});

View File

@@ -139,8 +139,8 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
livekitRoom,
props.e2eeSystem,
connStateObservable$,
reader.current.raisedHands,
reader.current.reactions,
reader.current.raisedHands$,
reader.current.reactions$,
);
setVm(vm);
return (): void => vm.destroy();

View File

@@ -80,8 +80,10 @@ test("preloads all audio elements", () => {
});
test("will play an audio sound when there is a reaction", () => {
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
playReactionsSound.setValue(true);
render(<TestComponent vm={vm} />);
@@ -93,7 +95,7 @@ test("will play an audio sound when there is a reaction", () => {
);
}
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: chosenReaction, ttl: 0 },
});
});
@@ -101,8 +103,10 @@ test("will play an audio sound when there is a reaction", () => {
});
test("will play the generic audio sound when there is soundless reaction", () => {
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
playReactionsSound.setValue(true);
render(<TestComponent vm={vm} />);
@@ -114,7 +118,7 @@ test("will play the generic audio sound when there is soundless reaction", () =>
);
}
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: chosenReaction, ttl: 0 },
});
});
@@ -122,8 +126,10 @@ test("will play the generic audio sound when there is soundless reaction", () =>
});
test("will play multiple audio sounds when there are multiple different reactions", () => {
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
playReactionsSound.setValue(true);
render(<TestComponent vm={vm} />);
@@ -135,7 +141,7 @@ test("will play multiple audio sounds when there are multiple different reaction
);
}
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: reaction1, ttl: 0 },
[bobRtcMember.deviceId]: { reactionOption: reaction2, ttl: 0 },
[localRtcMember.deviceId]: { reactionOption: reaction1, ttl: 0 },

View File

@@ -48,7 +48,7 @@ export function ReactionsAudioRenderer({
}, [soundCache, shouldPlay]);
useEffect(() => {
const sub = vm.audibleReactions.subscribe((newReactions) => {
const sub = vm.audibleReactions$.subscribe((newReactions) => {
for (const reactionName of newReactions) {
if (soundMap[reactionName]) {
void audioEngineRef.current?.playSound(reactionName);

View File

@@ -34,12 +34,14 @@ test("defaults to showing no reactions", () => {
test("shows a reaction when sent", () => {
showReactions.setValue(true);
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
const { getByRole } = render(<ReactionsOverlay vm={vm} />);
const reaction = ReactionSet[0];
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: reaction, ttl: 0 },
});
});
@@ -51,11 +53,13 @@ test("shows a reaction when sent", () => {
test("shows two of the same reaction when sent", () => {
showReactions.setValue(true);
const reaction = ReactionSet[0];
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
const { getAllByRole } = render(<ReactionsOverlay vm={vm} />);
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: reaction, ttl: 0 },
[bobRtcMember.deviceId]: { reactionOption: reaction, ttl: 0 },
});
@@ -66,11 +70,13 @@ test("shows two of the same reaction when sent", () => {
test("shows two different reactions when sent", () => {
showReactions.setValue(true);
const [reactionA, reactionB] = ReactionSet;
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
const { getAllByRole } = render(<ReactionsOverlay vm={vm} />);
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: reactionA, ttl: 0 },
[bobRtcMember.deviceId]: { reactionOption: reactionB, ttl: 0 },
});
@@ -83,11 +89,13 @@ test("shows two different reactions when sent", () => {
test("hides reactions when reaction animations are disabled", () => {
showReactions.setValue(false);
const reaction = ReactionSet[0];
const { vm, reactionsSubject$: reactionsSubject } =
getBasicCallViewModelEnvironment([local, alice]);
const { vm, reactionsSubject$ } = getBasicCallViewModelEnvironment([
local,
alice,
]);
const { container } = render(<ReactionsOverlay vm={vm} />);
act(() => {
reactionsSubject.next({
reactionsSubject$.next({
[aliceRtcMember.deviceId]: { reactionOption: reaction, ttl: 0 },
});
});

View File

@@ -12,7 +12,7 @@ import styles from "./ReactionsOverlay.module.css";
import { type CallViewModel } from "../state/CallViewModel";
export function ReactionsOverlay({ vm }: { vm: CallViewModel }): ReactNode {
const reactionsIcons = useObservableState(vm.visibleReactions);
const reactionsIcons = useObservableState(vm.visibleReactions$);
return (
<div className={styles.container}>
{reactionsIcons?.map(({ sender, emoji, startX }) => (

View File

@@ -194,7 +194,7 @@ function withCallViewModel(
speaking: Map<Participant, Observable<boolean>>,
continuation: (
vm: CallViewModel,
subjects: { raisedHands: BehaviorSubject<Record<string, RaisedHandInfo>> },
subjects: { raisedHands$: BehaviorSubject<Record<string, RaisedHandInfo>> },
) => void,
): void {
const room = mockMatrixRoom({
@@ -240,7 +240,7 @@ function withCallViewModel(
{ remoteParticipants$ },
);
const raisedHands = new BehaviorSubject<Record<string, RaisedHandInfo>>({});
const raisedHands$ = new BehaviorSubject<Record<string, RaisedHandInfo>>({});
const vm = new CallViewModel(
rtcSession as unknown as MatrixRTCSession,
@@ -249,7 +249,7 @@ function withCallViewModel(
kind: E2eeType.PER_PARTICIPANT,
},
connectionState$,
raisedHands,
raisedHands$,
new BehaviorSubject({}),
);
@@ -261,7 +261,7 @@ function withCallViewModel(
roomEventSelectorSpy!.mockRestore();
});
continuation(vm, { raisedHands });
continuation(vm, { raisedHands$: raisedHands$ });
}
test("participants are retained during a focus switch", () => {
@@ -802,7 +802,7 @@ it("should rank raised hands above video feeds and below speakers and presenters
of([aliceRtcMember, bobRtcMember]),
of(ConnectionState.Connected),
new Map(),
(vm, { raisedHands }) => {
(vm, { raisedHands$ }) => {
schedule("ab", {
a: () => {
// We imagine that only three tiles (the first three) will be visible
@@ -814,7 +814,7 @@ it("should rank raised hands above video feeds and below speakers and presenters
});
},
b: () => {
raisedHands.next({
raisedHands$.next({
[`${bobRtcMember.sender}:${bobRtcMember.deviceId}`]: {
time: new Date(),
reactionEventId: "",

View File

@@ -258,8 +258,8 @@ class UserMedia {
participant: LocalParticipant | RemoteParticipant | undefined,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
handRaised: Observable<Date | null>,
reaction: Observable<ReactionOption | null>,
handRaised$: Observable<Date | null>,
reaction$: Observable<ReactionOption | null>,
) {
this.participant$ = new BehaviorSubject(participant);
@@ -270,8 +270,8 @@ class UserMedia {
this.participant$.asObservable() as Observable<LocalParticipant>,
encryptionSystem,
livekitRoom,
handRaised,
reaction,
handRaised$,
reaction$,
);
} else {
this.vm = new RemoteUserMediaViewModel(
@@ -282,8 +282,8 @@ class UserMedia {
>,
encryptionSystem,
livekitRoom,
handRaised,
reaction,
handRaised$,
reaction$,
);
}
@@ -544,10 +544,10 @@ export class CallViewModel extends ViewModel {
participant,
this.encryptionSystem,
this.livekitRoom,
this.handsRaised.pipe(
this.handsRaised$.pipe(
map((v) => v[matrixIdentifier]?.time ?? null),
),
this.reactions.pipe(
this.reactions$.pipe(
map((v) => v[matrixIdentifier] ?? undefined),
),
),
@@ -711,7 +711,7 @@ export class CallViewModel extends ViewModel {
m.speaker$,
m.presenter$,
m.vm.videoEnabled$,
m.vm.handRaised,
m.vm.handRaised$,
m.vm instanceof LocalUserMediaViewModel
? m.vm.alwaysShow$
: of(false),
@@ -1203,7 +1203,7 @@ export class CallViewModel extends ViewModel {
this.scope.state(),
);
public readonly reactions = this.reactionsSubject.pipe(
public readonly reactions$ = this.reactionsSubject$.pipe(
map((v) =>
Object.fromEntries(
Object.entries(v).map(([a, { reactionOption }]) => [a, reactionOption]),
@@ -1211,13 +1211,13 @@ export class CallViewModel extends ViewModel {
),
);
public readonly handsRaised = this.handsRaisedSubject.pipe();
public readonly handsRaised$ = this.handsRaisedSubject$.pipe();
/**
* Emits an array of reactions that should be visible on the screen.
*/
public readonly visibleReactions = showReactions.value$
.pipe(switchMap((show) => (show ? this.reactions : of({}))))
public readonly visibleReactions$ = showReactions.value$
.pipe(switchMap((show) => (show ? this.reactions$ : of({}))))
.pipe(
scan<
Record<string, ReactionOption>,
@@ -1238,10 +1238,10 @@ export class CallViewModel extends ViewModel {
/**
* Emits an array of reactions that should be played.
*/
public readonly audibleReactions = playReactionsSound.value$
public readonly audibleReactions$ = playReactionsSound.value$
.pipe(
switchMap((show) =>
show ? this.reactions : of<Record<string, ReactionOption>>({}),
show ? this.reactions$ : of<Record<string, ReactionOption>>({}),
),
)
.pipe(
@@ -1267,7 +1267,7 @@ export class CallViewModel extends ViewModel {
* Emits an event every time a new hand is raised in
* the call.
*/
public readonly newHandRaised = this.handsRaised.pipe(
public readonly newHandRaised$ = this.handsRaised$.pipe(
map((v) => Object.keys(v).length),
scan(
(acc, newValue) => ({
@@ -1285,10 +1285,12 @@ export class CallViewModel extends ViewModel {
private readonly livekitRoom: LivekitRoom,
private readonly encryptionSystem: EncryptionSystem,
private readonly connectionState$: Observable<ECConnectionState>,
private readonly handsRaisedSubject: Observable<
private readonly handsRaisedSubject$: Observable<
Record<string, RaisedHandInfo>
>,
private readonly reactionsSubject: Observable<Record<string, ReactionInfo>>,
private readonly reactionsSubject$: Observable<
Record<string, ReactionInfo>
>,
) {
super();
}

View File

@@ -372,8 +372,8 @@ abstract class BaseUserMediaViewModel extends BaseMediaViewModel {
participant$: Observable<LocalParticipant | RemoteParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
public readonly handRaised: Observable<Date | null>,
public readonly reaction: Observable<ReactionOption | null>,
public readonly handRaised$: Observable<Date | null>,
public readonly reaction$: Observable<ReactionOption | null>,
) {
super(
id,
@@ -440,8 +440,8 @@ export class LocalUserMediaViewModel extends BaseUserMediaViewModel {
participant$: Observable<LocalParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
handRaised: Observable<Date | null>,
reaction: Observable<ReactionOption | null>,
handRaised$: Observable<Date | null>,
reaction$: Observable<ReactionOption | null>,
) {
super(
id,
@@ -449,8 +449,8 @@ export class LocalUserMediaViewModel extends BaseUserMediaViewModel {
participant$,
encryptionSystem,
livekitRoom,
handRaised,
reaction,
handRaised$,
reaction$,
);
}
}
@@ -511,8 +511,8 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
participant$: Observable<RemoteParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
handRaised: Observable<Date | null>,
reaction: Observable<ReactionOption | null>,
handRaised$: Observable<Date | null>,
reaction$: Observable<ReactionOption | null>,
) {
super(
id,
@@ -520,8 +520,8 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
participant$,
encryptionSystem,
livekitRoom,
handRaised,
reaction,
handRaised$,
reaction$,
);
// Sync the local volume with LiveKit

View File

@@ -53,8 +53,8 @@ test("GridTile is accessible", async () => {
memberships: [],
} as unknown as MatrixRTCSession;
const cVm = {
reactions: of({}),
handsRaised: of({}),
reactions$: of({}),
handsRaised$: of({}),
} as Partial<CallViewModel> as CallViewModel;
const { container } = render(
<ReactionsSenderProvider vm={cVm} rtcSession={fakeRtcSession}>

View File

@@ -97,8 +97,8 @@ const UserMediaTile = forwardRef<HTMLDivElement, UserMediaTileProps>(
},
[vm],
);
const handRaised = useObservableState(vm.handRaised);
const reaction = useObservableState(vm.reaction);
const handRaised = useObservableState(vm.handRaised$);
const reaction = useObservableState(vm.reaction$);
const AudioIcon = locallyMuted
? VolumeOffSolidIcon

View File

@@ -66,17 +66,17 @@ export function getBasicCallViewModelEnvironment(
roomId: matrixRoomId,
});
const remoteRtcMemberships = new BehaviorSubject<CallMembership[]>(
const remoteRtcMemberships$ = new BehaviorSubject<CallMembership[]>(
initialRemoteRtcMemberships,
);
const handRaisedSubject = new BehaviorSubject({});
const reactionsSubject = new BehaviorSubject({});
const handRaisedSubject$ = new BehaviorSubject({});
const reactionsSubject$ = new BehaviorSubject({});
const rtcSession = new MockRTCSession(
matrixRoom,
localRtcMember,
).withMemberships(remoteRtcMemberships);
).withMemberships(remoteRtcMemberships$);
const vm = new CallViewModel(
rtcSession as unknown as MatrixRTCSession,
@@ -85,14 +85,14 @@ export function getBasicCallViewModelEnvironment(
kind: E2eeType.PER_PARTICIPANT,
},
of(ConnectionState.Connected),
handRaisedSubject,
reactionsSubject,
handRaisedSubject$,
reactionsSubject$,
);
return {
vm,
remoteRtcMemberships$: remoteRtcMemberships,
remoteRtcMemberships$: remoteRtcMemberships$,
rtcSession,
handRaisedSubject$: handRaisedSubject,
reactionsSubject$: reactionsSubject,
handRaisedSubject$: handRaisedSubject$,
reactionsSubject$: reactionsSubject$,
};
}