+
+ Why not finish by setting up a password to keep your account?
+
+
+ You'll be able to keep your name and set an avatar for use on
+ future calls
+
+
+ Create account
+
+
+
+
+
+ Not now, return to home screen
+
+
+
+ >
+ );
+}
diff --git a/src/room/CallEndedView.module.css b/src/room/CallEndedView.module.css
new file mode 100644
index 00000000..f08f1d2c
--- /dev/null
+++ b/src/room/CallEndedView.module.css
@@ -0,0 +1,73 @@
+/*
+Copyright 2021 New Vector Ltd
+
+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.
+*/
+
+.headline {
+ text-align: center;
+ margin-bottom: 60px;
+}
+
+.callEndedContent {
+ text-align: center;
+ max-width: 360px;
+}
+
+.callEndedContent h3 {
+ margin-bottom: 32px;
+}
+
+.callEndedButton {
+ width: 100%;
+ margin-top: 54px;
+}
+
+.container {
+ display: flex;
+ min-height: calc(100% - 64px);
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.main {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+.logo {
+ display: flex;
+ margin-bottom: 54px;
+}
+
+.headline {
+ margin-bottom: 40px;
+}
+
+.footer {
+ margin-bottom: 44px;
+}
+
+@media (min-width: 800px) {
+ .logo {
+ display: none;
+ }
+
+ .container {
+ min-height: calc(100% - 76px);
+ }
+}
diff --git a/src/room/InCallView.jsx b/src/room/InCallView.jsx
new file mode 100644
index 00000000..8c22d985
--- /dev/null
+++ b/src/room/InCallView.jsx
@@ -0,0 +1,166 @@
+import React, { useCallback, useMemo } from "react";
+import styles from "./InCallView.module.css";
+import {
+ HangupButton,
+ MicButton,
+ VideoButton,
+ ScreenshareButton,
+} from "../button";
+import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
+import VideoGrid, {
+ useVideoGridLayout,
+} from "matrix-react-sdk/src/components/views/voip/GroupCallView/VideoGrid";
+import SimpleVideoGrid from "matrix-react-sdk/src/components/views/voip/GroupCallView/SimpleVideoGrid";
+import "matrix-react-sdk/res/css/views/voip/GroupCallView/_VideoGrid.scss";
+import { getAvatarUrl } from "../ConferenceCallManagerHooks";
+import { GroupCallInspector } from "../GroupCallInspector";
+import { OverflowMenu } from "../OverflowMenu";
+import { GridLayoutMenu } from "../GridLayoutMenu";
+import { Avatar } from "../Avatar";
+import { UserMenuContainer } from "../UserMenuContainer";
+
+const canScreenshare = "getDisplayMedia" in navigator.mediaDevices;
+// There is currently a bug in Safari our our code with cloning and sending MediaStreams
+// or with getUsermedia and getDisplaymedia being used within the same session.
+// For now we can disable screensharing in Safari.
+const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+
+export function InCallView({
+ client,
+ groupCall,
+ roomName,
+ microphoneMuted,
+ localVideoMuted,
+ toggleLocalVideoMuted,
+ toggleMicrophoneMuted,
+ userMediaFeeds,
+ activeSpeaker,
+ onLeave,
+ toggleScreensharing,
+ isScreensharing,
+ screenshareFeeds,
+ simpleGrid,
+ setShowInspector,
+ showInspector,
+ roomId,
+}) {
+ const [layout, setLayout] = useVideoGridLayout();
+
+ const items = useMemo(() => {
+ const participants = [];
+
+ for (const callFeed of userMediaFeeds) {
+ participants.push({
+ id: callFeed.stream.id,
+ usermediaCallFeed: callFeed,
+ isActiveSpeaker:
+ screenshareFeeds.length === 0
+ ? callFeed.userId === activeSpeaker
+ : false,
+ });
+ }
+
+ for (const callFeed of screenshareFeeds) {
+ const participant = participants.find(
+ (p) => p.usermediaCallFeed.userId === callFeed.userId
+ );
+
+ if (participant) {
+ participant.screenshareCallFeed = callFeed;
+ }
+ }
+
+ return participants;
+ }, [userMediaFeeds, activeSpeaker, screenshareFeeds]);
+
+ const onFocusTile = useCallback(
+ (tiles, focusedTile) => {
+ if (layout === "freedom") {
+ return tiles.map((tile) => {
+ if (tile === focusedTile) {
+ return { ...tile, presenter: !tile.presenter };
+ }
+
+ return tile;
+ });
+ } else {
+ return tiles;
+ }
+ },
+ [layout, setLayout]
+ );
+
+ const renderAvatar = useCallback(
+ (roomMember, width, height) => {
+ const avatarUrl = roomMember.user?.avatarUrl;
+ const size = Math.round(Math.min(width, height) / 2);
+
+ return (
+
+ );
+ },
+ [client]
+ );
+
+ return (
+