From 2927db5b8fe9863a85434c7f0ff97135a553fe37 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 23 Feb 2023 18:36:19 +0000 Subject: [PATCH 1/8] Use the room avatar as a placeholder in calls Rather than the image for the user we're in a call with. This makes it work correctly with virtual rooms easily since we'll get the avatar for the correct room. --- src/components/views/voip/LegacyCallView.tsx | 3 +- src/components/views/voip/VideoFeed.tsx | 9 ++- test/components/views/voip/VideoFeed-test.tsx | 69 +++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 test/components/views/voip/VideoFeed-test.tsx diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index 1e8b4621f9a..7ec054779dd 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -430,7 +430,8 @@ export default class LegacyCallView extends React.Component { const { pipMode, call, onResize } = this.props; const { isLocalOnHold, isRemoteOnHold, sidebarShown, primaryFeed, secondaryFeed, sidebarFeeds } = this.state; - const callRoom = MatrixClientPeg.get().getRoom(call.roomId) ?? undefined; + const callRoomId = LegacyCallHandler.instance.roomIdForCall(call); + const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : null; const avatarSize = pipMode ? 76 : 160; const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId); const isOnHold = isLocalOnHold || isRemoteOnHold; diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index 35fb851f4a2..e93f5003dd4 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -23,7 +23,9 @@ import { logger } from "matrix-js-sdk/src/logger"; import { SDPStreamMetadataPurpose } from "matrix-js-sdk/src/webrtc/callEventTypes"; import SettingsStore from "../../../settings/SettingsStore"; -import MemberAvatar from "../avatars/MemberAvatar"; +import LegacyCallHandler from "../../../LegacyCallHandler"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import RoomAvatar from "../avatars/RoomAvatar"; interface IProps { call: MatrixCall; @@ -197,7 +199,8 @@ export default class VideoFeed extends React.PureComponent { let content; if (this.state.videoMuted) { - const member = this.props.feed.getMember(); + const callRoomId = LegacyCallHandler.instance.roomIdForCall(this.props.call); + const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : null; let avatarSize; if (pipMode && primary) avatarSize = 76; @@ -205,7 +208,7 @@ export default class VideoFeed extends React.PureComponent { else if (!pipMode && primary) avatarSize = 160; else; // TBD - content = ; + content = } else { const videoClasses = classnames("mx_VideoFeed_video", { mx_VideoFeed_video_mirror: diff --git a/test/components/views/voip/VideoFeed-test.tsx b/test/components/views/voip/VideoFeed-test.tsx new file mode 100644 index 00000000000..41513484f4a --- /dev/null +++ b/test/components/views/voip/VideoFeed-test.tsx @@ -0,0 +1,69 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { CallFeed } from "matrix-js-sdk/src/webrtc/callFeed"; +import { MatrixCall } from "matrix-js-sdk/src/webrtc/call"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { Room } from "matrix-js-sdk/src/models/room"; + +import * as AvatarModule from "../../../../src/Avatar"; +import VideoFeed from "../../../../src/components/views/voip/VideoFeed"; +import { stubClient, useMockedCalls } from "../../../test-utils"; +import LegacyCallHandler from "../../../../src/LegacyCallHandler"; +import DMRoomMap from "../../../../src/utils/DMRoomMap"; + +const FAKE_AVATAR_URL = "http://fakeurl.dummy/fake.png"; + +describe("VideoFeed", () => { + useMockedCalls(); + + let client: MatrixClient; + + beforeAll(() => { + client = stubClient(); + (AvatarModule as any).avatarUrlForRoom = jest.fn().mockReturnValue(FAKE_AVATAR_URL); + + const dmRoomMap = new DMRoomMap(client); + jest.spyOn(dmRoomMap, "getUserIdForRoomId"); + jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap); + }); + + afterAll(() => { + DMRoomMap.shared = undefined; + }); + + it("Displays the room avatar when no video is available", () => { + window.mxLegacyCallHandler = { + roomIdForCall: jest.fn().mockReturnValue("!this:room.here"), + } as unknown as LegacyCallHandler; + + const mockCall = { + room: new Room("!room:example.com", client, client.getSafeUserId()), + }; + + const feed = { + isAudioMuted: jest.fn().mockReturnValue(false), + isVideoMuted: jest.fn().mockReturnValue(true), + addListener: jest.fn(), + removeListener: jest.fn(), + }; + render(); + const avatarImg = screen.getByRole("img"); + expect(avatarImg).toHaveAttribute("src", FAKE_AVATAR_URL); + }); +}); \ No newline at end of file From f38d55e76c4f4968498c40b33f1337de42a609cc Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 23 Feb 2023 18:48:06 +0000 Subject: [PATCH 2/8] Prettier --- src/components/views/voip/VideoFeed.tsx | 2 +- test/components/views/voip/VideoFeed-test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index e93f5003dd4..2d7172dd0b6 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -208,7 +208,7 @@ export default class VideoFeed extends React.PureComponent { else if (!pipMode && primary) avatarSize = 160; else; // TBD - content = + content = ; } else { const videoClasses = classnames("mx_VideoFeed_video", { mx_VideoFeed_video_mirror: diff --git a/test/components/views/voip/VideoFeed-test.tsx b/test/components/views/voip/VideoFeed-test.tsx index 41513484f4a..a2f0ba68c42 100644 --- a/test/components/views/voip/VideoFeed-test.tsx +++ b/test/components/views/voip/VideoFeed-test.tsx @@ -66,4 +66,4 @@ describe("VideoFeed", () => { const avatarImg = screen.getByRole("img"); expect(avatarImg).toHaveAttribute("src", FAKE_AVATAR_URL); }); -}); \ No newline at end of file +}); From 22b401afca35b00e766b542933db7a1125ce07ce Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 10:07:02 +0000 Subject: [PATCH 3/8] TS strict errors --- src/components/views/voip/LegacyCallView.tsx | 2 +- test/components/views/voip/VideoFeed-test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index 7ec054779dd..04a8327a06f 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -431,7 +431,7 @@ export default class LegacyCallView extends React.Component { const { isLocalOnHold, isRemoteOnHold, sidebarShown, primaryFeed, secondaryFeed, sidebarFeeds } = this.state; const callRoomId = LegacyCallHandler.instance.roomIdForCall(call); - const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : null; + const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : undefined; const avatarSize = pipMode ? 76 : 160; const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId); const isOnHold = isLocalOnHold || isRemoteOnHold; diff --git a/test/components/views/voip/VideoFeed-test.tsx b/test/components/views/voip/VideoFeed-test.tsx index a2f0ba68c42..85152437e00 100644 --- a/test/components/views/voip/VideoFeed-test.tsx +++ b/test/components/views/voip/VideoFeed-test.tsx @@ -44,7 +44,7 @@ describe("VideoFeed", () => { }); afterAll(() => { - DMRoomMap.shared = undefined; + jest.restoreAllMocks(); }); it("Displays the room avatar when no video is available", () => { From 301a30b9dca6ec533fba7ad8a8cdd7fed48d8bf2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 10:19:09 +0000 Subject: [PATCH 4/8] More TS strict fixes --- src/components/views/voip/LegacyCallView.tsx | 3 ++- src/components/views/voip/VideoFeed.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index 04a8327a06f..0346fa1b48b 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -528,9 +528,10 @@ export default class LegacyCallView extends React.Component { ); } else if (pipMode) { + // We've already checked that we have feeds so we cast away the optional when passing the feed return (
- +
); } else if (secondaryFeed) { diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index 2d7172dd0b6..503c53ec66e 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -200,7 +200,7 @@ export default class VideoFeed extends React.PureComponent { let content; if (this.state.videoMuted) { const callRoomId = LegacyCallHandler.instance.roomIdForCall(this.props.call); - const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : null; + const callRoom = (callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : undefined) ?? undefined; let avatarSize; if (pipMode && primary) avatarSize = 76; From fbf417aad6b2812147b7545b9ee80aa5dcdd1a52 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 10:27:32 +0000 Subject: [PATCH 5/8] More strict TS --- src/components/views/voip/LegacyCallView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index 0346fa1b48b..fc40d262604 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -431,7 +431,7 @@ export default class LegacyCallView extends React.Component { const { isLocalOnHold, isRemoteOnHold, sidebarShown, primaryFeed, secondaryFeed, sidebarFeeds } = this.state; const callRoomId = LegacyCallHandler.instance.roomIdForCall(call); - const callRoom = callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : undefined; + const callRoom = (callRoomId ? MatrixClientPeg.get().getRoom(callRoomId) : undefined) ?? undefined; const avatarSize = pipMode ? 76 : 160; const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId); const isOnHold = isLocalOnHold || isRemoteOnHold; From 79a41e510267f833a604931417b6cd7622272748 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 10:36:03 +0000 Subject: [PATCH 6/8] Prettier --- src/components/views/voip/LegacyCallView.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index fc40d262604..ad08fd2ed1a 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -531,7 +531,13 @@ export default class LegacyCallView extends React.Component { // We've already checked that we have feeds so we cast away the optional when passing the feed return (
- +
); } else if (secondaryFeed) { From 1d9bdf2662a087ab3594a31d9309bebe37fc5d70 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 10:50:03 +0000 Subject: [PATCH 7/8] Even more TS strict --- src/components/views/voip/LegacyCallView.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index ad08fd2ed1a..275e75cbfa4 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -543,14 +543,26 @@ export default class LegacyCallView extends React.Component { } else if (secondaryFeed) { return (
- + {secondaryFeedElement}
); } else { return (
- + {sidebarShown && }
); From 7519397e82319cc66e1df763716405d634f337cb Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 24 Feb 2023 11:26:46 +0000 Subject: [PATCH 8/8] more stricter --- src/components/views/voip/LegacyCallView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/voip/LegacyCallView.tsx b/src/components/views/voip/LegacyCallView.tsx index 275e75cbfa4..2d989d296a7 100644 --- a/src/components/views/voip/LegacyCallView.tsx +++ b/src/components/views/voip/LegacyCallView.tsx @@ -563,7 +563,9 @@ export default class LegacyCallView extends React.Component { onResize={onResize} primary={true} /> - {sidebarShown && } + {sidebarShown && ( + + )} ); }