blob: c965d450b7c00b81145f72a2f6e6d1bd538534fd [file] [log] [blame]
simon2d3b6532022-11-08 21:01:57 -05001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
18
simonf929a362022-11-18 16:53:45 -050019import { Box, CircularProgress, Grid, IconButtonProps, Stack, Typography } from '@mui/material';
simon5c677962022-12-02 16:51:54 -050020import { ComponentType, ReactNode, useEffect, useMemo, useRef } from 'react';
simon4e7445c2022-11-16 21:18:46 -050021import { useTranslation } from 'react-i18next';
simon9076a9a2022-11-29 17:13:01 -050022import { useLocation } from 'react-router-dom';
simon2d3b6532022-11-08 21:01:57 -050023
24import {
25 CallingAnswerAudioButton,
26 CallingAnswerVideoButton,
simonf929a362022-11-18 16:53:45 -050027 CallingCancelButton,
simon2d3b6532022-11-08 21:01:57 -050028 CallingRefuseButton,
29} from '../components/CallButtons';
Gabriel Rochon15a5fb22022-11-27 19:25:14 -050030import ConversationAvatar from '../components/ConversationAvatar';
simon5c677962022-12-02 16:51:54 -050031import { CallStatus, useCallContext } from '../contexts/CallProvider';
simon09fe4822022-11-30 23:36:25 -050032import { useConversationContext } from '../contexts/ConversationProvider';
idillon27dab022023-02-02 17:55:47 -050033import { useUserMediaContext } from '../contexts/UserMediaProvider';
simon571240f2022-11-29 23:59:27 -050034import { VideoElementWithSinkId } from '../utils/utils';
simon2d3b6532022-11-08 21:01:57 -050035
simon9076a9a2022-11-29 17:13:01 -050036export const CallPending = () => {
idillon07d31cc2022-12-06 22:40:14 -050037 const { conversationDisplayName } = useConversationContext();
idillon27dab022023-02-02 17:55:47 -050038 const { localStream } = useUserMediaContext();
39 const { callRole } = useCallContext();
simon571240f2022-11-29 23:59:27 -050040 const localVideoRef = useRef<VideoElementWithSinkId | null>(null);
Misha Krieger-Raynauldabc80e52022-11-29 19:44:41 -050041
42 useEffect(() => {
43 if (localStream && localVideoRef.current) {
44 localVideoRef.current.srcObject = localStream;
45 }
simon492e8402022-11-29 16:48:37 -050046 }, [localStream, localVideoRef]);
Misha Krieger-Raynauldabc80e52022-11-29 19:44:41 -050047
simon2d3b6532022-11-08 21:01:57 -050048 return (
49 <Stack
50 direction="column"
51 justifyContent="center"
52 alignItems="center"
53 height="100%"
54 spacing={4}
simon9f814a32022-11-22 21:40:53 -050055 flexGrow={1}
simon2d3b6532022-11-08 21:01:57 -050056 sx={{
Misha Krieger-Raynauldabc80e52022-11-29 19:44:41 -050057 position: 'relative',
simon2d3b6532022-11-08 21:01:57 -050058 }}
59 >
Misha Krieger-Raynauldabc80e52022-11-29 19:44:41 -050060 <video
61 ref={localVideoRef}
62 autoPlay
63 muted
64 style={{
65 width: '100%',
66 height: '100%',
67 position: 'absolute',
68 objectFit: 'cover',
69 backgroundColor: 'black',
70 zIndex: -1,
71 }}
72 />
simon2d3b6532022-11-08 21:01:57 -050073 <Box
74 sx={{
75 position: 'relative',
76 display: 'flex',
77 alignItems: 'center',
78 justifyContent: 'center',
79 width: '100%',
80 height: '30%',
81 }}
82 >
83 <Box
84 sx={{
85 aspectRatio: '1',
86 height: '100%',
87 position: 'absolute',
88 }}
89 >
90 <CircularProgress
91 disableShrink
92 thickness={1}
93 size="100%"
94 sx={{
95 position: 'absolute',
96 color: 'white',
97 zIndex: 1,
98 }}
99 />
Gabriel Rochon15a5fb22022-11-27 19:25:14 -0500100 <ConversationAvatar
simonf929a362022-11-18 16:53:45 -0500101 alt="contact profile picture"
idillon07d31cc2022-12-06 22:40:14 -0500102 displayName={conversationDisplayName}
simon2d3b6532022-11-08 21:01:57 -0500103 style={{
simon2d3b6532022-11-08 21:01:57 -0500104 width: '100%',
105 height: '100%',
simon2d3b6532022-11-08 21:01:57 -0500106 }}
107 />
108 </Box>
109 </Box>
simon9076a9a2022-11-29 17:13:01 -0500110 {callRole === 'caller' ? <CallPendingCallerInterface /> : <CallPendingReceiverInterface />}
simon2d3b6532022-11-08 21:01:57 -0500111 </Stack>
112 );
113};
114
simonf929a362022-11-18 16:53:45 -0500115const CallPendingDetails = ({
116 title,
117 buttons,
118}: {
119 title: ReactNode;
120 buttons: {
121 ButtonComponent: ComponentType<IconButtonProps>;
122 title: ReactNode;
123 }[];
124}) => {
simon2d3b6532022-11-08 21:01:57 -0500125 return (
simon4e7445c2022-11-16 21:18:46 -0500126 <>
simon2d3b6532022-11-08 21:01:57 -0500127 <Typography variant="h1" color="white">
simonf929a362022-11-18 16:53:45 -0500128 {title}
simon2d3b6532022-11-08 21:01:57 -0500129 </Typography>
simon4e7445c2022-11-16 21:18:46 -0500130 <Box width="50%">
simonf929a362022-11-18 16:53:45 -0500131 <Grid container justifyContent="center">
132 {buttons.map(({ ButtonComponent, title: buttonTitle }, i) => (
133 <Grid item key={i} xs={4}>
134 <Stack direction="column" alignItems="center" spacing={1} sx={{}}>
135 <ButtonComponent color="inherit" size="large" />
136 <Typography variant="body2" color="white" sx={{ opacity: 0.75 }}>
137 {buttonTitle}
138 </Typography>
139 </Stack>
140 </Grid>
141 ))}
142 </Grid>
simon4e7445c2022-11-16 21:18:46 -0500143 </Box>
144 </>
simon2d3b6532022-11-08 21:01:57 -0500145 );
146};
147
simon9076a9a2022-11-29 17:13:01 -0500148export const CallPendingCallerInterface = () => {
simon5c677962022-12-02 16:51:54 -0500149 const { callStatus } = useCallContext();
simon4e7445c2022-11-16 21:18:46 -0500150 const { t } = useTranslation();
idillon07d31cc2022-12-06 22:40:14 -0500151 const { members } = useConversationContext();
152 const memberName = useMemo(() => members[0].getDisplayName(), [members]);
simonf929a362022-11-18 16:53:45 -0500153
simon9076a9a2022-11-29 17:13:01 -0500154 let title = t('loading');
155
156 switch (callStatus) {
157 case CallStatus.Ringing:
158 title = t('calling', {
159 member0: memberName,
160 });
161 break;
162 case CallStatus.Connecting:
163 title = t('connecting');
164 break;
165 }
166
simon2d3b6532022-11-08 21:01:57 -0500167 return (
simonf929a362022-11-18 16:53:45 -0500168 <CallPendingDetails
simon9076a9a2022-11-29 17:13:01 -0500169 title={title}
simonf929a362022-11-18 16:53:45 -0500170 buttons={[
171 {
172 ButtonComponent: CallingCancelButton,
173 title: t('end_call'),
174 },
175 ]}
176 />
177 );
178};
179
simon9076a9a2022-11-29 17:13:01 -0500180export const CallPendingReceiverInterface = () => {
181 const { state } = useLocation();
simon5c677962022-12-02 16:51:54 -0500182 const { callStatus } = useCallContext();
simon9076a9a2022-11-29 17:13:01 -0500183
simonf929a362022-11-18 16:53:45 -0500184 const { t } = useTranslation();
idillon07d31cc2022-12-06 22:40:14 -0500185 const { members } = useConversationContext();
186 const memberName = useMemo(() => members[0].getDisplayName(), [members]);
simonf929a362022-11-18 16:53:45 -0500187
simon9076a9a2022-11-29 17:13:01 -0500188 let title = t('loading');
189
190 switch (callStatus) {
191 case CallStatus.Ringing:
simone35acc22022-12-02 16:51:12 -0500192 case CallStatus.Default:
simon9076a9a2022-11-29 17:13:01 -0500193 title = t('incoming_call', {
194 context: state?.isVideoOn ? 'video' : 'audio',
195 member0: memberName,
196 });
197 break;
198 case CallStatus.Connecting:
199 title = t('connecting');
200 break;
201 }
202
simonf929a362022-11-18 16:53:45 -0500203 return (
204 <CallPendingDetails
simon9076a9a2022-11-29 17:13:01 -0500205 title={title}
simonf929a362022-11-18 16:53:45 -0500206 buttons={[
207 {
208 ButtonComponent: CallingRefuseButton,
209 title: t('refuse_call'),
210 },
211 {
212 ButtonComponent: CallingAnswerAudioButton,
213 title: t('accept_call_audio'),
214 },
215 {
216 ButtonComponent: CallingAnswerVideoButton,
217 title: t('accept_call_video'),
218 },
219 ]}
220 />
simon2d3b6532022-11-08 21:01:57 -0500221 );
222};