Implement the incoming call screen in compose.

This commit is contained in:
Alex Hart
2025-02-19 09:20:54 -04:00
committed by GitHub
parent ca6c9d76b2
commit 31d80ed200
11 changed files with 428 additions and 20 deletions

View File

@@ -21,6 +21,7 @@ import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.signal.core.ui.Buttons import org.signal.core.ui.Buttons
import org.signal.core.ui.DarkPreview import org.signal.core.ui.DarkPreview
@@ -28,6 +29,8 @@ import org.signal.core.ui.IconButtons
import org.signal.core.ui.Previews import org.signal.core.ui.Previews
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
private val defaultCallButtonIconSize: Dp = 24.dp
@Composable @Composable
private fun ToggleCallButton( private fun ToggleCallButton(
checked: Boolean, checked: Boolean,
@@ -67,7 +70,8 @@ private fun CallButton(
contentDescription: String?, contentDescription: String?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
containerColor: Color = MaterialTheme.colorScheme.secondaryContainer, 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) val buttonSize = dimensionResource(id = R.dimen.webrtc_button_size)
IconButtons.IconButton( IconButtons.IconButton(
@@ -82,7 +86,8 @@ private fun CallButton(
Icon( Icon(
painter = painter, painter = painter,
contentDescription = contentDescription, contentDescription = contentDescription,
modifier = Modifier.size(28.dp) modifier = Modifier.size(iconSize),
tint = contentColor
) )
} }
} }
@@ -152,13 +157,51 @@ fun AdditionalActionsButton(
@Composable @Composable
fun HangupButton( fun HangupButton(
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
iconSize: Dp = defaultCallButtonIconSize
) { ) {
CallButton( CallButton(
onClick = onClick, onClick = onClick,
painter = painterResource(id = R.drawable.symbol_phone_down_fill_24), painter = painterResource(id = R.drawable.symbol_phone_down_fill_24),
contentDescription = stringResource(id = R.string.WebRtcCallView__end_call), contentDescription = stringResource(id = R.string.WebRtcCallView__end_call),
containerColor = colorResource(id = R.color.webrtc_hangup_background), 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 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 @DarkPreview
@Composable @Composable
private fun StartCallButtonPreview() { private fun StartCallButtonPreview() {

View File

@@ -77,6 +77,7 @@ private const val SHEET_BOTTOM_PADDING = 16
fun CallScreen( fun CallScreen(
callRecipient: Recipient, callRecipient: Recipient,
webRtcCallState: WebRtcViewModel.State, webRtcCallState: WebRtcViewModel.State,
isRemoteVideoOffer: Boolean,
callScreenState: CallScreenState, callScreenState: CallScreenState,
callControlsState: CallControlsState, callControlsState: CallControlsState,
callScreenController: CallScreenController = CallScreenController.rememberCallScreenController( callScreenController: CallScreenController = CallScreenController.rememberCallScreenController(
@@ -98,6 +99,16 @@ fun CallScreen(
onControlsToggled: (Boolean) -> Unit, onControlsToggled: (Boolean) -> Unit,
onCallScreenDialogDismissed: () -> Unit = {} onCallScreenDialogDismissed: () -> Unit = {}
) { ) {
if (webRtcCallState == WebRtcViewModel.State.CALL_INCOMING) {
IncomingCallScreen(
callRecipient = callRecipient,
isVideoCall = isRemoteVideoOffer,
callStatus = callScreenState.callStatus,
callScreenControlsListener = callScreenControlsListener
)
return
}
var peekPercentage by remember { var peekPercentage by remember {
mutableFloatStateOf(0f) mutableFloatStateOf(0f)
} }
@@ -284,8 +295,7 @@ private fun BoxScope.Viewport(
) { ) {
if (webRtcCallState.isPreJoinOrNetworkUnavailable) { if (webRtcCallState.isPreJoinOrNetworkUnavailable) {
LargeLocalVideoRenderer( LargeLocalVideoRenderer(
localParticipant = localParticipant, localParticipant = localParticipant
localRenderState = localRenderState
) )
} }
@@ -369,12 +379,10 @@ private fun BoxScope.Viewport(
*/ */
@Composable @Composable
private fun LargeLocalVideoRenderer( private fun LargeLocalVideoRenderer(
localParticipant: CallParticipant, localParticipant: CallParticipant
localRenderState: WebRtcLocalRenderState
) { ) {
LocalParticipantRenderer( LocalParticipantRenderer(
localParticipant = localParticipant, localParticipant = localParticipant,
localRenderState = localRenderState,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.clip(MaterialTheme.shapes.extraLarge) .clip(MaterialTheme.shapes.extraLarge)
@@ -407,7 +415,6 @@ private fun TinyLocalVideoRenderer(
LocalParticipantRenderer( LocalParticipantRenderer(
localParticipant = localParticipant, localParticipant = localParticipant,
localRenderState = localRenderState,
modifier = modifier modifier = modifier
.padding(16.dp) .padding(16.dp)
.height(height) .height(height)
@@ -449,7 +456,6 @@ private fun SmallMoveableLocalVideoRenderer(
) { ) {
LocalParticipantRenderer( LocalParticipantRenderer(
localParticipant = localParticipant, localParticipant = localParticipant,
localRenderState = localRenderState,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.clip(MaterialTheme.shapes.medium) .clip(MaterialTheme.shapes.medium)
@@ -498,6 +504,7 @@ private fun CallScreenPreview() {
CallScreen( CallScreen(
callRecipient = Recipient(systemContactName = "Test User"), callRecipient = Recipient(systemContactName = "Test User"),
webRtcCallState = WebRtcViewModel.State.CALL_CONNECTED, webRtcCallState = WebRtcViewModel.State.CALL_CONNECTED,
isRemoteVideoOffer = false,
callScreenState = CallScreenState(), callScreenState = CallScreenState(),
callControlsState = CallControlsState( callControlsState = CallControlsState(
displayMicToggle = true, displayMicToggle = true,

View File

@@ -53,6 +53,7 @@ interface CallScreenMediator {
fun enableParticipantUpdatePopup(enabled: Boolean) fun enableParticipantUpdatePopup(enabled: Boolean)
fun enableCallStateUpdatePopup(enabled: Boolean) fun enableCallStateUpdatePopup(enabled: Boolean)
fun showWifiToCellularPopupWindow() fun showWifiToCellularPopupWindow()
fun hideMissingPermissionsNotice()
fun setStatusFromGroupCallState(context: Context, groupCallState: WebRtcViewModel.GroupCallState) { fun setStatusFromGroupCallState(context: Context, groupCallState: WebRtcViewModel.GroupCallState) {
when (groupCallState) { when (groupCallState) {

View File

@@ -26,6 +26,7 @@ data class CallScreenState(
val displaySwipeToSpeakerHint: Boolean = false, val displaySwipeToSpeakerHint: Boolean = false,
val displayWifiToCellularPopup: Boolean = false, val displayWifiToCellularPopup: Boolean = false,
val displayAdditionalActionsPopup: Boolean = false, val displayAdditionalActionsPopup: Boolean = false,
val displayMissingPermissionsNotice: Boolean = false,
val pendingParticipantsState: PendingParticipantsState? = null, val pendingParticipantsState: PendingParticipantsState? = null,
val isParticipantUpdatePopupEnabled: Boolean = false, val isParticipantUpdatePopupEnabled: Boolean = false,
val isCallStateUpdatePopupEnabled: Boolean = false val isCallStateUpdatePopupEnabled: Boolean = false

View File

@@ -134,11 +134,12 @@ fun CallScreenPreJoinOverlay(
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun CallScreenTopAppBar( fun CallScreenTopAppBar(
callRecipient: Recipient? = null, callRecipient: Recipient? = null,
callStatus: String? = null, callStatus: String? = null,
onNavigationClick: () -> Unit = {}, onNavigationClick: () -> Unit = {},
onCallInfoClick: () -> Unit = {} onCallInfoClick: () -> Unit = {},
modifier: Modifier = Modifier
) { ) {
val textShadow = remember { val textShadow = remember {
Shadow( Shadow(
@@ -148,6 +149,7 @@ private fun CallScreenTopAppBar(
} }
TopAppBar( TopAppBar(
modifier = modifier,
colors = TopAppBarDefaults.topAppBarColors().copy( colors = TopAppBarDefaults.topAppBarColors().copy(
containerColor = Color.Transparent containerColor = Color.Transparent
), ),

View File

@@ -108,6 +108,7 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
CallScreen( CallScreen(
callRecipient = recipient, callRecipient = recipient,
webRtcCallState = webRtcCallState, webRtcCallState = webRtcCallState,
isRemoteVideoOffer = viewModel.isAnswerWithVideoAvailable(),
callScreenState = callScreenState, callScreenState = callScreenState,
callControlsState = callControlsState, callControlsState = callControlsState,
callScreenController = callScreenController, callScreenController = callScreenController,
@@ -276,6 +277,10 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
callScreenViewModel.callScreenState.update { it.copy(displayWifiToCellularPopup = true) } callScreenViewModel.callScreenState.update { it.copy(displayWifiToCellularPopup = true) }
} }
override fun hideMissingPermissionsNotice() {
callScreenViewModel.callScreenState.update { it.copy(displayMissingPermissionsNotice = false) }
}
/** /**
* State holder for compose call screen * State holder for compose call screen
*/ */

View File

@@ -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"
)
}
}

View File

@@ -17,7 +17,6 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import org.thoughtcrime.securesms.avatar.fallback.FallbackAvatarDrawable import org.thoughtcrime.securesms.avatar.fallback.FallbackAvatarDrawable
import org.thoughtcrime.securesms.components.webrtc.TextureViewRenderer import org.thoughtcrime.securesms.components.webrtc.TextureViewRenderer
import org.thoughtcrime.securesms.components.webrtc.WebRtcLocalRenderState
import org.thoughtcrime.securesms.compose.GlideImage import org.thoughtcrime.securesms.compose.GlideImage
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto
import org.thoughtcrime.securesms.events.CallParticipant import org.thoughtcrime.securesms.events.CallParticipant
@@ -31,8 +30,8 @@ import org.webrtc.RendererCommon
@Composable @Composable
fun LocalParticipantRenderer( fun LocalParticipantRenderer(
localParticipant: CallParticipant, localParticipant: CallParticipant,
localRenderState: WebRtcLocalRenderState, modifier: Modifier = Modifier,
modifier: Modifier = Modifier force: Boolean = false
) { ) {
BoxWithConstraints( BoxWithConstraints(
modifier = modifier modifier = modifier
@@ -70,7 +69,7 @@ fun LocalParticipantRenderer(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
if (localParticipant.isVideoEnabled) { if (force || localParticipant.isVideoEnabled) {
AndroidView( AndroidView(
factory = ::TextureViewRenderer, factory = ::TextureViewRenderer,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),

View File

@@ -5,6 +5,7 @@
package org.thoughtcrime.securesms.components.webrtc.v2 package org.thoughtcrime.securesms.components.webrtc.v2
import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import org.signal.core.util.concurrent.LifecycleDisposable 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.components.webrtc.controls.ControlsAndInfoViewModel
import org.thoughtcrime.securesms.events.WebRtcViewModel import org.thoughtcrime.securesms.events.WebRtcViewModel
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.visible
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
/** /**
@@ -194,4 +196,8 @@ class ViewCallScreenMediator(
override fun showWifiToCellularPopupWindow() { override fun showWifiToCellularPopupWindow() {
wifiToCellularPopupWindow.show() wifiToCellularPopupWindow.show()
} }
override fun hideMissingPermissionsNotice() {
callScreen.findViewById<View>(R.id.missing_permissions_container).visible = false
}
} }

View File

@@ -17,7 +17,6 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Rational import android.util.Rational
import android.view.Surface import android.view.Surface
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window import android.view.Window
import android.view.WindowManager 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.ThrottledDebouncer
import org.thoughtcrime.securesms.util.VibrateUtil import org.thoughtcrime.securesms.util.VibrateUtil
import org.thoughtcrime.securesms.util.WindowUtil import org.thoughtcrime.securesms.util.WindowUtil
import org.thoughtcrime.securesms.util.visible
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.ChosenAudioDeviceIdentifier import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.ChosenAudioDeviceIdentifier
@@ -386,6 +384,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
viewModel.setRecipient(event.recipient) viewModel.setRecipient(event.recipient)
callScreen.setRecipient(event.recipient) callScreen.setRecipient(event.recipient)
event.isRemoteVideoOffer
callScreen.setWebRtcCallState(event.state) callScreen.setWebRtcCallState(event.state)
when (event.state) { when (event.state) {
@@ -669,7 +668,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
callPermissionsDialogController.requestCameraAndAudioPermission( callPermissionsDialogController.requestCameraAndAudioPermission(
activity = this, activity = this,
onAllGranted = onGranted, onAllGranted = onGranted,
onCameraGranted = { findViewById<View>(R.id.missing_permissions_container).visible = false }, onCameraGranted = { callScreen.hideMissingPermissionsNotice() },
onAudioDenied = this::handleDenyCall onAudioDenied = this::handleDenyCall
) )
} }
@@ -677,7 +676,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
private fun askCameraPermissions(onGranted: () -> Unit) { private fun askCameraPermissions(onGranted: () -> Unit) {
callPermissionsDialogController.requestCameraPermission(this) { callPermissionsDialogController.requestCameraPermission(this) {
onGranted() onGranted()
findViewById<View>(R.id.missing_permissions_container).visible = false callScreen.hideMissingPermissionsNotice()
} }
} }

View File

@@ -9,6 +9,7 @@
<color name="story_caption_gradient_start">#CC000000</color> <color name="story_caption_gradient_start">#CC000000</color>
<color name="webrtc_hangup_background">#F07168</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_05">#0D000000</color>
<color name="transparent_black_08">#14000000</color> <color name="transparent_black_08">#14000000</color>