* feat: add AudioVolume component * feat: show volume slider label value * feat: update audio volume icon * feat: mute/unmute when volume icon is clicked * feat: show peer dividers
This commit is contained in:
parent
99a9ab7838
commit
870a13eac1
58
src/components/AudioVolume/AudioVolume.tsx
Normal file
58
src/components/AudioVolume/AudioVolume.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import Slider from '@mui/material/Slider'
|
||||||
|
import Box from '@mui/material/Box'
|
||||||
|
import ListItemIcon from '@mui/material/ListItemIcon'
|
||||||
|
import VolumeUp from '@mui/icons-material/VolumeUp'
|
||||||
|
import VolumeDown from '@mui/icons-material/VolumeDown'
|
||||||
|
import VolumeMute from '@mui/icons-material/VolumeMute'
|
||||||
|
|
||||||
|
interface AudioVolumeProps {
|
||||||
|
audioEl: HTMLAudioElement
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AudioVolume = ({ audioEl }: AudioVolumeProps) => {
|
||||||
|
const [audioVolume, setAudioVolume] = useState(audioEl.volume)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
audioEl.volume = audioVolume
|
||||||
|
}, [audioEl, audioVolume])
|
||||||
|
|
||||||
|
const handleIconClick = () => {
|
||||||
|
if (audioVolume === 0) {
|
||||||
|
setAudioVolume(1)
|
||||||
|
} else {
|
||||||
|
setAudioVolume(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSliderChange = (_event: Event, value: number | number[]) => {
|
||||||
|
value = Array.isArray(value) ? value[0] : value
|
||||||
|
setAudioVolume(value / 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatLabelValue = () => `${Math.round(audioVolume * 100)}%`
|
||||||
|
|
||||||
|
let VolumeIcon = VolumeUp
|
||||||
|
|
||||||
|
if (audioVolume === 0) {
|
||||||
|
VolumeIcon = VolumeMute
|
||||||
|
} else if (audioVolume < 0.5) {
|
||||||
|
VolumeIcon = VolumeDown
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', pt: 1, pr: 3, alignItems: 'center' }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<VolumeIcon sx={{ cursor: 'pointer' }} onClick={handleIconClick} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Slider
|
||||||
|
aria-label="Volume"
|
||||||
|
getAriaValueText={formatLabelValue}
|
||||||
|
valueLabelFormat={formatLabelValue}
|
||||||
|
valueLabelDisplay="auto"
|
||||||
|
onChange={handleSliderChange}
|
||||||
|
value={audioVolume * 100}
|
||||||
|
></Slider>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
1
src/components/AudioVolume/index.ts
Normal file
1
src/components/AudioVolume/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './AudioVolume'
|
@ -14,9 +14,6 @@ interface UseRoomAudioConfig {
|
|||||||
export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) {
|
export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) {
|
||||||
const shellContext = useContext(ShellContext)
|
const shellContext = useContext(ShellContext)
|
||||||
const [isSpeakingToRoom, setIsSpeakingToRoom] = useState(false)
|
const [isSpeakingToRoom, setIsSpeakingToRoom] = useState(false)
|
||||||
const [peerAudios, setPeerAudios] = useState<
|
|
||||||
Record<string, HTMLAudioElement>
|
|
||||||
>({})
|
|
||||||
const [audioStream, setAudioStream] = useState<MediaStream | null>()
|
const [audioStream, setAudioStream] = useState<MediaStream | null>()
|
||||||
|
|
||||||
const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([])
|
const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([])
|
||||||
@ -24,7 +21,8 @@ export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) {
|
|||||||
string | null
|
string | null
|
||||||
>(null)
|
>(null)
|
||||||
|
|
||||||
const { peerList, setPeerList, setAudioState } = shellContext
|
const { peerList, setPeerList, setAudioState, peerAudios, setPeerAudios } =
|
||||||
|
shellContext
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
|
@ -10,6 +10,7 @@ import VolumeUp from '@mui/icons-material/VolumeUp'
|
|||||||
import ListItem from '@mui/material/ListItem'
|
import ListItem from '@mui/material/ListItem'
|
||||||
|
|
||||||
import { PeerListHeader } from 'components/Shell/PeerListHeader'
|
import { PeerListHeader } from 'components/Shell/PeerListHeader'
|
||||||
|
import { AudioVolume } from 'components/AudioVolume'
|
||||||
import { PeerNameDisplay } from 'components/PeerNameDisplay'
|
import { PeerNameDisplay } from 'components/PeerNameDisplay'
|
||||||
import { AudioState, Peer } from 'models/chat'
|
import { AudioState, Peer } from 'models/chat'
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ export interface PeerListProps extends PropsWithChildren {
|
|||||||
onPeerListClose: () => void
|
onPeerListClose: () => void
|
||||||
peerList: Peer[]
|
peerList: Peer[]
|
||||||
audioState: AudioState
|
audioState: AudioState
|
||||||
|
peerAudios: Record<string, HTMLAudioElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PeerList = ({
|
export const PeerList = ({
|
||||||
@ -31,6 +33,7 @@ export const PeerList = ({
|
|||||||
onPeerListClose,
|
onPeerListClose,
|
||||||
peerList,
|
peerList,
|
||||||
audioState,
|
audioState,
|
||||||
|
peerAudios,
|
||||||
}: PeerListProps) => {
|
}: PeerListProps) => {
|
||||||
return (
|
return (
|
||||||
<MuiDrawer
|
<MuiDrawer
|
||||||
@ -57,7 +60,7 @@ export const PeerList = ({
|
|||||||
</PeerListHeader>
|
</PeerListHeader>
|
||||||
<Divider />
|
<Divider />
|
||||||
<List>
|
<List>
|
||||||
<ListItem>
|
<ListItem divider={true}>
|
||||||
{audioState === AudioState.PLAYING && (
|
{audioState === AudioState.PLAYING && (
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<VolumeUp />
|
<VolumeUp />
|
||||||
@ -68,20 +71,17 @@ export const PeerList = ({
|
|||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{peerList.map((peer: Peer) => (
|
{peerList.map((peer: Peer) => (
|
||||||
<ListItem key={peer.peerId}>
|
<ListItem key={peer.peerId} divider={true}>
|
||||||
<PeerDownloadFileButton peer={peer} />
|
<PeerDownloadFileButton peer={peer} />
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<PeerNameDisplay>{peer.userId}</PeerNameDisplay>
|
<PeerNameDisplay>{peer.userId}</PeerNameDisplay>
|
||||||
|
{peer.peerId in peerAudios && (
|
||||||
|
<AudioVolume audioEl={peerAudios[peer.peerId]} />
|
||||||
|
)}
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
{peer.audioState === AudioState.PLAYING && (
|
|
||||||
<ListItemIcon>
|
|
||||||
<VolumeUp />
|
|
||||||
</ListItemIcon>
|
|
||||||
)}
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
<Divider />
|
|
||||||
</MuiDrawer>
|
</MuiDrawer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,9 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
const [screenState, setScreenState] = useState<ScreenShareState>(
|
const [screenState, setScreenState] = useState<ScreenShareState>(
|
||||||
ScreenShareState.NOT_SHARING
|
ScreenShareState.NOT_SHARING
|
||||||
)
|
)
|
||||||
|
const [peerAudios, setPeerAudios] = useState<
|
||||||
|
Record<string, HTMLAudioElement>
|
||||||
|
>({})
|
||||||
const showAlert = useCallback<
|
const showAlert = useCallback<
|
||||||
(message: string, options?: AlertOptions) => void
|
(message: string, options?: AlertOptions) => void
|
||||||
>((message, options) => {
|
>((message, options) => {
|
||||||
@ -89,6 +92,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
setVideoState,
|
setVideoState,
|
||||||
screenState,
|
screenState,
|
||||||
setScreenState,
|
setScreenState,
|
||||||
|
peerAudios,
|
||||||
|
setPeerAudios,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
isPeerListOpen,
|
isPeerListOpen,
|
||||||
@ -112,6 +117,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
setVideoState,
|
setVideoState,
|
||||||
screenState,
|
screenState,
|
||||||
setScreenState,
|
setScreenState,
|
||||||
|
peerAudios,
|
||||||
|
setPeerAudios,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -322,6 +329,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
onPeerListClose={handlePeerListClick}
|
onPeerListClose={handlePeerListClick}
|
||||||
peerList={peerList}
|
peerList={peerList}
|
||||||
audioState={audioState}
|
audioState={audioState}
|
||||||
|
peerAudios={peerAudios}
|
||||||
/>
|
/>
|
||||||
<QRCodeDialog
|
<QRCodeDialog
|
||||||
isOpen={isQRCodeDialogOpen}
|
isOpen={isQRCodeDialogOpen}
|
||||||
|
@ -26,6 +26,8 @@ interface ShellContextProps {
|
|||||||
setVideoState: Dispatch<SetStateAction<VideoState>>
|
setVideoState: Dispatch<SetStateAction<VideoState>>
|
||||||
screenState: ScreenShareState
|
screenState: ScreenShareState
|
||||||
setScreenState: Dispatch<SetStateAction<ScreenShareState>>
|
setScreenState: Dispatch<SetStateAction<ScreenShareState>>
|
||||||
|
peerAudios: Record<string, HTMLAudioElement>
|
||||||
|
setPeerAudios: Dispatch<SetStateAction<Record<string, HTMLAudioElement>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShellContext = createContext<ShellContextProps>({
|
export const ShellContext = createContext<ShellContextProps>({
|
||||||
@ -51,4 +53,6 @@ export const ShellContext = createContext<ShellContextProps>({
|
|||||||
setVideoState: () => {},
|
setVideoState: () => {},
|
||||||
screenState: ScreenShareState.NOT_SHARING,
|
screenState: ScreenShareState.NOT_SHARING,
|
||||||
setScreenState: () => {},
|
setScreenState: () => {},
|
||||||
|
peerAudios: {},
|
||||||
|
setPeerAudios: () => {},
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user