Commit 6f5da362 authored by Thisara Kavinda's avatar Thisara Kavinda

feat: implemented control buttons

parent e6ce68d9
import { Box, Typography } from '@mui/material'
import { useTheme, type Theme } from '@mui/material/styles'
import ControlsButtonGroup from '../ControlsButtonGroup/ControlsButtonGroup'
import type { IMicrophoneAudioTrack, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import React, { useEffect } from 'react'
interface Props {
setJoined: (x: boolean) => void
localCameraTrack: ICameraVideoTrack | null
localMicrophoneTrack: IMicrophoneAudioTrack | null
}
const ControlCenter = ({ setJoined, localCameraTrack, localMicrophoneTrack }: Props) => {
const theme: Theme = useTheme()
const [currentTime, setCurrentTime] = React.useState(new Date())
const updateTime = () => {
setCurrentTime(new Date())
}
useEffect(() => {
const interval = setInterval(updateTime, 6000)
return () => clearInterval(interval)
}, [])
return (
<Box
sx={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Box
sx={{
width: '20%',
paddingLeft: '0px',
alignItems: 'center',
justifyContent: 'flex-start',
textAlign: 'left',
}}
>
<Typography
sx={{
fontSize: '18px',
color: theme.palette.common.white,
fontWeight: 600,
textAlign: 'left',
paddingLeft: '50px',
}}
>
{currentTime.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
hour12: true,
})}
</Typography>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}
>
<ControlsButtonGroup
setJoined={setJoined}
localCameraTrack={localCameraTrack}
localMicrophoneTrack={localMicrophoneTrack}
/>
</Box>
<Box
sx={{
width: '20%',
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
paddingRight: '50px',
alignItems: 'center',
}}
></Box>
</Box>
)
}
export default ControlCenter
import React, { useState } from 'react'
import type { IMicrophoneAudioTrack, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import { Box, IconButton } from '@mui/material'
import MicIcon from '@mui/icons-material/Mic'
import VideocamIcon from '@mui/icons-material/Videocam'
import { useTheme, type Theme } from '@mui/material/styles'
import ClosedCaptionIcon from '@mui/icons-material/ClosedCaption'
import PresentToAllIcon from '@mui/icons-material/PresentToAll'
import MicOffIcon from '@mui/icons-material/MicOff'
import CallEndIcon from '@mui/icons-material/CallEnd'
import VideocamOffIcon from '@mui/icons-material/VideocamOff'
interface Props {
setJoined: (x: boolean) => void
localCameraTrack: ICameraVideoTrack | null
localMicrophoneTrack: IMicrophoneAudioTrack | null
}
const ControlsButtonGroup = ({ setJoined, localCameraTrack, localMicrophoneTrack }: Props) => {
const theme: Theme = useTheme()
const [isAudioEnable, setIsAudioEnable] = useState(localMicrophoneTrack?.enabled)
const [isVideoEnabled, setIsVideoEnabled] = useState(localCameraTrack?.enabled)
const toogleAudio = async () => {
if (isAudioEnable) {
await localMicrophoneTrack?.setEnabled(false)
setIsAudioEnable(false)
} else {
await localMicrophoneTrack?.setEnabled(true)
setIsAudioEnable(true)
}
}
const toogleVideo = async () => {
if (isVideoEnabled) {
await localCameraTrack?.setEnabled(false)
setIsVideoEnabled(false)
} else {
await localCameraTrack?.setEnabled(true)
setIsVideoEnabled(true)
}
}
const handleLeaveCall = () => {
localCameraTrack?.close()
localMicrophoneTrack?.close()
setJoined(false)
}
return (
<Box sx={{ height: '100%', width: '100%' }}>
<IconButton
sx={{
borderRadius: '50%',
padding: '15px',
marginX: '15px',
backgroundColor: isAudioEnable ? 'green' : '#363739',
'&:hover': { backgroundColor: isAudioEnable ? 'green' : '#363739' },
}}
onClick={toogleAudio}
>
{isAudioEnable ? (
<MicIcon sx={{ color: theme.palette.common.white }} />
) : (
<MicOffIcon sx={{ color: theme.palette.common.white }} />
)}
</IconButton>
<IconButton
sx={{
borderRadius: '50%',
padding: '15px',
marginX: '15px',
backgroundColor: isVideoEnabled ? 'green' : '#363739',
'&:hover': { backgroundColor: isVideoEnabled ? 'green' : '#363739' },
}}
onClick={toogleVideo}
>
{isVideoEnabled ? (
<VideocamIcon sx={{ color: theme.palette.common.white }} />
) : (
<VideocamOffIcon sx={{ color: theme.palette.common.white }} />
)}
</IconButton>
<IconButton
sx={{
borderRadius: '50%',
padding: '15px',
marginX: '15px',
backgroundColor: '#363739',
'&:hover': { backgroundColor: '#363739' },
}}
>
<ClosedCaptionIcon sx={{ color: theme.palette.common.white }} />
</IconButton>
<IconButton
sx={{
borderRadius: '50%',
padding: '15px',
marginX: '15px',
backgroundColor: '#363739',
'&:hover': { backgroundColor: '#363739' },
}}
>
<PresentToAllIcon sx={{ color: theme.palette.common.white }} />
</IconButton>
<IconButton
sx={{
borderRadius: '40%',
padding: '15px',
paddingX: '25px',
marginX: '15px',
backgroundColor: 'red',
'&:hover': { backgroundColor: 'red' },
}}
onClick={handleLeaveCall}
>
<CallEndIcon sx={{ color: theme.palette.common.white }} />
</IconButton>
</Box>
)
}
export default ControlsButtonGroup
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import { Box } from '@mui/material' import { Box } from '@mui/material'
import { useTheme, type Theme } from '@mui/material/styles' import { useTheme, type Theme } from '@mui/material/styles'
import { import { useRemoteUsers, usePublish, useRTCClient, useClientEvent } from 'agora-rtc-react'
useLocalCameraTrack,
useLocalMicrophoneTrack,
useRemoteUsers,
usePublish,
useRTCClient,
useClientEvent,
} from 'agora-rtc-react'
import SymmetricGrid from '../SymmetricGrid/SymmetricGrid' import SymmetricGrid from '../SymmetricGrid/SymmetricGrid'
import PinnedGrid from '../PinnedGrid/PinnedGrid' import PinnedGrid from '../PinnedGrid/PinnedGrid'
import type { IAgoraRTCRemoteUser } from 'agora-rtc-sdk-ng' import type {
IAgoraRTCRemoteUser,
ICameraVideoTrack,
IMicrophoneAudioTrack,
} from 'agora-rtc-sdk-ng'
import ControlCenter from '../ControlCenter/ControlCenter'
const MeetingLayout = () => { interface Props {
setJoined: (x: boolean) => void
localCameraTrack: ICameraVideoTrack | null
localMicrophoneTrack: IMicrophoneAudioTrack | null
}
const MeetingLayout = ({ setJoined, localCameraTrack, localMicrophoneTrack }: Props) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
const agoraEngine = useRTCClient() const agoraEngine = useRTCClient()
const { localCameraTrack } = useLocalCameraTrack()
const { localMicrophoneTrack } = useLocalMicrophoneTrack()
usePublish([localMicrophoneTrack, localCameraTrack]) usePublish([localMicrophoneTrack, localCameraTrack])
const remoteUsers: IAgoraRTCRemoteUser[] = useRemoteUsers() const remoteUsers: IAgoraRTCRemoteUser[] = useRemoteUsers()
...@@ -52,11 +54,12 @@ const MeetingLayout = () => { ...@@ -52,11 +54,12 @@ const MeetingLayout = () => {
<Box <Box
sx={{ sx={{
width: '100%', width: '100%',
height: '80%', height: '100%',
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
padding: '30px', padding: '30px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'space-between',
}} }}
> >
<Box <Box
...@@ -64,7 +67,7 @@ const MeetingLayout = () => { ...@@ -64,7 +67,7 @@ const MeetingLayout = () => {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
width: '100%', width: '100%',
height: '100%', height: '80%',
}} }}
ref={gridContainerRef} ref={gridContainerRef}
> >
...@@ -75,6 +78,7 @@ const MeetingLayout = () => { ...@@ -75,6 +78,7 @@ const MeetingLayout = () => {
setIsPinned={setIsPinned} setIsPinned={setIsPinned}
pinnedUser={pinnedUser} pinnedUser={pinnedUser}
setPinnedUser={setPinnedUser} setPinnedUser={setPinnedUser}
localCameraTrack={localCameraTrack}
/> />
) : ( ) : (
<SymmetricGrid <SymmetricGrid
...@@ -83,9 +87,17 @@ const MeetingLayout = () => { ...@@ -83,9 +87,17 @@ const MeetingLayout = () => {
isPinned={isPinned} isPinned={isPinned}
setIsPinned={setIsPinned} setIsPinned={setIsPinned}
setPinnedUser={setPinnedUser} setPinnedUser={setPinnedUser}
localCameraTrack={localCameraTrack}
/> />
)} )}
</Box> </Box>
<Box sx={{ height: '10%', width: '100%', display: 'flex', marginBottom: '40px' }}>
<ControlCenter
setJoined={setJoined}
localCameraTrack={localCameraTrack}
localMicrophoneTrack={localMicrophoneTrack}
/>
</Box>
</Box> </Box>
) )
} }
......
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import type { IAgoraRTCRemoteUser } from 'agora-rtc-sdk-ng' import type { IAgoraRTCRemoteUser, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import { Box, Button, IconButton, Popover, Stack } from '@mui/material' import { Box, Button, IconButton, Popover, Stack } from '@mui/material'
import useMediaQuery from '@mui/material/useMediaQuery' import useMediaQuery from '@mui/material/useMediaQuery'
import { RemoteUser, useRemoteUsers } from 'agora-rtc-react' import { RemoteUser, useRemoteUsers } from 'agora-rtc-react'
...@@ -13,6 +13,7 @@ interface Props { ...@@ -13,6 +13,7 @@ interface Props {
setIsPinned: (value: boolean) => void setIsPinned: (value: boolean) => void
pinnedUser: IAgoraRTCRemoteUser pinnedUser: IAgoraRTCRemoteUser
setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void
localCameraTrack: ICameraVideoTrack | null
} }
const PinnedGrid = ({ const PinnedGrid = ({
...@@ -21,6 +22,7 @@ const PinnedGrid = ({ ...@@ -21,6 +22,7 @@ const PinnedGrid = ({
setIsPinned, setIsPinned,
pinnedUser, pinnedUser,
setPinnedUser, setPinnedUser,
localCameraTrack,
}: Props) => { }: Props) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
const isSm = useMediaQuery(theme.breakpoints.up('sm')) const isSm = useMediaQuery(theme.breakpoints.up('sm'))
...@@ -144,6 +146,7 @@ const PinnedGrid = ({ ...@@ -144,6 +146,7 @@ const PinnedGrid = ({
itemHeight={itemHeight} itemHeight={itemHeight}
setIsPinned={setIsPinned} setIsPinned={setIsPinned}
setPinnedUser={setPinnedUser} setPinnedUser={setPinnedUser}
localCameraTrack={localCameraTrack}
/> />
{remoteUsers.length > 1 && {remoteUsers.length > 1 &&
remoteUsers remoteUsers
......
...@@ -3,7 +3,7 @@ import { Box, Grid } from '@mui/material' ...@@ -3,7 +3,7 @@ import { Box, Grid } from '@mui/material'
import useMediaQuery from '@mui/material/useMediaQuery' import useMediaQuery from '@mui/material/useMediaQuery'
import { useRemoteUsers } from 'agora-rtc-react' import { useRemoteUsers } from 'agora-rtc-react'
import { useTheme, type Theme } from '@mui/material/styles' import { useTheme, type Theme } from '@mui/material/styles'
import type { IAgoraRTCRemoteUser } from 'agora-rtc-sdk-ng' import type { IAgoraRTCRemoteUser, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import UserCard from '../UserCard/UserCard' import UserCard from '../UserCard/UserCard'
interface Props { interface Props {
...@@ -12,6 +12,7 @@ interface Props { ...@@ -12,6 +12,7 @@ interface Props {
isPinned: boolean isPinned: boolean
setIsPinned: (value: boolean) => void setIsPinned: (value: boolean) => void
setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void
localCameraTrack: ICameraVideoTrack | null
} }
const SymmetricGrid = ({ const SymmetricGrid = ({
...@@ -20,6 +21,7 @@ const SymmetricGrid = ({ ...@@ -20,6 +21,7 @@ const SymmetricGrid = ({
isPinned, isPinned,
setIsPinned, setIsPinned,
setPinnedUser, setPinnedUser,
localCameraTrack,
}: Props) => { }: Props) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
const isSm = useMediaQuery(theme.breakpoints.up('sm')) const isSm = useMediaQuery(theme.breakpoints.up('sm'))
...@@ -133,6 +135,7 @@ const SymmetricGrid = ({ ...@@ -133,6 +135,7 @@ const SymmetricGrid = ({
itemHeight={itemHeight} itemHeight={itemHeight}
setIsPinned={setIsPinned} setIsPinned={setIsPinned}
setPinnedUser={setPinnedUser} setPinnedUser={setPinnedUser}
localCameraTrack={localCameraTrack}
/> />
</Grid> </Grid>
{remoteUsers.map((remoteUser, index) => ( {remoteUsers.map((remoteUser, index) => (
......
import { Box, Button, IconButton, Popover } from '@mui/material' import { Box, Button, IconButton, Popover } from '@mui/material'
import MoreVertIcon from '@mui/icons-material/MoreVert' import MoreVertIcon from '@mui/icons-material/MoreVert'
import { LocalVideoTrack, RemoteUser, useLocalCameraTrack } from 'agora-rtc-react' import { LocalVideoTrack, RemoteUser } from 'agora-rtc-react'
import type { IAgoraRTCRemoteUser } from 'agora-rtc-sdk-ng' import type { IAgoraRTCRemoteUser, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import { useTheme, type Theme } from '@mui/material/styles' import { useTheme, type Theme } from '@mui/material/styles'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
...@@ -11,11 +11,18 @@ interface Props { ...@@ -11,11 +11,18 @@ interface Props {
setIsPinned: (value: boolean) => void setIsPinned: (value: boolean) => void
setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void setPinnedUser: (value: IAgoraRTCRemoteUser | null) => void
remoteUser?: IAgoraRTCRemoteUser remoteUser?: IAgoraRTCRemoteUser
localCameraTrack?: ICameraVideoTrack | null
} }
const UserCard = ({ type, remoteUser, itemHeight, setIsPinned, setPinnedUser }: Props) => { const UserCard = ({
type,
remoteUser,
itemHeight,
setIsPinned,
setPinnedUser,
localCameraTrack,
}: Props) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
const { localCameraTrack } = useLocalCameraTrack()
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null) const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null)
......
...@@ -13,15 +13,11 @@ const VideoCall = () => { ...@@ -13,15 +13,11 @@ const VideoCall = () => {
setJoined(true) setJoined(true)
} }
// const handleLeaveClick = () => {
// setJoined(false)
// }
return ( return (
<Box sx={{ height: '100vh', width: '100vw', overflow: 'hidden' }}> <Box sx={{ height: '100vh', width: '100vw', overflow: 'hidden' }}>
{joined ? ( {joined ? (
<AgoraRTCProvider client={agoraEngine}> <AgoraRTCProvider client={agoraEngine}>
<AgoraManager> <AgoraManager setJoined={setJoined}>
<div>asas</div> <div>asas</div>
</AgoraManager> </AgoraManager>
</AgoraRTCProvider> </AgoraRTCProvider>
......
import { useJoin, useLocalCameraTrack, useLocalMicrophoneTrack } from 'agora-rtc-react'
import React, { createContext, useContext, useEffect } from 'react' import React, { createContext, useContext, useEffect } from 'react'
import { useJoin, useLocalCameraTrack, useLocalMicrophoneTrack } from 'agora-rtc-react'
import type { IMicrophoneAudioTrack, ICameraVideoTrack } from 'agora-rtc-sdk-ng' import type { IMicrophoneAudioTrack, ICameraVideoTrack } from 'agora-rtc-sdk-ng'
import { Box } from '@mui/material' import { Box } from '@mui/material'
import { useTheme, type Theme } from '@mui/material/styles' import { useTheme, type Theme } from '@mui/material/styles'
...@@ -31,7 +30,13 @@ export const useAgoraContext = () => { ...@@ -31,7 +30,13 @@ export const useAgoraContext = () => {
return context return context
} }
export const AgoraManager = ({ children }: { children: React.ReactNode }) => { export const AgoraManager = ({
setJoined,
children,
}: {
setJoined: (x: boolean) => void
children: React.ReactNode
}) => {
const theme: Theme = useTheme() const theme: Theme = useTheme()
const { const {
...@@ -73,7 +78,11 @@ export const AgoraManager = ({ children }: { children: React.ReactNode }) => { ...@@ -73,7 +78,11 @@ export const AgoraManager = ({ children }: { children: React.ReactNode }) => {
localCameraTrack={localCameraTrack} localCameraTrack={localCameraTrack}
localMicrophoneTrack={localMicrophoneTrack} localMicrophoneTrack={localMicrophoneTrack}
> >
<MeetingLayout /> <MeetingLayout
setJoined={setJoined}
localCameraTrack={localCameraTrack}
localMicrophoneTrack={localMicrophoneTrack}
/>
</AgoraProvider> </AgoraProvider>
) : joinError ? ( ) : joinError ? (
<MeetingLoading variant='error' /> <MeetingLoading variant='error' />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment