Last active
October 27, 2021 10:28
-
-
Save MikluhaMaclay/32a2ecaac25c022eb915588ede5a4590 to your computer and use it in GitHub Desktop.
Participants pager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@OptIn(ExperimentalPagerApi::class) | |
@Composable | |
fun ParticipantsPager(participants: List<Participant>) { | |
if (participants.isEmpty()) { | |
return | |
} | |
val participantPages = participants.chunked(4) | |
var fullScreenParticipantId by rememberSaveable { | |
mutableStateOf<String?>(null) | |
} | |
val fullScreenLayoutCoordinates = remember { | |
mutableStateOf<LayoutCoordinates?>(null) | |
} | |
val layoutCoordinates = remember { | |
mutableStateOf<LayoutCoordinates?>(null) | |
} | |
Box(Modifier.onGloballyPositioned { | |
layoutCoordinates.value = it | |
}) { | |
HorizontalPager( | |
count = participantPages.size, modifier = Modifier | |
.fillMaxHeight() | |
.fillMaxWidth() | |
) { page -> | |
val participantsPage = participantPages[page] | |
ParticipantsPage(participantsPage, onDoubleTap = { participant, layoutCoordinates -> | |
fullScreenParticipantId = participant.id | |
fullScreenLayoutCoordinates.value = layoutCoordinates | |
}, onGloballyPositioned = { participant, layoutCoordinates -> | |
if (fullScreenParticipantId == participant.id) { | |
fullScreenLayoutCoordinates.value = layoutCoordinates | |
} | |
}) | |
} | |
if (fullScreenParticipantId != null) { | |
FullScreenParticipant( | |
participant = participants.find { it.id == fullScreenParticipantId }!!, | |
coordinates = fullScreenLayoutCoordinates.value, | |
modifier = Modifier | |
.fillMaxSize() | |
.pointerInput(Unit) { | |
detectTapGestures(onDoubleTap = { | |
fullScreenLayoutCoordinates.value = null | |
fullScreenParticipantId = null | |
}) | |
}, | |
parentCoordinates = layoutCoordinates.value | |
) | |
} | |
} | |
} | |
@OptIn(ExperimentalFoundationApi::class) | |
@Composable | |
fun ParticipantsPage( | |
participantsPage: List<Participant>, | |
onDoubleTap: (participant: Participant, layoutCoordinates: LayoutCoordinates?) -> Unit, | |
onGloballyPositioned: (participant: Participant, layoutCoordinates: LayoutCoordinates) -> Unit | |
) { | |
LazyVerticalGrid( | |
cells = GridCells.Fixed(2), modifier = Modifier | |
.fillMaxHeight() | |
.fillMaxWidth() | |
.padding(top = 74.dp, bottom = 79.dp) | |
) { | |
items(participantsPage.size) { | |
val participant = participantsPage[it] | |
val paddingStart = if (it.isEven()) 16 else 2 | |
val paddingEnd = if (!it.isEven()) 16 else 2 | |
val position = remember { | |
mutableStateOf<LayoutCoordinates?>(null) | |
} | |
Participant( | |
participant = participant, | |
modifier = Modifier | |
.pointerInput(Unit) { | |
detectTapGestures( | |
onDoubleTap = { | |
onDoubleTap(participant, position.value) | |
} | |
) | |
} | |
.fillParentMaxSize(0.5f) | |
.padding(start = paddingStart.dp, end = paddingEnd.dp, bottom = 5.dp) | |
.onGloballyPositioned { coordinates -> | |
position.value = coordinates | |
onGloballyPositioned(participant, coordinates) | |
} | |
) | |
} | |
} | |
} | |
@Composable | |
fun FullScreenParticipant( | |
participant: Participant, | |
coordinates: LayoutCoordinates?, | |
parentCoordinates: LayoutCoordinates?, | |
modifier: Modifier = Modifier | |
) { | |
val density = LocalDensity.current.density | |
var height = 0f | |
var width = 0f | |
if (coordinates != null) { | |
height = coordinates.size.height / density | |
width = coordinates.size.width / density | |
} | |
val parentHeight = parentCoordinates!!.size.height / density | |
val parentWidth = parentCoordinates.size.width / density | |
var x = 0f | |
var y = 0f | |
if (coordinates != null) { | |
x = coordinates.positionInRoot().x / density | |
y = coordinates.positionInRoot().y / density | |
} | |
val isVideoStarted = remember { | |
mutableStateOf<Boolean>(!participant.isVideoOn) | |
} | |
val heightToAnimate = if (isVideoStarted.value) parentHeight else height | |
val heightAnimation by animateDpAsState(heightToAnimate.dp) | |
val widthToAnimate = if (isVideoStarted.value) parentWidth else width | |
val widthAnimation by animateDpAsState(widthToAnimate.dp) | |
val xToAnimate = if (isVideoStarted.value) 0f else x | |
val yToAnimate = if (isVideoStarted.value) 0f else y | |
val xAnimation by animateDpAsState(xToAnimate.dp) | |
val yAnimation by animateDpAsState(yToAnimate.dp) | |
Box(modifier = modifier.fillMaxSize()) { | |
AndroidView( | |
factory = { context -> | |
PeerView(context) | |
}, | |
update = { view -> | |
view.setRenderEventsListener(object : PeerView.PeerViewRenderEventsListener { | |
override fun onFirstFrameRender() { | |
isVideoStarted.value = true | |
} | |
}) | |
when (participant) { | |
is LocalParticipant -> { | |
if (participant.isVideoOn) { | |
view.showVideoSource(participant.videoSource!!) | |
} else { | |
view.removeVideoSource() | |
} | |
} | |
is RemoteParticipant -> { | |
if (participant.isVideoOn) { | |
view.showVideoSource(participant.peer.sdkPeer) | |
} else { | |
view.removeVideoSource() | |
} | |
} | |
} | |
}, modifier = Modifier | |
.height(heightAnimation) | |
.width(widthAnimation) | |
.offset(x = xAnimation, y = yAnimation) | |
) | |
} | |
} | |
@Composable | |
fun Participant(participant: Participant, modifier: Modifier = Modifier) { | |
Card( | |
modifier = modifier, | |
backgroundColor = colorResource(R.color.bg_no_video_card), | |
shape = RoundedCornerShape(12.dp) | |
) { | |
Box { | |
AndroidView( | |
factory = { context -> | |
PeerView(context) | |
}, | |
update = { view -> | |
when (participant) { | |
is LocalParticipant -> { | |
if (participant.isVideoOn) { | |
view.showVideoSource(participant.videoSource!!) | |
} else { | |
view.removeVideoSource() | |
} | |
} | |
is RemoteParticipant -> { | |
if (participant.isVideoOn) { | |
view.showVideoSource(participant.peer.sdkPeer) | |
} else { | |
view.removeVideoSource() | |
} | |
} | |
} | |
}, modifier = Modifier.fillMaxSize() | |
) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment