Skip to content

Instantly share code, notes, and snippets.

@skydoves
Last active February 23, 2023 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skydoves/ac7cf43b970c0df13e918130b2d2f11e to your computer and use it in GitHub Desktop.
Save skydoves/ac7cf43b970c0df13e918130b2d2f11e to your computer and use it in GitHub Desktop.
floating_video_renderer
// Copyright 2023 Stream.IO, Inc. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
@Composable
fun FloatingVideoRenderer(
videoTrack: VideoTrack,
parentBounds: IntSize,
paddingValues: PaddingValues,
modifier: Modifier = Modifier
) {
var videoSize by remember { mutableStateOf(IntSize(0, 0)) }
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
val offset by animateOffsetAsState(targetValue = Offset(offsetX, offsetY))
val density = LocalDensity.current
LaunchedEffect(parentBounds.width) {
offsetX = 0f
offsetY = 0f
}
val paddingOffset = density.run { 16.dp.toPx() }
Card(
elevation = 8.dp,
modifier = Modifier
.offset { IntOffset(offset.x.toInt(), offset.y.toInt()) }
.pointerInput(parentBounds) {
detectDragGestures { change, dragAmount ->
change.consume()
val newOffsetX = (offsetX + dragAmount.x)
.coerceAtLeast(
-calculateHorizontalOffsetBounds(
parentBounds = parentBounds,
paddingValues = paddingValues,
floatingVideoSize = videoSize,
density = density,
offset = paddingOffset * 2
)
)
.coerceAtMost(
0f
)
val newOffsetY = (offsetY + dragAmount.y)
.coerceAtLeast(0f)
.coerceAtMost(
calculateVerticalOffsetBounds(
parentBounds = parentBounds,
paddingValues = paddingValues,
floatingVideoSize = videoSize,
density = density,
offset = paddingOffset * 2
)
)
offsetX = newOffsetX
offsetY = newOffsetY
}
}
.then(modifier)
.padding(16.dp)
.onGloballyPositioned { videoSize = it.size },
shape = RoundedCornerShape(16.dp)
) {
VideoRenderer(
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(16.dp)),
videoTrack = videoTrack
)
}
}
private fun calculateHorizontalOffsetBounds(
parentBounds: IntSize,
paddingValues: PaddingValues,
floatingVideoSize: IntSize,
density: Density,
offset: Float
): Float {
val rightPadding =
density.run { paddingValues.calculateRightPadding(LayoutDirection.Ltr).toPx() }
return parentBounds.width - rightPadding - floatingVideoSize.width - offset
}
private fun calculateVerticalOffsetBounds(
parentBounds: IntSize,
paddingValues: PaddingValues,
floatingVideoSize: IntSize,
density: Density,
offset: Float
): Float {
val bottomPadding =
density.run { paddingValues.calculateBottomPadding().toPx() }
return parentBounds.height - bottomPadding - floatingVideoSize.height - offset
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment