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 { BottomNav } from './bottomNav/BottomNav';
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 { ThemeProvider } from "styled-components";
import { SettingsContext } from 'context/SettingsContext';
import avatar from 'images/avatar.png';
export function Session() {
const { state, actions } = useSession();
@ -347,43 +349,64 @@ export function Session() {
</Modal>
<Modal centered visible={state.callStatus} footer={null} closable={false} width={callModal.width} height={callModal.height} bodyStyle={{ padding: 6 }}>
<CallingWrapper>
{ !state.remoteVideo && (
<Logo url={state.callLogo} width={256} height={256} radius={8} />
)}
{ state.remoteStream && (
<video ref={remote} disablepictureinpicture playsInline autoPlay style={{ display: state.remoteVideo ? 'block' : 'none', width: '100%' }}
complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} />
)}
{ state.localStream && (
<div className="calling-local">
<video ref={local} disablepictureinpicture playsInline autoPlay muted style={{ width: '100%', display: 'block' }}
complete={() => console.log("VIDEO COMPLETE")} progress={() => console.log("VIDEO PROGRESS")} error={() => console.log("VIDEO ERROR")} waiting={() => console.log("VIDEO WAITING")} />
<div className={ state.fullscreen ? 'fullscreen' : 'modal' }>
<div className="window">
{ !state.remoteVideo && (
<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 && (
<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")} />
)}
{ state.localStream && (
<div className="calling-local">
<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")} />
</div>
)}
<div className="calling-options calling-hovered">
{ state.localVideo && (
<div className="calling-option" onClick={actions.disableVideo}>
<IoVideocamOutline />
</div>
)}
{ !state.localVideo && (
<div className="calling-option" onClick={actions.enableVideo}>
<IoVideocamOffOutline />
</div>
)}
{ state.localAudio && (
<div className="calling-option" onClick={actions.disableAudio}>
<IoMicOutline />
</div>
)}
{ !state.localAudio && (
<div className="calling-option" onClick={actions.enableAudio}>
<IoMicOffOutline />
</div>
)}
{ state.fullscreen && (
<div className="calling-option" onClick={() => actions.setFullscreen(false)}>
<ShrinkOutlined />
</div>
)}
{ !state.fullscreen && (
<div className="calling-option" onClick={() => actions.setFullscreen(true)}>
<ArrowsAltOutlined />
</div>
)}
<div className="calling-end" onClick={actions.end}>
<IoCallOutline />
</div>
</div>
</div>
)}
<div className="calling-options calling-hovered">
{ state.localVideo && (
<div className="calling-option" onClick={actions.disableVideo}>
<IoVideocamOutline />
</div>
)}
{ !state.localVideo && (
<div className="calling-option" onClick={actions.enableVideo}>
<IoVideocamOffOutline />
</div>
)}
{ state.localAudio && (
<div className="calling-option" onClick={actions.disableAudio}>
<IoMicOutline />
</div>
)}
{ !state.localAudio && (
<div className="calling-option" onClick={actions.enableAudio}>
<IoMicOffOutline />
</div>
)}
</div>
<div className="calling-end calling-hovered" onClick={actions.end}>
<IoCallOutline />
</div>
</CallingWrapper>
</Modal>

View File

@ -73,66 +73,94 @@ export const RingingWrapper = styled.div`
`;
export const CallingWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
&:hover .calling-hovered {
display: flex;
}
.calling-local {
width: 33%;
bottom: 16px;
left: 16px;
position: absolute;
}
.calling-logo {
position: absolute;
.fullscreen {
position: fixed;
top: 0;
left: 0;
width: 256px;
height: 256px;
background-color: yellow;
width: 100vw;
height: 100vh;
background-color: ${props => props.theme.frameArea};
}
.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);
.modal {
background-color: ${props => props.theme.frameArea};
}
.calling-options {
display: none;
position: absolute;
top: 16px;
flex-direction: row;
}
.calling-option {
color: ${Colors.white};
font-size: 24px;
background-color: ${Colors.primary};
.window {
display: flex;
align-items: center;
justify-content: center;
padding: 8px;
border-radius: 20px;
cursor: pointer;
margin-left: 8px;
margin-right: 8px;
}
`;
position: relative;
width: 100%;
height: 100%;
&:hover .calling-hovered {
display: flex;
}
.logo {
width: 100%;
height: 100%;
border-radius: 4px;
}
.image {
object-fit: contain;
}
.calling-local {
width: 33%;
bottom: 16px;
left: 16px;
position: absolute;
}
.calling-logo {
position: absolute;
top: 0;
left: 0;
width: 256px;
height: 256px;
background-color: yellow;
}
.calling-options {
display: none;
position: absolute;
bottom: 16px;
flex-direction: row;
}
.calling-option {
color: ${Colors.white};
background-color: ${Colors.primary};
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
padding: 8px;
border-radius: 20px;
cursor: pointer;
margin-left: 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`

View File

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