From dbc63e9ef76f386d8360e2bdb7a155ee8189c299 Mon Sep 17 00:00:00 2001 From: Hampus Date: Sat, 29 Aug 2026 22:05:06 +0200 Subject: [PATCH] fix(voice): surface stream audio volume for screen-share viewers (#2095) --- .../ui/action_menu/items/VoiceParticipantMenuData.tsx | 8 +++----- .../src/features/voice/components/CallVolumeControl.tsx | 4 ++++ .../features/voice/components/VoiceParticipantTile.tsx | 2 +- .../components/MediaVerticalVolumeControl.tsx | 5 ++++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fluxer_app/src/features/ui/action_menu/items/VoiceParticipantMenuData.tsx b/fluxer_app/src/features/ui/action_menu/items/VoiceParticipantMenuData.tsx index 08467a900..f2d480c55 100644 --- a/fluxer_app/src/features/ui/action_menu/items/VoiceParticipantMenuData.tsx +++ b/fluxer_app/src/features/ui/action_menu/items/VoiceParticipantMenuData.tsx @@ -199,10 +199,6 @@ const RELATIONSHIP_ACTIONS_DESCRIPTOR = msg({ message: 'Relationship', comment: 'Voice participant context menu submenu label for friend and block actions.', }); -const STREAM_CONTROLS_DESCRIPTOR = msg({ - message: 'Stream controls', - comment: 'Voice participant context menu submenu label for incoming screen share audio controls.', -}); const USER_ACTIONS_DESCRIPTOR = msg({ message: 'User actions', comment: 'Voice participant context menu submenu label for lower-frequency profile and communication actions.', @@ -492,6 +488,9 @@ export function useVoiceParticipantMenuData(options: VoiceParticipantMenuDataOpt if (streamRootActions.length > 0) { menuGroups.push({items: streamRootActions}); } + if (streamControlActions.length > 0) { + menuGroups.push({items: streamControlActions}); + } const primaryActions: Array = []; primaryActions.push({ icon: ( @@ -1384,7 +1383,6 @@ export function useVoiceParticipantMenuData(options: VoiceParticipantMenuDataOpt TextCopyCommands.copy(i18n, user.id, true); }, }); - addSecondarySubmenu(i18n._(STREAM_CONTROLS_DESCRIPTOR), streamControlActions); addSecondarySubmenu(i18n._(MEDIA_CONTROLS_DESCRIPTOR), mediaActions); addSecondarySubmenu(i18n._(DEVICE_CONTROLS_DESCRIPTOR), deviceActions); addSecondarySubmenu(i18n._(DISPLAY_OPTIONS_DESCRIPTOR), displayActions); diff --git a/fluxer_app/src/features/voice/components/CallVolumeControl.tsx b/fluxer_app/src/features/voice/components/CallVolumeControl.tsx index d06dc1c5d..21c9ce0ee 100644 --- a/fluxer_app/src/features/voice/components/CallVolumeControl.tsx +++ b/fluxer_app/src/features/voice/components/CallVolumeControl.tsx @@ -9,7 +9,9 @@ import { } from '@app/features/voice/components/CallVolumeState'; import {MediaVerticalVolumeControl} from '@app/features/voice/components/media_player/components/MediaVerticalVolumeControl'; import VoiceSettings from '@app/features/voice/state/VoiceSettings'; +import {VOICE_OUTPUT_VOLUME_DESCRIPTOR} from '@app/features/voice/utils/VoiceMessageDescriptors'; import {VOICE_VOLUME_MAX_SLIDER_VOLUME} from '@app/features/voice/utils/VoiceVolumeUtils'; +import {useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; import type React from 'react'; import {useCallback, useEffect, useRef} from 'react'; @@ -25,6 +27,7 @@ export const CallVolumeControl: React.FC = observer(func position = 'above', iconSize = 18, }) { + const {i18n} = useLingui(); const outputVolume = VoiceSettings.outputVolume; const lastNonZeroVolumeRef = useRef(resolveLastNonZeroCallVolume(outputVolume, 0)); useEffect(() => { @@ -50,6 +53,7 @@ export const CallVolumeControl: React.FC = observer(func iconSize={iconSize} className={className} position={position} + ariaLabel={i18n._(VOICE_OUTPUT_VOLUME_DESCRIPTOR)} data-flx="voice.call-volume-control.media-vertical-volume-control" /> ); diff --git a/fluxer_app/src/features/voice/components/VoiceParticipantTile.tsx b/fluxer_app/src/features/voice/components/VoiceParticipantTile.tsx index bf0638c6d..13f76187b 100644 --- a/fluxer_app/src/features/voice/components/VoiceParticipantTile.tsx +++ b/fluxer_app/src/features/voice/components/VoiceParticipantTile.tsx @@ -615,7 +615,7 @@ const VoiceParticipantTileInner = observer(function VoiceParticipantTileInner({ const participantDisplayName = (participantUser ? NicknameUtils.getNickname(participantUser, guildId, channelId) : participant.name) || i18n._(UNKNOWN_USER_DESCRIPTOR); - const showStreamAudioControls = isScreenShare && !isOwnScreenShare && isWatching; + const showStreamAudioControls = isScreenShare && !isOwnScreenShare && isWatching && hasScreenShareAudio; const viewerStreamCount = graphViewerStreamKeys.length; const addStreamTooltipText = plural( {count: viewerStreamCount}, diff --git a/fluxer_app/src/features/voice/components/media_player/components/MediaVerticalVolumeControl.tsx b/fluxer_app/src/features/voice/components/media_player/components/MediaVerticalVolumeControl.tsx index f6dd34d70..51853abb3 100644 --- a/fluxer_app/src/features/voice/components/media_player/components/MediaVerticalVolumeControl.tsx +++ b/fluxer_app/src/features/voice/components/media_player/components/MediaVerticalVolumeControl.tsx @@ -49,6 +49,7 @@ interface MediaVerticalVolumeControlProps { className?: string; position?: 'above' | 'below'; maxVolume?: number; + ariaLabel?: string; } function getVolumeIcon(volume: number, isMuted: boolean) { @@ -75,6 +76,7 @@ export function MediaVerticalVolumeControl({ className, position = 'above', maxVolume = 1, + ariaLabel, }: MediaVerticalVolumeControlProps) { const {i18n} = useLingui(); const buttonRef = useRef(null); @@ -286,7 +288,8 @@ export function MediaVerticalVolumeControl({
{popoutElement}