🚸(frontend) enhance mic indicator in participant list

The Gmeet-inspired indicator was misleading for users,
at least those not used to GSuite products.

They didn't understand how to mute a participant.

Plus, having the button disabled for the local participant,
was creating confusion. To simplify the UX, have all
the buttons enabled is simpler to understand.

Empirical observations with a few number of users, should be
enhance and challenge in the long run.
This commit is contained in:
lebaudantoine
2024-09-05 19:17:15 +02:00
committed by aleb_the_flash
parent aaf6b03a25
commit c5ce32ef79
5 changed files with 33 additions and 12 deletions

View File

@@ -81,6 +81,11 @@ const config: Config = {
'80%': { transform: 'rotate(20deg)' }, '80%': { transform: 'rotate(20deg)' },
'100%': { transform: 'rotate(0)' }, '100%': { transform: 'rotate(0)' },
}, },
pulse_mic: {
'0%': { color: 'primary', opacity: '1' },
'50%': { color: 'primary', opacity: '0.8' },
'100%': { color: 'primary', opacity: '1' },
},
}, },
tokens: defineTokens({ tokens: defineTokens({
/* we take a few things from the panda preset but for now we clear out some stuff. /* we take a few things from the panda preset but for now we clear out some stuff.

View File

@@ -13,7 +13,12 @@ import {
useTrackMutedIndicator, useTrackMutedIndicator,
} from '@livekit/components-react' } from '@livekit/components-react'
import Source = Track.Source import Source = Track.Source
import { RiMicOffLine } from '@remixicon/react' import {
RiMicFill,
RiMicLine,
RiMicOffFill,
RiMicOffLine,
} from '@remixicon/react'
import { Button, Dialog, P } from '@/primitives' import { Button, Dialog, P } from '@/primitives'
import { useState } from 'react' import { useState } from 'react'
import { useMuteParticipant } from '@/features/rooms/livekit/api/muteParticipant' import { useMuteParticipant } from '@/features/rooms/livekit/api/muteParticipant'
@@ -57,10 +62,7 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
source: Source.Microphone, source: Source.Microphone,
}) })
const isSpeaking = useIsSpeaking(participant) const isSpeaking = useIsSpeaking(participant)
const isDisabled = isLocal(participant) || (!isLocal(participant) && isMuted)
const [isAlertOpen, setIsAlertOpen] = useState(false) const [isAlertOpen, setIsAlertOpen] = useState(false)
const name = participant.name || participant.identity const name = participant.name || participant.identity
return ( return (
@@ -69,16 +71,28 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
square square
invisible invisible
size="sm" size="sm"
tooltip={t('participants.muteParticipant', { tooltip={
name, isLocal(participant)
})} ? t('participants.muteYourself')
isDisabled={isDisabled} : t('participants.muteParticipant', {
onPress={() => !isMuted && setIsAlertOpen(true)} name,
})
}
isDisabled={isMuted}
onPress={() =>
!isMuted && isLocal(participant)
? muteParticipant(participant)
: setIsAlertOpen(true)
}
> >
{isMuted ? ( {isMuted ? (
<RiMicOffLine color="gray" /> <RiMicOffFill color={'gray'} />
) : ( ) : (
<ActiveSpeaker isSpeaking={isSpeaking} /> <RiMicFill
style={{
animation: isSpeaking ? 'pulse_mic 800ms infinite' : undefined,
}}
/>
)} )}
</Button> </Button>
<MuteAlertDialog <MuteAlertDialog
@@ -102,7 +116,6 @@ export const ParticipantListItem = ({
}: ParticipantListItemProps) => { }: ParticipantListItemProps) => {
const { t } = useTranslation('rooms') const { t } = useTranslation('rooms')
const name = participant.name || participant.identity const name = participant.name || participant.identity
return ( return (
<HStack <HStack
role="listitem" role="listitem"

View File

@@ -61,6 +61,7 @@
"close": "" "close": ""
}, },
"you": "", "you": "",
"muteYourself": "",
"muteParticipant": "", "muteParticipant": "",
"muteParticipantAlert": { "muteParticipantAlert": {
"description": "", "description": "",

View File

@@ -61,6 +61,7 @@
"open": "Open {{name}} list", "open": "Open {{name}} list",
"close": "Close {{name}} list" "close": "Close {{name}} list"
}, },
"muteYourself": "Close your mic",
"muteParticipant": "Close the mic of {{name}}", "muteParticipant": "Close the mic of {{name}}",
"muteParticipantAlert": { "muteParticipantAlert": {
"description": "Mute {{name}} for all participants? {{name}} is the only person who can unmute themselves.", "description": "Mute {{name}} for all participants? {{name}} is the only person who can unmute themselves.",

View File

@@ -61,6 +61,7 @@
"open": "Ouvrir la liste {{name}}", "open": "Ouvrir la liste {{name}}",
"close": "Fermer la liste {{name}}" "close": "Fermer la liste {{name}}"
}, },
"muteYourself": "Couper votre micro",
"muteParticipant": "Couper le micro de {{name}}", "muteParticipant": "Couper le micro de {{name}}",
"muteParticipantAlert": { "muteParticipantAlert": {
"description": "Couper le micro de {{name}} pour tous les participants ? {{name}} est la seule personne habilitée à réactiver son micro", "description": "Couper le micro de {{name}} pour tous les participants ? {{name}} est la seule personne habilitée à réactiver son micro",