mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 20:18:36 +00:00
Implement the incoming call screen in compose.
This commit is contained in:
@@ -21,6 +21,7 @@ import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.Buttons
|
||||
import org.signal.core.ui.DarkPreview
|
||||
@@ -28,6 +29,8 @@ import org.signal.core.ui.IconButtons
|
||||
import org.signal.core.ui.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
private val defaultCallButtonIconSize: Dp = 24.dp
|
||||
|
||||
@Composable
|
||||
private fun ToggleCallButton(
|
||||
checked: Boolean,
|
||||
@@ -67,7 +70,8 @@ private fun CallButton(
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
containerColor: Color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
contentColor: Color = colorResource(id = R.color.signal_light_colorOnPrimary)
|
||||
contentColor: Color = colorResource(id = R.color.signal_light_colorOnPrimary),
|
||||
iconSize: Dp = defaultCallButtonIconSize
|
||||
) {
|
||||
val buttonSize = dimensionResource(id = R.dimen.webrtc_button_size)
|
||||
IconButtons.IconButton(
|
||||
@@ -82,7 +86,8 @@ private fun CallButton(
|
||||
Icon(
|
||||
painter = painter,
|
||||
contentDescription = contentDescription,
|
||||
modifier = Modifier.size(28.dp)
|
||||
modifier = Modifier.size(iconSize),
|
||||
tint = contentColor
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -152,13 +157,51 @@ fun AdditionalActionsButton(
|
||||
@Composable
|
||||
fun HangupButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
iconSize: Dp = defaultCallButtonIconSize
|
||||
) {
|
||||
CallButton(
|
||||
onClick = onClick,
|
||||
painter = painterResource(id = R.drawable.symbol_phone_down_fill_24),
|
||||
contentDescription = stringResource(id = R.string.WebRtcCallView__end_call),
|
||||
containerColor = colorResource(id = R.color.webrtc_hangup_background),
|
||||
modifier = modifier,
|
||||
iconSize = iconSize
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AcceptCallButton(
|
||||
onClick: () -> Unit,
|
||||
isVideoCall: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
iconSize: Dp = defaultCallButtonIconSize
|
||||
) {
|
||||
CallButton(
|
||||
onClick = onClick,
|
||||
painter = if (isVideoCall) {
|
||||
painterResource(id = R.drawable.symbol_video_fill_24)
|
||||
} else {
|
||||
painterResource(id = R.drawable.symbol_phone_fill_white_24)
|
||||
},
|
||||
contentDescription = stringResource(id = R.string.WebRtcCallScreen__answer),
|
||||
containerColor = colorResource(id = R.color.webrtc_answer_background),
|
||||
iconSize = iconSize,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AnswerWithoutVideoButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
CallButton(
|
||||
onClick = onClick,
|
||||
painter = painterResource(id = R.drawable.symbol_video_slash_fill_24),
|
||||
contentDescription = stringResource(id = R.string.WebRtcCallScreen__answer_without_video),
|
||||
containerColor = Color.White,
|
||||
contentColor = Color.Black,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -261,6 +304,38 @@ private fun HangupButtonPreview() {
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun VideoAcceptCallButtonPreview() {
|
||||
Previews.Preview {
|
||||
AcceptCallButton(
|
||||
onClick = {},
|
||||
isVideoCall = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun AcceptCallButtonPreview() {
|
||||
Previews.Preview {
|
||||
AcceptCallButton(
|
||||
onClick = {},
|
||||
isVideoCall = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun AnswerWithoutVideoButtonPreview() {
|
||||
Previews.Preview {
|
||||
AnswerWithoutVideoButton(
|
||||
onClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun StartCallButtonPreview() {
|
||||
|
||||
@@ -77,6 +77,7 @@ private const val SHEET_BOTTOM_PADDING = 16
|
||||
fun CallScreen(
|
||||
callRecipient: Recipient,
|
||||
webRtcCallState: WebRtcViewModel.State,
|
||||
isRemoteVideoOffer: Boolean,
|
||||
callScreenState: CallScreenState,
|
||||
callControlsState: CallControlsState,
|
||||
callScreenController: CallScreenController = CallScreenController.rememberCallScreenController(
|
||||
@@ -98,6 +99,16 @@ fun CallScreen(
|
||||
onControlsToggled: (Boolean) -> Unit,
|
||||
onCallScreenDialogDismissed: () -> Unit = {}
|
||||
) {
|
||||
if (webRtcCallState == WebRtcViewModel.State.CALL_INCOMING) {
|
||||
IncomingCallScreen(
|
||||
callRecipient = callRecipient,
|
||||
isVideoCall = isRemoteVideoOffer,
|
||||
callStatus = callScreenState.callStatus,
|
||||
callScreenControlsListener = callScreenControlsListener
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var peekPercentage by remember {
|
||||
mutableFloatStateOf(0f)
|
||||
}
|
||||
@@ -284,8 +295,7 @@ private fun BoxScope.Viewport(
|
||||
) {
|
||||
if (webRtcCallState.isPreJoinOrNetworkUnavailable) {
|
||||
LargeLocalVideoRenderer(
|
||||
localParticipant = localParticipant,
|
||||
localRenderState = localRenderState
|
||||
localParticipant = localParticipant
|
||||
)
|
||||
}
|
||||
|
||||
@@ -369,12 +379,10 @@ private fun BoxScope.Viewport(
|
||||
*/
|
||||
@Composable
|
||||
private fun LargeLocalVideoRenderer(
|
||||
localParticipant: CallParticipant,
|
||||
localRenderState: WebRtcLocalRenderState
|
||||
localParticipant: CallParticipant
|
||||
) {
|
||||
LocalParticipantRenderer(
|
||||
localParticipant = localParticipant,
|
||||
localRenderState = localRenderState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(MaterialTheme.shapes.extraLarge)
|
||||
@@ -407,7 +415,6 @@ private fun TinyLocalVideoRenderer(
|
||||
|
||||
LocalParticipantRenderer(
|
||||
localParticipant = localParticipant,
|
||||
localRenderState = localRenderState,
|
||||
modifier = modifier
|
||||
.padding(16.dp)
|
||||
.height(height)
|
||||
@@ -449,7 +456,6 @@ private fun SmallMoveableLocalVideoRenderer(
|
||||
) {
|
||||
LocalParticipantRenderer(
|
||||
localParticipant = localParticipant,
|
||||
localRenderState = localRenderState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
@@ -498,6 +504,7 @@ private fun CallScreenPreview() {
|
||||
CallScreen(
|
||||
callRecipient = Recipient(systemContactName = "Test User"),
|
||||
webRtcCallState = WebRtcViewModel.State.CALL_CONNECTED,
|
||||
isRemoteVideoOffer = false,
|
||||
callScreenState = CallScreenState(),
|
||||
callControlsState = CallControlsState(
|
||||
displayMicToggle = true,
|
||||
|
||||
@@ -53,6 +53,7 @@ interface CallScreenMediator {
|
||||
fun enableParticipantUpdatePopup(enabled: Boolean)
|
||||
fun enableCallStateUpdatePopup(enabled: Boolean)
|
||||
fun showWifiToCellularPopupWindow()
|
||||
fun hideMissingPermissionsNotice()
|
||||
|
||||
fun setStatusFromGroupCallState(context: Context, groupCallState: WebRtcViewModel.GroupCallState) {
|
||||
when (groupCallState) {
|
||||
|
||||
@@ -26,6 +26,7 @@ data class CallScreenState(
|
||||
val displaySwipeToSpeakerHint: Boolean = false,
|
||||
val displayWifiToCellularPopup: Boolean = false,
|
||||
val displayAdditionalActionsPopup: Boolean = false,
|
||||
val displayMissingPermissionsNotice: Boolean = false,
|
||||
val pendingParticipantsState: PendingParticipantsState? = null,
|
||||
val isParticipantUpdatePopupEnabled: Boolean = false,
|
||||
val isCallStateUpdatePopupEnabled: Boolean = false
|
||||
|
||||
@@ -134,11 +134,12 @@ fun CallScreenPreJoinOverlay(
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun CallScreenTopAppBar(
|
||||
fun CallScreenTopAppBar(
|
||||
callRecipient: Recipient? = null,
|
||||
callStatus: String? = null,
|
||||
onNavigationClick: () -> Unit = {},
|
||||
onCallInfoClick: () -> Unit = {}
|
||||
onCallInfoClick: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val textShadow = remember {
|
||||
Shadow(
|
||||
@@ -148,6 +149,7 @@ private fun CallScreenTopAppBar(
|
||||
}
|
||||
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
colors = TopAppBarDefaults.topAppBarColors().copy(
|
||||
containerColor = Color.Transparent
|
||||
),
|
||||
|
||||
@@ -108,6 +108,7 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
CallScreen(
|
||||
callRecipient = recipient,
|
||||
webRtcCallState = webRtcCallState,
|
||||
isRemoteVideoOffer = viewModel.isAnswerWithVideoAvailable(),
|
||||
callScreenState = callScreenState,
|
||||
callControlsState = callControlsState,
|
||||
callScreenController = callScreenController,
|
||||
@@ -276,6 +277,10 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayWifiToCellularPopup = true) }
|
||||
}
|
||||
|
||||
override fun hideMissingPermissionsNotice() {
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayMissingPermissionsNotice = false) }
|
||||
}
|
||||
|
||||
/**
|
||||
* State holder for compose call screen
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.webrtc.v2
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.BlurredEdgeTreatment
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shadow
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.DarkPreview
|
||||
import org.signal.core.ui.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.AvatarImage
|
||||
import org.thoughtcrime.securesms.compose.GlideImage
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
||||
private val textShadow = Shadow(
|
||||
color = Color(0f, 0f, 0f, 0.25f),
|
||||
blurRadius = 4f
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun IncomingCallScreen(
|
||||
callRecipient: Recipient,
|
||||
callStatus: String?,
|
||||
isVideoCall: Boolean,
|
||||
callScreenControlsListener: CallScreenControlsListener
|
||||
) {
|
||||
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
val callTypePadding = remember(isLandscape) {
|
||||
if (isLandscape) {
|
||||
PaddingValues(top = 0.dp, bottom = 20.dp)
|
||||
} else {
|
||||
PaddingValues(top = 22.dp, bottom = 30.dp)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold { contentPadding ->
|
||||
|
||||
GlideImage(
|
||||
model = callRecipient.contactPhoto,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.blur(
|
||||
radiusX = 25.dp,
|
||||
radiusY = 25.dp,
|
||||
edgeTreatment = BlurredEdgeTreatment.Rectangle
|
||||
)
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = Color.Black.copy(alpha = 0.4f))
|
||||
) {}
|
||||
|
||||
CallScreenTopAppBar(
|
||||
callRecipient = null,
|
||||
callStatus = null,
|
||||
onNavigationClick = callScreenControlsListener::onNavigateUpClicked,
|
||||
onCallInfoClick = callScreenControlsListener::onCallInfoClicked,
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(callTypePadding)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_signal_logo_small),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(end = 6.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = if (isVideoCall) {
|
||||
stringResource(R.string.WebRtcCallView__signal_video_call)
|
||||
} else {
|
||||
stringResource(R.string.WebRtcCallView__signal_call)
|
||||
},
|
||||
style = MaterialTheme.typography.bodyMedium.copy(shadow = textShadow)
|
||||
)
|
||||
}
|
||||
|
||||
AvatarImage(
|
||||
recipient = callRecipient,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = callRecipient.getDisplayName(LocalContext.current),
|
||||
style = if (isLandscape) {
|
||||
MaterialTheme.typography.titleLarge.copy(shadow = textShadow)
|
||||
} else {
|
||||
MaterialTheme.typography.headlineMedium.copy(shadow = textShadow)
|
||||
},
|
||||
color = Color.White,
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
|
||||
if (callStatus != null) {
|
||||
Text(
|
||||
text = callStatus,
|
||||
style = MaterialTheme.typography.bodyMedium.copy(shadow = textShadow),
|
||||
color = Color.White,
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if (isLandscape) {
|
||||
LandscapeButtons(isVideoCall, callScreenControlsListener)
|
||||
} else {
|
||||
PortraitButtons(isVideoCall, callScreenControlsListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PortraitButtons(
|
||||
isVideoCall: Boolean,
|
||||
callScreenControlsListener: CallScreenControlsListener
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = spacedBy(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 64.dp)
|
||||
.padding(bottom = 24.dp)
|
||||
) {
|
||||
if (isVideoCall) {
|
||||
AnswerWithoutVideoButtonAndLabel(
|
||||
onClick = callScreenControlsListener::onAcceptCallWithVoiceOnlyPressed
|
||||
)
|
||||
}
|
||||
|
||||
Row {
|
||||
DeclineButtonAndLabel(
|
||||
onClick = callScreenControlsListener::onDenyCallPressed
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
AnswerCallButtonAndLabel(
|
||||
isVideoCall = isVideoCall,
|
||||
onClick = callScreenControlsListener::onAcceptCallPressed
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LandscapeButtons(
|
||||
isVideoCall: Boolean,
|
||||
callScreenControlsListener: CallScreenControlsListener
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(20.dp),
|
||||
horizontalArrangement = spacedBy(45.dp)
|
||||
) {
|
||||
DeclineButtonAndLabel(
|
||||
onClick = callScreenControlsListener::onDenyCallPressed
|
||||
)
|
||||
|
||||
if (isVideoCall) {
|
||||
AnswerWithoutVideoButtonAndLabel(
|
||||
onClick = callScreenControlsListener::onAcceptCallWithVoiceOnlyPressed
|
||||
)
|
||||
}
|
||||
|
||||
AnswerCallButtonAndLabel(
|
||||
isVideoCall = isVideoCall,
|
||||
onClick = callScreenControlsListener::onAcceptCallPressed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeclineButtonAndLabel(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = spacedBy(6.dp)
|
||||
) {
|
||||
HangupButton(
|
||||
onClick = onClick,
|
||||
iconSize = 32.dp,
|
||||
modifier = Modifier.size(78.dp)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.WebRtcCallScreen__decline),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(shadow = textShadow)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnswerWithoutVideoButtonAndLabel(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = spacedBy(6.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.size(78.dp)
|
||||
) {
|
||||
AnswerWithoutVideoButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier
|
||||
.size(56.dp)
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.WebRtcCallScreen__answer_without_video),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(shadow = textShadow)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnswerCallButtonAndLabel(
|
||||
isVideoCall: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = spacedBy(6.dp)
|
||||
) {
|
||||
AcceptCallButton(
|
||||
isVideoCall = isVideoCall,
|
||||
onClick = onClick,
|
||||
iconSize = 32.dp,
|
||||
modifier = Modifier.size(78.dp)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.WebRtcCallScreen__answer),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(shadow = textShadow)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Preview(device = "spec:parent=pixel_5,orientation=landscape", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun IncomingVideoCallScreenPreview() {
|
||||
Previews.Preview {
|
||||
IncomingCallScreen(
|
||||
callRecipient = Recipient(
|
||||
systemContactName = "Test User"
|
||||
),
|
||||
callScreenControlsListener = CallScreenControlsListener.Empty,
|
||||
isVideoCall = true,
|
||||
callStatus = "Spiderman is calling the group"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Preview(device = "spec:parent=pixel_5,orientation=landscape", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun IncomingAudioCallScreenPreview() {
|
||||
Previews.Preview {
|
||||
IncomingCallScreen(
|
||||
callRecipient = Recipient(
|
||||
systemContactName = "Test User"
|
||||
),
|
||||
callScreenControlsListener = CallScreenControlsListener.Empty,
|
||||
isVideoCall = false,
|
||||
callStatus = "Spiderman is calling the group"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import org.thoughtcrime.securesms.avatar.fallback.FallbackAvatarDrawable
|
||||
import org.thoughtcrime.securesms.components.webrtc.TextureViewRenderer
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcLocalRenderState
|
||||
import org.thoughtcrime.securesms.compose.GlideImage
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto
|
||||
import org.thoughtcrime.securesms.events.CallParticipant
|
||||
@@ -31,8 +30,8 @@ import org.webrtc.RendererCommon
|
||||
@Composable
|
||||
fun LocalParticipantRenderer(
|
||||
localParticipant: CallParticipant,
|
||||
localRenderState: WebRtcLocalRenderState,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
force: Boolean = false
|
||||
) {
|
||||
BoxWithConstraints(
|
||||
modifier = modifier
|
||||
@@ -70,7 +69,7 @@ fun LocalParticipantRenderer(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
|
||||
if (localParticipant.isVideoEnabled) {
|
||||
if (force || localParticipant.isVideoEnabled) {
|
||||
AndroidView(
|
||||
factory = ::TextureViewRenderer,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.components.webrtc.v2
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
@@ -22,6 +23,7 @@ import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoCont
|
||||
import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoViewModel
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
|
||||
|
||||
/**
|
||||
@@ -194,4 +196,8 @@ class ViewCallScreenMediator(
|
||||
override fun showWifiToCellularPopupWindow() {
|
||||
wifiToCellularPopupWindow.show()
|
||||
}
|
||||
|
||||
override fun hideMissingPermissionsNotice() {
|
||||
callScreen.findViewById<View>(R.id.missing_permissions_container).visible = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Rational
|
||||
import android.view.Surface
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
@@ -85,7 +84,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer
|
||||
import org.thoughtcrime.securesms.util.VibrateUtil
|
||||
import org.thoughtcrime.securesms.util.WindowUtil
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.ChosenAudioDeviceIdentifier
|
||||
@@ -386,6 +384,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
|
||||
|
||||
viewModel.setRecipient(event.recipient)
|
||||
callScreen.setRecipient(event.recipient)
|
||||
event.isRemoteVideoOffer
|
||||
callScreen.setWebRtcCallState(event.state)
|
||||
|
||||
when (event.state) {
|
||||
@@ -669,7 +668,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
|
||||
callPermissionsDialogController.requestCameraAndAudioPermission(
|
||||
activity = this,
|
||||
onAllGranted = onGranted,
|
||||
onCameraGranted = { findViewById<View>(R.id.missing_permissions_container).visible = false },
|
||||
onCameraGranted = { callScreen.hideMissingPermissionsNotice() },
|
||||
onAudioDenied = this::handleDenyCall
|
||||
)
|
||||
}
|
||||
@@ -677,7 +676,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
|
||||
private fun askCameraPermissions(onGranted: () -> Unit) {
|
||||
callPermissionsDialogController.requestCameraPermission(this) {
|
||||
onGranted()
|
||||
findViewById<View>(R.id.missing_permissions_container).visible = false
|
||||
callScreen.hideMissingPermissionsNotice()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<color name="story_caption_gradient_start">#CC000000</color>
|
||||
|
||||
<color name="webrtc_hangup_background">#F07168</color>
|
||||
<color name="webrtc_answer_background">#34C759</color>
|
||||
|
||||
<color name="transparent_black_05">#0D000000</color>
|
||||
<color name="transparent_black_08">#14000000</color>
|
||||
|
||||
Reference in New Issue
Block a user