mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-20 07:10:15 +01:00
Fix call screen crash when participant count drops during speaker view.
This commit is contained in:
+40
-53
@@ -15,7 +15,6 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.movableContentOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
@@ -52,67 +51,55 @@ fun CallParticipantsPager(
|
||||
callParticipantsPagerState.callParticipants.firstOrNull()?.videoSink
|
||||
)
|
||||
|
||||
// Use movableContentOf to preserve CallGrid state when switching between
|
||||
// single participant (no pager) and multiple participants (with pager)
|
||||
val callGridContent = remember {
|
||||
movableContentOf { state: CallParticipantsPagerState, mod: Modifier, aspectRatio: Float? ->
|
||||
CallGrid(
|
||||
items = state.callParticipants,
|
||||
singleParticipantAspectRatio = aspectRatio,
|
||||
modifier = mod,
|
||||
itemKey = { it.callParticipantId }
|
||||
) { participant, itemModifier ->
|
||||
val longPressModifier = if (!participant.recipient.isSelf && currentOnLongPress.value != null) {
|
||||
var itemWindowOrigin by remember(participant.callParticipantId) { mutableStateOf(Offset.Zero) }
|
||||
itemModifier
|
||||
.onGloballyPositioned { coords -> itemWindowOrigin = coords.positionInRoot() }
|
||||
.pointerInput(participant.callParticipantId) {
|
||||
detectTapGestures(
|
||||
onTap = { currentOnTap.value?.invoke() },
|
||||
onLongPress = { local -> currentOnLongPress.value?.invoke(participant, itemWindowOrigin + local) }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
itemModifier
|
||||
}
|
||||
VerticalPager(
|
||||
state = pagerState,
|
||||
modifier = modifier
|
||||
.displayCutoutPadding()
|
||||
.statusBarsPadding()
|
||||
) { page ->
|
||||
when (page) {
|
||||
0 -> {
|
||||
CallGrid(
|
||||
items = callParticipantsPagerState.callParticipants,
|
||||
singleParticipantAspectRatio = firstParticipantAR,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
itemKey = { it.callParticipantId }
|
||||
) { participant, itemModifier ->
|
||||
val longPressModifier = if (!participant.recipient.isSelf && currentOnLongPress.value != null) {
|
||||
var itemWindowOrigin by remember(participant.callParticipantId) { mutableStateOf(Offset.Zero) }
|
||||
itemModifier
|
||||
.onGloballyPositioned { coords -> itemWindowOrigin = coords.positionInRoot() }
|
||||
.pointerInput(participant.callParticipantId) {
|
||||
detectTapGestures(
|
||||
onTap = { currentOnTap.value?.invoke() },
|
||||
onLongPress = { local -> currentOnLongPress.value?.invoke(participant, itemWindowOrigin + local) }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
itemModifier
|
||||
}
|
||||
|
||||
RemoteParticipantContent(
|
||||
participant = participant,
|
||||
renderInPip = state.isRenderInPip,
|
||||
raiseHandAllowed = false,
|
||||
onInfoMoreInfoClick = null,
|
||||
showAudioIndicator = state.callParticipants.size > 1,
|
||||
modifier = longPressModifier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callParticipantsPagerState.callParticipants.size > 1) {
|
||||
VerticalPager(
|
||||
state = pagerState,
|
||||
modifier = modifier
|
||||
.displayCutoutPadding()
|
||||
.statusBarsPadding()
|
||||
) { page ->
|
||||
when (page) {
|
||||
0 -> {
|
||||
callGridContent(callParticipantsPagerState, Modifier.fillMaxSize(), firstParticipantAR)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
RemoteParticipantContent(
|
||||
participant = callParticipantsPagerState.focusedParticipant,
|
||||
participant = participant,
|
||||
renderInPip = callParticipantsPagerState.isRenderInPip,
|
||||
raiseHandAllowed = false,
|
||||
onInfoMoreInfoClick = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
showAudioIndicator = callParticipantsPagerState.callParticipants.size > 1,
|
||||
modifier = longPressModifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
1 -> {
|
||||
RemoteParticipantContent(
|
||||
participant = callParticipantsPagerState.focusedParticipant,
|
||||
renderInPip = callParticipantsPagerState.isRenderInPip,
|
||||
raiseHandAllowed = false,
|
||||
onInfoMoreInfoClick = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callGridContent(callParticipantsPagerState, modifier, firstParticipantAR)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,8 +104,10 @@ fun CallScreen(
|
||||
savedLocalParticipantLandscape: Boolean = false,
|
||||
callScreenState: CallScreenState,
|
||||
callControlsState: CallControlsState,
|
||||
callParticipantsPagerState: CallParticipantsPagerState,
|
||||
callScreenController: CallScreenController = CallScreenController.rememberCallScreenController(
|
||||
skipHiddenState = callControlsState.skipHiddenState,
|
||||
hasMultipleRemoteParticipants = callParticipantsPagerState.callParticipants.size > 1,
|
||||
onControlsToggled = {},
|
||||
callControlsState = callControlsState,
|
||||
callControlsListener = CallScreenControlsListener.Empty
|
||||
@@ -113,7 +115,6 @@ fun CallScreen(
|
||||
callScreenControlsListener: CallScreenControlsListener = CallScreenControlsListener.Empty,
|
||||
callScreenSheetDisplayListener: CallScreenSheetDisplayListener = CallScreenSheetDisplayListener.Empty,
|
||||
additionalActionsListener: AdditionalActionsListener = AdditionalActionsListener.Empty,
|
||||
callParticipantsPagerState: CallParticipantsPagerState,
|
||||
pendingParticipantsListener: PendingParticipantsListener = PendingParticipantsListener.Empty,
|
||||
callParticipantUpdatePopupController: CallParticipantUpdatePopupController,
|
||||
overflowParticipants: List<CallParticipant>,
|
||||
|
||||
+3
-1
@@ -77,11 +77,13 @@ class CallScreenController private constructor(
|
||||
@Composable
|
||||
fun rememberCallScreenController(
|
||||
skipHiddenState: Boolean,
|
||||
hasMultipleRemoteParticipants: Boolean,
|
||||
onControlsToggled: (Boolean) -> Unit,
|
||||
callControlsState: CallControlsState,
|
||||
callControlsListener: CallScreenControlsListener
|
||||
): CallScreenController {
|
||||
val skip by rememberUpdatedState(skipHiddenState)
|
||||
val hasMultipleRemoteParticipantsState = rememberUpdatedState(hasMultipleRemoteParticipants)
|
||||
val valueChangeOperation: (SheetValue) -> Boolean = remember {
|
||||
{
|
||||
!(it == SheetValue.Hidden && skip)
|
||||
@@ -130,7 +132,7 @@ class CallScreenController private constructor(
|
||||
|
||||
val callParticipantsVerticalPagerState = rememberPagerState(
|
||||
initialPage = 0,
|
||||
pageCount = { 2 }
|
||||
pageCount = { if (hasMultipleRemoteParticipantsState.value) 2 else 1 }
|
||||
)
|
||||
|
||||
return remember(scaffoldState, callParticipantsVerticalPagerState, audioOutputPickerController) {
|
||||
|
||||
+1
@@ -164,6 +164,7 @@ class ComposeCallScreenMediator(private val activity: WebRtcCallActivity, viewMo
|
||||
|
||||
val callScreenController = CallScreenController.rememberCallScreenController(
|
||||
skipHiddenState = callControlsState.skipHiddenState,
|
||||
hasMultipleRemoteParticipants = callParticipantsPagerState.callParticipants.size > 1,
|
||||
onControlsToggled = onControlsToggled,
|
||||
callControlsState = callControlsState,
|
||||
callControlsListener = callScreenControlsListener
|
||||
|
||||
Reference in New Issue
Block a user