mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
improve/fix contents for picture in picture mode
depending on amount of participants, voiceOnly call and enabled/disabled own video, the contents of PIP windows are updated. This will be further improved when speaker-view is implemented. Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
eaed93087b
commit
6a048fde08
@ -938,35 +938,17 @@ class CallActivity : CallBaseActivity() {
|
||||
binding!!.pipSelfVideoRenderer.release()
|
||||
}
|
||||
|
||||
private fun initSelfVideoViewForPipMode() {
|
||||
if (!isVoiceOnlyCall) {
|
||||
binding!!.pipSelfVideoRenderer.visibility = View.VISIBLE
|
||||
try {
|
||||
binding!!.pipSelfVideoRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
} catch (e: IllegalStateException) {
|
||||
Log.d(TAG, "pipGroupVideoRenderer already initialized", e)
|
||||
}
|
||||
binding!!.pipSelfVideoRenderer.setZOrderMediaOverlay(true)
|
||||
// disabled because it causes some devices to crash
|
||||
binding!!.pipSelfVideoRenderer.setEnableHardwareScaler(false)
|
||||
binding!!.pipSelfVideoRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
|
||||
localVideoTrack?.addSink(binding?.pipSelfVideoRenderer)
|
||||
} else {
|
||||
binding!!.pipSelfVideoRenderer.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun initGrid() {
|
||||
Log.d(TAG, "initGrid")
|
||||
|
||||
binding!!.composeParticipantGrid.visibility = View.VISIBLE
|
||||
binding!!.composeParticipantGrid.setContent {
|
||||
MaterialTheme {
|
||||
val participantUiStates = participantItems.map { it.uiStateFlow.collectAsState().value }
|
||||
ParticipantGrid(
|
||||
participantUiStates = participantUiStates,
|
||||
eglBase = rootEglBase!!,
|
||||
isVoiceOnlyCall = isVoiceOnlyCall
|
||||
isVoiceOnlyCall = isVoiceOnlyCall,
|
||||
isInPipMode = isInPipMode
|
||||
) {
|
||||
animateCallControls(true, 0)
|
||||
}
|
||||
@ -3206,33 +3188,38 @@ class CallActivity : CallBaseActivity() {
|
||||
|
||||
override fun updateUiForPipMode() {
|
||||
Log.d(TAG, "updateUiForPipMode")
|
||||
val params = RelativeLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
params.setMargins(0, 0, 0, 0)
|
||||
binding!!.composeParticipantGrid.layoutParams = params
|
||||
binding!!.callControls.visibility = View.GONE
|
||||
binding!!.callInfosLinearLayout.visibility = View.GONE
|
||||
binding!!.selfVideoViewWrapper.visibility = View.GONE
|
||||
binding!!.callStates.callStateRelativeLayout.visibility = View.GONE
|
||||
binding!!.pipCallConversationNameTextView.text = conversationName
|
||||
|
||||
if (isVoiceOnlyCall) {
|
||||
if (participantItems.size > 1) {
|
||||
binding!!.pipOverlay.visibility = View.VISIBLE
|
||||
binding!!.pipSelfVideoRenderer.visibility = View.GONE
|
||||
} else {
|
||||
binding!!.pipOverlay.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
binding!!.selfVideoRenderer.clearImage()
|
||||
binding!!.selfVideoRenderer.release()
|
||||
if (participantItems.size > 1) {
|
||||
binding!!.pipOverlay.visibility = View.VISIBLE
|
||||
initSelfVideoViewForPipMode()
|
||||
} else {
|
||||
|
||||
if (participantItems.size == 1) {
|
||||
binding!!.pipOverlay.visibility = View.GONE
|
||||
} else {
|
||||
binding!!.composeParticipantGrid.visibility = View.GONE
|
||||
|
||||
if (localVideoTrack?.enabled() == true) {
|
||||
binding!!.pipOverlay.visibility = View.VISIBLE
|
||||
binding!!.pipSelfVideoRenderer.visibility = View.VISIBLE
|
||||
|
||||
try {
|
||||
binding!!.pipSelfVideoRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
} catch (e: IllegalStateException) {
|
||||
Log.d(TAG, "pipGroupVideoRenderer already initialized", e)
|
||||
}
|
||||
binding!!.pipSelfVideoRenderer.setZOrderMediaOverlay(true)
|
||||
// disabled because it causes some devices to crash
|
||||
binding!!.pipSelfVideoRenderer.setEnableHardwareScaler(false)
|
||||
binding!!.pipSelfVideoRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
|
||||
localVideoTrack?.addSink(binding?.pipSelfVideoRenderer)
|
||||
} else {
|
||||
binding!!.pipOverlay.visibility = View.VISIBLE
|
||||
binding!!.pipSelfVideoRenderer.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3240,6 +3227,7 @@ class CallActivity : CallBaseActivity() {
|
||||
override fun updateUiForNormalMode() {
|
||||
Log.d(TAG, "updateUiForNormalMode")
|
||||
binding!!.pipOverlay.visibility = View.GONE
|
||||
binding!!.composeParticipantGrid.visibility = View.VISIBLE
|
||||
|
||||
if (isVoiceOnlyCall) {
|
||||
binding!!.callControls.visibility = View.VISIBLE
|
||||
|
@ -10,7 +10,6 @@ package com.nextcloud.talk.call.components
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -19,7 +18,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
import com.nextcloud.talk.adapters.ParticipantUiState
|
||||
@ -34,7 +32,6 @@ fun AvatarWithFallback(participant: ParticipantUiState, modifier: Modifier = Mod
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(150.dp)
|
||||
.clip(CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
|
@ -29,12 +29,14 @@ import com.nextcloud.talk.adapters.ParticipantUiState
|
||||
import org.webrtc.EglBase
|
||||
import kotlin.math.ceil
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun ParticipantGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
eglBase: EglBase?,
|
||||
participantUiStates: List<ParticipantUiState>,
|
||||
isVoiceOnlyCall: Boolean,
|
||||
isInPipMode: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val configuration = LocalConfiguration.current
|
||||
@ -58,7 +60,7 @@ fun ParticipantGrid(
|
||||
|
||||
val rows = ceil(participantUiStates.size / columns.toFloat()).toInt()
|
||||
|
||||
val heightForNonGridComponents = if (isVoiceOnlyCall) {
|
||||
val heightForNonGridComponents = if (isVoiceOnlyCall && !isInPipMode) {
|
||||
// this is a workaround for now. It should ~summarize the height of callInfosLinearLayout and callControls
|
||||
// Once everything is migrated to jetpack, this workaround should be obsolete or solved in a better way
|
||||
240.dp
|
||||
@ -97,6 +99,7 @@ fun ParticipantGrid(
|
||||
.height(itemHeight)
|
||||
.fillMaxWidth(),
|
||||
eglBase = eglBase,
|
||||
isInPipMode = isInPipMode,
|
||||
isVoiceOnlyCall = isVoiceOnlyCall
|
||||
)
|
||||
}
|
||||
@ -109,7 +112,8 @@ fun ParticipantGridPreview() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(1),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -119,7 +123,8 @@ fun TwoParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(2),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -129,7 +134,8 @@ fun ThreeParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(3),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -139,7 +145,8 @@ fun FourParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(4),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -149,7 +156,8 @@ fun FiveParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(5),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -159,7 +167,8 @@ fun SevenParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(7),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -169,7 +178,8 @@ fun FiftyParticipants() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(50),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -183,7 +193,8 @@ fun OneParticipantLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(1),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -197,7 +208,8 @@ fun TwoParticipantsLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(2),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -211,7 +223,8 @@ fun ThreeParticipantsLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(3),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -225,7 +238,8 @@ fun FourParticipantsLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(4),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -239,7 +253,8 @@ fun SevenParticipantsLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(7),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -253,7 +268,8 @@ fun FiftyParticipantsLandscape() {
|
||||
ParticipantGrid(
|
||||
participantUiStates = getTestParticipants(50),
|
||||
eglBase = null,
|
||||
isVoiceOnlyCall = false
|
||||
isVoiceOnlyCall = false,
|
||||
isInPipMode = false
|
||||
) {}
|
||||
}
|
||||
|
||||
|
@ -36,10 +36,12 @@ import org.webrtc.EglBase
|
||||
const val NICK_OFFSET = 4f
|
||||
const val NICK_BLUR_RADIUS = 4f
|
||||
|
||||
@Suppress("Detekt.LongMethod")
|
||||
@Composable
|
||||
fun ParticipantTile(
|
||||
participantUiState: ParticipantUiState,
|
||||
eglBase: EglBase?,
|
||||
isInPipMode: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
isVoiceOnlyCall: Boolean
|
||||
) {
|
||||
@ -53,9 +55,17 @@ fun ParticipantTile(
|
||||
if (!isVoiceOnlyCall && participantUiState.isStreamEnabled && participantUiState.mediaStream != null) {
|
||||
WebRTCVideoView(participantUiState, eglBase)
|
||||
} else {
|
||||
val avatarSize = if (isInPipMode) {
|
||||
100.dp
|
||||
} else {
|
||||
150.dp
|
||||
}
|
||||
|
||||
AvatarWithFallback(
|
||||
participant = participantUiState,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(avatarSize)
|
||||
)
|
||||
}
|
||||
|
||||
@ -125,6 +135,7 @@ fun ParticipantTilePreview() {
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
eglBase = null,
|
||||
isInPipMode = false,
|
||||
isVoiceOnlyCall = false
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user