From 7741844055b6c26dc27d59958c313df14e309860 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 6 Feb 2026 11:24:28 -0400 Subject: [PATCH] Add audio-indicator slot to use for single-remote-participant calls. --- .../webrtc/v2/CallElementsLayout.kt | 35 ++++++++++++++++++- .../webrtc/v2/CallParticipantsPager.kt | 1 + .../components/webrtc/v2/CallScreen.kt | 9 +++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallElementsLayout.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallElementsLayout.kt index 6eb9aaa46b..44fb73e3f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallElementsLayout.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallElementsLayout.kt @@ -43,7 +43,8 @@ private enum class BlurrableContentSlot { BARS, GRID, REACTIONS, - OVERFLOW + OVERFLOW, + AUDIO_INDICATOR } @Composable @@ -54,6 +55,7 @@ fun CallElementsLayout( raiseHandSlot: @Composable () -> Unit, callLinkBarSlot: @Composable () -> Unit, callOverflowSlot: @Composable () -> Unit, + audioIndicatorSlot: @Composable () -> Unit, bottomInset: Dp, bottomSheetWidth: Dp, localRenderState: WebRtcLocalRenderState, @@ -100,6 +102,7 @@ fun CallElementsLayout( callGridSlot = callGridSlot, reactionsSlot = reactionsSlot, callOverflowSlot = callOverflowSlot, + audioIndicatorSlot = audioIndicatorSlot, onMeasured = { barsHeight, barsWidth -> measuredBarsHeightPx = barsHeight measuredBarsWidthPx = barsWidth @@ -146,6 +149,7 @@ private fun BlurrableContentLayer( callGridSlot: @Composable () -> Unit, reactionsSlot: @Composable () -> Unit, callOverflowSlot: @Composable () -> Unit, + audioIndicatorSlot: @Composable () -> Unit, onMeasured: (barsHeight: Int, barsWidth: Int) -> Unit ) { BlurContainer( @@ -187,6 +191,9 @@ private fun BlurrableContentLayer( val reactionsPlaceables = subcompose(BlurrableContentSlot.REACTIONS, reactionsSlot) .map { it.measure(reactionsConstraints) } + val audioIndicatorPlaceables = subcompose(BlurrableContentSlot.AUDIO_INDICATOR, audioIndicatorSlot) + .map { it.measure(looseConstraints) } + layout(looseConstraints.maxWidth, looseConstraints.maxHeight) { overflowPlaceables.forEach { if (isPortrait) { @@ -208,6 +215,17 @@ private fun BlurrableContentLayer( reactionsPlaceables.forEach { it.place(0, 0) } + + audioIndicatorPlaceables.forEach { + val gutterWidth = (looseConstraints.maxWidth - bottomSheetWidthPx) / 2 + val fitsInGutter = gutterWidth >= it.width + val y = if (fitsInGutter) { + looseConstraints.maxHeight - it.height + } else { + looseConstraints.maxHeight - bottomInsetPx - barsHeightPx - it.height + } + it.place(0, y) + } } } } @@ -322,6 +340,21 @@ private fun CallElementsLayoutPreview() { .background(color = Color.Red) ) }, + audioIndicatorSlot = { + val mutedParticipant = CallParticipant( + recipient = Recipient( + id = RecipientId.from(2L), + isResolving = false, + systemContactName = "Muted Participant" + ), + audioLevel = null + ) + + ParticipantAudioIndicator( + participant = mutedParticipant, + selfPipMode = SelfPipMode.NOT_SELF_PIP + ) + }, bottomInset = 120.dp, bottomSheetWidth = CallScreenMetrics.SheetMaxWidth, localRenderState = localRenderState diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallParticipantsPager.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallParticipantsPager.kt index a0f9e9dec4..5c8a6e98fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallParticipantsPager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallParticipantsPager.kt @@ -53,6 +53,7 @@ fun CallParticipantsPager( renderInPip = state.isRenderInPip, raiseHandAllowed = false, onInfoMoreInfoClick = null, + showAudioIndicator = state.callParticipants.size > 1, modifier = itemModifier ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreen.kt index dce0f1f590..368d0e0602 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreen.kt @@ -383,6 +383,15 @@ fun CallScreen( ) } }, + audioIndicatorSlot = { + if (callParticipantsPagerState.callParticipants.size == 1) { + val participant = callParticipantsPagerState.callParticipants.first() + ParticipantAudioIndicator( + participant = participant, + selfPipMode = SelfPipMode.NOT_SELF_PIP + ) + } + }, bottomInset = padding, bottomSheetWidth = CallScreenMetrics.SheetMaxWidth, localRenderState = localRenderState,