mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Fix call link join issue and add denial dialogs into call UI v2.
This commit is contained in:
committed by
Greyson Parrelli
parent
5bd3eda17d
commit
cd846f2b6d
@@ -25,8 +25,10 @@ import androidx.compose.runtime.rxjava3.subscribeAsState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -94,6 +96,16 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||
observeCallEvents()
|
||||
viewModel.processCallIntent(CallIntent(intent))
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
viewModel.callActions.collect {
|
||||
when (it) {
|
||||
CallViewModel.Action.EnableVideo -> onVideoToggleClick(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setContent {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val callControlsState by webRtcCallViewModel.getCallControlsState(lifecycleOwner).subscribeAsState(initial = CallControlsState())
|
||||
@@ -139,6 +151,8 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||
}
|
||||
}
|
||||
|
||||
val callScreenDialogType by viewModel.dialog.collectAsState(CallScreenDialogType.NONE)
|
||||
|
||||
SignalTheme {
|
||||
Surface {
|
||||
CallScreen(
|
||||
@@ -156,6 +170,7 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||
overflowParticipants = callParticipantsState.listParticipants,
|
||||
localParticipant = callParticipantsState.localParticipant,
|
||||
localRenderState = callParticipantsState.localRenderState,
|
||||
callScreenDialogType = callScreenDialogType,
|
||||
callInfoView = {
|
||||
CallInfoView.View(
|
||||
webRtcCallViewModel = webRtcCallViewModel,
|
||||
@@ -174,7 +189,8 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||
},
|
||||
onNavigationClick = { finish() },
|
||||
onLocalPictureInPictureClicked = webRtcCallViewModel::onLocalPictureInPictureClicked,
|
||||
onControlsToggled = { areControlsVisible = it }
|
||||
onControlsToggled = { areControlsVisible = it },
|
||||
onCallScreenDialogDismissed = viewModel::onCallScreenDialogDismissed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,13 @@ fun CallScreen(
|
||||
overflowParticipants: List<CallParticipant>,
|
||||
localParticipant: CallParticipant,
|
||||
localRenderState: WebRtcLocalRenderState,
|
||||
callScreenDialogType: CallScreenDialogType,
|
||||
callInfoView: @Composable (Float) -> Unit,
|
||||
raiseHandSnackbar: @Composable (Modifier) -> Unit,
|
||||
onNavigationClick: () -> Unit,
|
||||
onLocalPictureInPictureClicked: () -> Unit,
|
||||
onControlsToggled: (Boolean) -> Unit
|
||||
onControlsToggled: (Boolean) -> Unit,
|
||||
onCallScreenDialogDismissed: () -> Unit = {}
|
||||
) {
|
||||
var peekPercentage by remember {
|
||||
mutableFloatStateOf(0f)
|
||||
@@ -250,6 +252,8 @@ fun CallScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
CallScreenDialog(callScreenDialogType, onCallScreenDialogDismissed)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,6 +507,7 @@ private fun CallScreenPreview() {
|
||||
callParticipantsPagerState = CallParticipantsPagerState(),
|
||||
localParticipant = CallParticipant(),
|
||||
localRenderState = WebRtcLocalRenderState.LARGE,
|
||||
callScreenDialogType = CallScreenDialogType.NONE,
|
||||
callInfoView = {
|
||||
Text(text = "Call Info View Preview", modifier = Modifier.alpha(it))
|
||||
},
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.webrtc.v2
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import org.signal.core.ui.DarkPreview
|
||||
import org.signal.core.ui.Dialogs
|
||||
import org.signal.core.ui.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Displays the current dialog to the user, or nothing.
|
||||
*/
|
||||
@Composable
|
||||
fun CallScreenDialog(
|
||||
callScreenDialogType: CallScreenDialogType,
|
||||
onDialogDismissed: () -> Unit
|
||||
) {
|
||||
when (callScreenDialogType) {
|
||||
CallScreenDialogType.NONE -> return
|
||||
CallScreenDialogType.REMOVED_FROM_CALL_LINK -> RemovedFromCallLinkDialog(onDialogDismissed)
|
||||
CallScreenDialogType.DENIED_REQUEST_TO_JOIN_CALL_LINK -> DeniedRequestToJoinCallDialog(onDialogDismissed)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RemovedFromCallLinkDialog(onDialogDismissed: () -> Unit = {}) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(R.string.WebRtcCallActivity__removed_from_call),
|
||||
body = stringResource(R.string.WebRtcCallActivity__someone_has_removed_you_from_the_call),
|
||||
confirm = stringResource(android.R.string.ok),
|
||||
onConfirm = {},
|
||||
onDismiss = onDialogDismissed
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeniedRequestToJoinCallDialog(onDialogDismissed: () -> Unit = {}) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(R.string.WebRtcCallActivity__join_request_denied),
|
||||
body = stringResource(R.string.WebRtcCallActivity__your_request_to_join_this_call_has_been_denied),
|
||||
confirm = stringResource(android.R.string.ok),
|
||||
onConfirm = {},
|
||||
onDismiss = onDialogDismissed
|
||||
)
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun RemovedFromCallLinkDialogPreview() {
|
||||
Previews.Preview {
|
||||
RemovedFromCallLinkDialog()
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun DeniedRequestToJoinCallDialogPreview() {
|
||||
Previews.Preview {
|
||||
DeniedRequestToJoinCallDialog()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of available call screen dialog types.
|
||||
*/
|
||||
enum class CallScreenDialogType {
|
||||
NONE,
|
||||
REMOVED_FROM_CALL_LINK,
|
||||
DENIED_REQUEST_TO_JOIN_CALL_LINK
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
@@ -27,6 +29,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.CallLinkDisconnectReason
|
||||
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager
|
||||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
|
||||
@@ -48,13 +51,23 @@ class CallViewModel(
|
||||
}
|
||||
|
||||
private var previousEvent: WebRtcViewModel? = null
|
||||
|
||||
private var enableVideoIfAvailable = false
|
||||
|
||||
private var lastProcessedIntentTimestamp = 0L
|
||||
private var lastCallLinkDisconnectDialogShowTime = 0L
|
||||
|
||||
private var enterPipOnResume = false
|
||||
|
||||
private val internalCallScreenState = MutableStateFlow(CallScreenState())
|
||||
val callScreenState: StateFlow<CallScreenState> = internalCallScreenState
|
||||
|
||||
private val internalDialog = MutableStateFlow(CallScreenDialogType.NONE)
|
||||
val dialog: StateFlow<CallScreenDialogType> = internalDialog
|
||||
|
||||
private val internalCallActions = MutableSharedFlow<Action>()
|
||||
val callActions: Flow<Action> = internalCallActions
|
||||
|
||||
fun consumeEnterPipOnResume(): Boolean {
|
||||
val enter = enterPipOnResume
|
||||
enterPipOnResume = false
|
||||
@@ -127,6 +140,10 @@ class CallViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun onCallScreenDialogDismissed() {
|
||||
internalDialog.update { CallScreenDialogType.NONE }
|
||||
}
|
||||
|
||||
fun onCallEvent(event: CallEvent) {
|
||||
when (event) {
|
||||
CallEvent.DismissSwitchCameraTooltip -> Unit // TODO
|
||||
@@ -175,12 +192,24 @@ class CallViewModel(
|
||||
WebRtcViewModel.State.CALL_ONGOING_ELSEWHERE -> handleCallTerminated(HangupMessage.Type.BUSY)
|
||||
}
|
||||
|
||||
// TODO [alex] -- Call link handling block
|
||||
if (event.callLinkDisconnectReason != null && event.callLinkDisconnectReason.postedAt > lastCallLinkDisconnectDialogShowTime) {
|
||||
lastCallLinkDisconnectDialogShowTime = System.currentTimeMillis()
|
||||
|
||||
when (event.callLinkDisconnectReason) {
|
||||
is CallLinkDisconnectReason.RemovedFromCall -> internalDialog.update { CallScreenDialogType.REMOVED_FROM_CALL_LINK }
|
||||
is CallLinkDisconnectReason.DeniedRequestToJoinCall -> internalDialog.update { CallScreenDialogType.DENIED_REQUEST_TO_JOIN_CALL_LINK }
|
||||
}
|
||||
}
|
||||
|
||||
val enableVideo = event.localParticipant.cameraState.cameraCount > 0 && enableVideoIfAvailable
|
||||
webRtcCallViewModel.updateFromWebRtcViewModel(event, enableVideo)
|
||||
|
||||
// TODO [alex] -- handle enable video
|
||||
if (enableVideo) {
|
||||
enableVideoIfAvailable = false
|
||||
viewModelScope.launch {
|
||||
internalCallActions.emit(Action.EnableVideo)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [alex] -- handle denied bluetooth permission
|
||||
}
|
||||
@@ -373,4 +402,15 @@ class CallViewModel(
|
||||
|
||||
lastProcessedIntentTimestamp = now
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions that require activity-level context (for example, to request permissions.)
|
||||
*/
|
||||
enum class Action {
|
||||
/**
|
||||
* Tries to enable local video via the normal toggle callback. Should display permissions
|
||||
* dialogs as necessary.
|
||||
*/
|
||||
EnableVideo
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ class CallLinkPreJoinActionProcessor(
|
||||
private val TAG = Log.tag(CallLinkPreJoinActionProcessor::class.java)
|
||||
}
|
||||
|
||||
override fun handleSetRingGroup(currentState: WebRtcServiceState, ringGroup: Boolean): WebRtcServiceState {
|
||||
Log.i(TAG, "handleSetRingGroup(): Ignoring.")
|
||||
return currentState
|
||||
}
|
||||
|
||||
override fun handlePreJoinCall(currentState: WebRtcServiceState, remotePeer: RemotePeer): WebRtcServiceState {
|
||||
Log.i(TAG, "handlePreJoinCall():")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user