Add visibility rules and timeout for call controls for v2.
This commit is contained in:
parent
3f71f90234
commit
5f66e2eb15
5 changed files with 115 additions and 44 deletions
|
@ -18,8 +18,10 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rxjava3.subscribeAsState
|
import androidx.compose.runtime.rxjava3.subscribeAsState
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
|
@ -36,11 +38,13 @@ import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState
|
||||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallViewModel
|
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallViewModel
|
||||||
import org.thoughtcrime.securesms.components.webrtc.controls.CallInfoView
|
import org.thoughtcrime.securesms.components.webrtc.controls.CallInfoView
|
||||||
import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoViewModel
|
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.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||||
import org.thoughtcrime.securesms.messagerequests.CalleeMustAcceptMessageRequestActivity
|
import org.thoughtcrime.securesms.messagerequests.CalleeMustAcceptMessageRequestActivity
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.util.FullscreenHelper
|
||||||
import org.thoughtcrime.securesms.util.VibrateUtil
|
import org.thoughtcrime.securesms.util.VibrateUtil
|
||||||
import org.thoughtcrime.securesms.util.viewModel
|
import org.thoughtcrime.securesms.util.viewModel
|
||||||
import org.whispersystems.signalservice.api.messages.calls.HangupMessage
|
import org.whispersystems.signalservice.api.messages.calls.HangupMessage
|
||||||
|
@ -77,6 +81,8 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val fullscreenHelper = FullscreenHelper(this)
|
||||||
|
|
||||||
lifecycleDisposable.bindTo(this)
|
lifecycleDisposable.bindTo(this)
|
||||||
val compositeDisposable = CompositeDisposable()
|
val compositeDisposable = CompositeDisposable()
|
||||||
lifecycleDisposable.add(compositeDisposable)
|
lifecycleDisposable.add(compositeDisposable)
|
||||||
|
@ -120,10 +126,20 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var areControlsVisible by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
LaunchedEffect(areControlsVisible) {
|
||||||
|
if (areControlsVisible) {
|
||||||
|
fullscreenHelper.showSystemUI()
|
||||||
|
} else {
|
||||||
|
fullscreenHelper.hideSystemUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SignalTheme {
|
SignalTheme {
|
||||||
Surface {
|
Surface {
|
||||||
CallScreen(
|
CallScreen(
|
||||||
callRecipient = recipient ?: Recipient.UNKNOWN,
|
callRecipient = recipient,
|
||||||
webRtcCallState = callParticipantsState.callState,
|
webRtcCallState = callParticipantsState.callState,
|
||||||
callScreenState = callScreenState,
|
callScreenState = callScreenState,
|
||||||
callControlsState = callControlsState,
|
callControlsState = callControlsState,
|
||||||
|
@ -146,8 +162,16 @@ class CallActivity : BaseActivity(), CallControlsCallback {
|
||||||
.alpha(it)
|
.alpha(it)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
raiseHandSnackbar = {
|
||||||
|
RaiseHandSnackbar.View(
|
||||||
|
webRtcCallViewModel = webRtcCallViewModel,
|
||||||
|
showCallInfoListener = { /*TODO*/ },
|
||||||
|
modifier = it
|
||||||
|
)
|
||||||
|
},
|
||||||
onNavigationClick = { finish() },
|
onNavigationClick = { finish() },
|
||||||
onLocalPictureInPictureClicked = webRtcCallViewModel::onLocalPictureInPictureClicked
|
onLocalPictureInPictureClicked = webRtcCallViewModel::onLocalPictureInPictureClicked,
|
||||||
|
onControlsToggled = { areControlsVisible = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,19 @@ import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
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.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
@ -41,10 +48,20 @@ fun CallControls(
|
||||||
) {
|
) {
|
||||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val padBottom = with(density) { WindowInsets.navigationBars.getBottom(density).toDp() }
|
||||||
|
var bottom by remember {
|
||||||
|
mutableStateOf(padBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padBottom != 0.dp) {
|
||||||
|
bottom = padBottom
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = spacedBy(30.dp),
|
verticalArrangement = spacedBy(30.dp),
|
||||||
modifier = modifier.navigationBarsPadding()
|
modifier = modifier.padding(bottom = bottom)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = spacedBy(20.dp)
|
horizontalArrangement = spacedBy(20.dp)
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.components.webrtc.v2
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
|
@ -19,12 +20,10 @@ import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
@ -38,10 +37,12 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||||
import androidx.compose.material3.rememberStandardBottomSheetState
|
import androidx.compose.material3.rememberStandardBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -50,11 +51,10 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.signal.core.ui.BottomSheets
|
import org.signal.core.ui.BottomSheets
|
||||||
import org.signal.core.ui.Previews
|
import org.signal.core.ui.Previews
|
||||||
|
@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
private const val DRAG_HANDLE_HEIGHT = 22
|
private const val DRAG_HANDLE_HEIGHT = 22
|
||||||
private const val SHEET_TOP_PADDING = 9
|
private const val SHEET_TOP_PADDING = 9
|
||||||
|
@ -86,19 +87,26 @@ fun CallScreen(
|
||||||
localParticipant: CallParticipant,
|
localParticipant: CallParticipant,
|
||||||
localRenderState: WebRtcLocalRenderState,
|
localRenderState: WebRtcLocalRenderState,
|
||||||
callInfoView: @Composable (Float) -> Unit,
|
callInfoView: @Composable (Float) -> Unit,
|
||||||
|
raiseHandSnackbar: @Composable (Modifier) -> Unit,
|
||||||
onNavigationClick: () -> Unit,
|
onNavigationClick: () -> Unit,
|
||||||
onLocalPictureInPictureClicked: () -> Unit
|
onLocalPictureInPictureClicked: () -> Unit,
|
||||||
|
onControlsToggled: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
var peekPercentage by remember {
|
var peekPercentage by remember {
|
||||||
mutableFloatStateOf(0f)
|
mutableFloatStateOf(0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val skipHiddenState by rememberUpdatedState(newValue = callControlsState.skipHiddenState)
|
||||||
|
val valueChangeOperation: (SheetValue) -> Boolean = remember {
|
||||||
|
{
|
||||||
|
!(it == SheetValue.Hidden && skipHiddenState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val scaffoldState = rememberBottomSheetScaffoldState(
|
val scaffoldState = rememberBottomSheetScaffoldState(
|
||||||
bottomSheetState = rememberStandardBottomSheetState(
|
bottomSheetState = rememberStandardBottomSheetState(
|
||||||
confirmValueChange = {
|
confirmValueChange = valueChangeOperation,
|
||||||
!(it == SheetValue.Hidden && callControlsState.skipHiddenState)
|
|
||||||
},
|
|
||||||
skipHiddenState = false
|
skipHiddenState = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -169,7 +177,8 @@ fun CallScreen(
|
||||||
overflowParticipants = overflowParticipants,
|
overflowParticipants = overflowParticipants,
|
||||||
scaffoldState = scaffoldState,
|
scaffoldState = scaffoldState,
|
||||||
callControlsState = callControlsState,
|
callControlsState = callControlsState,
|
||||||
onPipClick = onLocalPictureInPictureClicked
|
onPipClick = onLocalPictureInPictureClicked,
|
||||||
|
onControlsToggled = onControlsToggled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +196,8 @@ fun CallScreen(
|
||||||
overflowParticipants = overflowParticipants,
|
overflowParticipants = overflowParticipants,
|
||||||
scaffoldState = scaffoldState,
|
scaffoldState = scaffoldState,
|
||||||
callControlsState = callControlsState,
|
callControlsState = callControlsState,
|
||||||
onPipClick = onLocalPictureInPictureClicked
|
onPipClick = onLocalPictureInPictureClicked,
|
||||||
|
onControlsToggled = onControlsToggled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,13 +213,19 @@ fun CallScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webRtcCallState.isPassedPreJoin) {
|
if (webRtcCallState.isPassedPreJoin) {
|
||||||
CallScreenTopBar(
|
AnimatedVisibility(
|
||||||
callRecipient = callRecipient,
|
visible = scaffoldState.bottomSheetState.targetValue != SheetValue.Hidden,
|
||||||
callStatus = callScreenState.callStatus,
|
enter = fadeIn(),
|
||||||
onNavigationClick = onNavigationClick,
|
exit = fadeOut()
|
||||||
onCallInfoClick = onCallInfoClick,
|
) {
|
||||||
modifier = Modifier.padding(bottom = padding)
|
CallScreenTopBar(
|
||||||
)
|
callRecipient = callRecipient,
|
||||||
|
callStatus = callScreenState.callStatus,
|
||||||
|
onNavigationClick = onNavigationClick,
|
||||||
|
onCallInfoClick = onCallInfoClick,
|
||||||
|
modifier = Modifier.padding(bottom = padding)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
CallScreenPreJoinOverlay(
|
CallScreenPreJoinOverlay(
|
||||||
callRecipient = callRecipient,
|
callRecipient = callRecipient,
|
||||||
|
@ -221,6 +237,8 @@ fun CallScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raiseHandSnackbar(Modifier.fillMaxWidth())
|
||||||
|
|
||||||
AnimatedCallStateUpdate(
|
AnimatedCallStateUpdate(
|
||||||
callControlsChange = callScreenState.callControlsChange,
|
callControlsChange = callScreenState.callControlsChange,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -246,7 +264,8 @@ private fun BoxScope.Viewport(
|
||||||
overflowParticipants: List<CallParticipant>,
|
overflowParticipants: List<CallParticipant>,
|
||||||
scaffoldState: BottomSheetScaffoldState,
|
scaffoldState: BottomSheetScaffoldState,
|
||||||
callControlsState: CallControlsState,
|
callControlsState: CallControlsState,
|
||||||
onPipClick: () -> Unit
|
onPipClick: () -> Unit,
|
||||||
|
onControlsToggled: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
if (webRtcCallState.isPreJoinOrNetworkUnavailable) {
|
if (webRtcCallState.isPreJoinOrNetworkUnavailable) {
|
||||||
LargeLocalVideoRenderer(
|
LargeLocalVideoRenderer(
|
||||||
|
@ -260,6 +279,15 @@ private fun BoxScope.Viewport(
|
||||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val hideSheet by rememberUpdatedState(newValue = scaffoldState.bottomSheetState.currentValue == SheetValue.PartiallyExpanded && !callControlsState.skipHiddenState)
|
||||||
|
LaunchedEffect(hideSheet) {
|
||||||
|
if (hideSheet) {
|
||||||
|
delay(5.seconds)
|
||||||
|
scaffoldState.bottomSheetState.hide()
|
||||||
|
onControlsToggled(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
|
@ -275,7 +303,9 @@ private fun BoxScope.Viewport(
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (scaffoldState.bottomSheetState.isVisible) {
|
if (scaffoldState.bottomSheetState.isVisible) {
|
||||||
scaffoldState.bottomSheetState.hide()
|
scaffoldState.bottomSheetState.hide()
|
||||||
|
onControlsToggled(false)
|
||||||
} else {
|
} else {
|
||||||
|
onControlsToggled(true)
|
||||||
scaffoldState.bottomSheetState.show()
|
scaffoldState.bottomSheetState.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,17 +347,9 @@ private fun BoxScope.Viewport(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webRtcCallState.inOngoingCall && localParticipant.isVideoEnabled && !isLargeGroupCall) {
|
if (webRtcCallState.inOngoingCall && localParticipant.isVideoEnabled && !isLargeGroupCall) {
|
||||||
val padBottom: Dp = if (scaffoldState.bottomSheetState.isVisible) {
|
|
||||||
0.dp
|
|
||||||
} else {
|
|
||||||
val density = LocalDensity.current
|
|
||||||
with(density) { WindowInsets.navigationBars.getBottom(density).toDp() }
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallMoveableLocalVideoRenderer(
|
SmallMoveableLocalVideoRenderer(
|
||||||
localParticipant = localParticipant,
|
localParticipant = localParticipant,
|
||||||
localRenderState = localRenderState,
|
localRenderState = localRenderState,
|
||||||
extraPadBottom = padBottom,
|
|
||||||
onClick = onPipClick
|
onClick = onPipClick
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -365,12 +387,14 @@ private fun TinyLocalVideoRenderer(
|
||||||
val smallSize = remember(isPortrait) {
|
val smallSize = remember(isPortrait) {
|
||||||
if (isPortrait) DpSize(40.dp, 72.dp) else DpSize(72.dp, 40.dp)
|
if (isPortrait) DpSize(40.dp, 72.dp) else DpSize(72.dp, 40.dp)
|
||||||
}
|
}
|
||||||
val largeSize = remember(isPortrait) {
|
val expandedSize = remember(isPortrait) {
|
||||||
if (isPortrait) DpSize(180.dp, 320.dp) else DpSize(320.dp, 180.dp)
|
if (isPortrait) DpSize(180.dp, 320.dp) else DpSize(320.dp, 180.dp)
|
||||||
}
|
}
|
||||||
|
|
||||||
val width by animateDpAsState(label = "tiny-width", targetValue = if (localRenderState == WebRtcLocalRenderState.EXPANDED) largeSize.width else smallSize.width)
|
val size = if (localRenderState == WebRtcLocalRenderState.EXPANDED) expandedSize else smallSize
|
||||||
val height by animateDpAsState(label = "tiny-height", targetValue = if (localRenderState == WebRtcLocalRenderState.EXPANDED) largeSize.height else smallSize.height)
|
|
||||||
|
val width by animateDpAsState(label = "tiny-width", targetValue = size.width)
|
||||||
|
val height by animateDpAsState(label = "tiny-height", targetValue = size.height)
|
||||||
|
|
||||||
LocalParticipantRenderer(
|
LocalParticipantRenderer(
|
||||||
localParticipant = localParticipant,
|
localParticipant = localParticipant,
|
||||||
|
@ -391,7 +415,6 @@ private fun TinyLocalVideoRenderer(
|
||||||
private fun SmallMoveableLocalVideoRenderer(
|
private fun SmallMoveableLocalVideoRenderer(
|
||||||
localParticipant: CallParticipant,
|
localParticipant: CallParticipant,
|
||||||
localRenderState: WebRtcLocalRenderState,
|
localRenderState: WebRtcLocalRenderState,
|
||||||
extraPadBottom: Dp,
|
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
@ -399,15 +422,14 @@ private fun SmallMoveableLocalVideoRenderer(
|
||||||
val smallSize = remember(isPortrait) {
|
val smallSize = remember(isPortrait) {
|
||||||
if (isPortrait) DpSize(90.dp, 160.dp) else DpSize(160.dp, 90.dp)
|
if (isPortrait) DpSize(90.dp, 160.dp) else DpSize(160.dp, 90.dp)
|
||||||
}
|
}
|
||||||
val largeSize = remember(isPortrait) {
|
val expandedSize = remember(isPortrait) {
|
||||||
if (isPortrait) DpSize(180.dp, 320.dp) else DpSize(320.dp, 180.dp)
|
if (isPortrait) DpSize(180.dp, 320.dp) else DpSize(320.dp, 180.dp)
|
||||||
}
|
}
|
||||||
|
|
||||||
val size = if (localRenderState == WebRtcLocalRenderState.SMALL_RECTANGLE) smallSize else largeSize
|
val size = if (localRenderState == WebRtcLocalRenderState.EXPANDED) expandedSize else smallSize
|
||||||
|
|
||||||
val targetWidth by animateDpAsState(label = "animate-pip-width", targetValue = size.width, animationSpec = tween())
|
val targetWidth by animateDpAsState(label = "animate-pip-width", targetValue = size.width, animationSpec = tween())
|
||||||
val targetHeight by animateDpAsState(label = "animate-pip-height", targetValue = size.height, animationSpec = tween())
|
val targetHeight by animateDpAsState(label = "animate-pip-height", targetValue = size.height, animationSpec = tween())
|
||||||
val bottomPadding by animateDpAsState(label = "animate-pip-bottom-pad", targetValue = extraPadBottom, animationSpec = tween())
|
|
||||||
|
|
||||||
PictureInPicture(
|
PictureInPicture(
|
||||||
contentSize = DpSize(targetWidth, targetHeight),
|
contentSize = DpSize(targetWidth, targetHeight),
|
||||||
|
@ -415,7 +437,6 @@ private fun SmallMoveableLocalVideoRenderer(
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
.statusBarsPadding()
|
.statusBarsPadding()
|
||||||
.padding(bottom = bottomPadding)
|
|
||||||
) {
|
) {
|
||||||
LocalParticipantRenderer(
|
LocalParticipantRenderer(
|
||||||
localParticipant = localParticipant,
|
localParticipant = localParticipant,
|
||||||
|
@ -482,9 +503,11 @@ private fun CallScreenPreview() {
|
||||||
callInfoView = {
|
callInfoView = {
|
||||||
Text(text = "Call Info View Preview", modifier = Modifier.alpha(it))
|
Text(text = "Call Info View Preview", modifier = Modifier.alpha(it))
|
||||||
},
|
},
|
||||||
|
raiseHandSnackbar = {},
|
||||||
onNavigationClick = {},
|
onNavigationClick = {},
|
||||||
onLocalPictureInPictureClicked = {},
|
onLocalPictureInPictureClicked = {},
|
||||||
overflowParticipants = (1..5).map { CallParticipant() }
|
overflowParticipants = emptyList(),
|
||||||
|
onControlsToggled = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalInspectionMode
|
||||||
import androidx.compose.ui.unit.DpSize
|
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
|
||||||
|
@ -47,13 +48,19 @@ fun LocalParticipantRenderer(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val localRecipient = if (LocalInspectionMode.current) {
|
||||||
|
Recipient()
|
||||||
|
} else {
|
||||||
|
localParticipant.recipient
|
||||||
|
}
|
||||||
|
|
||||||
val model = remember {
|
val model = remember {
|
||||||
ProfileContactPhoto(Recipient.self())
|
ProfileContactPhoto(localRecipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val fallback = remember {
|
val fallback = remember {
|
||||||
FallbackAvatarDrawable(context, Recipient.self().getFallbackAvatar())
|
FallbackAvatarDrawable(context, localRecipient.getFallbackAvatar())
|
||||||
}
|
}
|
||||||
|
|
||||||
GlideImage(
|
GlideImage(
|
||||||
|
|
|
@ -91,9 +91,9 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
|
||||||
seen.add(Recipient.self());
|
seen.add(Recipient.self());
|
||||||
|
|
||||||
for (GroupCall.RemoteDeviceState device : remoteDeviceStates) {
|
for (GroupCall.RemoteDeviceState device : remoteDeviceStates) {
|
||||||
Recipient recipient = Recipient.externalPush(ACI.from(device.getUserId()));
|
Recipient recipient = Recipient.externalPush(ACI.from(device.getUserId()));
|
||||||
CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId());
|
CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId());
|
||||||
CallParticipant callParticipant = participants.get(callParticipantId);
|
CallParticipant callParticipant = participants.get(callParticipantId);
|
||||||
|
|
||||||
BroadcastVideoSink videoSink;
|
BroadcastVideoSink videoSink;
|
||||||
VideoTrack videoTrack = device.getVideoTrack();
|
VideoTrack videoTrack = device.getVideoTrack();
|
||||||
|
|
Loading…
Add table
Reference in a new issue