Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Show room broadcast when ending a recording (#9841)
Browse files Browse the repository at this point in the history
  • Loading branch information
weeman1337 authored Jan 2, 2023
1 parent 3ce0647 commit 91e078d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 12 deletions.
18 changes: 17 additions & 1 deletion src/stores/RoomViewStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import { ThreadPayload } from "../dispatcher/payloads/ThreadPayload";
import {
doClearCurrentVoiceBroadcastPlaybackIfStopped,
doMaybeSetCurrentVoiceBroadcastPlayback,
VoiceBroadcastRecording,
VoiceBroadcastRecordingsStoreEvent,
} from "../voice-broadcast";
import { IRoomStateEventsActionPayload } from "../actions/MatrixActionCreators";
import { showCantStartACallDialog } from "../voice-broadcast/utils/showCantStartACallDialog";
Expand Down Expand Up @@ -153,6 +155,10 @@ export class RoomViewStore extends EventEmitter {
public constructor(dis: MatrixDispatcher, private readonly stores: SdkContextClass) {
super();
this.resetDispatcher(dis);
this.stores.voiceBroadcastRecordingsStore.addListener(
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
this.onCurrentBroadcastRecordingChanged,
);
}

public addRoomListener(roomId: string, fn: Listener): void {
Expand All @@ -167,13 +173,23 @@ export class RoomViewStore extends EventEmitter {
this.emit(roomId, isActive);
}

private onCurrentBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null) => {
if (recording === null) {
const room = this.stores.client?.getRoom(this.state.roomId || undefined);

if (room) {
this.doMaybeSetCurrentVoiceBroadcastPlayback(room);
}
}
};

private setState(newState: Partial<State>): void {
// If values haven't changed, there's nothing to do.
// This only tries a shallow comparison, so unchanged objects will slip
// through, but that's probably okay for now.
let stateChanged = false;
for (const key of Object.keys(newState)) {
if (this.state[key] !== newState[key]) {
if (this.state[key as keyof State] !== newState[key as keyof State]) {
stateChanged = true;
break;
}
Expand Down
20 changes: 14 additions & 6 deletions src/voice-broadcast/stores/VoiceBroadcastRecordingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export enum VoiceBroadcastRecordingsStoreEvent {
}

interface EventMap {
[VoiceBroadcastRecordingsStoreEvent.CurrentChanged]: (recording: VoiceBroadcastRecording) => void;
[VoiceBroadcastRecordingsStoreEvent.CurrentChanged]: (recording: VoiceBroadcastRecording | null) => void;
}

/**
Expand All @@ -41,17 +41,23 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
public setCurrent(current: VoiceBroadcastRecording): void {
if (this.current === current) return;

const infoEventId = current.infoEvent.getId();

if (!infoEventId) {
throw new Error("Got broadcast info event without Id");
}

if (this.current) {
this.current.off(VoiceBroadcastRecordingEvent.StateChanged, this.onCurrentStateChanged);
}

this.current = current;
this.current.on(VoiceBroadcastRecordingEvent.StateChanged, this.onCurrentStateChanged);
this.recordings.set(current.infoEvent.getId(), current);
this.recordings.set(infoEventId, current);
this.emit(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, current);
}

public getCurrent(): VoiceBroadcastRecording {
public getCurrent(): VoiceBroadcastRecording | null {
return this.current;
}

Expand All @@ -70,11 +76,13 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
public getByInfoEvent(infoEvent: MatrixEvent, client: MatrixClient): VoiceBroadcastRecording {
const infoEventId = infoEvent.getId();

if (!this.recordings.has(infoEventId)) {
this.recordings.set(infoEventId, new VoiceBroadcastRecording(infoEvent, client));
if (!infoEventId) {
throw new Error("Got broadcast info event without Id");
}

return this.recordings.get(infoEventId);
const recording = this.recordings.get(infoEventId) || new VoiceBroadcastRecording(infoEvent, client);
this.recordings.set(infoEventId, recording);
return recording;
}

private onCurrentStateChanged = (state: VoiceBroadcastInfoState) => {
Expand Down
53 changes: 48 additions & 5 deletions test/stores/RoomViewStore-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ jest.mock("../../src/utils/DMRoomMap", () => {
describe("RoomViewStore", function () {
const userId = "@alice:server";
const roomId = "!randomcharacters:aser.ver";
const roomId2 = "!room2:example.com";
// we need to change the alias to ensure cache misses as the cache exists
// through all tests.
let alias = "#somealias2:aser.ver";
Expand All @@ -87,9 +88,14 @@ describe("RoomViewStore", function () {
getRoom: jest.fn(),
getRoomIdForAlias: jest.fn(),
isGuest: jest.fn(),
getSafeUserId: jest.fn(),
getUserId: jest.fn().mockReturnValue(userId),
getSafeUserId: jest.fn().mockReturnValue(userId),
getDeviceId: jest.fn().mockReturnValue("ABC123"),
sendStateEvent: jest.fn().mockResolvedValue({}),
supportsExperimentalThreads: jest.fn(),
});
const room = new Room(roomId, mockClient, userId);
const room2 = new Room(roomId2, mockClient, userId);

const viewCall = async (): Promise<void> => {
dis.dispatch<ViewRoomPayload>({
Expand All @@ -110,14 +116,19 @@ describe("RoomViewStore", function () {
jest.clearAllMocks();
mockClient.credentials = { userId: userId };
mockClient.joinRoom.mockResolvedValue(room);
mockClient.getRoom.mockReturnValue(room);
mockClient.getRoom.mockImplementation((roomId: string): Room | null => {
if (roomId === room.roomId) return room;
if (roomId === room2.roomId) return room2;
return null;
});
mockClient.isGuest.mockReturnValue(false);
mockClient.getSafeUserId.mockReturnValue(userId);

// Make the RVS to test
dis = new MatrixDispatcher();
slidingSyncManager = new MockSlidingSyncManager();
stores = new TestSdkContext();
stores.client = mockClient;
stores._SlidingSyncManager = slidingSyncManager;
stores._PosthogAnalytics = new MockPosthogAnalytics();
stores._SpaceStore = new MockSpaceStore();
Expand All @@ -142,7 +153,6 @@ describe("RoomViewStore", function () {
});

it("emits ActiveRoomChanged when the viewed room changes", async () => {
const roomId2 = "!roomid:2";
dis.dispatch({ action: Action.ViewRoom, room_id: roomId });
let payload = (await untilDispatch(Action.ActiveRoomChanged, dis)) as ActiveRoomChangedPayload;
expect(payload.newRoomId).toEqual(roomId);
Expand All @@ -155,7 +165,6 @@ describe("RoomViewStore", function () {
});

it("invokes room activity listeners when the viewed room changes", async () => {
const roomId2 = "!roomid:2";
const callback = jest.fn();
roomViewStore.addRoomListener(roomId, callback);
dis.dispatch({ action: Action.ViewRoom, room_id: roomId });
Expand Down Expand Up @@ -225,7 +234,6 @@ describe("RoomViewStore", function () {
});

it("swaps to the replied event room if it is not the current room", async () => {
const roomId2 = "!room2:bar";
dis.dispatch({ action: Action.ViewRoom, room_id: roomId });
await untilDispatch(Action.ActiveRoomChanged, dis);
const replyToEvent = {
Expand Down Expand Up @@ -295,6 +303,41 @@ describe("RoomViewStore", function () {
expect(Modal.createDialog).toMatchSnapshot();
expect(roomViewStore.isViewingCall()).toBe(false);
});

describe("and viewing a room with a broadcast", () => {
beforeEach(async () => {
const broadcastEvent = mkVoiceBroadcastInfoStateEvent(
roomId2,
VoiceBroadcastInfoState.Started,
mockClient.getSafeUserId(),
"ABC123",
);
room2.addLiveEvents([broadcastEvent]);

stores.voiceBroadcastPlaybacksStore.getByInfoEvent(broadcastEvent, mockClient);
dis.dispatch({ action: Action.ViewRoom, room_id: roomId2 });
await untilDispatch(Action.ActiveRoomChanged, dis);
});

it("should continue recording", () => {
expect(stores.voiceBroadcastPlaybacksStore.getCurrent()).toBeNull();
expect(stores.voiceBroadcastRecordingsStore.getCurrent()?.getState()).toBe(
VoiceBroadcastInfoState.Started,
);
});

describe("and stopping the recording", () => {
beforeEach(async () => {
await stores.voiceBroadcastRecordingsStore.getCurrent()?.stop();
// check test precondition
expect(stores.voiceBroadcastRecordingsStore.getCurrent()).toBeNull();
});

it("should view the broadcast", () => {
expect(stores.voiceBroadcastPlaybacksStore.getCurrent()?.infoEvent.getRoomId()).toBe(roomId2);
});
});
});
});

describe("Sliding Sync", function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ describe("VoiceBroadcastRecordingsStore", () => {
recordings.off(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, onCurrentChanged);
});

it("when setting a recording without info event Id, it should raise an error", () => {
infoEvent.event.event_id = undefined;
expect(() => {
recordings.setCurrent(recording);
}).toThrowError("Got broadcast info event without Id");
});

describe("when setting a current Voice Broadcast recording", () => {
beforeEach(() => {
recordings.setCurrent(recording);
Expand Down

0 comments on commit 91e078d

Please sign in to comment.