[feat] Video Player lock
This commit is contained in:
@@ -60,13 +60,18 @@ import androidx.compose.material.icons.filled.Brightness4
|
|||||||
import androidx.compose.material.icons.filled.FastForward
|
import androidx.compose.material.icons.filled.FastForward
|
||||||
import androidx.compose.material.icons.filled.Fullscreen
|
import androidx.compose.material.icons.filled.Fullscreen
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material.icons.filled.Lock
|
||||||
|
import androidx.compose.material.icons.filled.LockOpen
|
||||||
import androidx.compose.material.icons.filled.Share
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.material.icons.filled.Star
|
import androidx.compose.material.icons.filled.Star
|
||||||
import androidx.compose.material.icons.filled.ThumbDown
|
import androidx.compose.material.icons.filled.ThumbDown
|
||||||
import androidx.compose.material.icons.filled.ThumbUp
|
import androidx.compose.material.icons.filled.ThumbUp
|
||||||
import androidx.compose.material.icons.filled.VolumeUp
|
import androidx.compose.material.icons.filled.VolumeUp
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardColors
|
import androidx.compose.material3.CardColors
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.DividerDefaults
|
import androidx.compose.material3.DividerDefaults
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
@@ -92,6 +97,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInteropFilter
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
@@ -230,7 +236,9 @@ fun SubtitleOverlay(
|
|||||||
cornerRadius: Dp = 6.dp,
|
cornerRadius: Dp = 6.dp,
|
||||||
textColor: Color = Color.White
|
textColor: Color = Color.White
|
||||||
) {
|
) {
|
||||||
val raw = if (cues.isEmpty()) "" else cues.joinToString(separator = "\n") { it.text?.toString() ?: "" }.trim()
|
val raw = if (cues.isEmpty()) "" else cues.joinToString(separator = "\n") {
|
||||||
|
it.text?.toString() ?: ""
|
||||||
|
}.trim()
|
||||||
if (raw.isEmpty()) return
|
if (raw.isEmpty()) return
|
||||||
|
|
||||||
val textAlign = when (cues.firstOrNull()?.textAlignment) {
|
val textAlign = when (cues.firstOrNull()?.textAlignment) {
|
||||||
@@ -281,15 +289,45 @@ fun VideoPlayer(
|
|||||||
videoId: String,
|
videoId: String,
|
||||||
navController: NavHostController
|
navController: NavHostController
|
||||||
) {
|
) {
|
||||||
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
videoPlayerViewModel.init(videoId)
|
videoPlayerViewModel.init(videoId)
|
||||||
|
|
||||||
if(videoPlayerViewModel.startPlaying)
|
if (videoPlayerViewModel.startPlaying) {
|
||||||
{
|
|
||||||
if (isLandscape()) {
|
if (isLandscape()) {
|
||||||
|
Box {
|
||||||
VideoPlayerLandscape(videoPlayerViewModel)
|
VideoPlayerLandscape(videoPlayerViewModel)
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = videoPlayerViewModel.locked || videoPlayerViewModel.planeVisibility,
|
||||||
|
enter = fadeIn(
|
||||||
|
initialAlpha = 0f,
|
||||||
|
),
|
||||||
|
exit = fadeOut(
|
||||||
|
targetAlpha = 0f
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterEnd)
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.padding(4.dp),
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = colorScheme.primary.copy(
|
||||||
|
if (videoPlayerViewModel.locked) 0.2f else 1f
|
||||||
|
)
|
||||||
|
),
|
||||||
|
onClick = {
|
||||||
|
videoPlayerViewModel.locked = !videoPlayerViewModel.locked
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (videoPlayerViewModel.locked) Icons.Default.LockOpen else Icons.Default.Lock,
|
||||||
|
contentDescription = "Lock",
|
||||||
|
tint = Color.White.copy(if (videoPlayerViewModel.locked) 0.2f else 1f),
|
||||||
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.padding(6.dp)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
|
} else {
|
||||||
VideoPlayerPortal(videoPlayerViewModel, navController)
|
VideoPlayerPortal(videoPlayerViewModel, navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,15 +335,18 @@ fun VideoPlayer(
|
|||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel, cover: Float)
|
fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel, cover: Float) {
|
||||||
{
|
|
||||||
val exoPlayer: ExoPlayer = videoPlayerViewModel._player!!;
|
val exoPlayer: ExoPlayer = videoPlayerViewModel._player!!;
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val activity = context as? Activity
|
val activity = context as? Activity
|
||||||
|
|
||||||
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
|
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
|
||||||
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
|
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
|
||||||
var volFactor by remember { mutableFloatStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()) }
|
var volFactor by remember {
|
||||||
|
mutableFloatStateOf(
|
||||||
|
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun setVolume(value: Int) {
|
fun setVolume(value: Int) {
|
||||||
audioManager.setStreamVolume(
|
audioManager.setStreamVolume(
|
||||||
@@ -335,10 +376,10 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
detectDragGestures(
|
detectDragGestures(
|
||||||
onDragStart = { offset ->
|
onDragStart = { offset ->
|
||||||
if(offset.x < size.width / 2)
|
if (videoPlayerViewModel.locked) return@detectDragGestures
|
||||||
{
|
if (offset.x < size.width / 2) {
|
||||||
videoPlayerViewModel.draggingPurpose = -1;
|
videoPlayerViewModel.draggingPurpose = -1;
|
||||||
}else{
|
} else {
|
||||||
videoPlayerViewModel.draggingPurpose = -2;
|
videoPlayerViewModel.draggingPurpose = -2;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -349,31 +390,36 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
videoPlayerViewModel.draggingPurpose = -1;
|
videoPlayerViewModel.draggingPurpose = -1;
|
||||||
},
|
},
|
||||||
onDrag = { change, dragAmount ->
|
onDrag = { change, dragAmount ->
|
||||||
if(abs(dragAmount.x) > abs(dragAmount.y) &&
|
if (videoPlayerViewModel.locked) return@detectDragGestures
|
||||||
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2))
|
if (abs(dragAmount.x) > abs(dragAmount.y) &&
|
||||||
{
|
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2)
|
||||||
|
) {
|
||||||
videoPlayerViewModel.draggingPurpose = 0
|
videoPlayerViewModel.draggingPurpose = 0
|
||||||
videoPlayerViewModel.planeVisibility = true
|
videoPlayerViewModel.planeVisibility = true
|
||||||
exoPlayer.pause()
|
exoPlayer.pause()
|
||||||
}
|
} else if (videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose =
|
||||||
else if(videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose = 1
|
1
|
||||||
else if(videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose = 2
|
else if (videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose =
|
||||||
|
2
|
||||||
|
|
||||||
if(videoPlayerViewModel.draggingPurpose == 0)
|
if (videoPlayerViewModel.draggingPurpose == 0) {
|
||||||
{
|
|
||||||
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
|
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
|
||||||
videoPlayerViewModel.playProcess = exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
|
videoPlayerViewModel.playProcess =
|
||||||
}else if(videoPlayerViewModel.draggingPurpose == 2)
|
exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
|
||||||
{
|
} else if (videoPlayerViewModel.draggingPurpose == 2) {
|
||||||
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
volFactor = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
|
volFactor = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
if(dragAmount.y < 0)
|
.toFloat() / maxVolume.toFloat()
|
||||||
setVolume( cu + 1);
|
if (dragAmount.y < 0)
|
||||||
else if(dragAmount.y > 0)
|
setVolume(cu + 1);
|
||||||
setVolume( cu - 1);
|
else if (dragAmount.y > 0)
|
||||||
}else if(videoPlayerViewModel.draggingPurpose == 1)
|
setVolume(cu - 1);
|
||||||
{
|
} else if (videoPlayerViewModel.draggingPurpose == 1) {
|
||||||
videoPlayerViewModel.brit = (videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(0f, 1f);
|
videoPlayerViewModel.brit =
|
||||||
|
(videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
);
|
||||||
|
|
||||||
activity?.window?.attributes = activity.window.attributes.apply {
|
activity?.window?.attributes = activity.window.attributes.apply {
|
||||||
screenBrightness = videoPlayerViewModel.brit.coerceIn(0f, 1f)
|
screenBrightness = videoPlayerViewModel.brit.coerceIn(0f, 1f)
|
||||||
@@ -387,14 +433,17 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
detectTapGestures(
|
detectTapGestures(
|
||||||
onDoubleTap = {
|
onDoubleTap = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
videoPlayerViewModel.isPlaying = !videoPlayerViewModel.isPlaying
|
videoPlayerViewModel.isPlaying = !videoPlayerViewModel.isPlaying
|
||||||
if (videoPlayerViewModel.isPlaying) exoPlayer.play() else exoPlayer.pause()
|
if (videoPlayerViewModel.isPlaying) exoPlayer.play() else exoPlayer.pause()
|
||||||
},
|
},
|
||||||
onTap = {
|
onTap = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
videoPlayerViewModel.planeVisibility =
|
videoPlayerViewModel.planeVisibility =
|
||||||
!videoPlayerViewModel.planeVisibility
|
!videoPlayerViewModel.planeVisibility
|
||||||
},
|
},
|
||||||
onLongPress = {
|
onLongPress = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
videoPlayerViewModel.isLongPressing = true
|
videoPlayerViewModel.isLongPressing = true
|
||||||
exoPlayer.playbackParameters = exoPlayer.playbackParameters
|
exoPlayer.playbackParameters = exoPlayer.playbackParameters
|
||||||
.withSpeed(3.0f)
|
.withSpeed(3.0f)
|
||||||
@@ -419,19 +468,29 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
.align(Alignment.TopCenter)
|
.align(Alignment.TopCenter)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Box(modifier = Modifier.align(Alignment.TopCenter).padding(top = 24.dp).background(Color(0x44000000), RoundedCornerShape(18)))
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.padding(top = 24.dp)
|
||||||
|
.background(Color(0x44000000), RoundedCornerShape(18))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Row{
|
Row {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.FastForward,
|
imageVector = Icons.Filled.FastForward,
|
||||||
contentDescription = "Fast Forward",
|
contentDescription = "Fast Forward",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(36.dp).padding(4.dp).align(Alignment.CenterVertically)
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "3X Speed...",
|
text = "3X Speed...",
|
||||||
modifier = Modifier.padding(4.dp).align(Alignment.CenterVertically),
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color(0xFFFFFFFF)
|
color = Color(0xFFFFFFFF)
|
||||||
@@ -474,13 +533,17 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
|
Row(Modifier
|
||||||
|
.background(Color(0x88000000), RoundedCornerShape(18))
|
||||||
|
.width(200.dp))
|
||||||
{
|
{
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
|
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
|
||||||
contentDescription = "Vol",
|
contentDescription = "Vol",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(48.dp).padding(8.dp)
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(8.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
BiliMiniSlider(
|
BiliMiniSlider(
|
||||||
@@ -505,13 +568,17 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
|
Row(Modifier
|
||||||
|
.background(Color(0x88000000), RoundedCornerShape(18))
|
||||||
|
.width(200.dp))
|
||||||
{
|
{
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Brightness4,
|
imageVector = Icons.Default.Brightness4,
|
||||||
contentDescription = "Brightness",
|
contentDescription = "Brightness",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(48.dp).padding(8.dp)
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(8.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
BiliMiniSlider(
|
BiliMiniSlider(
|
||||||
@@ -525,18 +592,22 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cover > 0.0f)
|
if (cover > 0.0f)
|
||||||
Spacer(Modifier.background(MaterialTheme.colorScheme.primary.copy(cover)).fillMaxSize())
|
Spacer(Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.primary.copy(cover))
|
||||||
|
.fillMaxSize())
|
||||||
|
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
visible = !videoPlayerViewModel.planeVisibility,
|
visible = (!videoPlayerViewModel.planeVisibility) || videoPlayerViewModel.locked,
|
||||||
enter = fadeIn(
|
enter = fadeIn(
|
||||||
initialAlpha = 0f,
|
initialAlpha = 0f,
|
||||||
),
|
),
|
||||||
exit = fadeOut(
|
exit = fadeOut(
|
||||||
targetAlpha = 0f
|
targetAlpha = 0f
|
||||||
),
|
),
|
||||||
modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
) {
|
) {
|
||||||
BiliMiniSlider(
|
BiliMiniSlider(
|
||||||
value = videoPlayerViewModel.playProcess,
|
value = videoPlayerViewModel.playProcess,
|
||||||
@@ -548,26 +619,31 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
visible = videoPlayerViewModel.planeVisibility,
|
visible = videoPlayerViewModel.planeVisibility && (!videoPlayerViewModel.locked),
|
||||||
enter = fadeIn(
|
enter = fadeIn(
|
||||||
initialAlpha = 0f,
|
initialAlpha = 0f,
|
||||||
),
|
),
|
||||||
exit = fadeOut(
|
exit = fadeOut(
|
||||||
targetAlpha = 0f
|
targetAlpha = 0f
|
||||||
),
|
),
|
||||||
modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter).height(42.dp)
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.height(42.dp)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.align(Alignment.BottomCenter).background(
|
.align(Alignment.BottomCenter)
|
||||||
|
.background(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
Color.Black.copy(alpha = 0.4f),
|
Color.Black.copy(alpha = 0.4f),
|
||||||
)
|
)
|
||||||
)),
|
)
|
||||||
|
),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -636,13 +712,16 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController: NavHostController)
|
fun VideoPlayerPortal(
|
||||||
{
|
videoPlayerViewModel: VideoPlayerViewModel,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
val screenHeight = configuration.screenHeightDp.dp;
|
val screenHeight = configuration.screenHeightDp.dp;
|
||||||
|
|
||||||
val minHeight = 42.dp
|
val minHeight = 42.dp
|
||||||
var coverAlpha by remember{ mutableFloatStateOf(0.0f) }
|
var coverAlpha by remember { mutableFloatStateOf(0.0f) }
|
||||||
var maxHeight = remember { screenHeight * 0.65f }
|
var maxHeight = remember { screenHeight * 0.65f }
|
||||||
var posed = remember { false }
|
var posed = remember { false }
|
||||||
val dens = LocalDensity.current
|
val dens = LocalDensity.current
|
||||||
@@ -662,7 +741,7 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
playerHeight = newHeight
|
playerHeight = newHeight
|
||||||
val consumedPx = with(dens) { consumedDp.toPx() }
|
val consumedPx = with(dens) { consumedDp.toPx() }
|
||||||
Offset(0f, consumedPx)
|
Offset(0f, consumedPx)
|
||||||
} else if(deltaY > 0 && playerHeight < maxHeight && listState.firstVisibleItemIndex == 0 && listState.firstVisibleItemScrollOffset == 0) {
|
} else if (deltaY > 0 && playerHeight < maxHeight && listState.firstVisibleItemIndex == 0 && listState.firstVisibleItemScrollOffset == 0) {
|
||||||
val newHeight = (playerHeight + deltaDp).coerceIn(minHeight, maxHeight)
|
val newHeight = (playerHeight + deltaDp).coerceIn(minHeight, maxHeight)
|
||||||
val consumedDp = newHeight - playerHeight
|
val consumedDp = newHeight - playerHeight
|
||||||
playerHeight = newHeight
|
playerHeight = newHeight
|
||||||
@@ -673,7 +752,7 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
val dh = playerHeight - minHeight;
|
val dh = playerHeight - minHeight;
|
||||||
coverAlpha = (if(dh > 10.dp)
|
coverAlpha = (if (dh > 10.dp)
|
||||||
0f
|
0f
|
||||||
else
|
else
|
||||||
(10.dp.value - dh.value) / 10.0f)
|
(10.dp.value - dh.value) / 10.0f)
|
||||||
@@ -684,25 +763,60 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToggleFullScreen(false)
|
ToggleFullScreen(false)
|
||||||
Column(Modifier.nestedScroll(nestedScrollConnection).fillMaxHeight())
|
Column(Modifier
|
||||||
|
.nestedScroll(nestedScrollConnection)
|
||||||
|
.fillMaxHeight())
|
||||||
{
|
{
|
||||||
|
Box {
|
||||||
PortalCorePlayer(
|
PortalCorePlayer(
|
||||||
Modifier
|
Modifier
|
||||||
.padding(top = 42.dp)
|
.padding(top = 32.dp)
|
||||||
.heightIn(max = playerHeight)
|
.heightIn(max = playerHeight)
|
||||||
.onGloballyPositioned { layoutCoordinates ->
|
.onGloballyPositioned { layoutCoordinates ->
|
||||||
if(!posed && videoPlayerViewModel.renderedFirst)
|
if (!posed && videoPlayerViewModel.renderedFirst) {
|
||||||
{
|
maxHeight = with(dens) { layoutCoordinates.size.height.toDp() }
|
||||||
maxHeight = with(dens) {layoutCoordinates.size.height.toDp()}
|
|
||||||
playerHeight = maxHeight
|
playerHeight = maxHeight
|
||||||
posed = true
|
posed = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
videoPlayerViewModel = videoPlayerViewModel, coverAlpha)
|
videoPlayerViewModel = videoPlayerViewModel, coverAlpha
|
||||||
|
)
|
||||||
|
|
||||||
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
|
visible = videoPlayerViewModel.locked || videoPlayerViewModel.planeVisibility,
|
||||||
|
enter = fadeIn(
|
||||||
|
initialAlpha = 0f,
|
||||||
|
),
|
||||||
|
exit = fadeOut(
|
||||||
|
targetAlpha = 0f
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterEnd)
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.padding(4.dp),
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = colorScheme.primary.copy(
|
||||||
|
if (videoPlayerViewModel.locked) 0.2f else 1f
|
||||||
|
)
|
||||||
|
),
|
||||||
|
onClick = {
|
||||||
|
videoPlayerViewModel.locked = !videoPlayerViewModel.locked
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (videoPlayerViewModel.locked) Icons.Default.LockOpen else Icons.Default.Lock,
|
||||||
|
contentDescription = "Lock",
|
||||||
|
tint = Color.White.copy(if (videoPlayerViewModel.locked) 0.2f else 1f),
|
||||||
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.padding(6.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row()
|
Row()
|
||||||
{
|
{
|
||||||
TabRow (
|
TabRow(
|
||||||
selectedTabIndex = videoPlayerViewModel.tabIndex,
|
selectedTabIndex = videoPlayerViewModel.tabIndex,
|
||||||
modifier = Modifier.height(38.dp)
|
modifier = Modifier.height(38.dp)
|
||||||
) {
|
) {
|
||||||
@@ -723,16 +837,22 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(state = listState, modifier = Modifier.fillMaxWidth()) {
|
LazyColumn(state = listState, modifier = Modifier.fillMaxWidth()) {
|
||||||
item{
|
item {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.align(Alignment.Start).padding(horizontal = 12.dp).padding(top = 12.dp),
|
modifier = Modifier
|
||||||
|
.align(Alignment.Start)
|
||||||
|
.padding(horizontal = 12.dp)
|
||||||
|
.padding(top = 12.dp),
|
||||||
text = videoPlayerViewModel.video?.video?.name ?: "",
|
text = videoPlayerViewModel.video?.video?.name ?: "",
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(Modifier.align(Alignment.Start).padding(horizontal = 4.dp).alpha(0.5f)) {
|
Row(Modifier
|
||||||
|
.align(Alignment.Start)
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.alpha(0.5f)) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp),
|
modifier = Modifier.padding(horizontal = 8.dp),
|
||||||
text = videoPlayerViewModel.video?.klass ?: "",
|
text = videoPlayerViewModel.video?.klass ?: "",
|
||||||
@@ -752,16 +872,20 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
|
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
||||||
|
|
||||||
SocialPanel(Modifier.align(Alignment.CenterHorizontally).fillMaxWidth(), videoPlayerViewModel = videoPlayerViewModel)
|
SocialPanel(
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
videoPlayerViewModel = videoPlayerViewModel
|
||||||
|
)
|
||||||
|
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
||||||
|
|
||||||
HorizontalGallery(videoPlayerViewModel)
|
HorizontalGallery(videoPlayerViewModel)
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
HorizontalDivider(Modifier.padding(vertical = 8.dp), 1.dp, DividerDefaults.color)
|
||||||
|
|
||||||
for(i in Global.sameClassVideos ?: listOf())
|
for (i in Global.sameClassVideos ?: listOf()) {
|
||||||
{
|
if (i.id == videoPlayerViewModel.video?.id) continue
|
||||||
if(i.id == videoPlayerViewModel.video?.id) continue
|
|
||||||
|
|
||||||
MiniVideoCard(
|
MiniVideoCard(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -770,10 +894,17 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
{
|
{
|
||||||
videoPlayerViewModel.isPlaying = false
|
videoPlayerViewModel.isPlaying = false
|
||||||
videoPlayerViewModel._player?.pause()
|
videoPlayerViewModel._player?.pause()
|
||||||
val route = "video_player_route/${ "${i.klass}/${i.id}".toHex() }"
|
val route = "video_player_route/${"${i.klass}/${i.id}".toHex()}"
|
||||||
navController.navigate(route)
|
navController.navigate(route)
|
||||||
}, videoPlayerViewModel.imageLoader!!)
|
}, videoPlayerViewModel.imageLoader!!
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp).alpha(0.25f), 1.dp, DividerDefaults.color)
|
)
|
||||||
|
HorizontalDivider(
|
||||||
|
Modifier
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
.alpha(0.25f),
|
||||||
|
1.dp,
|
||||||
|
DividerDefaults.color
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,8 +912,7 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel) {
|
||||||
{
|
|
||||||
val colorScheme = MaterialTheme.colorScheme
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
Row(
|
Row(
|
||||||
modifier,
|
modifier,
|
||||||
@@ -792,7 +922,10 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { },
|
onClick = { },
|
||||||
modifier = Modifier.padding(horizontal = 4.dp).align(Alignment.CenterHorizontally).size(36.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.size(36.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
@@ -807,13 +940,17 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
text = videoPlayerViewModel.thumbUp.toString(),
|
text = videoPlayerViewModel.thumbUp.toString(),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontWeight = FontWeight.Bold)
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { },
|
onClick = { },
|
||||||
modifier = Modifier.padding(horizontal = 4.dp).align(Alignment.CenterHorizontally).size(36.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.size(36.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
@@ -828,19 +965,23 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
text = videoPlayerViewModel.thumbDown.toString(),
|
text = videoPlayerViewModel.thumbDown.toString(),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontWeight = FontWeight.Bold)
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { videoPlayerViewModel.star = !videoPlayerViewModel.star },
|
onClick = { videoPlayerViewModel.star = !videoPlayerViewModel.star },
|
||||||
modifier = Modifier.padding(horizontal = 4.dp).align(Alignment.CenterHorizontally).size(36.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.size(36.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
imageVector = Icons.Filled.Star,
|
imageVector = Icons.Filled.Star,
|
||||||
contentDescription = "Star",
|
contentDescription = "Star",
|
||||||
tint = if(videoPlayerViewModel.star) colorScheme.primary else Color.Gray
|
tint = if (videoPlayerViewModel.star) colorScheme.primary else Color.Gray
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -848,7 +989,10 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { },
|
onClick = { },
|
||||||
modifier = Modifier.padding(horizontal = 4.dp).align(Alignment.CenterHorizontally).size(36.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.size(36.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
@@ -862,7 +1006,10 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 12.dp)) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { },
|
onClick = { },
|
||||||
modifier = Modifier.padding(horizontal = 4.dp).align(Alignment.CenterHorizontally).size(36.dp),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.size(36.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
@@ -876,10 +1023,11 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HorizontalGallery(videoPlayerViewModel: VideoPlayerViewModel)
|
fun HorizontalGallery(videoPlayerViewModel: VideoPlayerViewModel) {
|
||||||
{
|
|
||||||
LazyRow(
|
LazyRow(
|
||||||
modifier = Modifier.fillMaxWidth().height(120.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
contentPadding = PaddingValues(horizontal = 24.dp)
|
contentPadding = PaddingValues(horizontal = 24.dp)
|
||||||
) {
|
) {
|
||||||
@@ -908,15 +1056,18 @@ fun SingleImageItem(img: KeyImage, imageLoader: ImageLoader) {
|
|||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
|
||||||
{
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val activity = context as? Activity
|
val activity = context as? Activity
|
||||||
val exoPlayer: ExoPlayer = videoPlayerViewModel._player!!;
|
val exoPlayer: ExoPlayer = videoPlayerViewModel._player!!;
|
||||||
|
|
||||||
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
|
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
|
||||||
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
|
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
|
||||||
var volFactor by remember { mutableFloatStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()) }
|
var volFactor by remember {
|
||||||
|
mutableFloatStateOf(
|
||||||
|
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun setVolume(value: Int) {
|
fun setVolume(value: Int) {
|
||||||
audioManager.setStreamVolume(
|
audioManager.setStreamVolume(
|
||||||
@@ -935,7 +1086,8 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
{
|
{
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(Color.Black).align(Alignment.Center)
|
.background(Color.Black)
|
||||||
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AndroidView(
|
AndroidView(
|
||||||
@@ -955,10 +1107,10 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
detectDragGestures(
|
detectDragGestures(
|
||||||
onDragStart = { offset ->
|
onDragStart = { offset ->
|
||||||
if(offset.x < size.width / 2)
|
if (videoPlayerViewModel.locked) return@detectDragGestures
|
||||||
{
|
if (offset.x < size.width / 2) {
|
||||||
videoPlayerViewModel.draggingPurpose = -1;
|
videoPlayerViewModel.draggingPurpose = -1;
|
||||||
}else{
|
} else {
|
||||||
videoPlayerViewModel.draggingPurpose = -2;
|
videoPlayerViewModel.draggingPurpose = -2;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -969,34 +1121,42 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
videoPlayerViewModel.draggingPurpose = -1;
|
videoPlayerViewModel.draggingPurpose = -1;
|
||||||
},
|
},
|
||||||
onDrag = { change, dragAmount ->
|
onDrag = { change, dragAmount ->
|
||||||
if(abs(dragAmount.x) > abs(dragAmount.y) &&
|
if (videoPlayerViewModel.locked) return@detectDragGestures
|
||||||
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2))
|
if (abs(dragAmount.x) > abs(dragAmount.y) &&
|
||||||
{
|
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2)
|
||||||
|
) {
|
||||||
videoPlayerViewModel.draggingPurpose = 0
|
videoPlayerViewModel.draggingPurpose = 0
|
||||||
videoPlayerViewModel.planeVisibility = true
|
videoPlayerViewModel.planeVisibility = true
|
||||||
exoPlayer.pause()
|
exoPlayer.pause()
|
||||||
}
|
} else if (videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose =
|
||||||
else if(videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose = 1
|
1
|
||||||
else if(videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose = 2
|
else if (videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose =
|
||||||
|
2
|
||||||
|
|
||||||
if(videoPlayerViewModel.draggingPurpose == 0)
|
if (videoPlayerViewModel.draggingPurpose == 0) {
|
||||||
{
|
|
||||||
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
|
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
|
||||||
videoPlayerViewModel.playProcess = exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
|
videoPlayerViewModel.playProcess =
|
||||||
}else if(videoPlayerViewModel.draggingPurpose == 2)
|
exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
|
||||||
{
|
} else if (videoPlayerViewModel.draggingPurpose == 2) {
|
||||||
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
volFactor = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
|
volFactor =
|
||||||
if(dragAmount.y < 0)
|
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
setVolume( cu + 1);
|
.toFloat() / maxVolume.toFloat()
|
||||||
else if(dragAmount.y > 0)
|
if (dragAmount.y < 0)
|
||||||
setVolume( cu - 1);
|
setVolume(cu + 1);
|
||||||
}else if(videoPlayerViewModel.draggingPurpose == 1)
|
else if (dragAmount.y > 0)
|
||||||
{
|
setVolume(cu - 1);
|
||||||
videoPlayerViewModel.brit = (videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(0f, 1f);
|
} else if (videoPlayerViewModel.draggingPurpose == 1) {
|
||||||
|
videoPlayerViewModel.brit =
|
||||||
|
(videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
);
|
||||||
|
|
||||||
activity?.window?.attributes = activity.window.attributes.apply {
|
activity?.window?.attributes =
|
||||||
screenBrightness = videoPlayerViewModel.brit.coerceIn(0f, 1f)
|
activity.window.attributes.apply {
|
||||||
|
screenBrightness =
|
||||||
|
videoPlayerViewModel.brit.coerceIn(0f, 1f)
|
||||||
}
|
}
|
||||||
activity?.window?.setAttributes(activity.window.attributes)
|
activity?.window?.setAttributes(activity.window.attributes)
|
||||||
}
|
}
|
||||||
@@ -1007,14 +1167,20 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
detectTapGestures(
|
detectTapGestures(
|
||||||
onDoubleTap = {
|
onDoubleTap = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
|
|
||||||
videoPlayerViewModel.isPlaying = !videoPlayerViewModel.isPlaying
|
videoPlayerViewModel.isPlaying = !videoPlayerViewModel.isPlaying
|
||||||
if (videoPlayerViewModel.isPlaying) exoPlayer.play() else exoPlayer.pause()
|
if (videoPlayerViewModel.isPlaying) exoPlayer.play() else exoPlayer.pause()
|
||||||
},
|
},
|
||||||
onTap = {
|
onTap = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
|
|
||||||
videoPlayerViewModel.planeVisibility =
|
videoPlayerViewModel.planeVisibility =
|
||||||
!videoPlayerViewModel.planeVisibility
|
!videoPlayerViewModel.planeVisibility
|
||||||
},
|
},
|
||||||
onLongPress = {
|
onLongPress = {
|
||||||
|
if (videoPlayerViewModel.locked) return@detectTapGestures
|
||||||
|
|
||||||
videoPlayerViewModel.isLongPressing = true
|
videoPlayerViewModel.isLongPressing = true
|
||||||
exoPlayer.playbackParameters = exoPlayer.playbackParameters
|
exoPlayer.playbackParameters = exoPlayer.playbackParameters
|
||||||
.withSpeed(3.0f)
|
.withSpeed(3.0f)
|
||||||
@@ -1065,13 +1231,17 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
|
Row(Modifier
|
||||||
|
.background(Color(0x88000000), RoundedCornerShape(18))
|
||||||
|
.width(200.dp))
|
||||||
{
|
{
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
|
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
|
||||||
contentDescription = "Vol",
|
contentDescription = "Vol",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(48.dp).padding(8.dp)
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(8.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
BiliMiniSlider(
|
BiliMiniSlider(
|
||||||
@@ -1096,13 +1266,17 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
|
Row(Modifier
|
||||||
|
.background(Color(0x88000000), RoundedCornerShape(18))
|
||||||
|
.width(200.dp))
|
||||||
{
|
{
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Brightness4,
|
imageVector = Icons.Default.Brightness4,
|
||||||
contentDescription = "Brightness",
|
contentDescription = "Brightness",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(48.dp).padding(8.dp)
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(8.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
BiliMiniSlider(
|
BiliMiniSlider(
|
||||||
@@ -1124,19 +1298,29 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
.align(Alignment.TopCenter)
|
.align(Alignment.TopCenter)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Box(modifier = Modifier.align(Alignment.TopCenter).padding(top = 24.dp).background(Color(0x44000000), RoundedCornerShape(18)))
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.padding(top = 24.dp)
|
||||||
|
.background(Color(0x44000000), RoundedCornerShape(18))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Row{
|
Row {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.FastForward,
|
imageVector = Icons.Filled.FastForward,
|
||||||
contentDescription = "Fast Forward",
|
contentDescription = "Fast Forward",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(36.dp).padding(4.dp).align(Alignment.CenterVertically)
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "3X Speed...",
|
text = "3X Speed...",
|
||||||
modifier = Modifier.padding(4.dp).align(Alignment.CenterVertically),
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color(0xFFFFFFFF)
|
color = Color(0xFFFFFFFF)
|
||||||
@@ -1146,7 +1330,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = videoPlayerViewModel.planeVisibility,
|
visible = videoPlayerViewModel.planeVisibility && (!videoPlayerViewModel.locked),
|
||||||
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
|
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
|
||||||
exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }),
|
exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -1154,21 +1338,28 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Row(Modifier
|
Row(
|
||||||
|
Modifier
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
.padding(horizontal = 32.dp).background(
|
.padding(horizontal = 42.dp)
|
||||||
|
.background(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(
|
||||||
Color.Black.copy(alpha = 0.4f),
|
Color.Black.copy(alpha = 0.4f),
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
)
|
)
|
||||||
)))
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
activity?.requestedOrientation =
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
},
|
},
|
||||||
modifier = Modifier.size(36.dp).align(Alignment.CenterVertically)
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(36.dp),
|
modifier = Modifier.size(36.dp),
|
||||||
@@ -1181,14 +1372,16 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
Text(
|
Text(
|
||||||
text = "${videoPlayerViewModel.video?.video?.name}",
|
text = "${videoPlayerViewModel.video?.video?.name}",
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = Modifier.padding(horizontal = 12.dp).align(Alignment.CenterVertically),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 12.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = videoPlayerViewModel.planeVisibility,
|
visible = videoPlayerViewModel.planeVisibility && (!videoPlayerViewModel.locked),
|
||||||
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }),
|
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }),
|
||||||
exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight }),
|
exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight }),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -1200,12 +1393,14 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomCenter)
|
.align(Alignment.BottomCenter)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background( brush = Brush.verticalGradient(
|
.background(
|
||||||
|
brush = Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
Color.Black.copy(alpha = 0.4f)
|
Color.Black.copy(alpha = 0.4f)
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
.padding(horizontal = 36.dp)
|
.padding(horizontal = 36.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -1223,7 +1418,10 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
onValueChange = { value ->
|
onValueChange = { value ->
|
||||||
exoPlayer.seekTo((exoPlayer.duration * value).toLong())
|
exoPlayer.seekTo((exoPlayer.duration * value).toLong())
|
||||||
},
|
},
|
||||||
modifier = Modifier.height(16.dp).fillMaxWidth().padding(bottom = 8.dp)
|
modifier = Modifier
|
||||||
|
.height(16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 8.dp)
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -1259,11 +1457,12 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MiniVideoCard(modifier: Modifier, video: Video, onClick: () -> Unit, imageLoader: ImageLoader)
|
fun MiniVideoCard(modifier: Modifier, video: Video, onClick: () -> Unit, imageLoader: ImageLoader) {
|
||||||
{
|
|
||||||
var isImageLoaded by remember { mutableStateOf(false) }
|
var isImageLoaded by remember { mutableStateOf(false) }
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier.height(80.dp).fillMaxWidth(),
|
modifier = modifier
|
||||||
|
.height(80.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
colors = CardColors(
|
colors = CardColors(
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
contentColor = MaterialTheme.colorScheme.onSurface,
|
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
@@ -1288,14 +1487,19 @@ fun MiniVideoCard(modifier: Modifier, video: Video, onClick: () -> Unit, imageLo
|
|||||||
.build(),
|
.build(),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(128.dp).fillMaxHeight()
|
.width(128.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
.clip(RoundedCornerShape(8.dp)),
|
.clip(RoundedCornerShape(8.dp)),
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
imageLoader = imageLoader
|
imageLoader = imageLoader
|
||||||
)
|
)
|
||||||
|
|
||||||
Column (
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp).fillMaxHeight().fillMaxWidth().align(Alignment.CenterVertically),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class VideoPlayerViewModel @Inject constructor(
|
|||||||
var thumbUp by mutableIntStateOf(0)
|
var thumbUp by mutableIntStateOf(0)
|
||||||
var thumbDown by mutableIntStateOf(0)
|
var thumbDown by mutableIntStateOf(0)
|
||||||
var star by mutableStateOf(false)
|
var star by mutableStateOf(false)
|
||||||
|
var locked by mutableStateOf(false)
|
||||||
private var _init: Boolean = false;
|
private var _init: Boolean = false;
|
||||||
var startPlaying by mutableStateOf(false)
|
var startPlaying by mutableStateOf(false)
|
||||||
var renderedFirst = false
|
var renderedFirst = false
|
||||||
|
|||||||
Reference in New Issue
Block a user