From 076b78759e39720d06664ca6ea84d659157a9094 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 5 Nov 2025 13:24:08 -0400 Subject: [PATCH] Fix reaction and state bar placement on new call screen. --- .../webrtc/controls/RaiseHandSnackbar.kt | 30 ++++---- .../components/webrtc/v2/CallScreen.kt | 75 +++++++++++++------ .../webrtc/v2/CallScreenReactionsContainer.kt | 3 +- 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/controls/RaiseHandSnackbar.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/controls/RaiseHandSnackbar.kt index 309e0f530e..fa4f784dc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/controls/RaiseHandSnackbar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/controls/RaiseHandSnackbar.kt @@ -27,7 +27,6 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -54,6 +53,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.events.CallParticipant import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent import org.thoughtcrime.securesms.events.GroupCallSpeechEvent +import org.thoughtcrime.securesms.recipients.Recipient import java.util.concurrent.TimeUnit import kotlin.math.max import kotlin.time.Duration @@ -69,9 +69,7 @@ object RaiseHandSnackbar { @Composable fun View(webRtcCallViewModel: WebRtcCallViewModel, showCallInfoListener: () -> Unit, modifier: Modifier = Modifier) { - var expansionState by remember { mutableStateOf(ExpansionState(shouldExpand = false, forced = false, collapseTimestamp = Duration.ZERO)) } - - val raisedHandsState by remember { + val raisedHandsState: List by remember { webRtcCallViewModel.callParticipantsState .map { state -> val raisedHands = state.raisedHands.sortedBy { @@ -90,12 +88,17 @@ object RaiseHandSnackbar { } }.collectAsState(initial = emptyList()) - val speechEvent by webRtcCallViewModel.groupCallSpeechEvents.collectAsStateWithLifecycle() + val speechEvent: GroupCallSpeechEvent? by webRtcCallViewModel.groupCallSpeechEvents.collectAsStateWithLifecycle() - val state by remember { - derivedStateOf { - RaiseHandState(raisedHands = raisedHandsState, expansionState = expansionState, speechEvent = speechEvent) - } + View(raisedHandsState, speechEvent, showCallInfoListener, modifier) + } + + @Composable + fun View(raisedHandsState: List, speechEvent: GroupCallSpeechEvent?, showCallInfoListener: () -> Unit, modifier: Modifier = Modifier) { + var expansionState by remember { mutableStateOf(ExpansionState(shouldExpand = false, forced = false, collapseTimestamp = Duration.ZERO)) } + + val state = remember(raisedHandsState, speechEvent, expansionState) { + RaiseHandState(raisedHands = raisedHandsState, expansionState = expansionState, speechEvent = speechEvent) } LaunchedEffect(raisedHandsState, speechEvent) { @@ -119,7 +122,7 @@ object RaiseHandSnackbar { @Composable private fun RaiseHandSnackbarPreview() { RaiseHand( - state = RaiseHandState(listOf(GroupCallRaiseHandEvent(CallParticipant.EMPTY, System.currentTimeMillis()))) + state = RaiseHandState(listOf(GroupCallRaiseHandEvent(CallParticipant(recipient = Recipient(isResolving = false, systemContactName = "Miles Morales")), System.currentTimeMillis()))) ) } @@ -133,19 +136,20 @@ private fun RaiseHand( AnimatedVisibility( visible = state.raisedHands.isNotEmpty(), enter = fadeIn() + expandIn(expandFrom = Alignment.CenterEnd), - exit = shrinkOut(shrinkTowards = Alignment.CenterEnd) + fadeOut() + exit = shrinkOut(shrinkTowards = Alignment.CenterEnd) + fadeOut(), + modifier = modifier ) { SignalTheme( isDarkMode = true ) { Surface( - modifier = modifier + modifier = Modifier .padding(horizontal = 16.dp) .clip(shape = RoundedCornerShape(16.dp, 16.dp, 16.dp, 16.dp)) .background(SignalTheme.colors.colorSurface1) .animateContentSize() ) { - val boxModifier = modifier + val boxModifier = Modifier .padding(horizontal = 16.dp) .clickable( !state.isExpanded, 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 9783bda5ba..6066501459 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 @@ -75,8 +75,10 @@ import org.signal.core.util.DimensionUnit import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.webrtc.CallParticipantView import org.thoughtcrime.securesms.components.webrtc.WebRtcLocalRenderState +import org.thoughtcrime.securesms.components.webrtc.controls.RaiseHandSnackbar import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette import org.thoughtcrime.securesms.events.CallParticipant +import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent import org.thoughtcrime.securesms.events.GroupCallReactionEvent import org.thoughtcrime.securesms.events.WebRtcViewModel import org.thoughtcrime.securesms.recipients.Recipient @@ -249,11 +251,6 @@ fun CallScreen( } else Modifier ) - CallScreenReactionsContainer( - reactions = reactions, - modifier = Modifier.padding(bottom = padding) - ) - val onCallInfoClick: () -> Unit = { scope.launch { if (scaffoldState.bottomSheetState.currentValue == SheetValue.Expanded) { @@ -291,25 +288,44 @@ fun CallScreen( ) } - raiseHandSnackbar(Modifier.fillMaxWidth()) - - AnimatedCallStateUpdate( - callControlsChange = callScreenState.callControlsChange, + // This content lives "above" the controls sheet and includes raised hands, status updates, etc. + Box( modifier = Modifier - .align(Alignment.BottomCenter) + .fillMaxSize() .padding(bottom = padding) - .padding(bottom = 20.dp) - ) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(bottom = 20.dp) + ) { + CallScreenReactionsContainer( + reactions = reactions, + modifier = Modifier.weight(1f) + ) - val state = remember(callScreenState.pendingParticipantsState) { - callScreenState.pendingParticipantsState - } + raiseHandSnackbar( + Modifier + ) + } - if (state != null) { - PendingParticipants( - pendingParticipantsState = state, - pendingParticipantsListener = pendingParticipantsListener + AnimatedCallStateUpdate( + callControlsChange = callScreenState.callControlsChange, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 20.dp) ) + + val state = remember(callScreenState.pendingParticipantsState) { + callScreenState.pendingParticipantsState + } + + if (state != null) { + PendingParticipants( + pendingParticipantsState = state, + pendingParticipantsListener = pendingParticipantsListener + ) + } } } } @@ -649,7 +665,7 @@ private fun CallScreenPreview() { Previews.Preview { CallScreen( callRecipient = Recipient(systemContactName = "Test User"), - webRtcCallState = WebRtcViewModel.State.CALL_PRE_JOIN, + webRtcCallState = WebRtcViewModel.State.CALL_CONNECTED, isRemoteVideoOffer = false, isInPipMode = false, callScreenState = CallScreenState( @@ -682,7 +698,24 @@ private fun CallScreenPreview() { callInfoView = { Text(text = "Call Info View Preview", modifier = Modifier.alpha(it)) }, - raiseHandSnackbar = {}, + raiseHandSnackbar = { + RaiseHandSnackbar.View( + raisedHandsState = listOf( + GroupCallRaiseHandEvent( + sender = CallParticipant( + recipient = Recipient( + isResolving = false, + systemContactName = "Miles Morales" + ) + ), + timestampMillis = System.currentTimeMillis() + ) + ), + speechEvent = null, + showCallInfoListener = {}, + modifier = it + ) + }, onNavigationClick = {}, onLocalPictureInPictureClicked = {}, overflowParticipants = participants, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreenReactionsContainer.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreenReactionsContainer.kt index 661738bb28..3df696c66c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreenReactionsContainer.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallScreenReactionsContainer.kt @@ -5,7 +5,6 @@ package org.thoughtcrime.securesms.components.webrtc.v2 -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -42,7 +41,7 @@ fun CallScreenReactionsContainer( view.isVerticalScrollBarEnabled = false view - }, modifier = modifier.fillMaxSize().padding(16.dp).padding(bottom = 16.dp)) { + }, modifier = modifier.padding(16.dp)) { adapter.submitList(reactions.toMutableList()) } }