mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-03 07:48:36 +00:00
Reimplement the call overflow menu in compose.
This commit is contained in:
committed by
Greyson Parrelli
parent
993192d38e
commit
47ce28a721
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.webrtc.v2
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.signal.core.ui.DarkPreview
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.TriggerAlignedPopup
|
||||
import org.signal.core.ui.TriggerAlignedPopupState
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.emoji.Emojifier
|
||||
|
||||
data class AdditionalActionsState(
|
||||
val triggerAlignedPopupState: TriggerAlignedPopupState,
|
||||
val isShown: Boolean = false,
|
||||
val reactions: PersistentList<String> = persistentListOf(),
|
||||
val isSelfHandRaised: Boolean = false,
|
||||
@Stable val listener: AdditionalActionsListener = AdditionalActionsListener.Empty
|
||||
)
|
||||
|
||||
interface AdditionalActionsListener {
|
||||
fun onReactClick(reaction: String)
|
||||
fun onReactWithAnyClick()
|
||||
fun onRaiseHandClick(raised: Boolean)
|
||||
|
||||
object Empty : AdditionalActionsListener {
|
||||
override fun onReactClick(reaction: String) = Unit
|
||||
override fun onReactWithAnyClick() = Unit
|
||||
override fun onRaiseHandClick(raised: Boolean) = Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AdditionalActionsPopup(
|
||||
onDismissRequest: () -> Unit,
|
||||
state: AdditionalActionsState
|
||||
) {
|
||||
TriggerAlignedPopup(
|
||||
onDismissRequest = onDismissRequest,
|
||||
state = state.triggerAlignedPopupState
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = spacedBy(12.dp),
|
||||
modifier = Modifier
|
||||
.width(320.dp)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
CallReactionScrubber(
|
||||
reactions = state.reactions,
|
||||
listener = state.listener
|
||||
)
|
||||
|
||||
CallScreenMenu(
|
||||
onRaiseHandClick = state.listener::onRaiseHandClick,
|
||||
isSelfHandRaised = state.isSelfHandRaised
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CallReactionScrubber(
|
||||
reactions: PersistentList<String>,
|
||||
listener: AdditionalActionsListener
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(SignalTheme.colors.colorSurface2, RoundedCornerShape(percent = 50))
|
||||
.padding(start = 6.dp, top = 12.dp, bottom = 12.dp, end = 12.dp)
|
||||
) {
|
||||
reactions.forEach {
|
||||
Emojifier(it) { annotatedText, inlineContent ->
|
||||
Text(
|
||||
text = annotatedText,
|
||||
inlineContent = inlineContent,
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.width(44.dp)
|
||||
.clickable(onClick = {
|
||||
listener.onReactClick(it)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
|
||||
IconButton(
|
||||
onClick = listener::onReactWithAnyClick,
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_any_emoji_32),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CallScreenMenu(
|
||||
isSelfHandRaised: Boolean,
|
||||
onRaiseHandClick: (Boolean) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(SignalTheme.colors.colorSurface2, RoundedCornerShape(18.dp))
|
||||
) {
|
||||
CallScreenMenuOption(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_raise_hand_24),
|
||||
title = if (isSelfHandRaised) stringResource(R.string.CallOverflowPopupWindow__lower_hand) else stringResource(R.string.CallOverflowPopupWindow__raise_hand),
|
||||
onClick = { onRaiseHandClick(!isSelfHandRaised) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CallScreenMenuOption(
|
||||
imageVector: ImageVector,
|
||||
title: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = title,
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DarkPreview
|
||||
@Composable
|
||||
private fun CallScreenAdditionalActionsPopupPreview() {
|
||||
Previews.Preview {
|
||||
AdditionalActionsPopup(
|
||||
onDismissRequest = {},
|
||||
state = AdditionalActionsState(
|
||||
isShown = false,
|
||||
reactions = persistentListOf(
|
||||
"\u2764\ufe0f",
|
||||
"\ud83d\udc4d",
|
||||
"\ud83d\udc4e",
|
||||
"\ud83d\ude02",
|
||||
"\ud83d\ude2e",
|
||||
"\ud83d\ude22"
|
||||
),
|
||||
isSelfHandRaised = false,
|
||||
listener = AdditionalActionsListener.Empty,
|
||||
triggerAlignedPopupState = TriggerAlignedPopupState.rememberTriggerAlignedPopupState()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.signal.core.ui.DarkPreview
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.TriggerAlignedPopupState.Companion.popupTrigger
|
||||
import org.signal.core.ui.TriggerAlignedPopupState.Companion.rememberTriggerAlignedPopupState
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState
|
||||
import org.thoughtcrime.securesms.components.webrtc.ToggleButtonOutputState
|
||||
@@ -50,6 +52,7 @@ fun CallControls(
|
||||
callControlsState: CallControlsState,
|
||||
callScreenControlsListener: CallScreenControlsListener,
|
||||
callScreenSheetDisplayListener: CallScreenSheetDisplayListener,
|
||||
additionalActionsState: AdditionalActionsState,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
@@ -138,7 +141,10 @@ fun CallControls(
|
||||
}
|
||||
|
||||
if (callControlsState.displayAdditionalActions) {
|
||||
AdditionalActionsButton(onClick = callScreenControlsListener::onOverflowClicked)
|
||||
AdditionalActionsButton(
|
||||
onClick = callScreenControlsListener::onOverflowClicked,
|
||||
modifier = Modifier.popupTrigger(additionalActionsState.triggerAlignedPopupState)
|
||||
)
|
||||
}
|
||||
|
||||
if (callControlsState.displayEndCallButton) {
|
||||
@@ -187,7 +193,10 @@ fun CallControlsPreview() {
|
||||
),
|
||||
displayVideoTooltip = false,
|
||||
callScreenControlsListener = CallScreenControlsListener.Empty,
|
||||
callScreenSheetDisplayListener = CallScreenSheetDisplayListener.Empty
|
||||
callScreenSheetDisplayListener = CallScreenSheetDisplayListener.Empty,
|
||||
additionalActionsState = AdditionalActionsState(
|
||||
triggerAlignedPopupState = rememberTriggerAlignedPopupState()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -197,10 +206,12 @@ fun CallControlsPreview() {
|
||||
*/
|
||||
interface CallScreenSheetDisplayListener {
|
||||
fun onAudioDeviceSheetDisplayChanged(displayed: Boolean)
|
||||
fun onOverflowDisplayChanged(displayed: Boolean)
|
||||
fun onVideoTooltipDismissed()
|
||||
|
||||
object Empty : CallScreenSheetDisplayListener {
|
||||
override fun onAudioDeviceSheetDisplayChanged(displayed: Boolean) = Unit
|
||||
override fun onOverflowDisplayChanged(displayed: Boolean) = Unit
|
||||
override fun onVideoTooltipDismissed() = Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.signal.core.ui.BottomSheets
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.TriggerAlignedPopupState
|
||||
import org.signal.core.util.DimensionUnit
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcLocalRenderState
|
||||
import org.thoughtcrime.securesms.events.CallParticipant
|
||||
@@ -86,6 +87,7 @@ fun CallScreen(
|
||||
),
|
||||
callScreenControlsListener: CallScreenControlsListener = CallScreenControlsListener.Empty,
|
||||
callScreenSheetDisplayListener: CallScreenSheetDisplayListener = CallScreenSheetDisplayListener.Empty,
|
||||
additionalActionsListener: AdditionalActionsListener = AdditionalActionsListener.Empty,
|
||||
callParticipantsPagerState: CallParticipantsPagerState,
|
||||
pendingParticipantsListener: PendingParticipantsListener = PendingParticipantsListener.Empty,
|
||||
overflowParticipants: List<CallParticipant>,
|
||||
@@ -117,6 +119,21 @@ fun CallScreen(
|
||||
val scope = rememberCoroutineScope()
|
||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
val additionalActionsPopupState = TriggerAlignedPopupState.rememberTriggerAlignedPopupState()
|
||||
val additionalActionsState = remember(
|
||||
callScreenState.reactions,
|
||||
localParticipant.isHandRaised
|
||||
) {
|
||||
AdditionalActionsState(
|
||||
reactions = callScreenState.reactions,
|
||||
isSelfHandRaised = localParticipant.isHandRaised,
|
||||
listener = additionalActionsListener,
|
||||
triggerAlignedPopupState = additionalActionsPopupState
|
||||
)
|
||||
}
|
||||
|
||||
additionalActionsPopupState.display = callScreenState.displayAdditionalActionsDialog
|
||||
|
||||
BoxWithConstraints {
|
||||
val maxHeight = constraints.maxHeight
|
||||
val maxSheetHeight = round(constraints.maxHeight * 0.66f)
|
||||
@@ -133,6 +150,11 @@ fun CallScreen(
|
||||
sheetContent = {
|
||||
BottomSheets.Handle(modifier = Modifier.align(Alignment.CenterHorizontally))
|
||||
|
||||
AdditionalActionsPopup(
|
||||
onDismissRequest = callScreenControlsListener::onDismissOverflow,
|
||||
state = additionalActionsState
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -159,6 +181,7 @@ fun CallScreen(
|
||||
callScreenControlsListener = callScreenControlsListener,
|
||||
callScreenSheetDisplayListener = callScreenSheetDisplayListener,
|
||||
displayVideoTooltip = callScreenState.displayVideoTooltip,
|
||||
additionalActionsState = additionalActionsState,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.alpha(callControlsAlpha)
|
||||
@@ -304,7 +327,7 @@ private fun BoxScope.Viewport(
|
||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val hideSheet by rememberUpdatedState(newValue = scaffoldState.bottomSheetState.currentValue == SheetValue.PartiallyExpanded && !callControlsState.skipHiddenState && !callScreenState.isDisplayingAudioToggleSheet)
|
||||
val hideSheet by rememberUpdatedState(newValue = scaffoldState.bottomSheetState.currentValue == SheetValue.PartiallyExpanded && !callControlsState.skipHiddenState && !callScreenState.isDisplayingControlMenu())
|
||||
LaunchedEffect(callScreenController.restartTimerRequests, hideSheet) {
|
||||
if (hideSheet) {
|
||||
delay(5.seconds)
|
||||
|
||||
@@ -23,6 +23,7 @@ interface CallScreenControlsListener {
|
||||
fun onVideoChanged(isVideoEnabled: Boolean)
|
||||
fun onMicChanged(isMicEnabled: Boolean)
|
||||
fun onOverflowClicked()
|
||||
fun onDismissOverflow()
|
||||
fun onCameraDirectionChanged()
|
||||
fun onEndCallPressed()
|
||||
fun onDenyCallPressed()
|
||||
@@ -44,6 +45,7 @@ interface CallScreenControlsListener {
|
||||
override fun onVideoChanged(isVideoEnabled: Boolean) = Unit
|
||||
override fun onMicChanged(isMicEnabled: Boolean) = Unit
|
||||
override fun onOverflowClicked() = Unit
|
||||
override fun onDismissOverflow() = Unit
|
||||
override fun onCameraDirectionChanged() = Unit
|
||||
override fun onEndCallPressed() = Unit
|
||||
override fun onDenyCallPressed() = Unit
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.thoughtcrime.securesms.components.webrtc.v2
|
||||
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
||||
/**
|
||||
@@ -25,9 +27,12 @@ data class CallScreenState(
|
||||
val displayVideoTooltip: Boolean = false,
|
||||
val displaySwipeToSpeakerHint: Boolean = false,
|
||||
val displayWifiToCellularPopup: Boolean = false,
|
||||
val displayAdditionalActionsPopup: Boolean = false,
|
||||
val displayAdditionalActionsDialog: Boolean = false,
|
||||
val displayMissingPermissionsNotice: Boolean = false,
|
||||
val pendingParticipantsState: PendingParticipantsState? = null,
|
||||
val isParticipantUpdatePopupEnabled: Boolean = false,
|
||||
val isCallStateUpdatePopupEnabled: Boolean = false
|
||||
)
|
||||
val isCallStateUpdatePopupEnabled: Boolean = false,
|
||||
val reactions: PersistentList<String> = persistentListOf()
|
||||
) {
|
||||
fun isDisplayingControlMenu(): Boolean = isDisplayingAudioToggleSheet || displayAdditionalActionsDialog
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -27,11 +28,15 @@ import org.signal.core.ui.theme.SignalTheme
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallParticipantListUpdate
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallReactionScrubber.Companion.CUSTOM_REACTION_BOTTOM_SHEET_TAG
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcControls
|
||||
import org.thoughtcrime.securesms.components.webrtc.controls.CallInfoView
|
||||
import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoViewModel
|
||||
import org.thoughtcrime.securesms.components.webrtc.controls.RaiseHandSnackbar
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState
|
||||
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
|
||||
@@ -40,7 +45,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
/**
|
||||
* Compose call screen wrapper
|
||||
*/
|
||||
class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcCallViewModel) : CallScreenMediator {
|
||||
class ComposeCallScreenMediator(private val activity: WebRtcCallActivity, viewModel: WebRtcCallViewModel) : CallScreenMediator, AdditionalActionsListener {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(ComposeCallScreenMediator::class)
|
||||
@@ -78,6 +83,10 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
callScreenViewModel.callScreenState.update { it.copy(isDisplayingAudioToggleSheet = displayed) }
|
||||
}
|
||||
|
||||
override fun onOverflowDisplayChanged(displayed: Boolean) {
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsDialog = displayed) }
|
||||
}
|
||||
|
||||
override fun onVideoTooltipDismissed() {
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayVideoTooltip = false) }
|
||||
}
|
||||
@@ -117,6 +126,7 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
callControlsState = callControlsState,
|
||||
callScreenController = callScreenController,
|
||||
callScreenControlsListener = callScreenControlsListener,
|
||||
additionalActionsListener = this,
|
||||
callScreenSheetDisplayListener = callScreenSheetDisplayListener,
|
||||
callParticipantsPagerState = callParticipantsPagerState,
|
||||
pendingParticipantsListener = pendingParticipantsListener,
|
||||
@@ -163,7 +173,7 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
|
||||
override fun toggleOverflowPopup() {
|
||||
callScreenViewModel.callScreenState.update {
|
||||
it.copy(displayAdditionalActionsPopup = !it.displayAdditionalActionsPopup)
|
||||
it.copy(displayAdditionalActionsDialog = !it.displayAdditionalActionsDialog)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +272,7 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
}
|
||||
|
||||
override fun dismissCallOverflowPopup() {
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsPopup = false) }
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsDialog = false) }
|
||||
}
|
||||
|
||||
override fun onParticipantListUpdate(callParticipantListUpdate: CallParticipantListUpdate) {
|
||||
@@ -285,13 +295,35 @@ class ComposeCallScreenMediator(activity: WebRtcCallActivity, viewModel: WebRtcC
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayMissingPermissionsNotice = false) }
|
||||
}
|
||||
|
||||
override fun onReactWithAnyClick() {
|
||||
val bottomSheet = ReactWithAnyEmojiBottomSheetDialogFragment.createForCallingReactions()
|
||||
bottomSheet.show(activity.supportFragmentManager, CUSTOM_REACTION_BOTTOM_SHEET_TAG)
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsDialog = false) }
|
||||
}
|
||||
|
||||
override fun onReactClick(reaction: String) {
|
||||
AppDependencies.signalCallManager.react(reaction)
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsDialog = false) }
|
||||
}
|
||||
|
||||
override fun onRaiseHandClick(raised: Boolean) {
|
||||
AppDependencies.signalCallManager.raiseHand(raised)
|
||||
callScreenViewModel.callScreenState.update { it.copy(displayAdditionalActionsDialog = false) }
|
||||
}
|
||||
|
||||
/**
|
||||
* State holder for compose call screen
|
||||
*/
|
||||
class CallScreenViewModel : ViewModel() {
|
||||
val callScreenControllerEvents = MutableSharedFlow<CallScreenController.Event>()
|
||||
val callState = MutableStateFlow(WebRtcViewModel.State.IDLE)
|
||||
val callScreenState = MutableStateFlow(CallScreenState())
|
||||
val callScreenState = MutableStateFlow(
|
||||
CallScreenState(
|
||||
reactions = SignalStore.emoji.reactions.map {
|
||||
SignalStore.emoji.getPreferredVariation(it)
|
||||
}.toPersistentList()
|
||||
)
|
||||
)
|
||||
val dialog = MutableStateFlow(CallScreenDialogType.NONE)
|
||||
val callParticipantsViewState = MutableStateFlow(
|
||||
CallParticipantsViewState(
|
||||
|
||||
@@ -1139,6 +1139,10 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
|
||||
callScreen.toggleOverflowPopup()
|
||||
}
|
||||
|
||||
override fun onDismissOverflow() {
|
||||
callScreen.dismissCallOverflowPopup()
|
||||
}
|
||||
|
||||
override fun onCameraDirectionChanged() {
|
||||
handleFlipCamera()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user