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

Add Element call related functionality to new room header #12091

Merged
merged 27 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fac8317
New room header
toger5 Dec 27, 2023
7c328fe
dont show start call, join button in video rooms.
toger5 Dec 27, 2023
fe0472e
Make active call check based on participant count
toger5 Jan 24, 2024
d11c4a7
fix room header tests
toger5 Jan 24, 2024
d5a2525
fix room header tests
toger5 Jan 24, 2024
0aa5e00
remove chat button test for displaying.
toger5 Jan 24, 2024
770e191
Merge branch 'develop' into toger5/call-new-room-header
toger5 Jan 24, 2024
992f43e
remove duplicate notification Tread icon
toger5 Jan 24, 2024
a94b95a
remove obsolete jest snapshot
toger5 Jan 24, 2024
ca170d3
Merge branch 'develop' into toger5/call-new-room-header
toger5 Jan 24, 2024
9fd8dbf
Update src/components/views/rooms/RoomHeader.tsx
toger5 Jan 25, 2024
5d1d1b8
update isECWidget logic
toger5 Jan 25, 2024
9ec0913
remove dead code
toger5 Jan 25, 2024
dc1c028
refactor call options
toger5 Jan 25, 2024
076df3b
join ec when clicking join button (dont start jitsi)
toger5 Jan 25, 2024
0fa4ee7
refactor isViewingCall
toger5 Jan 25, 2024
9d46c49
Merge branch 'develop' into toger5/call-new-room-header
toger5 Jan 25, 2024
7f2d311
fix room header tests
toger5 Jan 26, 2024
2b6cb96
fix header snapshot
toger5 Jan 26, 2024
887cfaf
sonar proposals
toger5 Jan 26, 2024
f8f105e
Merge branch 'develop' into toger5/call-new-room-header
toger5 Jan 29, 2024
aeecf8d
fix event shiftKey may be undefined
toger5 Jan 29, 2024
5373658
more lobby time before timeout
toger5 Jan 29, 2024
0498e74
don't allow starting new calls if there is an ongoing other call.
toger5 Jan 30, 2024
479b4b3
Merge branch 'develop' into toger5/call-new-room-header
toger5 Jan 30, 2024
5ac670c
review
toger5 Jan 31, 2024
2f6dfde
fix translation typo
toger5 Jan 31, 2024
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
1 change: 0 additions & 1 deletion src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onActiveCalls = (): void => {
if (this.state.roomId === undefined) return;
const activeCall = CallStore.instance.getActiveCall(this.state.roomId);

if (activeCall === null) {
// We disconnected from the call, so stop viewing it
dis.dispatch<ViewRoomPayload>(
Expand Down
143 changes: 117 additions & 26 deletions src/components/views/rooms/RoomHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useEffect, useMemo, useState } from "react";
import { Body as BodyText, IconButton, Tooltip } from "@vector-im/compound-web";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Body as BodyText, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
import { Icon as VideoCallIcon } from "@vector-im/compound-design-tokens/icons/video-call-solid.svg";
import { Icon as VoiceCallIcon } from "@vector-im/compound-design-tokens/icons/voice-call.svg";
import { Icon as CloseCallIcon } from "@vector-im/compound-design-tokens/icons/close.svg";
import { Icon as ThreadsIcon } from "@vector-im/compound-design-tokens/icons/threads-solid.svg";
import { Icon as NotificationsIcon } from "@vector-im/compound-design-tokens/icons/notifications-solid.svg";
import { Icon as VerifiedIcon } from "@vector-im/compound-design-tokens/icons/verified.svg";
Expand All @@ -35,7 +36,7 @@ import { useRoomMemberCount, useRoomMembers } from "../../../hooks/useRoomMember
import { _t } from "../../../languageHandler";
import { Flex } from "../../utils/Flex";
import { Box } from "../../utils/Box";
import { useRoomCall } from "../../../hooks/room/useRoomCall";
import { getPlatformCallTypeLabel, useRoomCall } from "../../../hooks/room/useRoomCall";
import { useRoomThreadNotifications } from "../../../hooks/room/useRoomThreadNotifications";
import { useGlobalNotificationState } from "../../../hooks/useGlobalNotificationState";
import SdkConfig from "../../../SdkConfig";
Expand All @@ -51,6 +52,7 @@ import { Linkify, topicToHtml } from "../../../HtmlUtils";
import PosthogTrackers from "../../../PosthogTrackers";
import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton";
import { RoomKnocksBar } from "./RoomKnocksBar";
import { isVideoRoom } from "../../../utils/video-rooms";
import { notificationLevelToIndicator } from "../../../utils/notifications";

export default function RoomHeader({
Expand All @@ -69,7 +71,17 @@ export default function RoomHeader({
const members = useRoomMembers(room, 2500);
const memberCount = useRoomMemberCount(room, { throttleWait: 2500 });

const { voiceCallDisabledReason, voiceCallClick, videoCallDisabledReason, videoCallClick } = useRoomCall(room);
const {
voiceCallDisabledReason,
voiceCallClick,
videoCallDisabledReason,
videoCallClick,
toggleCallMaximized: toggleCall,
isViewingCall,
isConnectedToCall,
hasActiveCallSession,
callOptions,
} = useRoomCall(room);

const groupCallsEnabled = useFeatureEnabled("feature_group_calls");
/**
Expand Down Expand Up @@ -104,6 +116,97 @@ export default function RoomHeader({

const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");

const videoClick = useCallback((ev) => videoCallClick(ev, callOptions[0]), [callOptions, videoCallClick]);

const toggleCallButton = (
<Tooltip label={isViewingCall ? _t("voip|minimise_call") : _t("voip|maximise_call")}>
<IconButton onClick={toggleCall}>
<VideoCallIcon />
</IconButton>
</Tooltip>
);
const joinCallButton = (
<Button
size="sm"
onClick={videoClick}
Icon={VideoCallIcon}
className="mx_RoomHeader_join_button"
color="primary"
>
{_t("action|join")}
</Button>
);
const [menuOpen, setMenuOpen] = useState(false);
const callIconWithTooltip = (
<Tooltip label={videoCallDisabledReason ?? _t("voip|video_call")}>
<VideoCallIcon />
</Tooltip>
);
const startVideoCallButton = (
<>
{/* Can be either a menu or just a button depending on the number of call options.*/}
{callOptions.length > 1 ? (
<Menu
open={menuOpen}
onOpenChange={setMenuOpen}
title={_t("voip|video_call_using")}
trigger={
<IconButton
disabled={!!videoCallDisabledReason}
aria-label={videoCallDisabledReason ?? _t("voip|video_call")}
>
{callIconWithTooltip}
</IconButton>
}
side="left"
align="start"
>
{callOptions.map((option) => (
<MenuItem
key={option}
label={getPlatformCallTypeLabel(option)}
onClick={(ev) => videoCallClick(ev, option)}
Icon={VideoCallIcon}
onSelect={() => {} /* Dummy handler since we want the click event.*/}
toger5 marked this conversation as resolved.
Show resolved Hide resolved
/>
))}
</Menu>
) : (
<IconButton
disabled={!!videoCallDisabledReason}
aria-label={videoCallDisabledReason ?? _t("voip|video_call")}
onClick={videoClick}
>
{callIconWithTooltip}
</IconButton>
)}
</>
);
const voiceCallButton = (
<Tooltip label={voiceCallDisabledReason ?? _t("voip|voice_call")}>
<IconButton
disabled={!!voiceCallDisabledReason}
aria-label={voiceCallDisabledReason ?? _t("voip|voice_call")}
onClick={(ev) => voiceCallClick(ev, callOptions[0])}
>
<VoiceCallIcon />
</IconButton>
</Tooltip>
);
const closeLobbyButton = (
<Tooltip label={_t("voip|close_lobby")}>
<IconButton onClick={toggleCall}>
<CloseCallIcon />
</IconButton>
</Tooltip>
);
let videoCallButton = startVideoCallButton;
if (isConnectedToCall) {
videoCallButton = toggleCallButton;
} else if (isViewingCall) {
videoCallButton = closeLobbyButton;
}

return (
<>
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
Expand Down Expand Up @@ -190,29 +293,17 @@ export default function RoomHeader({
</Tooltip>
);
})}
<Tooltip label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}>
<IconButton
disabled={!!videoCallDisabledReason}
aria-label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}
onClick={videoCallClick}
>
<VideoCallIcon />
</IconButton>
</Tooltip>
{!useElementCallExclusively && (
<Tooltip label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}>
<IconButton
disabled={!!voiceCallDisabledReason}
aria-label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}
onClick={voiceCallClick}
>
<VoiceCallIcon />
</IconButton>
</Tooltip>
)}

{/* Renders nothing when room is not a video room */}
<VideoRoomChatButton room={room} />
{((isConnectedToCall && isViewingCall) || isVideoRoom(room)) && <VideoRoomChatButton room={room} />}

{hasActiveCallSession && !isConnectedToCall ? (
joinCallButton
) : (
<>
{!isVideoRoom(room) && videoCallButton}
{!useElementCallExclusively && !isVideoRoom(room) && voiceCallButton}
</>
)}

<Tooltip label={_t("common|threads")}>
<IconButton
Expand Down
12 changes: 2 additions & 10 deletions src/components/views/rooms/RoomHeader/VideoRoomChatButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { Icon as ChatIcon } from "@vector-im/compound-design-tokens/icons/chat-s
import { Room } from "matrix-js-sdk/src/matrix";
import { IconButton, Tooltip } from "@vector-im/compound-web";

import { isVideoRoom as calcIsVideoRoom } from "../../../../utils/video-rooms";
import { _t } from "../../../../languageHandler";
import { useEventEmitterState } from "../../../../hooks/useEventEmitter";
import { NotificationStateEvents } from "../../../../stores/notifications/NotificationState";
Expand All @@ -31,25 +30,18 @@ import { ButtonEvent } from "../../elements/AccessibleButton";
/**
* Display a button to toggle timeline for video rooms
* @param room
* @returns for a video room: a button to toggle timeline in the right panel
* otherwise null
* @returns A button to toggle timeline in the right panel.
*/
export const VideoRoomChatButton: React.FC<{ room: Room }> = ({ room }) => {
const sdkContext = useContext(SDKContext);

const isVideoRoom = calcIsVideoRoom(room);

const notificationState = isVideoRoom ? sdkContext.roomNotificationStateStore.getRoomState(room) : undefined;
const notificationState = sdkContext.roomNotificationStateStore.getRoomState(room);
const notificationColor = useEventEmitterState(
notificationState,
NotificationStateEvents.Update,
() => notificationState?.level,
);

if (!isVideoRoom) {
return null;
}

const displayUnreadIndicator =
!!notificationColor &&
[NotificationLevel.Activity, NotificationLevel.Notification, NotificationLevel.Highlight].includes(
Expand Down
Loading
Loading