parent
202f64024d
commit
37446bb804
12 changed files with 388 additions and 56 deletions
@ -0,0 +1,60 @@ |
|||||||
|
|
||||||
|
import React, { Component } from 'react'; |
||||||
|
import { withStyles } from "@material-ui/core/styles"; |
||||||
|
import Switch from "@material-ui/core/Switch"; |
||||||
|
|
||||||
|
|
||||||
|
const IOSSwitch = withStyles((theme) => ({ |
||||||
|
root: { |
||||||
|
width: 42, |
||||||
|
height: 26, |
||||||
|
padding: 0, |
||||||
|
margin: theme.spacing(1), |
||||||
|
}, |
||||||
|
switchBase: { |
||||||
|
padding: 1, |
||||||
|
"&$checked": { |
||||||
|
transform: "translateX(16px)", |
||||||
|
color: theme.palette.common.white, |
||||||
|
"& + $track": { |
||||||
|
backgroundColor: "#52d869", |
||||||
|
opacity: 1, |
||||||
|
border: "none", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"&$focusVisible $thumb": { |
||||||
|
color: "#52d869", |
||||||
|
border: "6px solid #fff", |
||||||
|
}, |
||||||
|
}, |
||||||
|
thumb: { |
||||||
|
width: 24, |
||||||
|
height: 24, |
||||||
|
}, |
||||||
|
track: { |
||||||
|
borderRadius: 26 / 2, |
||||||
|
border: `1px solid ${theme.palette.grey[400]}`, |
||||||
|
backgroundColor: theme.palette.grey[50], |
||||||
|
opacity: 1, |
||||||
|
transition: theme.transitions.create(["background-color", "border"]), |
||||||
|
}, |
||||||
|
checked: {}, |
||||||
|
focusVisible: {}, |
||||||
|
}))(({ classes, ...props }) => { |
||||||
|
return ( |
||||||
|
<Switch |
||||||
|
focusVisibleClassName={classes.focusVisible} |
||||||
|
disableRipple |
||||||
|
classes={{ |
||||||
|
root: classes.root, |
||||||
|
switchBase: classes.switchBase, |
||||||
|
thumb: classes.thumb, |
||||||
|
track: classes.track, |
||||||
|
checked: classes.checked, |
||||||
|
}} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
export default IOSSwitch; |
@ -0,0 +1,67 @@ |
|||||||
|
import React from "react"; |
||||||
|
import Badge from "@material-ui/core/Badge"; |
||||||
|
import Avatar from "@material-ui/core/Avatar"; |
||||||
|
import { makeStyles, withStyles } from "@material-ui/core/styles"; |
||||||
|
|
||||||
|
const StyledBadge = withStyles((theme) => ({ |
||||||
|
badge: { |
||||||
|
backgroundColor: "#44b700", |
||||||
|
color: "#44b700", |
||||||
|
boxShadow: `0 0 0 2px ${theme.palette.background.paper}`, |
||||||
|
"&::after": { |
||||||
|
position: "absolute", |
||||||
|
top: 0, |
||||||
|
left: 0, |
||||||
|
width: "100%", |
||||||
|
height: "100%", |
||||||
|
borderRadius: "50%", |
||||||
|
animation: "$ripple 1.2s infinite ease-in-out", |
||||||
|
border: "1px solid currentColor", |
||||||
|
content: '""', |
||||||
|
}, |
||||||
|
}, |
||||||
|
"@keyframes ripple": { |
||||||
|
"0%": { |
||||||
|
transform: "scale(.8)", |
||||||
|
opacity: 1, |
||||||
|
}, |
||||||
|
"100%": { |
||||||
|
transform: "scale(2.4)", |
||||||
|
opacity: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}))(Badge); |
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({ |
||||||
|
root: { |
||||||
|
display: "flex", |
||||||
|
"& > *": { |
||||||
|
margin: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
})); |
||||||
|
|
||||||
|
export default function StatusAvatar(props) { |
||||||
|
const classes = useStyles(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={classes.root}> |
||||||
|
{props.status ? ( |
||||||
|
<StyledBadge |
||||||
|
overlap="circle" |
||||||
|
anchorOrigin={{ |
||||||
|
vertical: "bottom", |
||||||
|
horizontal: "right", |
||||||
|
}} |
||||||
|
variant="dot" |
||||||
|
> |
||||||
|
<Avatar style={{ width : 90, height :90}} alt="Remy Sharp" src={props.src} /> |
||||||
|
</StyledBadge> |
||||||
|
) : ( |
||||||
|
<StyledBadge> |
||||||
|
<Avatar style={{ width : 90, height :90}} alt="Remy Sharp" src={props.src} /> |
||||||
|
</StyledBadge> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
import MicIcon from '@material-ui/icons/Mic'; |
||||||
|
import MicOffIcon from '@material-ui/icons/MicOff'; |
||||||
|
import VideocamOffIcon from '@material-ui/icons/VideocamOff'; |
||||||
|
import VideocamIcon from '@material-ui/icons/Videocam'; |
||||||
|
import FlipCameraIosIcon from "@material-ui/icons/FlipCameraIos"; |
||||||
|
import FormControlLabel from '@material-ui/core/FormControlLabel'; |
||||||
|
import Checkbox from '@material-ui/core/Checkbox'; |
||||||
|
|
||||||
|
|
||||||
|
import "./BottomControl.scss"; |
||||||
|
export default class BottomControl extends Component { |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<div className="bottom-control d-flex"> |
||||||
|
<FormControlLabel |
||||||
|
control={ |
||||||
|
<Checkbox |
||||||
|
icon={<MicIcon style={{ width: 31, height: 31, color: "#dfdfdf" }} />} |
||||||
|
checkedIcon={<MicOffIcon style={{ width: 31, height: 31, color: "#dfdfdf" }} />} |
||||||
|
name="checkedI" |
||||||
|
/> |
||||||
|
} |
||||||
|
label="" |
||||||
|
/> |
||||||
|
<FormControlLabel |
||||||
|
control={ |
||||||
|
<Checkbox |
||||||
|
icon={<VideocamIcon style={{ width: 31, height: 31, color: "#dfdfdf" }} />} |
||||||
|
checkedIcon={<VideocamOffIcon style={{ width: 31, height: 31, color: "#dfdfdf" }} />} |
||||||
|
name="checkedI" |
||||||
|
/> |
||||||
|
} |
||||||
|
label="" |
||||||
|
/> |
||||||
|
<FlipCameraIosIcon style={{ width: 31, height: 31, color: "#dfdfdf" }} /> |
||||||
|
|
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
.bottom-control{ |
||||||
|
width: 100%; |
||||||
|
height: 70px; |
||||||
|
align-items: center; |
||||||
|
justify-content:space-between; |
||||||
|
padding : 0px 30px; |
||||||
|
position: fixed; |
||||||
|
bottom: 0px; |
||||||
|
left : 0px; |
||||||
|
.MuiFormControlLabel-root{ |
||||||
|
margin : 0px !important; |
||||||
|
} |
||||||
|
.PrivateSwitchBase-root-4{ |
||||||
|
padding : 0px !important; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; |
||||||
|
|
||||||
|
import StatusAvatar from '../Avatar/Avatar'; |
||||||
|
|
||||||
|
export default class CallEnd extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
}; |
||||||
|
} |
||||||
|
render() { |
||||||
|
const {brand,user} = this.props; |
||||||
|
return ( |
||||||
|
<div className="video-end d-flex"> |
||||||
|
<header className="d-flex justify-content-center"> |
||||||
|
<div className="video-calling__logo d-flex">{brand}</div> |
||||||
|
<div className="video-calling__expand"> |
||||||
|
<ExpandMoreIcon style={{ width : 30, height : 30 , color : 'white'}} /> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
<StatusAvatar status={user.status} src={user.src} /> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; |
||||||
|
|
||||||
|
import StatusAvatar from '../Avatar/Avatar'; |
||||||
|
|
||||||
|
export default class CallStart extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
}; |
||||||
|
} |
||||||
|
render() { |
||||||
|
const {brand,user} = this.props; |
||||||
|
return ( |
||||||
|
<div className="video-end d-flex"> |
||||||
|
<header className="d-flex"> |
||||||
|
<div className="video-calling__logo">{brand}</div> |
||||||
|
<div className="video-calling__expand"> |
||||||
|
<ExpandMoreIcon style={{ width : 30, height : 30 , color : 'white'}} /> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
<StatusAvatar status={user.status} src={user.src} /> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; |
||||||
|
import CallEndIcon from "@material-ui/icons/CallEnd"; |
||||||
|
|
||||||
|
import BottomControl from "../BottomControl/BottomControl"; |
||||||
|
import StatusAvatar from "../Avatar/Avatar"; |
||||||
|
|
||||||
|
import "./Calling.scss"; |
||||||
|
export default class Calling extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = {}; |
||||||
|
} |
||||||
|
render() { |
||||||
|
const { brand, user, phase } = this.props; |
||||||
|
return ( |
||||||
|
<div className="video-calling d-flex flex-column"> |
||||||
|
<header className="video-calling__header d-flex"> |
||||||
|
<h1 className="video-calling__header--logo">{brand}</h1> |
||||||
|
<div className="video-calling__header--expand d-flex"> |
||||||
|
<ExpandMoreIcon style={{ width: 30, height: 30, color: "white" }} /> |
||||||
|
</div> |
||||||
|
</header> |
||||||
|
<div className="video-calling__avatar d-flex"> |
||||||
|
<StatusAvatar status={user.status} src={user.src} /> |
||||||
|
</div> |
||||||
|
<h2>{user.name}</h2> |
||||||
|
<div className="video-calling__phase">{phase}</div> |
||||||
|
<button className="video-calling__endButton"> |
||||||
|
<CallEndIcon style={{ width: 30, height: 30, color: "white" }} /> |
||||||
|
</button> |
||||||
|
<BottomControl /> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
.video-calling{ |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
align-items: center; |
||||||
|
padding : 15px; |
||||||
|
position: relative; |
||||||
|
&__header{ |
||||||
|
justify-content : center; |
||||||
|
align-items: center; |
||||||
|
width: 100%; |
||||||
|
margin-bottom: 25px; |
||||||
|
font-size: 16px; |
||||||
|
position: fixed; |
||||||
|
top : 20px; |
||||||
|
left : 0px; |
||||||
|
h1{ |
||||||
|
font-size: 18px; |
||||||
|
margin : 0px; |
||||||
|
font-weight: 100; |
||||||
|
letter-spacing: 1px; |
||||||
|
// position : fixed; |
||||||
|
// left : calc(50% - 35px); |
||||||
|
// top : 100px; |
||||||
|
} |
||||||
|
&--expand{ |
||||||
|
position: absolute; |
||||||
|
left: 0px; |
||||||
|
top : 0px; |
||||||
|
} |
||||||
|
} |
||||||
|
&__avatar{ |
||||||
|
position: fixed; |
||||||
|
left: calc(50% - 45px); |
||||||
|
top : 55px; |
||||||
|
} |
||||||
|
h2{ |
||||||
|
font-size: 22px; |
||||||
|
margin-top: 20px; |
||||||
|
position: fixed; |
||||||
|
left: calc(50% - 25px); |
||||||
|
top : 140px; |
||||||
|
} |
||||||
|
&__phase{ |
||||||
|
margin-top: 15px; |
||||||
|
position: fixed; |
||||||
|
left: calc(50% - 25px); |
||||||
|
top : 200px; |
||||||
|
} |
||||||
|
&__endButton{ |
||||||
|
width: 56px; |
||||||
|
height: 56px; |
||||||
|
border: none; |
||||||
|
background-color:rgb(209, 52, 52); |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
border-radius: 50%; |
||||||
|
position: fixed; |
||||||
|
bottom : 100px; |
||||||
|
left : calc(50% - 28px); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
|
||||||
|
import Calling from "./Calling/Calling"; |
||||||
|
import CallStart from "./CallStart/CallStart"; |
||||||
|
import CallEnd from "./CallEnd/CallEnd"; |
||||||
|
|
||||||
|
import pic from "../../assets/images/pic.png"; |
||||||
|
|
||||||
|
import "./VideoCall.scss"; |
||||||
|
export default class VideoCall extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
phase: "Calling", |
||||||
|
}; |
||||||
|
} |
||||||
|
render() { |
||||||
|
const { phase } = this.state; |
||||||
|
return ( |
||||||
|
<div className="video-call d-flex"> |
||||||
|
{phase === "Calling" ? ( |
||||||
|
<Calling |
||||||
|
brand={this.props.brand} |
||||||
|
user={this.props.user} |
||||||
|
phase={phase} |
||||||
|
/> |
||||||
|
) : null} |
||||||
|
{phase === "Start" ? <CallStart /> : null} |
||||||
|
{phase === "End" ? <CallEnd user={this.props.user} /> : null} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
VideoCall.defaultProps = { |
||||||
|
brand: "نام برند", |
||||||
|
user: { |
||||||
|
status: 0, |
||||||
|
src: pic, |
||||||
|
name: "حسن", |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,7 @@ |
|||||||
|
.video-call{ |
||||||
|
height: 100vh; |
||||||
|
width: 100vw; |
||||||
|
overflow: hidden; |
||||||
|
background-color: rgba(6, 14, 8, 0.849); |
||||||
|
color: white; |
||||||
|
} |
Loading…
Reference in new issue