mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-23 19:26:50 +00:00
feat(player): enhance video aspect ratio handling and resize mode logic
This commit is contained in:
@@ -12,7 +12,6 @@ import androidx.compose.animation.slideOutHorizontally
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
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
|
||||||
@@ -24,6 +23,7 @@ import androidx.compose.material.icons.outlined.VolumeUp
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
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
|
||||||
@@ -39,6 +39,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.VideoSize
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.ui.AspectRatioFrameLayout
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
@@ -61,6 +63,7 @@ import kotlin.math.abs
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
private const val CONTROLS_VISIBLE_SUBTITLE_BOTTOM_PADDING_FRACTION = 0.32f
|
private const val CONTROLS_VISIBLE_SUBTITLE_BOTTOM_PADDING_FRACTION = 0.32f
|
||||||
|
private const val WIDE_VIDEO_ASPECT_RATIO = 16f / 9f
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -80,12 +83,25 @@ fun PlayerScreen(
|
|||||||
var showQueuePanel by remember { mutableStateOf(false) }
|
var showQueuePanel by remember { mutableStateOf(false) }
|
||||||
var horizontalSeekFeedback by remember { mutableStateOf<Long?>(null) }
|
var horizontalSeekFeedback by remember { mutableStateOf<Long?>(null) }
|
||||||
var horizontalSeekPreviewPositionMs by remember { mutableStateOf<Long?>(null) }
|
var horizontalSeekPreviewPositionMs by remember { mutableStateOf<Long?>(null) }
|
||||||
|
var videoAspectRatio by remember { mutableStateOf(calculateVideoAspectRatio(viewModel.player.videoSize)) }
|
||||||
val overlayController = rememberPersistentOverlayController()
|
val overlayController = rememberPersistentOverlayController()
|
||||||
|
|
||||||
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
||||||
viewModel.pausePlayback()
|
viewModel.pausePlayback()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DisposableEffect(viewModel.player) {
|
||||||
|
val listener = object : Player.Listener {
|
||||||
|
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||||
|
videoAspectRatio = calculateVideoAspectRatio(videoSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewModel.player.addListener(listener)
|
||||||
|
onDispose {
|
||||||
|
viewModel.player.removeListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(uiState.isPlaying) {
|
LaunchedEffect(uiState.isPlaying) {
|
||||||
if (uiState.isPlaying) {
|
if (uiState.isPlaying) {
|
||||||
showQueuePanel = false
|
showQueuePanel = false
|
||||||
@@ -93,6 +109,7 @@ fun PlayerScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val playerControlsVisible = controlsVisible || uiState.isEnded || uiState.error != null
|
val playerControlsVisible = controlsVisible || uiState.isEnded || uiState.error != null
|
||||||
|
val playerResizeMode = playerResizeMode(videoAspectRatio)
|
||||||
val subtitleBottomPaddingFraction =
|
val subtitleBottomPaddingFraction =
|
||||||
if (playerControlsVisible) {
|
if (playerControlsVisible) {
|
||||||
CONTROLS_VISIBLE_SUBTITLE_BOTTOM_PADDING_FRACTION
|
CONTROLS_VISIBLE_SUBTITLE_BOTTOM_PADDING_FRACTION
|
||||||
@@ -109,18 +126,18 @@ fun PlayerScreen(
|
|||||||
factory = { ctx ->
|
factory = { ctx ->
|
||||||
PlayerView(ctx).apply {
|
PlayerView(ctx).apply {
|
||||||
useController = false
|
useController = false
|
||||||
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
|
resizeMode = playerResizeMode
|
||||||
player = viewModel.player
|
player = viewModel.player
|
||||||
subtitleView?.setBottomPaddingFraction(subtitleBottomPaddingFraction)
|
subtitleView?.setBottomPaddingFraction(subtitleBottomPaddingFraction)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update = {
|
update = {
|
||||||
it.player = viewModel.player
|
it.player = viewModel.player
|
||||||
|
it.resizeMode = playerResizeMode
|
||||||
it.subtitleView?.setBottomPaddingFraction(subtitleBottomPaddingFraction)
|
it.subtitleView?.setBottomPaddingFraction(subtitleBottomPaddingFraction)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxSize()
|
||||||
.align(Alignment.Center)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
PlayerGesturesLayer(
|
PlayerGesturesLayer(
|
||||||
@@ -294,6 +311,21 @@ fun PlayerScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun playerResizeMode(videoAspectRatio: Float): Int =
|
||||||
|
if (videoAspectRatio >= WIDE_VIDEO_ASPECT_RATIO) {
|
||||||
|
AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||||
|
} else {
|
||||||
|
AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateVideoAspectRatio(videoSize: VideoSize): Float {
|
||||||
|
if (videoSize.width <= 0 || videoSize.height <= 0) {
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
return videoSize.width * videoSize.pixelWidthHeightRatio / videoSize.height
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HiddenSeekTimeline(
|
private fun HiddenSeekTimeline(
|
||||||
positionMs: Long,
|
positionMs: Long,
|
||||||
|
|||||||
Reference in New Issue
Block a user