restructure NewPlayerUI and VideoPlayerUI
This commit is contained in:
parent
a222a7c9a0
commit
25593c8ed6
|
@ -53,7 +53,7 @@ import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.model.UIModeState
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
|
@ -62,6 +62,7 @@ import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
||||||
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerControllerUI
|
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerControllerUI
|
||||||
|
import net.newpipe.newplayer.ui.videoplayer.VideoPlayerUi
|
||||||
import net.newpipe.newplayer.utils.LockScreenOrientation
|
import net.newpipe.newplayer.utils.LockScreenOrientation
|
||||||
import net.newpipe.newplayer.utils.getDefaultBrightness
|
import net.newpipe.newplayer.utils.getDefaultBrightness
|
||||||
import net.newpipe.newplayer.utils.setScreenBrightness
|
import net.newpipe.newplayer.utils.setScreenBrightness
|
||||||
|
@ -79,11 +80,6 @@ fun NewPlayerUI(
|
||||||
VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.embeddedUiRatio)
|
VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.embeddedUiRatio)
|
||||||
} else {
|
} else {
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
val exoPlayer by viewModel.newPlayer?.exoPlayer!!.collectAsState()
|
|
||||||
|
|
||||||
var lifecycle by remember {
|
|
||||||
mutableStateOf(Lifecycle.Event.ON_CREATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
val activity = LocalContext.current as Activity
|
val activity = LocalContext.current as Activity
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
@ -93,8 +89,6 @@ fun NewPlayerUI(
|
||||||
windowInsetsController.systemBarsBehavior =
|
windowInsetsController.systemBarsBehavior =
|
||||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
|
||||||
|
|
||||||
val defaultBrightness = getDefaultBrightness(activity)
|
val defaultBrightness = getDefaultBrightness(activity)
|
||||||
|
|
||||||
// Setup fullscreen
|
// Setup fullscreen
|
||||||
|
@ -141,24 +135,6 @@ fun NewPlayerUI(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare stuff for the SurfaceView to which the video will be rendered
|
|
||||||
DisposableEffect(lifecycleOwner) {
|
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
|
||||||
lifecycle = event
|
|
||||||
}
|
|
||||||
lifecycleOwner.lifecycle.addObserver(observer)
|
|
||||||
|
|
||||||
onDispose {
|
|
||||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val displayMetrics = activity.resources.displayMetrics
|
|
||||||
val screenRatio =
|
|
||||||
displayMetrics.widthPixels.toFloat() / displayMetrics.heightPixels.toFloat()
|
|
||||||
|
|
||||||
|
|
||||||
LaunchedEffect(key1 = uiState.brightness) {
|
LaunchedEffect(key1 = uiState.brightness) {
|
||||||
Log.d(TAG, "New Brightnes: ${uiState.brightness}")
|
Log.d(TAG, "New Brightnes: ${uiState.brightness}")
|
||||||
setScreenBrightness(
|
setScreenBrightness(
|
||||||
|
@ -170,48 +146,7 @@ fun NewPlayerUI(
|
||||||
if (uiState.uiMode == UIModeState.PLACEHOLDER) {
|
if (uiState.uiMode == UIModeState.PLACEHOLDER) {
|
||||||
VideoPlayerLoadingPlaceholder(uiState.embeddedUiRatio)
|
VideoPlayerLoadingPlaceholder(uiState.embeddedUiRatio)
|
||||||
} else {
|
} else {
|
||||||
Surface(
|
VideoPlayerUi(viewModel = viewModel, uiState = uiState)
|
||||||
modifier = Modifier.then(
|
|
||||||
if (uiState.uiMode.fullscreen) Modifier.fillMaxSize()
|
|
||||||
else Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.aspectRatio(uiState.embeddedUiRatio)
|
|
||||||
), color = Color.Black
|
|
||||||
) {
|
|
||||||
|
|
||||||
exoPlayer?.let { exoPlayer ->
|
|
||||||
Box(contentAlignment = Alignment.Center) {
|
|
||||||
PlaySurface(
|
|
||||||
player = exoPlayer,
|
|
||||||
lifecycle = lifecycle,
|
|
||||||
fitMode = uiState.contentFitMode,
|
|
||||||
uiRatio = if (uiState.uiMode.fullscreen) screenRatio
|
|
||||||
else uiState.embeddedUiRatio,
|
|
||||||
contentRatio = uiState.contentRatio
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// the checks if VideoPlayerControllerUI should be visible or not are done by
|
|
||||||
// The VideoPlayerControllerUI composable itself. This is because Visibility of
|
|
||||||
// the controller is more complicated than just using a simple if statement.
|
|
||||||
VideoPlayerControllerUI(
|
|
||||||
viewModel, uiState = uiState
|
|
||||||
)
|
|
||||||
|
|
||||||
AnimatedVisibility(visible = uiState.uiMode.isStreamSelect) {
|
|
||||||
StreamSelectUI(
|
|
||||||
viewModel = viewModel,
|
|
||||||
uiState = uiState,
|
|
||||||
isChapterSelect = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AnimatedVisibility(visible = uiState.uiMode.isChapterSelect) {
|
|
||||||
StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.ui.videoplayer
|
package net.newpipe.newplayer.ui.videoplayer
|
||||||
|
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.defaultMinSize
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
|
@ -38,6 +39,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
|
@ -50,6 +52,7 @@ import net.newpipe.newplayer.utils.getInsets
|
||||||
val CONTROLLER_UI_BACKGROUND_COLOR = Color(0x75000000)
|
val CONTROLLER_UI_BACKGROUND_COLOR = Color(0x75000000)
|
||||||
val STREAMSELECT_UI_BACKGROUND_COLOR = Color(0xba000000)
|
val STREAMSELECT_UI_BACKGROUND_COLOR = Color(0xba000000)
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerUI(
|
fun VideoPlayerControllerUI(
|
||||||
viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
||||||
|
@ -136,6 +139,7 @@ fun PreviewBackgroundSurface(
|
||||||
// Preview
|
// Preview
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
@Preview(device = "spec:width=1080px,height=600px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerUIPreviewEmbedded() {
|
fun VideoPlayerControllerUIPreviewEmbedded() {
|
||||||
|
@ -146,6 +150,7 @@ fun VideoPlayerControllerUIPreviewEmbedded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=2340px,height=1080px,dpi=440,orientation=landscape")
|
@Preview(device = "spec:width=2340px,height=1080px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerUIPreviewLandscape() {
|
fun VideoPlayerControllerUIPreviewLandscape() {
|
||||||
|
@ -156,6 +161,7 @@ fun VideoPlayerControllerUIPreviewLandscape() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=2340px,height=1080px,dpi=440,orientation=portrait")
|
@Preview(device = "spec:width=2340px,height=1080px,dpi=440,orientation=portrait")
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerUIPreviewPortrait() {
|
fun VideoPlayerControllerUIPreviewPortrait() {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/* NewPlayer
|
||||||
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
|
*
|
||||||
|
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
|
||||||
|
*
|
||||||
|
* NewPlayer is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPlayer is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.newpipe.newplayer.ui.videoplayer
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.ui.PlaySurface
|
||||||
|
import net.newpipe.newplayer.ui.streamselect.StreamSelectUI
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
@Composable
|
||||||
|
fun VideoPlayerUi(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
|
val exoPlayer by viewModel.newPlayer?.exoPlayer!!.collectAsState()
|
||||||
|
|
||||||
|
var lifecycle by remember {
|
||||||
|
mutableStateOf(Lifecycle.Event.ON_CREATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val activity = LocalContext.current as Activity
|
||||||
|
|
||||||
|
val displayMetrics = activity.resources.displayMetrics
|
||||||
|
|
||||||
|
val screenRatio =
|
||||||
|
displayMetrics.widthPixels.toFloat() / displayMetrics.heightPixels.toFloat()
|
||||||
|
|
||||||
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
|
||||||
|
// Prepare stuff for the SurfaceView to which the video will be rendered
|
||||||
|
DisposableEffect(lifecycleOwner) {
|
||||||
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
|
lifecycle = event
|
||||||
|
}
|
||||||
|
lifecycleOwner.lifecycle.addObserver(observer)
|
||||||
|
|
||||||
|
onDispose {
|
||||||
|
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.then(
|
||||||
|
if (uiState.uiMode.fullscreen) Modifier.fillMaxSize()
|
||||||
|
else Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(uiState.embeddedUiRatio)
|
||||||
|
), color = Color.Black
|
||||||
|
) {
|
||||||
|
|
||||||
|
exoPlayer?.let { exoPlayer ->
|
||||||
|
Box(contentAlignment = Alignment.Center) {
|
||||||
|
PlaySurface(
|
||||||
|
player = exoPlayer,
|
||||||
|
lifecycle = lifecycle,
|
||||||
|
fitMode = uiState.contentFitMode,
|
||||||
|
uiRatio = if (uiState.uiMode.fullscreen) screenRatio
|
||||||
|
else uiState.embeddedUiRatio,
|
||||||
|
contentRatio = uiState.contentRatio
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// the checks if VideoPlayerControllerUI should be visible or not are done by
|
||||||
|
// The VideoPlayerControllerUI composable itself. This is because Visibility of
|
||||||
|
// the controller is more complicated than just using a simple if statement.
|
||||||
|
VideoPlayerControllerUI(
|
||||||
|
viewModel, uiState = uiState
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(visible = uiState.uiMode.isStreamSelect) {
|
||||||
|
StreamSelectUI(
|
||||||
|
viewModel = viewModel,
|
||||||
|
uiState = uiState,
|
||||||
|
isChapterSelect = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AnimatedVisibility(visible = uiState.uiMode.isChapterSelect) {
|
||||||
|
StreamSelectUI(viewModel = viewModel, uiState = uiState, isChapterSelect = true)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue