blob: 25ddf3908d0b263791282b4022dfc1e67c13d31f [file] [log] [blame]
simon26e79f72022-10-05 22:16:08 -04001/*
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 */
simond47ef9e2022-09-28 22:24:28 -040018import { QuestionMark } from '@mui/icons-material';
simon35378692022-10-02 23:25:57 -040019import { Box, ClickAwayListener, IconButton, IconButtonProps, Popper, SvgIconProps } from '@mui/material';
simond47ef9e2022-09-28 22:24:28 -040020import { styled } from '@mui/material/styles';
simon35378692022-10-02 23:25:57 -040021import EmojiPicker, { IEmojiData } from 'emoji-picker-react';
22import React, { ComponentType, MouseEvent, useCallback, useState } from 'react';
simon07b4eb02022-09-29 17:50:26 -040023
simond47ef9e2022-09-28 22:24:28 -040024import {
25 Arrow2Icon,
26 Arrow3Icon,
27 ArrowIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040028 CallEndIcon,
simond47ef9e2022-09-28 22:24:28 -040029 CameraIcon,
30 CameraInBubbleIcon,
31 CancelIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040032 ChatBubbleIcon,
simond47ef9e2022-09-28 22:24:28 -040033 CrossedEyeIcon,
34 CrossIcon,
35 EmojiIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040036 ExtensionIcon,
simond47ef9e2022-09-28 22:24:28 -040037 EyeIcon,
38 FolderIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040039 FullscreenIcon,
40 GroupAddIcon,
simond47ef9e2022-09-28 22:24:28 -040041 InfoIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040042 MicroIcon,
simond47ef9e2022-09-28 22:24:28 -040043 MicroInBubbleIcon,
44 PaperClipIcon,
45 PenIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040046 RecordingIcon,
simond47ef9e2022-09-28 22:24:28 -040047 SaltireIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040048 ScreenShareIcon,
49 VideoCameraIcon,
50 VolumeIcon,
simon35378692022-10-02 23:25:57 -040051} from './SvgIcon';
idillon-sfl44b05342022-08-24 15:46:42 -040052
simon35378692022-10-02 23:25:57 -040053type ShapedButtonProps = IconButtonProps & {
54 Icon: ComponentType<SvgIconProps>;
55};
56
57const RoundButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -040058 <IconButton {...props} disableRipple={true}>
59 <Icon fontSize="inherit" />
60 </IconButton>
61))(({ theme }) => ({
62 border: `1px solid ${theme.palette.primary.dark}`,
63 color: theme.palette.primary.dark,
64 fontSize: '15px',
65 '&:hover': {
66 background: theme.palette.primary.light,
67 },
68 '&:active': {
69 color: '#FFF',
70 background: theme.palette.primary.dark,
71 },
72 '&.MuiIconButton-sizeSmall': {
73 height: '15px',
74 width: '15px',
75 },
76 '&.MuiIconButton-sizeMedium': {
77 height: '30px',
78 width: '30px',
79 },
80 '&.MuiIconButton-sizeLarge': {
81 height: '53px',
82 width: '53px',
83 },
idillon-sfld5cc7862022-08-25 11:11:34 -040084}));
idillon-sfl44b05342022-08-24 15:46:42 -040085
simon35378692022-10-02 23:25:57 -040086export const CancelPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040087 return <RoundButton {...props} aria-label="remove picture" Icon={CancelIcon} size="large" />;
88};
idillon-sfl44b05342022-08-24 15:46:42 -040089
simon35378692022-10-02 23:25:57 -040090export const EditPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040091 return <RoundButton {...props} aria-label="edit picture" Icon={PenIcon} size="large" />;
92};
idillon-sfl44b05342022-08-24 15:46:42 -040093
simon35378692022-10-02 23:25:57 -040094export const UploadPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040095 return <RoundButton {...props} aria-label="upload picture" Icon={FolderIcon} size="large" />;
96};
idillon-sfl44b05342022-08-24 15:46:42 -040097
simon35378692022-10-02 23:25:57 -040098export const TakePictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040099 return <RoundButton {...props} aria-label="take picture" Icon={CameraIcon} size="large" />;
100};
idillon-sfl37c18df2022-08-26 18:44:27 -0400101
simon35378692022-10-02 23:25:57 -0400102export const InfoButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400103 return <RoundButton {...props} aria-label="informations" Icon={InfoIcon} size="small" />;
104};
idillon-sfl37c18df2022-08-26 18:44:27 -0400105
simon35378692022-10-02 23:25:57 -0400106export const TipButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400107 return <RoundButton {...props} aria-label="tip" Icon={QuestionMark} size="medium" />;
108};
idillon-sfl37c18df2022-08-26 18:44:27 -0400109
simon35378692022-10-02 23:25:57 -0400110export const MoreButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400111 return (
112 <IconButton {...props} disableRipple={true} aria-label="more">
113 <CrossIcon fontSize="inherit" />
114 </IconButton>
115 );
116})(({ theme }) => ({
117 border: `1px solid ${theme.palette.primary.dark}`,
118 color: theme.palette.primary.dark,
119 fontSize: '10px',
120 height: '20px',
121 width: '20px',
122 '&:hover': {
123 background: theme.palette.primary.light,
124 },
125 '&:active': {
126 color: '#FFF',
127 background: theme.palette.primary.dark,
128 },
129}));
idillon927b7592022-09-15 12:56:45 -0400130
simon35378692022-10-02 23:25:57 -0400131export const BackButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400132 return (
133 <IconButton {...props} disableRipple={true} aria-label="back">
134 <ArrowIcon fontSize="inherit" />
135 </IconButton>
136 );
137})(({ theme }) => ({
138 color: theme.palette.primary.dark,
139 fontSize: '15px',
140 height: '30px',
141 width: '51px',
142 borderRadius: '5px',
143 '&:hover': {
144 background: theme.palette.primary.light,
145 },
146}));
idillonb3788bf2022-08-29 15:57:57 -0400147
Gabriel Rochone3ec0d22022-10-08 14:27:03 -0400148export const CallingChatButton = (props: IconButtonProps) => {
149 return (
150 <IconButton {...props} aria-label="chat" sx={{ color: 'white' }}>
151 <ChatBubbleIcon />
152 </IconButton>
153 );
154};
155
156export const CallingEndButton = (props: IconButtonProps) => {
157 return (
158 <IconButton {...props} aria-label="end call" sx={{ color: 'white', backgroundColor: 'red' }}>
159 <CallEndIcon />
160 </IconButton>
161 );
162};
163
164export const CallingExtensionButton = (props: IconButtonProps) => {
165 return (
166 <IconButton {...props} aria-label="extensions" sx={{ color: 'white' }}>
167 <ExtensionIcon />
168 </IconButton>
169 );
170};
171
172export const CallingFullscreenButton = (props: IconButtonProps) => {
173 return (
174 <IconButton {...props} aria-label="fullscreen" sx={{ color: 'white' }}>
175 <FullscreenIcon />
176 </IconButton>
177 );
178};
179
180export const CallingGroupButton = (props: IconButtonProps) => {
181 return (
182 <IconButton {...props} aria-label="group options" sx={{ color: 'white' }}>
183 <GroupAddIcon />
184 </IconButton>
185 );
186};
187
188export const CallingMicButton = (props: IconButtonProps) => {
189 return (
190 <IconButton {...props} aria-label="microphone options" sx={{ color: 'white' }}>
191 <MicroIcon />
192 </IconButton>
193 );
194};
195
196export const CallingRecordButton = (props: IconButtonProps) => {
197 return (
198 <IconButton {...props} aria-label="recording options" sx={{ color: 'white' }}>
199 <RecordingIcon />
200 </IconButton>
201 );
202};
203
204export const CallingScreenShareButton = (props: IconButtonProps) => {
205 return (
206 <IconButton {...props} aria-label="screen share" sx={{ color: 'white' }}>
207 <ScreenShareIcon />
208 </IconButton>
209 );
210};
211
212export const CallingVideoCameraButton = (props: IconButtonProps) => {
213 return (
214 <IconButton {...props} aria-label="camera options" sx={{ color: 'white' }}>
215 <VideoCameraIcon />
216 </IconButton>
217 );
218};
219export const CallingVolumeButton = (props: IconButtonProps) => {
220 return (
221 <IconButton {...props} aria-label="volume options" sx={{ color: 'white' }}>
222 <VolumeIcon />
223 </IconButton>
224 );
225};
226
simon35378692022-10-02 23:25:57 -0400227export const CloseButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400228 return (
229 <IconButton {...props} disableRipple={true} aria-label="close">
230 <SaltireIcon fontSize="inherit" />
231 </IconButton>
232 );
233})(({ theme }) => ({
234 color: theme.palette.primary.dark,
235 fontSize: '15px',
236 height: '30px',
237 width: '30px',
238 borderRadius: '5px',
239 '&:hover': {
240 background: theme.palette.primary.light,
241 },
242}));
idillonb3788bf2022-08-29 15:57:57 -0400243
simon35378692022-10-02 23:25:57 -0400244type ToggleVisibilityButtonProps = IconButtonProps & {
245 visible: boolean;
246};
247export const ToggleVisibilityButton = styled(({ visible, ...props }: ToggleVisibilityButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400248 const Icon = visible ? CrossedEyeIcon : EyeIcon;
249 return (
250 <IconButton {...props} disableRipple={true}>
251 <Icon fontSize="inherit" />
252 </IconButton>
253 );
254})(({ theme }) => ({
255 color: theme.palette.primary.dark,
256 fontSize: '15px',
257 height: '15px',
258 width: '15px',
259 '&:hover': {
260 background: theme.palette.primary.light,
261 },
262}));
idillonaedab942022-09-01 14:29:43 -0400263
simon35378692022-10-02 23:25:57 -0400264const SquareButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400265 <IconButton {...props} disableRipple={true}>
266 <Icon fontSize="inherit" />
267 </IconButton>
268))(({ theme }) => ({
269 color: '#7E7E7E',
270 fontSize: '25px',
271 height: '36px',
272 width: '36px',
273 borderRadius: '5px',
274 '&:hover': {
275 background: '#E5E5E5',
276 },
idillonaedab942022-09-01 14:29:43 -0400277}));
278
simon35378692022-10-02 23:25:57 -0400279export const RecordVideoMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400280 return <SquareButton {...props} aria-label="record video message" Icon={CameraInBubbleIcon} />;
281};
idillonaedab942022-09-01 14:29:43 -0400282
simon35378692022-10-02 23:25:57 -0400283export const RecordVoiceMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400284 return <SquareButton {...props} aria-label="record voice message" Icon={MicroInBubbleIcon} />;
285};
idillonaedab942022-09-01 14:29:43 -0400286
simon35378692022-10-02 23:25:57 -0400287export const UploadFileButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400288 return <SquareButton {...props} aria-label="upload file" Icon={PaperClipIcon} />;
289};
idillonaedab942022-09-01 14:29:43 -0400290
simon35378692022-10-02 23:25:57 -0400291export const SendMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400292 return <SquareButton {...props} aria-label="send message" Icon={Arrow2Icon} />;
293};
idillonaedab942022-09-01 14:29:43 -0400294
simon35378692022-10-02 23:25:57 -0400295export const ReplyMessageButton = styled((props: IconButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400296 <IconButton {...props} disableRipple={true} aria-label="send message">
297 <Arrow3Icon fontSize="inherit" />
298 </IconButton>
299))(({ theme }) => ({
300 color: theme.palette.primary.dark,
301 fontSize: '20px',
302 height: '20px',
303 width: '20px',
304 borderRadius: '5px',
305 '&:hover': {
306 background: '#E5E5E5',
307 },
idillon927b7592022-09-15 12:56:45 -0400308}));
309
simon35378692022-10-02 23:25:57 -0400310type EmojiButtonProps = IconButtonProps & {
311 emoji: string;
312};
313export const EmojiButton = styled(({ emoji, ...props }: EmojiButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400314 <IconButton {...props} disableRipple={true}>
315 {emoji}
316 </IconButton>
317))(({ theme }) => ({
318 color: 'white',
319 fontSize: '20px',
320 height: '20px',
321 width: '20px',
idillon927b7592022-09-15 12:56:45 -0400322}));
323
simon35378692022-10-02 23:25:57 -0400324type SelectEmojiButtonProps = {
325 onEmojiSelected: (emoji: string) => void;
326};
327export const SelectEmojiButton = ({ onEmojiSelected, ...props }: SelectEmojiButtonProps) => {
328 const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
idillon1664bb22022-09-14 17:18:15 -0400329
simon35378692022-10-02 23:25:57 -0400330 const handleOpenEmojiPicker = useCallback(
331 (e: MouseEvent<HTMLButtonElement>) => setAnchorEl(anchorEl ? null : e.currentTarget),
332 [anchorEl]
333 );
simond47ef9e2022-09-28 22:24:28 -0400334
335 const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]);
336
337 const onEmojiClick = useCallback(
simon35378692022-10-02 23:25:57 -0400338 (e: MouseEvent, emojiObject: IEmojiData) => {
simon80b7b3b2022-09-28 17:50:10 -0400339 onEmojiSelected(emojiObject.emoji);
simond47ef9e2022-09-28 22:24:28 -0400340 handleClose();
341 },
simon80b7b3b2022-09-28 17:50:10 -0400342 [handleClose, onEmojiSelected]
simond47ef9e2022-09-28 22:24:28 -0400343 );
344
345 const open = Boolean(anchorEl);
346 const id = open ? 'simple-popover' : undefined;
347
348 return (
349 <ClickAwayListener onClickAway={handleClose}>
350 <Box>
simon35378692022-10-02 23:25:57 -0400351 <SquareButton aria-describedby={id} aria-label="select emoji" Icon={EmojiIcon} onClick={(e) => {}} />
352 <Popper id={id} open={open} anchorEl={anchorEl}>
353 <EmojiPicker onEmojiClick={onEmojiClick} disableAutoFocus={true} disableSkinTonePicker={true} native />
simond47ef9e2022-09-28 22:24:28 -0400354 </Popper>
355 </Box>
356 </ClickAwayListener>
357 );
358};