1- import { StreamMask , StreamPosition } from '@api.video/media-stream-composer'
2- import CircleIcon from '@mui/icons-material/AccountCircle'
3- import PhotoCameraFrontIcon from '@mui/icons-material/PhotoCameraFront'
4- import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor'
5- import { FormControl , FormControlLabel , FormGroup , FormLabel , InputLabel , MenuItem , Radio , RadioGroup , Select , Slider , Switch , ToggleButton , ToggleButtonGroup } from '@mui/material'
6- import Button from '@mui/material/Button'
7- import Dialog from '@mui/material/Dialog'
8- import DialogActions from '@mui/material/DialogActions'
9- import DialogContent from '@mui/material/DialogContent'
10- import DialogTitle from '@mui/material/DialogTitle'
11- import { useEffect , useState } from 'react'
12- import { ContainDimentionIcon , CoverDimentionIcon , FixedDimensionIcon } from './Icons'
13- import styles from '../../styles/Home.module.css'
1+ import { StreamMask , StreamPosition } from '@api.video/media-stream-composer' ;
2+ import CircleIcon from '@mui/icons-material/AccountCircle' ;
3+ import ImageIcon from '@mui/icons-material/Image' ;
4+ import PhotoCameraFrontIcon from '@mui/icons-material/PhotoCameraFront' ;
5+ import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor' ;
6+ import { FormControl , FormControlLabel , FormGroup , FormLabel , InputLabel , MenuItem , Radio , RadioGroup , Select , Slider , Switch , ToggleButton , ToggleButtonGroup } from '@mui/material' ;
7+ import Button from '@mui/material/Button' ;
8+ import Dialog from '@mui/material/Dialog' ;
9+ import DialogActions from '@mui/material/DialogActions' ;
10+ import DialogContent from '@mui/material/DialogContent' ;
11+ import DialogTitle from '@mui/material/DialogTitle' ;
12+ import { createRef , useEffect , useState } from 'react' ;
13+ import styles from '../../styles/Home.module.css' ;
14+ import { ContainDimentionIcon , CoverDimentionIcon , FixedDimensionIcon } from './Icons' ;
1415
1516export interface StreamFormValues {
1617 type : StreamType ;
17- position : StreamPosition ;
18+ position : StreamPosition ;
1819 mask : StreamMask ;
1920 width ?: string ;
2021 height ?: string ;
@@ -24,6 +25,7 @@ export interface StreamFormValues {
2425 resizable : boolean ;
2526 deviceId ?: string ;
2627 opacity ?: number ;
28+ imageUrl ?: string ;
2729}
2830
2931interface StreamDialogProps {
@@ -33,7 +35,7 @@ interface StreamDialogProps {
3335 onClose ?: ( ) => void ;
3436}
3537
36- type StreamType = "screen" | "webcam" ;
38+ type StreamType = "screen" | "webcam" | "image" ;
3739
3840
3941const StreamDialog = ( props : StreamDialogProps ) => {
@@ -48,7 +50,9 @@ const StreamDialog = (props: StreamDialogProps) => {
4850 const [ draggable , setDraggable ] = useState ( false ) ;
4951 const [ resizable , setResizable ] = useState ( false ) ;
5052 const [ deviceId , setDeviceId ] = useState < string > ( ) ;
53+ const [ imageUrl , setImageUrl ] = useState < string > ( "" ) ;
5154 const [ screencastAvailable , setScreencastAvailable ] = useState ( typeof navigator !== "undefined" && ! ! navigator . mediaDevices . getDisplayMedia )
55+ const fileInputRef = createRef < HTMLInputElement > ( ) ;
5256
5357 // select the first device when the devices are loaded
5458 useEffect ( ( ) => {
@@ -90,11 +94,32 @@ const StreamDialog = (props: StreamDialogProps) => {
9094 value = { type }
9195 exclusive
9296 onChange = { ( v , w ) => w && setType ( w ) } >
93- < ToggleButton disabled = { ! screencastAvailable } value = "screen" > < ScreenshotMonitorIcon className = { styles . toogleButtonIcon } /> Screencast</ ToggleButton >
94- < ToggleButton disabled = { props . devices . length === 0 } value = "webcam" > < PhotoCameraFrontIcon className = { styles . toogleButtonIcon } /> Webcam</ ToggleButton >
97+ < ToggleButton disabled = { ! screencastAvailable } value = "screen" > < ScreenshotMonitorIcon className = { styles . toogleButtonIcon } /> Screencast</ ToggleButton >
98+ < ToggleButton disabled = { props . devices . length === 0 } value = "webcam" > < PhotoCameraFrontIcon className = { styles . toogleButtonIcon } /> Webcam</ ToggleButton >
99+ < ToggleButton value = "image" > < ImageIcon className = { styles . toogleButtonIcon } /> Image</ ToggleButton >
95100 </ ToggleButtonGroup >
96101 </ FormGroup >
97102 </ FormControl >
103+ { type === "image" && < div >
104+ < FormControl style = { { width : "100%" } } >
105+ < FormLabel component = "legend" id = "device-radio-buttons-group-label" > Image</ FormLabel >
106+ < Button variant = "contained" onClick = { ( ) => fileInputRef . current && fileInputRef . current . click ( ) } > Select an image</ Button >
107+ < input style = { { display : "none" } } ref = { fileInputRef } type = "file" accept = "image/*" onChange = { ( e ) => {
108+ if ( e . target . files && e . target . files . length > 0 ) {
109+ const file = e . target . files [ 0 ] ;
110+ const reader = new FileReader ( ) ;
111+ reader . onload = ( e ) => {
112+ if ( e . target && e . target . result ) {
113+ setImageUrl ( e . target . result as string ) ;
114+ }
115+ }
116+ reader . readAsDataURL ( file ) ;
117+ }
118+ } } />
119+ < img src = { imageUrl } style = { { width : "100%" , marginTop : "10px" } } />
120+ </ FormControl >
121+ </ div >
122+ }
98123 { type === "webcam" && < div >
99124 < FormControl >
100125 < FormLabel component = "legend" id = "device-radio-buttons-group-label" > Device</ FormLabel >
@@ -122,9 +147,9 @@ const StreamDialog = (props: StreamDialogProps) => {
122147 value = { position }
123148 exclusive
124149 onChange = { ( v , w ) => w && setPosition ( w ) } >
125- < ToggleButton value = "cover" > < CoverDimentionIcon className = { styles . toogleButtonIcon } /> cover</ ToggleButton >
126- < ToggleButton value = "contain" > < ContainDimentionIcon className = { styles . toogleButtonIcon } /> contain</ ToggleButton >
127- < ToggleButton value = "fixed" > < FixedDimensionIcon className = { styles . toogleButtonIcon } /> fixed</ ToggleButton >
150+ < ToggleButton value = "cover" > < CoverDimentionIcon className = { styles . toogleButtonIcon } /> cover</ ToggleButton >
151+ < ToggleButton value = "contain" > < ContainDimentionIcon className = { styles . toogleButtonIcon } /> contain</ ToggleButton >
152+ < ToggleButton value = "fixed" > < FixedDimensionIcon className = { styles . toogleButtonIcon } /> fixed</ ToggleButton >
128153 </ ToggleButtonGroup >
129154 </ FormGroup >
130155 </ FormControl >
@@ -224,7 +249,7 @@ const StreamDialog = (props: StreamDialogProps) => {
224249 onChange = { ( v , w ) => w && setMask ( w ) }
225250 >
226251 < ToggleButton value = "none" > none</ ToggleButton >
227- < ToggleButton value = "circle" > < CircleIcon className = { styles . toogleButtonIcon } /> circle</ ToggleButton >
252+ < ToggleButton value = "circle" > < CircleIcon className = { styles . toogleButtonIcon } /> circle</ ToggleButton >
228253 </ ToggleButtonGroup >
229254 </ FormGroup >
230255 </ FormControl >
@@ -253,8 +278,9 @@ const StreamDialog = (props: StreamDialogProps) => {
253278 </ DialogContent >
254279 < DialogActions >
255280 < Button onClick = { ( ) => props . onClose && props . onClose ( ) } > Cancel</ Button >
256- < Button disabled = { ! screencastAvailable && props . devices . length === 0 } onClick = { ( ) => props . onSubmit && props . onSubmit ( {
281+ < Button disabled = { ! screencastAvailable && props . devices . length === 0 || ( type === "image" && imageUrl === "" ) } onClick = { ( ) => props . onSubmit && props . onSubmit ( {
257282 type,
283+ imageUrl,
258284 position : position ! ,
259285 mask : mask ! ,
260286 width,
0 commit comments