/* * Wire * Copyright (C) 2020 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import React, {CSSProperties, useEffect, useState} from 'react'; import {css} from '@emotion/react'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import {Avatar, AVATAR_SIZE} from 'Components/Avatar'; import * as Icon from 'Components/Icon'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {t} from 'Util/LocalizerUtil'; import {GroupVideoGridTile} from './GroupVideoGridTile'; import {Video} from './Video'; import type {Participant} from '../../calling/Participant'; import type {Grid} from '../../calling/videoGridHandler'; export interface GroupVideoGripProps { grid: Grid; maximizedParticipant: Participant | null; minimized?: boolean; selfParticipant: Participant; setMaximizedParticipant?: (participant: Participant | null) => void; } interface RowsAndColumns extends CSSProperties { '--columns': number; '--rows': number; } const calculateRowsAndColumns = (totalCount: number): RowsAndColumns => { const columns = totalCount ? Math.ceil(Math.sqrt(totalCount)) : 1; const rows = totalCount ? Math.ceil(totalCount / columns) : 1; return {'--columns': columns, '--rows': rows}; }; const GroupVideoThumbnailWrapper: React.FC<{children?: React.ReactNode; minimized: boolean}> = ({ minimized, children, }) => (
{children}
); const GroupVideoGrid: React.FunctionComponent = ({ minimized = false, grid, selfParticipant, maximizedParticipant, setMaximizedParticipant, }) => { const thumbnail = useKoSubscribableChildren(grid.thumbnail!, [ 'hasActiveVideo', 'sharesScreen', 'videoStream', 'blurredVideoStream', ]); const [rowsAndColumns, setRowsAndColumns] = useState(calculateRowsAndColumns(grid?.grid.length)); const doubleClickedOnVideo = (userId: QualifiedId, clientId: string) => { if (typeof setMaximizedParticipant !== 'function') { return; } if (maximizedParticipant !== null) { setMaximizedParticipant(null); return; } if (grid.grid.length < 2) { return; } const participant = grid.grid.find(participant => participant?.doesMatchIds(userId, clientId)) || null; setMaximizedParticipant(participant); }; const participants = (maximizedParticipant ? [maximizedParticipant] : grid.grid).filter(Boolean); useEffect(() => { setRowsAndColumns(calculateRowsAndColumns(participants.length)); }, [participants.length]); const {isMuted: selfIsMuted} = useKoSubscribableChildren(selfParticipant, ['isMuted']); return (
{grid.grid.length === 0 && (
path': { fill: 'var(--main-color)', }, height: 32, marginBottom: 32, width: 32, }} />
{t('noActiveSpeakers')}
)} {participants.map(participant => ( ))}
{thumbnail.videoStream && !maximizedParticipant && ( )} {!!grid.thumbnail && !thumbnail.hasActiveVideo && !!selfParticipant && (
{selfIsMuted && !minimized && ( )}
)}
); }; export {GroupVideoGrid};