Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion apps/web/src/viewmodels/room-list/RoomListItemViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { RoomEvent } from "matrix-js-sdk/src/matrix";
import { CallType } from "matrix-js-sdk/src/webrtc/call";

import type { Room, MatrixClient } from "matrix-js-sdk/src/matrix";
import type { Room, MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
import type { RoomNotificationState } from "../../stores/notifications/RoomNotificationState";
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
import { NotificationStateEvents } from "../../stores/notifications/NotificationState";
Expand All @@ -36,6 +36,7 @@ import dispatcher from "../../dispatcher/dispatcher";
import { Action } from "../../dispatcher/actions";
import type { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import PosthogTrackers from "../../PosthogTrackers";
import { CallEvent } from "../../models/Call";

interface RoomItemProps {
room: Room;
Expand Down Expand Up @@ -100,9 +101,26 @@ export class RoomListItemViewModel
void this.loadAndSetMessagePreview();
};

/**
* Handler for call participant changes. Only updates the item if the call moves between having participants and not having participants, to avoid unnecessary updates.
* @param participants - The current call participants
*/
private onCallParticipantsChanged = (participants: Map<RoomMember, Set<string>>): void => {
const hasCall = Boolean(this.snapshot.current.notification.callType);
// There is already an active call, we don't need to update the item
if (hasCall && participants.size > 0) return;

this.updateItem();
};

private onCallStateChanged = (): void => {
// Only update if call state for this room actually changed
const call = CallStore.instance.getCall(this.props.room.roomId);

// Unsubscribe from previous call participants if there was a call before
call?.off(CallEvent.Participants, this.onCallParticipantsChanged);
call?.on(CallEvent.Participants, this.onCallParticipantsChanged);

const currentCallType = this.snapshot.current.notification.callType;
const newCallType =
call && call.participants.size > 0 ? (call.callType === CallType.Voice ? "voice" : "video") : undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
* Please see LICENSE files in the repository root for full details.
*/

import { type MatrixClient, type MatrixEvent, Room, RoomEvent, PendingEventOrdering } from "matrix-js-sdk/src/matrix";
import {
type MatrixClient,
type MatrixEvent,
Room,
RoomEvent,
PendingEventOrdering,
type RoomMember,
} from "matrix-js-sdk/src/matrix";
import { CallType } from "matrix-js-sdk/src/webrtc/call";

import { createTestClient, flushPromises } from "../../test-utils";
Expand Down Expand Up @@ -310,6 +317,33 @@ describe("RoomListItemViewModel", () => {

expect(viewModel.getSnapshot().notification.callType).toBeUndefined();
});

it("should listen to call participant changes", () => {
const mockCall = {
callType: CallType.Voice,
participants: new Map(),
off: jest.fn(),
on: jest.fn(),
};
jest.spyOn(CallStore.instance, "getCall").mockReturnValue(mockCall as unknown as Call);

viewModel = new RoomListItemViewModel({ room, client: matrixClient });
expect(viewModel.getSnapshot().notification.callType).toBeUndefined();

// Get the callback registered for call state changes
const mockCalls = (CallStore.instance.on as jest.Mock).mock.calls;
const callStateCallback = mockCalls[mockCalls.length - 1][1];
callStateCallback();

// Simulate participant joining
mockCall.participants.set(matrixClient.getUserId()! as unknown as RoomMember, new Set());

// Get the callback registered for participant changes
const participantsChangeCallback = mockCall.on.mock.calls[0][1];
participantsChangeCallback();

expect(viewModel.getSnapshot().notification.callType).toBe("voice");
});
});

describe("Room name updates", () => {
Expand Down
Loading