adding fullscreen support to video calls

This commit is contained in:
Roland Osborne 2024-03-06 13:34:00 -08:00
parent 48baa779fb
commit f03ca2dbe0
3 changed files with 147 additions and 87 deletions

View File

@ -14,11 +14,13 @@ import { Account } from './account/Account';
import { Welcome } from './welcome/Welcome'; import { Welcome } from './welcome/Welcome';
import { BottomNav } from './bottomNav/BottomNav'; import { BottomNav } from './bottomNav/BottomNav';
import { Logo } from 'logo/Logo'; import { Logo } from 'logo/Logo';
import { EyeInvisibleOutlined, PhoneOutlined } from '@ant-design/icons'; import { EyeInvisibleOutlined, PhoneOutlined, ShrinkOutlined, ArrowsAltOutlined } from '@ant-design/icons';
import { IoVideocamOffOutline, IoVideocamOutline, IoMicOffOutline, IoMicOutline, IoCallOutline } from "react-icons/io5"; import { IoVideocamOffOutline, IoVideocamOutline, IoMicOffOutline, IoMicOutline, IoCallOutline } from "react-icons/io5";
import { ThemeProvider } from "styled-components"; import { ThemeProvider } from "styled-components";
import { SettingsContext } from 'context/SettingsContext'; import { SettingsContext } from 'context/SettingsContext';
import avatar from 'images/avatar.png';
export function Session() { export function Session() {
const { state, actions } = useSession(); const { state, actions } = useSession();
@ -347,16 +349,25 @@ export function Session() {
</Modal> </Modal>
<Modal centered visible={state.callStatus} footer={null} closable={false} width={callModal.width} height={callModal.height} bodyStyle={{ padding: 6 }}> <Modal centered visible={state.callStatus} footer={null} closable={false} width={callModal.width} height={callModal.height} bodyStyle={{ padding: 6 }}>
<CallingWrapper> <CallingWrapper>
<div className={ state.fullscreen ? 'fullscreen' : 'modal' }>
<div className="window">
{ !state.remoteVideo && ( { !state.remoteVideo && (
<Logo url={state.callLogo} width={256} height={256} radius={8} /> <div className="logo">
{ state.callLogo && (
<img className="image" src={state.callLogo} alt="logo" width="100%" height="100%" />
)}
{ !state.callLogo && (
<img className="image" src={avatar} alt="default logo" width="100%" height="100%" />
)}
</div>
)} )}
{ state.remoteStream && ( { state.remoteStream && (
<video ref={remote} disablepictureinpicture playsInline autoPlay style={{ display: state.remoteVideo ? 'block' : 'none', width: '100%' }} <video ref={remote} disablepictureinpicture playsInline autoPlay style={{ display: state.remoteVideo ? 'block' : 'none', width: '100%', height: '100%' }}
complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} /> complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} />
)} )}
{ state.localStream && ( { state.localStream && (
<div className="calling-local"> <div className="calling-local">
<video ref={local} disablepictureinpicture playsInline autoPlay muted style={{ width: '100%', display: 'block' }} <video ref={local} disablepictureinpicture playsInline autoPlay muted style={{ width: '100%', height: '100%', display: 'block' }}
complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} /> complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} />
</div> </div>
)} )}
@ -381,10 +392,22 @@ export function Session() {
<IoMicOffOutline /> <IoMicOffOutline />
</div> </div>
)} )}
{ state.fullscreen && (
<div className="calling-option" onClick={() => actions.setFullscreen(false)}>
<ShrinkOutlined />
</div> </div>
<div className="calling-end calling-hovered" onClick={actions.end}> )}
{ !state.fullscreen && (
<div className="calling-option" onClick={() => actions.setFullscreen(true)}>
<ArrowsAltOutlined />
</div>
)}
<div className="calling-end" onClick={actions.end}>
<IoCallOutline /> <IoCallOutline />
</div> </div>
</div>
</div>
</div>
</CallingWrapper> </CallingWrapper>
</Modal> </Modal>
</SessionWrapper> </SessionWrapper>

View File

@ -73,14 +73,42 @@ export const RingingWrapper = styled.div`
`; `;
export const CallingWrapper = styled.div` export const CallingWrapper = styled.div`
.fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: ${props => props.theme.frameArea};
}
.modal {
background-color: ${props => props.theme.frameArea};
}
.window {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
width: 100%;
height: 100%;
&:hover .calling-hovered { &:hover .calling-hovered {
display: flex; display: flex;
} }
.logo {
width: 100%;
height: 100%;
border-radius: 4px;
}
.image {
object-fit: contain;
}
.calling-local { .calling-local {
width: 33%; width: 33%;
bottom: 16px; bottom: 16px;
@ -97,32 +125,17 @@ export const CallingWrapper = styled.div`
background-color: yellow; background-color: yellow;
} }
.calling-end {
position: absolute;
bottom: 16px;
color: ${Colors.white};
font-size: 24px;
background-color: ${Colors.alert};
display: none;
align-items: center;
justify-content: center;
padding: 8px;
border-radius: 20px;
cursor: pointer;
transform: rotate(135deg);
}
.calling-options { .calling-options {
display: none; display: none;
position: absolute; position: absolute;
top: 16px; bottom: 16px;
flex-direction: row; flex-direction: row;
} }
.calling-option { .calling-option {
color: ${Colors.white}; color: ${Colors.white};
font-size: 24px;
background-color: ${Colors.primary}; background-color: ${Colors.primary};
font-size: 24px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -132,7 +145,22 @@ export const CallingWrapper = styled.div`
margin-left: 8px; margin-left: 8px;
margin-right: 8px; margin-right: 8px;
} }
`;
.calling-end {
color: ${Colors.white};
background-color: ${Colors.alert};
transform: rotate(135deg);
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
padding: 8px;
border-radius: 20px;
cursor: pointer;
margin-left: 8px;
margin-right: 8px;
}
`;
export const SessionWrapper = styled.div` export const SessionWrapper = styled.div`

View File

@ -34,6 +34,7 @@ export function useSession() {
remoteAudio: false, remoteAudio: false,
audioId: null, audioId: null,
videoId: null, videoId: null,
fullscreen: false,
}); });
const app = useContext(AppContext); const app = useContext(AppContext);
@ -78,6 +79,11 @@ export function useSession() {
const { callStatus, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio } = ring.state; const { callStatus, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio } = ring.state;
updateState({ ringing, callStatus, callLogo, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio }); updateState({ ringing, callStatus, callLogo, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio });
if (!callStatus && state.fullscreen) {
updateState({ fullscreen: false });
}
// eslint-disable-next-line // eslint-disable-next-line
}, [ring.state]); }, [ring.state]);
@ -120,6 +126,9 @@ export function useSession() {
}, [store]); }, [store]);
const actions = { const actions = {
setFullscreen: (fullscreen) => {
updateState({ fullscreen });
},
openCards: () => { openCards: () => {
updateState({ cards: true }); updateState({ cards: true });
}, },